From 2345c8662928b0484a3faa5f085e6c425046c297 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Madar=C3=A1sz?= Date: Mon, 17 May 2021 18:05:22 +0200 Subject: [PATCH] texed stack ops + few new assets :) --- art/dirt.ecotex | Bin 0 -> 359 bytes art/gen/dirt.h | 837 + art/gen/dirt.png | Bin 0 -> 5819 bytes art/rock.ecotex | Bin 0 -> 122 bytes art/tile.ecotex | Bin 0 -> 177 bytes code/game/source/editors/texed.c | 30 +- code/game/source/editors/texed_ops.c | 205 + code/game/source/editors/texed_ops_list.c | 54 + code/vendors/librg.h | 35216 ++++++++++---------- code/vendors/zpl.h | 33421 ++++++++++--------- 10 files changed, 35439 insertions(+), 34324 deletions(-) create mode 100644 art/dirt.ecotex create mode 100644 art/gen/dirt.h create mode 100644 art/gen/dirt.png create mode 100644 art/rock.ecotex create mode 100644 art/tile.ecotex diff --git a/art/dirt.ecotex b/art/dirt.ecotex new file mode 100644 index 0000000000000000000000000000000000000000..a34c933117f179e762607ced8e8e49cf7c23efcb GIT binary patch literal 359 zcmZutOAdlC5G7$@q8lZigUrCtmYsa;4fF_}$EX~jy0GUMcb>t+SfF4;-)qul-s_uA z!_{-s?Dnr93LbpE3UbRHJeJHSgExrNIgg_502p_Nzok? zAtb_*L=9W5Tlb&HpOP-SF4CwWkd#E_0!6!n)sup6{y7)le0Ov4e$V>WC>N#kIsO~~0Qeb- zxmm6o`rlzQUEk(4Up@o?kv3zle92e2`SI?3W7BVTTnDJZl@kR>p&EHV@h(*-nas8S z{j$DhZpHgWmmM?Yu?^zTnKHh}L?M_*n+9)gwe z3Vq2}-$O#3myOB@XFbss;ksHHt&!;j@LxW=JR!46nKi>iObmJ_>~BL7wNRv(-g@NE z%8%M0!A<~QZoC8z%PW+K?LPDNRr{4TbnxNjkA8kgxgQQlW94b!#eaJn{3gae+_LhP z+_zG9MHh$F#(i`PZzy#CXM~I5L!p7%iD4$cVRgRDE zqck$xnHky}lvwDwyznd~f4|{C!{bz0HS~6D;$86CYG0Z6_K(BgV&CX%De5UZ#yyO! zNFh3c-kH!n*I8bsdIo#NfS;X}FZLjLc=8Tr?>M(8L?H-g-WKMa8v{mp&i^P+VexUY zIaoycWE1>1krP8JVNuEx*QL;n$8=J$!Y0y!@F}X-bWBZPR`%nk1>`8!Z9$KW#0d8}L zlF4)6Rq)wo#?{Dk`R0(-G~)*-zV$Hl1+AAmqy6(a(hqD&Ol@aBC&7*pHko zdy^@2sMXtuh zBgvdrnp)sE3i_*k$VIRp@I-f?b*%OQy_8EHf8<-Brf+r2wzl18d(wNkr9$#s#~x*Qc%nQq zsK_}1$TxS5h+A3*~dEd|gM0%FwI^F$}b;Y^Lte4be*cFL6w3U|YX zrQDW1NFPhGKJFZp40JvNOOaZ3ELZdjOjPXcn@r@+J7Z8yU`hV!D9Hw7UDf3-E!Fvz z(SVfW`3%uv^6{`w6OJ)tW|YxH^DdNaGoe%l;P?%^1g7hnm%|}f0Y^5`D5x`B@Iby` zG}PqY&}Mm=Uoo!5U{Y=0GI)ZOL~ZnQ%Hdo}Ul9C|=?C04d>!FJdB1gN@{a00l{Fu;M5sTOmQajJPikC z6NfncDK3Th1RKPfw({3?Yn`>U;D?@75fM05Ewn91WHGQeJz5Q3+l^5?!=yZrWnWOS zf$MP!u!w*Nm2t8>Lu_f{mL_M4MMe_i?b?R>l450X6+^JQ+TvY*OSR4)&xJ3t>OVE+ zhF%!1%@52zjpgyx9^_HbU~87*&yaPMunBc&3%p^6HJS0mUKg$iGKaI0Ji`SgfwoXU z9VzX^?r4))$5flKyX0nTtA`?$JZ;hnXKzKFP(SJbdbv~XHy|0Tx%LGacp9EAuYfH; z-tlL0*hc4iskz8n+zzc(dZwSDsxGjlx3op-GNVC7p|;$rJx3)!mA$h!tKep|`<)5Z zp74ho=%v$7{eoZ}(-a=&_IWo2O=FL8_PoT`^`AEwmbC&Ft^ zPg{*%x97bKKEI6B%I!~q|6ugc^aWw?W=6LsPx;Ef=^LtMa_a*yE(bXT1@Up3{8Egw zm_EA)3E^nK%;}P*&}FMhhQRzn7&}Rws1TCVl-(T7)9+t?^dlPFNJjqJ+U9wJFEO5a?!*U__D(BXHJ8pT&w9W%%c@LNg)x8%CEF3FLpPPcOsofSLJ2-*#I6uTcy z5iR-2){b-MD%-&y{h%-AObbBze5Bs?tgxSI_pPkc@(g{c%D3o&2@=!h9@0u_-B&@o zJc=sHF`bNZNPYRym^@w~bj%@&MQWk>=Xu#&4NFr==@9@;hJp+i`wml_lM4r4iOrGJ z2JTK@D;wm=>?3SaGV1eZwt zwtk{}_!p zU&D(7>USdoy&vZ`E0!iw$kMHj4--DOKLa}GZqNdw=l*j` zcb$a?tul2_Yy4t0Ahg)Crb@e1QPln%1C(P(9Lt?3&5Ft z3*d+2zS5I&3N<BqzZ0+Nq^ck}M-4 zVCm!8I(qHZ$6dq88XJ=nh^HfcfK;X`^ABg`>GFim4Nj_OICJM3xSR1CcSvHkGA@iF zF~aCEyk({m3jLe)dR1CLG8os@vH_Ow3XGDPwDddCR5xw99{X1)DhAWBd-qJ$x6&KC zsv>3?ugaOF(A6i_ax{Mj$g&QF(Y&l#KCXFw6W|2sQTinJ_Udllqr21|e=u%BK1*S; zG8(W!0o*`a*iG#9KbARq3pIbsXqVso-2~6sJi{!jS{g#W*of0qG@g6vL_YKhw|=91 zZ`G#El(c7{D#P2$N>qDE-e8WZ19QNXa!;T1L!C}lHSca)C_nKG`?l~lH`XVyn!P|z zM)^7gC;#mFA%#R=cFknWwbzNsTF?$rXeFezF3eF&gmYuLme)F|Fiz;A-}i#f6!Mxl z`wcdT9*7_s`IBf(hVEgoRQ1-H6)E+`2HQkm5t}KBBfq9;Kctd!QtwLw@Ic69AGk)i zYbiccU8Z~=a+twQ##zX}!Sz9SzQSv!fE_&xVgySMpw}bRDdvYPhF7Lw_6qclHH)4p zsE@!)rYhg6FmKKD+UMKg$JA>aDG&Do&d44uen2EM0uUgHxj#@96znpWVua!r7uXQ7DJmuYl*U)PhVQD@&Z7$jX-3Ia&Bc z`R2AF#RsgGvgE&}@7!GyGsZm<#O&~wL_)eMg25-R1=P=VrBJ8Plh*BTQdaRZQHM=5 z$K=K6+_kEUnG8K4kLWw%!~0#4z1AiSd;u^(=||llt0UHYU;cxSQ{`+FoC^?jk(4(2 zuteg7j4Uiq#EsAB9W>HUb~T5D03ML#f_ta6S2Q^9kNy({({;8O6IFvNv6#~ z?`63REX6$ffxFJ8y@R#O<0UA**vpYhXoYHK>$sFqyJfw97CcH%3V)%?qgZwWdT=N( z*&MNB^MVwuqJI~5-3wVhr_A8vKnA-XQsc<&?HHs1o*&O!`tJ&EfbyEGCGe{Jz-JqA6 zbE{vw-adxkJb};Vb=qbAYJrA3NquE{QOl&28rmGHC5TdI*prUlm2JTsu7v*d_`3w; zA3cLpz5-DDtQ`af6X7HJH9&-YdRMsaYbuh#7Ci-%oXLAuw%Mtir0Kdm|3-0@%D#%A zy6+E#`rEPs9G{W}oXk`gogZkFQoDn8BJ{2z&iodg2PlFyWy8Yd+tGv9uyANEBZ->$ z!vy2>`S~|Rg#J?^ZIWe*Zs~L)%eVd#Qs%RN3=fDR86xs5aWYW~sYb1s+h9J*$u%|* zX`=c)c*`en8Fh-JHXw`qv}}V2)r(1ulC2#ArTwZHbg&FRF|e&1K0>{Q)q!SI+d%7d zu@c!>PcvB&s}$Z2>MD5Z&L0-B3scHDbH(nAd35u)R8Q7l*n3vqH0cE^ zXE|)K(W5)$F1y+Z&Z|87fO;1WE~<%=w1>QjRvZ13*4X?(qJr7-4{~}oKAUKEt1n0T z*ybzHw8ynAxp=;+sV`yU9sl~BP`oQS<$!Vc3L~!wC}f$fh1h|&;6j8!GyjYxc?ATE z781TJKi;8{{~33ou3e>{LfVM^`oI?OOI!>;WF&bew$VLlH+<#QKYQrnz|vJ|B_bt9 z|Avu!?8TR;SM#a-dhpUKiyTgw_YNTQW&5n06l0jGOgz`_A4iyh#K4(5x%oOOKj~ZD zm0+lepOoEz|NLa2Z;~{}{(Mv9!2QrnVNpiP&t-&{+YoEi81a*T)u!~?6$?OG?cr18 zUTqmuG)(LVe!InycBo3%yK2?iu<0;`2xIU=lm6139hKbulhrq z+nS4&&FC9h19EOUkuXBMo^5;z>4PrE$q%^#1dK-wIv(rV@T`e@fvxx7&Q&P5jN#~5U%NASza+LZasJ9i(+J3LVT{v zKCyHD!;}KytcUUXTs*`eYfTxMDGFx=K)Q}l$7{lh_RUgi<}JEM9+|)Bq-hEE^&99c z^QnDw6cp<2Yjby@_i5Y;<2aG#<(kt8Nb@L44pUrx(jQ@hoi?g#1D5?nchVw%GN2Dv z@Vvr6AsWbw?o-8+zmY+c@vEvAO#EN`9#;EUcsn`597K%`u&kp*zp179W`Cm{WLap= z6gd1#(>g0cO=4z0x4T++y!?<#pzn)z^@nKpcBUV1F>82+lz=Gu+&yjnFd-1`7HZ<9 zUC4)O0fXYl?ENcEswlK$}eO6u4U7HNG>+=&OiR@On_n zYq=Orn2#^ag^%i2cDS+%M~u&w-2yx9oNVLlNB2;_R+C#&9daV2bt^O&48L`=Q74K1 z7)bCWSI*y3_RB|*LCpNXJs-ubt4b(P*{{nCR$jG!prmnphHH_SPyr3Kdz~WM+_PWW z2bnL2#<&>?vWw7&Ph)?ga3eh{3;`MmL literal 0 HcmV?d00001 diff --git a/art/rock.ecotex b/art/rock.ecotex new file mode 100644 index 0000000000000000000000000000000000000000..2fef605fff155f38dd83af9dfeddbe22b23e07cb GIT binary patch literal 122 zcmZQ(J>{^t&vF{W;X{)bnVA65iZmz?ICN;zLc=8ndM2h^hv2eqU|?V<1e9H5XtdCT s`_Q4O3k@J}g`2aRxtqDADLYVbg@K;AF$e$|rUpi)K%*g=-P}N`0hhQfc>n+a literal 0 HcmV?d00001 diff --git a/art/tile.ecotex b/art/tile.ecotex new file mode 100644 index 0000000000000000000000000000000000000000..30ef886108ef971b9137ddc195a1bea52d10cf29 GIT binary patch literal 177 zcmZQ(KjqNCz%Yy9@S(|z%uIl2g{!HHxuc1j8`mMYP#P2n96B^hXv!i(Gay=F?q=?2>gwjU!T<_H4jr0+ IVg<|z03GQparams, sizeof(td_param)*dop->num_params); - zpl_array_append(ctx.ops, op); - ctx.selected_op = zpl_array_count(ctx.ops)-1; + //TODO(zaklaus): weird stuff down there + //zpl_array_append_at(ctx.ops, op, ctx.selected_op+1); + int ind = ctx.selected_op+1; + do { + if (ind >= zpl_array_count(ctx.ops)) { zpl_array_append(ctx.ops, op); break; } + if (zpl_array_capacity(ctx.ops) < zpl_array_count(ctx.ops) + 1) zpl_array_grow(ctx.ops, 0); + zpl_memmove(&(ctx.ops)[ind + 1], (ctx.ops + ind), zpl_size_of(td_op) * (zpl_array_count(ctx.ops) - ind)); + ctx.ops[ind] = op; + zpl_array_count(ctx.ops)++; + } while (0); + ctx.selected_op++; texed_repaint_preview(); } diff --git a/code/game/source/editors/texed_ops.c b/code/game/source/editors/texed_ops.c index b8ad33b..3f0710d 100644 --- a/code/game/source/editors/texed_ops.c +++ b/code/game/source/editors/texed_ops.c @@ -1,6 +1,12 @@ static inline float texed_map_value(float v, float min, float max); +static inline +Image texed_generate_noise(uint32_t seed, int width, int height, float factor); + +static inline +Image texed_generate_cellular(uint32_t seed, int width, int height, int tileSize); + void texed_process_ops(void) { for (int i = 0; i <= ctx.img_pos; i+=1) UnloadImage(ctx.img[i]); @@ -23,6 +29,14 @@ void texed_process_ops(void) { op->params[3].i32, op->params[4].color); }break; + case TOP_IMAGE_ALPHA_MASK: { + if (ctx.img_pos == 0) break; + + Image *oi = &ctx.img[ctx.img_pos]; + Image *di = &ctx.img[ctx.img_pos-1]; + ImageAlphaMask(di, *oi); + ctx.img_pos--; + }break; case TOP_DRAW_RECT: { ImageDrawRectangle(&ctx.img[ctx.img_pos], op->params[0].i32, @@ -114,6 +128,86 @@ void texed_process_ops(void) { ImageColorGrayscale(&ctx.img[ctx.img_pos]); } }break; + case TOP_COLOR_REPLACE: { + ImageColorReplace(&ctx.img[ctx.img_pos], op->params[0].color, op->params[1].color); + }break; + case TOP_IMAGE_GRAD_V: { + Image *dst = &ctx.img[ctx.img_pos]; + int w = dst->width; + int h = dst->height; + Image img = GenImageGradientV(w, h, op->params[0].color, op->params[1].color); + Rectangle rec = {0, 0, w, h}; + ImageDraw(dst, img, rec, rec, WHITE); + UnloadImage(img); + }break; + case TOP_IMAGE_GRAD_H: { + Image *dst = &ctx.img[ctx.img_pos]; + int w = dst->width; + int h = dst->height; + Image img = GenImageGradientH(w, h, op->params[0].color, op->params[1].color); + Rectangle rec = {0, 0, w, h}; + ImageDraw(dst, img, rec, rec, WHITE); + UnloadImage(img); + }break; + case TOP_IMAGE_GRAD_RAD: { + Image *dst = &ctx.img[ctx.img_pos]; + int w = dst->width; + int h = dst->height; + Image img = GenImageGradientRadial(w, h, + op->params[0].flt, + op->params[1].color, + op->params[2].color); + Rectangle rec = {0, 0, w, h}; + ImageDraw(dst, img, rec, rec, WHITE); + UnloadImage(img); + }break; + case TOP_IMAGE_CHECKED: { + Image *dst = &ctx.img[ctx.img_pos]; + int w = dst->width; + int h = dst->height; + Image img = GenImageChecked(w, h, + op->params[0].i32, + op->params[1].i32, + op->params[2].color, + op->params[3].color); + Rectangle rec = {0, 0, w, h}; + ImageDraw(dst, img, rec, rec, WHITE); + UnloadImage(img); + }break; + case TOP_IMAGE_NOISE_WHITE: { + Image *dst = &ctx.img[ctx.img_pos]; + int w = dst->width; + int h = dst->height; + Image img = texed_generate_noise(op->params[0].u32, + w, h, + op->params[1].flt); + Rectangle rec = {0, 0, w, h}; + ImageDraw(dst, img, rec, rec, WHITE); + UnloadImage(img); + }break; + case TOP_IMAGE_NOISE_PERLIN: { + Image *dst = &ctx.img[ctx.img_pos]; + int w = dst->width; + int h = dst->height; + Image img = GenImagePerlinNoise(w, h, + op->params[0].i32, + op->params[1].i32, + op->params[2].flt); + Rectangle rec = {0, 0, w, h}; + ImageDraw(dst, img, rec, rec, WHITE); + UnloadImage(img); + }break; + case TOP_IMAGE_CELLULAR: { + Image *dst = &ctx.img[ctx.img_pos]; + int w = dst->width; + int h = dst->height; + Image img = texed_generate_cellular(op->params[0].u32, + w, h, + op->params[1].i32); + Rectangle rec = {0, 0, w, h}; + ImageDraw(dst, img, rec, rec, WHITE); + UnloadImage(img); + }break; default: { zpl_printf("%s\n", "unsupported op!"); }break; @@ -156,4 +250,115 @@ static inline float texed_map_value(float v, float min, float max) { float slope = max-min; return min + zpl_round(slope * v); +} + +/* This algorithm is mentioned in the ISO C standard, here extended + for 32 bits. */ +static inline +int _rand_r(unsigned int *seed) { + unsigned int next = *seed; + int result; + + next *= 1103515245; + next += 12345; + result = (unsigned int) (next / 65536) % 2048; + + next *= 1103515245; + next += 12345; + result <<= 10; + result ^= (unsigned int) (next / 65536) % 1024; + + next *= 1103515245; + next += 12345; + result <<= 10; + result ^= (unsigned int) (next / 65536) % 1024; + + *seed = next; + + return result; +} + +static inline +Image texed_generate_noise(uint32_t seed, int width, int height, float factor) { + Color *pixels = (Color *)RL_MALLOC(width*height*sizeof(Color)); + + for (int i = 0; i < width*height; i++) { + if ((_rand_r(&seed)%99) < (int)(factor*100.0f)) pixels[i] = WHITE; + else pixels[i] = BLACK; + } + + Image image = { + .data = pixels, + .width = width, + .height = height, + .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, + .mipmaps = 1 + }; + + return image; +} + +static inline +Image texed_generate_cellular(uint32_t seed, int width, int height, int tileSize) +{ + Color *pixels = (Color *)RL_MALLOC(width*height*sizeof(Color)); + + int seedsPerRow = width/tileSize; + int seedsPerCol = height/tileSize; + int seedsCount = seedsPerRow*seedsPerCol; + + Vector2 *seeds = (Vector2 *)RL_MALLOC(seedsCount*sizeof(Vector2)); + + for (int i = 0; i < seedsCount; i++) + { + int y = (i/seedsPerRow)*tileSize + _rand_r(&seed)%(tileSize - 1); + int x = (i%seedsPerRow)*tileSize + _rand_r(&seed)%(tileSize - 1); + seeds[i] = (Vector2){ (float)x, (float)y}; + } + + for (int y = 0; y < height; y++) + { + int tileY = y/tileSize; + + for (int x = 0; x < width; x++) + { + int tileX = x/tileSize; + + float minDistance = (float)strtod("Inf", NULL); + + // Check all adjacent tiles + for (int i = -1; i < 2; i++) + { + if ((tileX + i < 0) || (tileX + i >= seedsPerRow)) continue; + + for (int j = -1; j < 2; j++) + { + if ((tileY + j < 0) || (tileY + j >= seedsPerCol)) continue; + + Vector2 neighborSeed = seeds[(tileY + j)*seedsPerRow + tileX + i]; + + float dist = (float)hypot(x - (int)neighborSeed.x, y - (int)neighborSeed.y); + minDistance = (float)fmin(minDistance, dist); + } + } + + // I made this up but it seems to give good results at all tile sizes + int intensity = (int)(minDistance*256.0f/tileSize); + if (intensity > 255) intensity = 255; + + pixels[y*width + x] = (Color){ intensity, intensity, intensity, 255 }; + } + } + + RL_FREE(seeds); + + Image image = { + .data = pixels, + .width = width, + .height = height, + .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, + .mipmaps = 1 + }; + + return image; } \ No newline at end of file diff --git a/code/game/source/editors/texed_ops_list.c b/code/game/source/editors/texed_ops_list.c index 18d66e3..5f6dd66 100644 --- a/code/game/source/editors/texed_ops_list.c +++ b/code/game/source/editors/texed_ops_list.c @@ -28,6 +28,8 @@ static td_op default_ops[] = { PARAM(TPARAM_COORD, "h", "0"), PARAM(TPARAM_COLOR, "tint", "ffffffff"), } + },{ + OP(TOP_IMAGE_ALPHA_MASK), },{ OP(TOP_DRAW_RECT), PARAMS(5) { @@ -91,6 +93,58 @@ static td_op default_ops[] = { PARAM(TPARAM_INT, "invert?", "0"), PARAM(TPARAM_INT, "grayscale?", "0"), } + },{ + OP(TOP_COLOR_REPLACE), + PARAMS(2) { + PARAM(TPARAM_COLOR, "original", "FFFFFFFF"), + PARAM(TPARAM_COLOR, "new", "FF0000FF"), + } + },{ + OP(TOP_IMAGE_GRAD_V), + PARAMS(2) { + PARAM(TPARAM_COLOR, "top", "ffffffff"), + PARAM(TPARAM_COLOR, "bottom", "00000000"), + } + },{ + OP(TOP_IMAGE_GRAD_H), + PARAMS(2) { + PARAM(TPARAM_COLOR, "left", "ffffffff"), + PARAM(TPARAM_COLOR, "right", "00000000"), + } + },{ + OP(TOP_IMAGE_GRAD_RAD), + PARAMS(3) { + PARAM(TPARAM_FLOAT, "density", "0.5"), + PARAM(TPARAM_COLOR, "inner", "ffffffff"), + PARAM(TPARAM_COLOR, "outer", "00000000"), + } + },{ + OP(TOP_IMAGE_CHECKED), + PARAMS(4) { + PARAM(TPARAM_COORD, "checks_x", "16"), + PARAM(TPARAM_COORD, "checks_y", "16"), + PARAM(TPARAM_COLOR, "color1", "ffffffff"), + PARAM(TPARAM_COLOR, "color2", "00000000"), + } + },{ + OP(TOP_IMAGE_NOISE_WHITE), + PARAMS(2) { + PARAM(TPARAM_COORD, "seed", "1"), + PARAM(TPARAM_FLOAT, "factor", "0.5"), + } + },{ + OP(TOP_IMAGE_NOISE_PERLIN), + PARAMS(3) { + PARAM(TPARAM_COORD, "offset_x", "0"), + PARAM(TPARAM_COORD, "offset_y", "0"), + PARAM(TPARAM_FLOAT, "scale", "1.0"), + } + },{ + OP(TOP_IMAGE_CELLULAR), + PARAMS(2) { + PARAM(TPARAM_COORD, "seed", "1"), + PARAM(TPARAM_COORD, "tile_size", "16"), + } } }; diff --git a/code/vendors/librg.h b/code/vendors/librg.h index 649acda..f617a7a 100644 --- a/code/vendors/librg.h +++ b/code/vendors/librg.h @@ -378,12 +378,12 @@ # undef LIBRG_TI_VERSION #endif #if \ - defined(__TI_COMPILER_VERSION__) && \ - ( \ - defined(__TMS470__) || defined(__TI_ARM__) || \ - defined(__MSP430__) || \ - defined(__TMS320C2000__) \ - ) +defined(__TI_COMPILER_VERSION__) && \ +( \ +defined(__TMS470__) || defined(__TI_ARM__) || \ +defined(__MSP430__) || \ +defined(__TMS320C2000__) \ +) # if (__TI_COMPILER_VERSION__ >= 16000000) # define LIBRG_TI_VERSION LIBRG_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) # endif @@ -602,19 +602,19 @@ # undef LIBRG_GCC_VERSION #endif #if \ - defined(LIBRG_GNUC_VERSION) && \ - !defined(__clang__) && \ - !defined(LIBRG_INTEL_VERSION) && \ - !defined(LIBRG_PGI_VERSION) && \ - !defined(LIBRG_ARM_VERSION) && \ - !defined(LIBRG_TI_VERSION) && \ - !defined(LIBRG_TI_ARMCL_VERSION) && \ - !defined(LIBRG_TI_CL430_VERSION) && \ - !defined(LIBRG_TI_CL2000_VERSION) && \ - !defined(LIBRG_TI_CL6X_VERSION) && \ - !defined(LIBRG_TI_CL7X_VERSION) && \ - !defined(LIBRG_TI_CLPRU_VERSION) && \ - !defined(__COMPCERT__) +defined(LIBRG_GNUC_VERSION) && \ +!defined(__clang__) && \ +!defined(LIBRG_INTEL_VERSION) && \ +!defined(LIBRG_PGI_VERSION) && \ +!defined(LIBRG_ARM_VERSION) && \ +!defined(LIBRG_TI_VERSION) && \ +!defined(LIBRG_TI_ARMCL_VERSION) && \ +!defined(LIBRG_TI_CL430_VERSION) && \ +!defined(LIBRG_TI_CL2000_VERSION) && \ +!defined(LIBRG_TI_CL6X_VERSION) && \ +!defined(LIBRG_TI_CL7X_VERSION) && \ +!defined(LIBRG_TI_CLPRU_VERSION) && \ +!defined(__COMPCERT__) # define LIBRG_GCC_VERSION LIBRG_GNUC_VERSION #endif @@ -658,9 +658,9 @@ # undef LIBRG_HAS_CPP_ATTRIBUTE #endif #if \ - defined(__has_cpp_attribute) && \ - defined(__cplusplus) && \ - (!defined(LIBRG_SUNPRO_VERSION) || LIBRG_SUNPRO_VERSION_CHECK(5,15,0)) +defined(__has_cpp_attribute) && \ +defined(__cplusplus) && \ +(!defined(LIBRG_SUNPRO_VERSION) || LIBRG_SUNPRO_VERSION_CHECK(5,15,0)) # define LIBRG_HAS_CPP_ATTRIBUTE(attribute) __has_cpp_attribute(attribute) #else # define LIBRG_HAS_CPP_ATTRIBUTE(attribute) (0) @@ -672,10 +672,10 @@ #if !defined(__cplusplus) || !defined(__has_cpp_attribute) # define LIBRG_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) #elif \ - !defined(LIBRG_PGI_VERSION) && \ - !defined(LIBRG_IAR_VERSION) && \ - (!defined(LIBRG_SUNPRO_VERSION) || LIBRG_SUNPRO_VERSION_CHECK(5,15,0)) && \ - (!defined(LIBRG_MSVC_VERSION) || LIBRG_MSVC_VERSION_CHECK(19,20,0)) +!defined(LIBRG_PGI_VERSION) && \ +!defined(LIBRG_IAR_VERSION) && \ +(!defined(LIBRG_SUNPRO_VERSION) || LIBRG_SUNPRO_VERSION_CHECK(5,15,0)) && \ +(!defined(LIBRG_MSVC_VERSION) || LIBRG_MSVC_VERSION_CHECK(19,20,0)) # define LIBRG_HAS_CPP_ATTRIBUTE_NS(ns,attribute) LIBRG_HAS_CPP_ATTRIBUTE(ns::attribute) #else # define LIBRG_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) @@ -843,17 +843,17 @@ # if LIBRG_HAS_WARNING("-Wc++98-compat") # if LIBRG_HAS_WARNING("-Wc++17-extensions") # define LIBRG_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ - LIBRG_DIAGNOSTIC_PUSH \ - _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ - _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \ - xpr \ - LIBRG_DIAGNOSTIC_POP +LIBRG_DIAGNOSTIC_PUSH \ +_Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ +_Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \ +xpr \ +LIBRG_DIAGNOSTIC_POP # else # define LIBRG_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ - LIBRG_DIAGNOSTIC_PUSH \ - _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ - xpr \ - LIBRG_DIAGNOSTIC_POP +LIBRG_DIAGNOSTIC_PUSH \ +_Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ +xpr \ +LIBRG_DIAGNOSTIC_POP # endif # endif #endif @@ -867,15 +867,15 @@ #if defined(__cplusplus) # define LIBRG_CONST_CAST(T, expr) (const_cast(expr)) #elif \ - LIBRG_HAS_WARNING("-Wcast-qual") || \ - LIBRG_GCC_VERSION_CHECK(4,6,0) || \ - LIBRG_INTEL_VERSION_CHECK(13,0,0) +LIBRG_HAS_WARNING("-Wcast-qual") || \ +LIBRG_GCC_VERSION_CHECK(4,6,0) || \ +LIBRG_INTEL_VERSION_CHECK(13,0,0) # define LIBRG_CONST_CAST(T, expr) (__extension__ ({ \ - LIBRG_DIAGNOSTIC_PUSH \ - LIBRG_DIAGNOSTIC_DISABLE_CAST_QUAL \ - ((T) (expr)); \ - LIBRG_DIAGNOSTIC_POP \ - })) +LIBRG_DIAGNOSTIC_PUSH \ +LIBRG_DIAGNOSTIC_DISABLE_CAST_QUAL \ +((T) (expr)); \ +LIBRG_DIAGNOSTIC_POP \ +})) #else # define LIBRG_CONST_CAST(T, expr) ((T) (expr)) #endif @@ -904,15 +904,15 @@ #if defined(__cplusplus) # if LIBRG_HAS_WARNING("-Wold-style-cast") # define LIBRG_CPP_CAST(T, expr) \ - LIBRG_DIAGNOSTIC_PUSH \ - _Pragma("clang diagnostic ignored \"-Wold-style-cast\"") \ - ((T) (expr)) \ - LIBRG_DIAGNOSTIC_POP +LIBRG_DIAGNOSTIC_PUSH \ +_Pragma("clang diagnostic ignored \"-Wold-style-cast\"") \ +((T) (expr)) \ +LIBRG_DIAGNOSTIC_POP # elif LIBRG_IAR_VERSION_CHECK(8,3,0) # define LIBRG_CPP_CAST(T, expr) \ - LIBRG_DIAGNOSTIC_PUSH \ - _Pragma("diag_suppress=Pe137") \ - LIBRG_DIAGNOSTIC_POP \ +LIBRG_DIAGNOSTIC_PUSH \ +_Pragma("diag_suppress=Pe137") \ +LIBRG_DIAGNOSTIC_POP \ # else # define LIBRG_CPP_CAST(T, expr) ((T) (expr)) # endif @@ -921,24 +921,24 @@ #endif #if \ - (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ - defined(__clang__) || \ - LIBRG_GCC_VERSION_CHECK(3,0,0) || \ - LIBRG_INTEL_VERSION_CHECK(13,0,0) || \ - LIBRG_IAR_VERSION_CHECK(8,0,0) || \ - LIBRG_PGI_VERSION_CHECK(18,4,0) || \ - LIBRG_ARM_VERSION_CHECK(4,1,0) || \ - LIBRG_TI_VERSION_CHECK(15,12,0) || \ - LIBRG_TI_ARMCL_VERSION_CHECK(4,7,0) || \ - LIBRG_TI_CL430_VERSION_CHECK(2,0,1) || \ - LIBRG_TI_CL2000_VERSION_CHECK(6,1,0) || \ - LIBRG_TI_CL6X_VERSION_CHECK(7,0,0) || \ - LIBRG_TI_CL7X_VERSION_CHECK(1,2,0) || \ - LIBRG_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - LIBRG_CRAY_VERSION_CHECK(5,0,0) || \ - LIBRG_TINYC_VERSION_CHECK(0,9,17) || \ - LIBRG_SUNPRO_VERSION_CHECK(8,0,0) || \ - (LIBRG_IBM_VERSION_CHECK(10,1,0) && defined(__C99_PRAGMA_OPERATOR)) +(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ +defined(__clang__) || \ +LIBRG_GCC_VERSION_CHECK(3,0,0) || \ +LIBRG_INTEL_VERSION_CHECK(13,0,0) || \ +LIBRG_IAR_VERSION_CHECK(8,0,0) || \ +LIBRG_PGI_VERSION_CHECK(18,4,0) || \ +LIBRG_ARM_VERSION_CHECK(4,1,0) || \ +LIBRG_TI_VERSION_CHECK(15,12,0) || \ +LIBRG_TI_ARMCL_VERSION_CHECK(4,7,0) || \ +LIBRG_TI_CL430_VERSION_CHECK(2,0,1) || \ +LIBRG_TI_CL2000_VERSION_CHECK(6,1,0) || \ +LIBRG_TI_CL6X_VERSION_CHECK(7,0,0) || \ +LIBRG_TI_CL7X_VERSION_CHECK(1,2,0) || \ +LIBRG_TI_CLPRU_VERSION_CHECK(2,1,0) || \ +LIBRG_CRAY_VERSION_CHECK(5,0,0) || \ +LIBRG_TINYC_VERSION_CHECK(0,9,17) || \ +LIBRG_SUNPRO_VERSION_CHECK(8,0,0) || \ +(LIBRG_IBM_VERSION_CHECK(10,1,0) && defined(__C99_PRAGMA_OPERATOR)) # define LIBRG_PRAGMA(value) _Pragma(#value) #elif LIBRG_MSVC_VERSION_CHECK(15,0,0) # define LIBRG_PRAGMA(value) __pragma(value) @@ -968,12 +968,12 @@ # define LIBRG_DIAGNOSTIC_PUSH _Pragma("push") # define LIBRG_DIAGNOSTIC_POP _Pragma("pop") #elif \ - LIBRG_TI_VERSION_CHECK(15,12,0) || \ - LIBRG_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - LIBRG_TI_CL430_VERSION_CHECK(4,4,0) || \ - LIBRG_TI_CL6X_VERSION_CHECK(8,1,0) || \ - LIBRG_TI_CL7X_VERSION_CHECK(1,2,0) || \ - LIBRG_TI_CLPRU_VERSION_CHECK(2,1,0) +LIBRG_TI_VERSION_CHECK(15,12,0) || \ +LIBRG_TI_ARMCL_VERSION_CHECK(5,2,0) || \ +LIBRG_TI_CL430_VERSION_CHECK(4,4,0) || \ +LIBRG_TI_CL6X_VERSION_CHECK(8,1,0) || \ +LIBRG_TI_CL7X_VERSION_CHECK(1,2,0) || \ +LIBRG_TI_CLPRU_VERSION_CHECK(2,1,0) # define LIBRG_DIAGNOSTIC_PUSH _Pragma("diag_push") # define LIBRG_DIAGNOSTIC_POP _Pragma("diag_pop") #elif LIBRG_PELLES_VERSION_CHECK(2,90,0) @@ -998,17 +998,17 @@ #elif LIBRG_MSVC_VERSION_CHECK(15,0,0) # define LIBRG_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:4996)) #elif \ - LIBRG_TI_VERSION_CHECK(15,12,0) || \ - (LIBRG_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - LIBRG_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (LIBRG_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - LIBRG_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (LIBRG_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - LIBRG_TI_CL430_VERSION_CHECK(4,3,0) || \ - (LIBRG_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - LIBRG_TI_CL6X_VERSION_CHECK(7,5,0) || \ - LIBRG_TI_CL7X_VERSION_CHECK(1,2,0) || \ - LIBRG_TI_CLPRU_VERSION_CHECK(2,1,0) +LIBRG_TI_VERSION_CHECK(15,12,0) || \ +(LIBRG_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +LIBRG_TI_ARMCL_VERSION_CHECK(5,2,0) || \ +(LIBRG_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +LIBRG_TI_CL2000_VERSION_CHECK(6,4,0) || \ +(LIBRG_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +LIBRG_TI_CL430_VERSION_CHECK(4,3,0) || \ +(LIBRG_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +LIBRG_TI_CL6X_VERSION_CHECK(7,5,0) || \ +LIBRG_TI_CL7X_VERSION_CHECK(1,2,0) || \ +LIBRG_TI_CLPRU_VERSION_CHECK(2,1,0) # define LIBRG_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1291,1718") #elif LIBRG_SUNPRO_VERSION_CHECK(5,13,0) && !defined(__cplusplus) # define LIBRG_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)") @@ -1036,10 +1036,10 @@ #elif LIBRG_MSVC_VERSION_CHECK(15,0,0) # define LIBRG_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:4068)) #elif \ - LIBRG_TI_VERSION_CHECK(16,9,0) || \ - LIBRG_TI_CL6X_VERSION_CHECK(8,0,0) || \ - LIBRG_TI_CL7X_VERSION_CHECK(1,2,0) || \ - LIBRG_TI_CLPRU_VERSION_CHECK(2,3,0) +LIBRG_TI_VERSION_CHECK(16,9,0) || \ +LIBRG_TI_CL6X_VERSION_CHECK(8,0,0) || \ +LIBRG_TI_CL7X_VERSION_CHECK(1,2,0) || \ +LIBRG_TI_CLPRU_VERSION_CHECK(2,3,0) # define LIBRG_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") #elif LIBRG_TI_CL6X_VERSION_CHECK(8,0,0) # define LIBRG_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") @@ -1065,9 +1065,9 @@ #elif LIBRG_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus) # define LIBRG_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("error_messages(off,attrskipunsup)") #elif \ - LIBRG_TI_VERSION_CHECK(18,1,0) || \ - LIBRG_TI_CL6X_VERSION_CHECK(8,3,0) || \ - LIBRG_TI_CL7X_VERSION_CHECK(1,2,0) +LIBRG_TI_VERSION_CHECK(18,1,0) || \ +LIBRG_TI_CL6X_VERSION_CHECK(8,3,0) || \ +LIBRG_TI_CL7X_VERSION_CHECK(1,2,0) # define LIBRG_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1173") #elif LIBRG_IAR_VERSION_CHECK(8,0,0) # define LIBRG_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress=Pe1097") @@ -1101,39 +1101,39 @@ # define LIBRG_DEPRECATED(since) LIBRG_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since)]]) # define LIBRG_DEPRECATED_FOR(since, replacement) LIBRG_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since "; use " #replacement)]]) #elif \ - LIBRG_HAS_EXTENSION(attribute_deprecated_with_message) || \ - LIBRG_GCC_VERSION_CHECK(4,5,0) || \ - LIBRG_INTEL_VERSION_CHECK(13,0,0) || \ - LIBRG_ARM_VERSION_CHECK(5,6,0) || \ - LIBRG_SUNPRO_VERSION_CHECK(5,13,0) || \ - LIBRG_PGI_VERSION_CHECK(17,10,0) || \ - LIBRG_TI_VERSION_CHECK(18,1,0) || \ - LIBRG_TI_ARMCL_VERSION_CHECK(18,1,0) || \ - LIBRG_TI_CL6X_VERSION_CHECK(8,3,0) || \ - LIBRG_TI_CL7X_VERSION_CHECK(1,2,0) || \ - LIBRG_TI_CLPRU_VERSION_CHECK(2,3,0) +LIBRG_HAS_EXTENSION(attribute_deprecated_with_message) || \ +LIBRG_GCC_VERSION_CHECK(4,5,0) || \ +LIBRG_INTEL_VERSION_CHECK(13,0,0) || \ +LIBRG_ARM_VERSION_CHECK(5,6,0) || \ +LIBRG_SUNPRO_VERSION_CHECK(5,13,0) || \ +LIBRG_PGI_VERSION_CHECK(17,10,0) || \ +LIBRG_TI_VERSION_CHECK(18,1,0) || \ +LIBRG_TI_ARMCL_VERSION_CHECK(18,1,0) || \ +LIBRG_TI_CL6X_VERSION_CHECK(8,3,0) || \ +LIBRG_TI_CL7X_VERSION_CHECK(1,2,0) || \ +LIBRG_TI_CLPRU_VERSION_CHECK(2,3,0) # define LIBRG_DEPRECATED(since) __attribute__((__deprecated__("Since " #since))) # define LIBRG_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__("Since " #since "; use " #replacement))) #elif \ - LIBRG_HAS_ATTRIBUTE(deprecated) || \ - LIBRG_GCC_VERSION_CHECK(3,1,0) || \ - LIBRG_ARM_VERSION_CHECK(4,1,0) || \ - LIBRG_TI_VERSION_CHECK(15,12,0) || \ - (LIBRG_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - LIBRG_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (LIBRG_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - LIBRG_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (LIBRG_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - LIBRG_TI_CL430_VERSION_CHECK(4,3,0) || \ - (LIBRG_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - LIBRG_TI_CL6X_VERSION_CHECK(7,5,0) || \ - LIBRG_TI_CL7X_VERSION_CHECK(1,2,0) || \ - LIBRG_TI_CLPRU_VERSION_CHECK(2,1,0) +LIBRG_HAS_ATTRIBUTE(deprecated) || \ +LIBRG_GCC_VERSION_CHECK(3,1,0) || \ +LIBRG_ARM_VERSION_CHECK(4,1,0) || \ +LIBRG_TI_VERSION_CHECK(15,12,0) || \ +(LIBRG_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +LIBRG_TI_ARMCL_VERSION_CHECK(5,2,0) || \ +(LIBRG_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +LIBRG_TI_CL2000_VERSION_CHECK(6,4,0) || \ +(LIBRG_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +LIBRG_TI_CL430_VERSION_CHECK(4,3,0) || \ +(LIBRG_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +LIBRG_TI_CL6X_VERSION_CHECK(7,5,0) || \ +LIBRG_TI_CL7X_VERSION_CHECK(1,2,0) || \ +LIBRG_TI_CLPRU_VERSION_CHECK(2,1,0) # define LIBRG_DEPRECATED(since) __attribute__((__deprecated__)) # define LIBRG_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__)) #elif \ - LIBRG_MSVC_VERSION_CHECK(13,10,0) || \ - LIBRG_PELLES_VERSION_CHECK(6,50,0) +LIBRG_MSVC_VERSION_CHECK(13,10,0) || \ +LIBRG_PELLES_VERSION_CHECK(6,50,0) # define LIBRG_DEPRECATED(since) __declspec(deprecated) # define LIBRG_DEPRECATED_FOR(since, replacement) __declspec(deprecated) #elif LIBRG_IAR_VERSION_CHECK(8,0,0) @@ -1148,9 +1148,9 @@ # undef LIBRG_UNAVAILABLE #endif #if \ - LIBRG_HAS_ATTRIBUTE(warning) || \ - LIBRG_GCC_VERSION_CHECK(4,3,0) || \ - LIBRG_INTEL_VERSION_CHECK(13,0,0) +LIBRG_HAS_ATTRIBUTE(warning) || \ +LIBRG_GCC_VERSION_CHECK(4,3,0) || \ +LIBRG_INTEL_VERSION_CHECK(13,0,0) # define LIBRG_UNAVAILABLE(available_since) __attribute__((__warning__("Not available until " #available_since))) #else # define LIBRG_UNAVAILABLE(available_since) @@ -1169,22 +1169,22 @@ # define LIBRG_WARN_UNUSED_RESULT LIBRG_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) # define LIBRG_WARN_UNUSED_RESULT_MSG(msg) LIBRG_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) #elif \ - LIBRG_HAS_ATTRIBUTE(warn_unused_result) || \ - LIBRG_GCC_VERSION_CHECK(3,4,0) || \ - LIBRG_INTEL_VERSION_CHECK(13,0,0) || \ - LIBRG_TI_VERSION_CHECK(15,12,0) || \ - (LIBRG_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - LIBRG_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (LIBRG_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - LIBRG_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (LIBRG_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - LIBRG_TI_CL430_VERSION_CHECK(4,3,0) || \ - (LIBRG_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - LIBRG_TI_CL6X_VERSION_CHECK(7,5,0) || \ - LIBRG_TI_CL7X_VERSION_CHECK(1,2,0) || \ - LIBRG_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - (LIBRG_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ - LIBRG_PGI_VERSION_CHECK(17,10,0) +LIBRG_HAS_ATTRIBUTE(warn_unused_result) || \ +LIBRG_GCC_VERSION_CHECK(3,4,0) || \ +LIBRG_INTEL_VERSION_CHECK(13,0,0) || \ +LIBRG_TI_VERSION_CHECK(15,12,0) || \ +(LIBRG_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +LIBRG_TI_ARMCL_VERSION_CHECK(5,2,0) || \ +(LIBRG_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +LIBRG_TI_CL2000_VERSION_CHECK(6,4,0) || \ +(LIBRG_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +LIBRG_TI_CL430_VERSION_CHECK(4,3,0) || \ +(LIBRG_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +LIBRG_TI_CL6X_VERSION_CHECK(7,5,0) || \ +LIBRG_TI_CL7X_VERSION_CHECK(1,2,0) || \ +LIBRG_TI_CLPRU_VERSION_CHECK(2,1,0) || \ +(LIBRG_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ +LIBRG_PGI_VERSION_CHECK(17,10,0) # define LIBRG_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__)) # define LIBRG_WARN_UNUSED_RESULT_MSG(msg) __attribute__((__warn_unused_result__)) #elif defined(_Check_return_) /* SAL */ @@ -1199,10 +1199,10 @@ # undef LIBRG_SENTINEL #endif #if \ - LIBRG_HAS_ATTRIBUTE(sentinel) || \ - LIBRG_GCC_VERSION_CHECK(4,0,0) || \ - LIBRG_INTEL_VERSION_CHECK(13,0,0) || \ - LIBRG_ARM_VERSION_CHECK(5,4,0) +LIBRG_HAS_ATTRIBUTE(sentinel) || \ +LIBRG_GCC_VERSION_CHECK(4,0,0) || \ +LIBRG_INTEL_VERSION_CHECK(13,0,0) || \ +LIBRG_ARM_VERSION_CHECK(5,4,0) # define LIBRG_SENTINEL(position) __attribute__((__sentinel__(position))) #else # define LIBRG_SENTINEL(position) @@ -1220,22 +1220,22 @@ #elif defined(__cplusplus) && (__cplusplus >= 201103L) # define LIBRG_NO_RETURN LIBRG_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[noreturn]]) #elif \ - LIBRG_HAS_ATTRIBUTE(noreturn) || \ - LIBRG_GCC_VERSION_CHECK(3,2,0) || \ - LIBRG_SUNPRO_VERSION_CHECK(5,11,0) || \ - LIBRG_ARM_VERSION_CHECK(4,1,0) || \ - LIBRG_IBM_VERSION_CHECK(10,1,0) || \ - LIBRG_TI_VERSION_CHECK(15,12,0) || \ - (LIBRG_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - LIBRG_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (LIBRG_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - LIBRG_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (LIBRG_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - LIBRG_TI_CL430_VERSION_CHECK(4,3,0) || \ - (LIBRG_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - LIBRG_TI_CL6X_VERSION_CHECK(7,5,0) || \ - LIBRG_TI_CL7X_VERSION_CHECK(1,2,0) || \ - LIBRG_TI_CLPRU_VERSION_CHECK(2,1,0) +LIBRG_HAS_ATTRIBUTE(noreturn) || \ +LIBRG_GCC_VERSION_CHECK(3,2,0) || \ +LIBRG_SUNPRO_VERSION_CHECK(5,11,0) || \ +LIBRG_ARM_VERSION_CHECK(4,1,0) || \ +LIBRG_IBM_VERSION_CHECK(10,1,0) || \ +LIBRG_TI_VERSION_CHECK(15,12,0) || \ +(LIBRG_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +LIBRG_TI_ARMCL_VERSION_CHECK(5,2,0) || \ +(LIBRG_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +LIBRG_TI_CL2000_VERSION_CHECK(6,4,0) || \ +(LIBRG_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +LIBRG_TI_CL430_VERSION_CHECK(4,3,0) || \ +(LIBRG_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +LIBRG_TI_CL6X_VERSION_CHECK(7,5,0) || \ +LIBRG_TI_CL7X_VERSION_CHECK(1,2,0) || \ +LIBRG_TI_CLPRU_VERSION_CHECK(2,1,0) # define LIBRG_NO_RETURN __attribute__((__noreturn__)) #elif LIBRG_SUNPRO_VERSION_CHECK(5,10,0) # define LIBRG_NO_RETURN _Pragma("does_not_return") @@ -1270,14 +1270,14 @@ # undef LIBRG_ASSUME #endif #if \ - LIBRG_MSVC_VERSION_CHECK(13,10,0) || \ - LIBRG_INTEL_VERSION_CHECK(13,0,0) +LIBRG_MSVC_VERSION_CHECK(13,10,0) || \ +LIBRG_INTEL_VERSION_CHECK(13,0,0) # define LIBRG_ASSUME(expr) __assume(expr) #elif LIBRG_HAS_BUILTIN(__builtin_assume) # define LIBRG_ASSUME(expr) __builtin_assume(expr) #elif \ - LIBRG_TI_CL2000_VERSION_CHECK(6,2,0) || \ - LIBRG_TI_CL6X_VERSION_CHECK(4,0,0) +LIBRG_TI_CL2000_VERSION_CHECK(6,2,0) || \ +LIBRG_TI_CL6X_VERSION_CHECK(4,0,0) # if defined(__cplusplus) # define LIBRG_ASSUME(expr) std::_nassert(expr) # else @@ -1285,11 +1285,11 @@ # endif #endif #if \ - (LIBRG_HAS_BUILTIN(__builtin_unreachable) && (!defined(LIBRG_ARM_VERSION))) || \ - LIBRG_GCC_VERSION_CHECK(4,5,0) || \ - LIBRG_PGI_VERSION_CHECK(18,10,0) || \ - LIBRG_INTEL_VERSION_CHECK(13,0,0) || \ - LIBRG_IBM_VERSION_CHECK(13,1,5) +(LIBRG_HAS_BUILTIN(__builtin_unreachable) && (!defined(LIBRG_ARM_VERSION))) || \ +LIBRG_GCC_VERSION_CHECK(4,5,0) || \ +LIBRG_PGI_VERSION_CHECK(18,10,0) || \ +LIBRG_INTEL_VERSION_CHECK(13,0,0) || \ +LIBRG_IBM_VERSION_CHECK(13,1,5) # define LIBRG_UNREACHABLE() __builtin_unreachable() #elif defined(LIBRG_ASSUME) # define LIBRG_UNREACHABLE() LIBRG_ASSUME(0) @@ -1303,8 +1303,8 @@ #endif #if defined(LIBRG_UNREACHABLE) # if \ - LIBRG_TI_CL2000_VERSION_CHECK(6,2,0) || \ - LIBRG_TI_CL6X_VERSION_CHECK(4,0,0) +LIBRG_TI_CL2000_VERSION_CHECK(6,2,0) || \ +LIBRG_TI_CL6X_VERSION_CHECK(4,0,0) # define LIBRG_UNREACHABLE_RETURN(value) return (LIBRG_STATIC_CAST(void, LIBRG_ASSUME(0)), (value)) # else # define LIBRG_UNREACHABLE_RETURN(value) LIBRG_UNREACHABLE() @@ -1334,10 +1334,10 @@ LIBRG_DIAGNOSTIC_PUSH # undef LIBRG_NON_NULL #endif #if \ - LIBRG_HAS_ATTRIBUTE(nonnull) || \ - LIBRG_GCC_VERSION_CHECK(3,3,0) || \ - LIBRG_INTEL_VERSION_CHECK(13,0,0) || \ - LIBRG_ARM_VERSION_CHECK(4,1,0) +LIBRG_HAS_ATTRIBUTE(nonnull) || \ +LIBRG_GCC_VERSION_CHECK(3,3,0) || \ +LIBRG_INTEL_VERSION_CHECK(13,0,0) || \ +LIBRG_ARM_VERSION_CHECK(4,1,0) # define LIBRG_NON_NULL(...) __attribute__((__nonnull__(__VA_ARGS__))) #else # define LIBRG_NON_NULL(...) @@ -1352,22 +1352,22 @@ LIBRG_DIAGNOSTIC_POP #elif defined(__MINGW32__) && LIBRG_GCC_HAS_ATTRIBUTE(format,4,4,0) && defined(__USE_MINGW_ANSI_STDIO) # define LIBRG_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(gnu_printf, string_idx, first_to_check))) #elif \ - LIBRG_HAS_ATTRIBUTE(format) || \ - LIBRG_GCC_VERSION_CHECK(3,1,0) || \ - LIBRG_INTEL_VERSION_CHECK(13,0,0) || \ - LIBRG_ARM_VERSION_CHECK(5,6,0) || \ - LIBRG_IBM_VERSION_CHECK(10,1,0) || \ - LIBRG_TI_VERSION_CHECK(15,12,0) || \ - (LIBRG_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - LIBRG_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (LIBRG_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - LIBRG_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (LIBRG_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - LIBRG_TI_CL430_VERSION_CHECK(4,3,0) || \ - (LIBRG_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - LIBRG_TI_CL6X_VERSION_CHECK(7,5,0) || \ - LIBRG_TI_CL7X_VERSION_CHECK(1,2,0) || \ - LIBRG_TI_CLPRU_VERSION_CHECK(2,1,0) +LIBRG_HAS_ATTRIBUTE(format) || \ +LIBRG_GCC_VERSION_CHECK(3,1,0) || \ +LIBRG_INTEL_VERSION_CHECK(13,0,0) || \ +LIBRG_ARM_VERSION_CHECK(5,6,0) || \ +LIBRG_IBM_VERSION_CHECK(10,1,0) || \ +LIBRG_TI_VERSION_CHECK(15,12,0) || \ +(LIBRG_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +LIBRG_TI_ARMCL_VERSION_CHECK(5,2,0) || \ +(LIBRG_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +LIBRG_TI_CL2000_VERSION_CHECK(6,4,0) || \ +(LIBRG_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +LIBRG_TI_CL430_VERSION_CHECK(4,3,0) || \ +(LIBRG_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +LIBRG_TI_CL6X_VERSION_CHECK(7,5,0) || \ +LIBRG_TI_CL7X_VERSION_CHECK(1,2,0) || \ +LIBRG_TI_CLPRU_VERSION_CHECK(2,1,0) # define LIBRG_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(__printf__, string_idx, first_to_check))) #elif LIBRG_PELLES_VERSION_CHECK(6,0,0) # define LIBRG_PRINTF_FORMAT(string_idx,first_to_check) __declspec(vaformat(printf,string_idx,first_to_check)) @@ -1403,41 +1403,41 @@ LIBRG_DIAGNOSTIC_POP # define LIBRG_UNPREDICTABLE(expr) __builtin_unpredictable((expr)) #endif #if \ - LIBRG_HAS_BUILTIN(__builtin_expect_with_probability) || \ - LIBRG_GCC_VERSION_CHECK(9,0,0) +LIBRG_HAS_BUILTIN(__builtin_expect_with_probability) || \ +LIBRG_GCC_VERSION_CHECK(9,0,0) # define LIBRG_PREDICT(expr, value, probability) __builtin_expect_with_probability( (expr), (value), (probability)) # define LIBRG_PREDICT_TRUE(expr, probability) __builtin_expect_with_probability(!!(expr), 1 , (probability)) # define LIBRG_PREDICT_FALSE(expr, probability) __builtin_expect_with_probability(!!(expr), 0 , (probability)) # define LIBRG_LIKELY(expr) __builtin_expect (!!(expr), 1 ) # define LIBRG_UNLIKELY(expr) __builtin_expect (!!(expr), 0 ) #elif \ - LIBRG_HAS_BUILTIN(__builtin_expect) || \ - LIBRG_GCC_VERSION_CHECK(3,0,0) || \ - LIBRG_INTEL_VERSION_CHECK(13,0,0) || \ - (LIBRG_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ - LIBRG_ARM_VERSION_CHECK(4,1,0) || \ - LIBRG_IBM_VERSION_CHECK(10,1,0) || \ - LIBRG_TI_VERSION_CHECK(15,12,0) || \ - LIBRG_TI_ARMCL_VERSION_CHECK(4,7,0) || \ - LIBRG_TI_CL430_VERSION_CHECK(3,1,0) || \ - LIBRG_TI_CL2000_VERSION_CHECK(6,1,0) || \ - LIBRG_TI_CL6X_VERSION_CHECK(6,1,0) || \ - LIBRG_TI_CL7X_VERSION_CHECK(1,2,0) || \ - LIBRG_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - LIBRG_TINYC_VERSION_CHECK(0,9,27) || \ - LIBRG_CRAY_VERSION_CHECK(8,1,0) +LIBRG_HAS_BUILTIN(__builtin_expect) || \ +LIBRG_GCC_VERSION_CHECK(3,0,0) || \ +LIBRG_INTEL_VERSION_CHECK(13,0,0) || \ +(LIBRG_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ +LIBRG_ARM_VERSION_CHECK(4,1,0) || \ +LIBRG_IBM_VERSION_CHECK(10,1,0) || \ +LIBRG_TI_VERSION_CHECK(15,12,0) || \ +LIBRG_TI_ARMCL_VERSION_CHECK(4,7,0) || \ +LIBRG_TI_CL430_VERSION_CHECK(3,1,0) || \ +LIBRG_TI_CL2000_VERSION_CHECK(6,1,0) || \ +LIBRG_TI_CL6X_VERSION_CHECK(6,1,0) || \ +LIBRG_TI_CL7X_VERSION_CHECK(1,2,0) || \ +LIBRG_TI_CLPRU_VERSION_CHECK(2,1,0) || \ +LIBRG_TINYC_VERSION_CHECK(0,9,27) || \ +LIBRG_CRAY_VERSION_CHECK(8,1,0) # define LIBRG_PREDICT(expr, expected, probability) \ - (((probability) >= 0.9) ? __builtin_expect((expr), (expected)) : (LIBRG_STATIC_CAST(void, expected), (expr))) +(((probability) >= 0.9) ? __builtin_expect((expr), (expected)) : (LIBRG_STATIC_CAST(void, expected), (expr))) # define LIBRG_PREDICT_TRUE(expr, probability) \ - (__extension__ ({ \ - double librg_hedley_probability_ = (probability); \ - ((librg_hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 1) : ((librg_hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 0) : !!(expr))); \ - })) +(__extension__ ({ \ +double librg_hedley_probability_ = (probability); \ +((librg_hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 1) : ((librg_hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 0) : !!(expr))); \ +})) # define LIBRG_PREDICT_FALSE(expr, probability) \ - (__extension__ ({ \ - double librg_hedley_probability_ = (probability); \ - ((librg_hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 0) : ((librg_hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 1) : !!(expr))); \ - })) +(__extension__ ({ \ +double librg_hedley_probability_ = (probability); \ +((librg_hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 0) : ((librg_hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 1) : !!(expr))); \ +})) # define LIBRG_LIKELY(expr) __builtin_expect(!!(expr), 1) # define LIBRG_UNLIKELY(expr) __builtin_expect(!!(expr), 0) #else @@ -1455,23 +1455,23 @@ LIBRG_DIAGNOSTIC_POP # undef LIBRG_MALLOC #endif #if \ - LIBRG_HAS_ATTRIBUTE(malloc) || \ - LIBRG_GCC_VERSION_CHECK(3,1,0) || \ - LIBRG_INTEL_VERSION_CHECK(13,0,0) || \ - LIBRG_SUNPRO_VERSION_CHECK(5,11,0) || \ - LIBRG_ARM_VERSION_CHECK(4,1,0) || \ - LIBRG_IBM_VERSION_CHECK(12,1,0) || \ - LIBRG_TI_VERSION_CHECK(15,12,0) || \ - (LIBRG_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - LIBRG_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (LIBRG_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - LIBRG_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (LIBRG_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - LIBRG_TI_CL430_VERSION_CHECK(4,3,0) || \ - (LIBRG_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - LIBRG_TI_CL6X_VERSION_CHECK(7,5,0) || \ - LIBRG_TI_CL7X_VERSION_CHECK(1,2,0) || \ - LIBRG_TI_CLPRU_VERSION_CHECK(2,1,0) +LIBRG_HAS_ATTRIBUTE(malloc) || \ +LIBRG_GCC_VERSION_CHECK(3,1,0) || \ +LIBRG_INTEL_VERSION_CHECK(13,0,0) || \ +LIBRG_SUNPRO_VERSION_CHECK(5,11,0) || \ +LIBRG_ARM_VERSION_CHECK(4,1,0) || \ +LIBRG_IBM_VERSION_CHECK(12,1,0) || \ +LIBRG_TI_VERSION_CHECK(15,12,0) || \ +(LIBRG_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +LIBRG_TI_ARMCL_VERSION_CHECK(5,2,0) || \ +(LIBRG_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +LIBRG_TI_CL2000_VERSION_CHECK(6,4,0) || \ +(LIBRG_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +LIBRG_TI_CL430_VERSION_CHECK(4,3,0) || \ +(LIBRG_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +LIBRG_TI_CL6X_VERSION_CHECK(7,5,0) || \ +LIBRG_TI_CL7X_VERSION_CHECK(1,2,0) || \ +LIBRG_TI_CLPRU_VERSION_CHECK(2,1,0) # define LIBRG_MALLOC __attribute__((__malloc__)) #elif LIBRG_SUNPRO_VERSION_CHECK(5,10,0) # define LIBRG_MALLOC _Pragma("returns_new_memory") @@ -1485,33 +1485,33 @@ LIBRG_DIAGNOSTIC_POP # undef LIBRG_PURE #endif #if \ - LIBRG_HAS_ATTRIBUTE(pure) || \ - LIBRG_GCC_VERSION_CHECK(2,96,0) || \ - LIBRG_INTEL_VERSION_CHECK(13,0,0) || \ - LIBRG_SUNPRO_VERSION_CHECK(5,11,0) || \ - LIBRG_ARM_VERSION_CHECK(4,1,0) || \ - LIBRG_IBM_VERSION_CHECK(10,1,0) || \ - LIBRG_TI_VERSION_CHECK(15,12,0) || \ - (LIBRG_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - LIBRG_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (LIBRG_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - LIBRG_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (LIBRG_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - LIBRG_TI_CL430_VERSION_CHECK(4,3,0) || \ - (LIBRG_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - LIBRG_TI_CL6X_VERSION_CHECK(7,5,0) || \ - LIBRG_TI_CL7X_VERSION_CHECK(1,2,0) || \ - LIBRG_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - LIBRG_PGI_VERSION_CHECK(17,10,0) +LIBRG_HAS_ATTRIBUTE(pure) || \ +LIBRG_GCC_VERSION_CHECK(2,96,0) || \ +LIBRG_INTEL_VERSION_CHECK(13,0,0) || \ +LIBRG_SUNPRO_VERSION_CHECK(5,11,0) || \ +LIBRG_ARM_VERSION_CHECK(4,1,0) || \ +LIBRG_IBM_VERSION_CHECK(10,1,0) || \ +LIBRG_TI_VERSION_CHECK(15,12,0) || \ +(LIBRG_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +LIBRG_TI_ARMCL_VERSION_CHECK(5,2,0) || \ +(LIBRG_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +LIBRG_TI_CL2000_VERSION_CHECK(6,4,0) || \ +(LIBRG_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +LIBRG_TI_CL430_VERSION_CHECK(4,3,0) || \ +(LIBRG_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +LIBRG_TI_CL6X_VERSION_CHECK(7,5,0) || \ +LIBRG_TI_CL7X_VERSION_CHECK(1,2,0) || \ +LIBRG_TI_CLPRU_VERSION_CHECK(2,1,0) || \ +LIBRG_PGI_VERSION_CHECK(17,10,0) # define LIBRG_PURE __attribute__((__pure__)) #elif LIBRG_SUNPRO_VERSION_CHECK(5,10,0) # define LIBRG_PURE _Pragma("does_not_write_global_data") #elif defined(__cplusplus) && \ - ( \ - LIBRG_TI_CL430_VERSION_CHECK(2,0,1) || \ - LIBRG_TI_CL6X_VERSION_CHECK(4,0,0) || \ - LIBRG_TI_CL7X_VERSION_CHECK(1,2,0) \ - ) +( \ +LIBRG_TI_CL430_VERSION_CHECK(2,0,1) || \ +LIBRG_TI_CL6X_VERSION_CHECK(4,0,0) || \ +LIBRG_TI_CL7X_VERSION_CHECK(1,2,0) \ +) # define LIBRG_PURE _Pragma("FUNC_IS_PURE;") #else # define LIBRG_PURE @@ -1521,27 +1521,27 @@ LIBRG_DIAGNOSTIC_POP # undef LIBRG_CONST #endif #if \ - LIBRG_HAS_ATTRIBUTE(const) || \ - LIBRG_GCC_VERSION_CHECK(2,5,0) || \ - LIBRG_INTEL_VERSION_CHECK(13,0,0) || \ - LIBRG_SUNPRO_VERSION_CHECK(5,11,0) || \ - LIBRG_ARM_VERSION_CHECK(4,1,0) || \ - LIBRG_IBM_VERSION_CHECK(10,1,0) || \ - LIBRG_TI_VERSION_CHECK(15,12,0) || \ - (LIBRG_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - LIBRG_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (LIBRG_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - LIBRG_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (LIBRG_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - LIBRG_TI_CL430_VERSION_CHECK(4,3,0) || \ - (LIBRG_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - LIBRG_TI_CL6X_VERSION_CHECK(7,5,0) || \ - LIBRG_TI_CL7X_VERSION_CHECK(1,2,0) || \ - LIBRG_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - LIBRG_PGI_VERSION_CHECK(17,10,0) +LIBRG_HAS_ATTRIBUTE(const) || \ +LIBRG_GCC_VERSION_CHECK(2,5,0) || \ +LIBRG_INTEL_VERSION_CHECK(13,0,0) || \ +LIBRG_SUNPRO_VERSION_CHECK(5,11,0) || \ +LIBRG_ARM_VERSION_CHECK(4,1,0) || \ +LIBRG_IBM_VERSION_CHECK(10,1,0) || \ +LIBRG_TI_VERSION_CHECK(15,12,0) || \ +(LIBRG_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +LIBRG_TI_ARMCL_VERSION_CHECK(5,2,0) || \ +(LIBRG_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +LIBRG_TI_CL2000_VERSION_CHECK(6,4,0) || \ +(LIBRG_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +LIBRG_TI_CL430_VERSION_CHECK(4,3,0) || \ +(LIBRG_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +LIBRG_TI_CL6X_VERSION_CHECK(7,5,0) || \ +LIBRG_TI_CL7X_VERSION_CHECK(1,2,0) || \ +LIBRG_TI_CLPRU_VERSION_CHECK(2,1,0) || \ +LIBRG_PGI_VERSION_CHECK(17,10,0) # define LIBRG_CONST __attribute__((__const__)) #elif \ - LIBRG_SUNPRO_VERSION_CHECK(5,10,0) +LIBRG_SUNPRO_VERSION_CHECK(5,10,0) # define LIBRG_CONST _Pragma("no_side_effect") #else # define LIBRG_CONST LIBRG_PURE @@ -1553,19 +1553,19 @@ LIBRG_DIAGNOSTIC_POP #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && !defined(__cplusplus) # define LIBRG_RESTRICT restrict #elif \ - LIBRG_GCC_VERSION_CHECK(3,1,0) || \ - LIBRG_MSVC_VERSION_CHECK(14,0,0) || \ - LIBRG_INTEL_VERSION_CHECK(13,0,0) || \ - LIBRG_ARM_VERSION_CHECK(4,1,0) || \ - LIBRG_IBM_VERSION_CHECK(10,1,0) || \ - LIBRG_PGI_VERSION_CHECK(17,10,0) || \ - LIBRG_TI_CL430_VERSION_CHECK(4,3,0) || \ - LIBRG_TI_CL2000_VERSION_CHECK(6,2,4) || \ - LIBRG_TI_CL6X_VERSION_CHECK(8,1,0) || \ - LIBRG_TI_CL7X_VERSION_CHECK(1,2,0) || \ - (LIBRG_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)) || \ - LIBRG_IAR_VERSION_CHECK(8,0,0) || \ - defined(__clang__) +LIBRG_GCC_VERSION_CHECK(3,1,0) || \ +LIBRG_MSVC_VERSION_CHECK(14,0,0) || \ +LIBRG_INTEL_VERSION_CHECK(13,0,0) || \ +LIBRG_ARM_VERSION_CHECK(4,1,0) || \ +LIBRG_IBM_VERSION_CHECK(10,1,0) || \ +LIBRG_PGI_VERSION_CHECK(17,10,0) || \ +LIBRG_TI_CL430_VERSION_CHECK(4,3,0) || \ +LIBRG_TI_CL2000_VERSION_CHECK(6,2,4) || \ +LIBRG_TI_CL6X_VERSION_CHECK(8,1,0) || \ +LIBRG_TI_CL7X_VERSION_CHECK(1,2,0) || \ +(LIBRG_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)) || \ +LIBRG_IAR_VERSION_CHECK(8,0,0) || \ +defined(__clang__) # define LIBRG_RESTRICT __restrict #elif LIBRG_SUNPRO_VERSION_CHECK(5,3,0) && !defined(__cplusplus) # define LIBRG_RESTRICT _Restrict @@ -1577,22 +1577,22 @@ LIBRG_DIAGNOSTIC_POP # undef LIBRG_INLINE #endif #if \ - (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ - (defined(__cplusplus) && (__cplusplus >= 199711L)) +(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ +(defined(__cplusplus) && (__cplusplus >= 199711L)) # define LIBRG_INLINE inline #elif \ - defined(LIBRG_GCC_VERSION) || \ - LIBRG_ARM_VERSION_CHECK(6,2,0) +defined(LIBRG_GCC_VERSION) || \ +LIBRG_ARM_VERSION_CHECK(6,2,0) # define LIBRG_INLINE __inline__ #elif \ - LIBRG_MSVC_VERSION_CHECK(12,0,0) || \ - LIBRG_ARM_VERSION_CHECK(4,1,0) || \ - LIBRG_TI_ARMCL_VERSION_CHECK(5,1,0) || \ - LIBRG_TI_CL430_VERSION_CHECK(3,1,0) || \ - LIBRG_TI_CL2000_VERSION_CHECK(6,2,0) || \ - LIBRG_TI_CL6X_VERSION_CHECK(8,0,0) || \ - LIBRG_TI_CL7X_VERSION_CHECK(1,2,0) || \ - LIBRG_TI_CLPRU_VERSION_CHECK(2,1,0) +LIBRG_MSVC_VERSION_CHECK(12,0,0) || \ +LIBRG_ARM_VERSION_CHECK(4,1,0) || \ +LIBRG_TI_ARMCL_VERSION_CHECK(5,1,0) || \ +LIBRG_TI_CL430_VERSION_CHECK(3,1,0) || \ +LIBRG_TI_CL2000_VERSION_CHECK(6,2,0) || \ +LIBRG_TI_CL6X_VERSION_CHECK(8,0,0) || \ +LIBRG_TI_CL7X_VERSION_CHECK(1,2,0) || \ +LIBRG_TI_CLPRU_VERSION_CHECK(2,1,0) # define LIBRG_INLINE __inline #else # define LIBRG_INLINE @@ -1602,35 +1602,35 @@ LIBRG_DIAGNOSTIC_POP # undef LIBRG_ALWAYS_INLINE #endif #if \ - LIBRG_HAS_ATTRIBUTE(always_inline) || \ - LIBRG_GCC_VERSION_CHECK(4,0,0) || \ - LIBRG_INTEL_VERSION_CHECK(13,0,0) || \ - LIBRG_SUNPRO_VERSION_CHECK(5,11,0) || \ - LIBRG_ARM_VERSION_CHECK(4,1,0) || \ - LIBRG_IBM_VERSION_CHECK(10,1,0) || \ - LIBRG_TI_VERSION_CHECK(15,12,0) || \ - (LIBRG_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - LIBRG_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (LIBRG_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - LIBRG_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (LIBRG_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - LIBRG_TI_CL430_VERSION_CHECK(4,3,0) || \ - (LIBRG_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - LIBRG_TI_CL6X_VERSION_CHECK(7,5,0) || \ - LIBRG_TI_CL7X_VERSION_CHECK(1,2,0) || \ - LIBRG_TI_CLPRU_VERSION_CHECK(2,1,0) +LIBRG_HAS_ATTRIBUTE(always_inline) || \ +LIBRG_GCC_VERSION_CHECK(4,0,0) || \ +LIBRG_INTEL_VERSION_CHECK(13,0,0) || \ +LIBRG_SUNPRO_VERSION_CHECK(5,11,0) || \ +LIBRG_ARM_VERSION_CHECK(4,1,0) || \ +LIBRG_IBM_VERSION_CHECK(10,1,0) || \ +LIBRG_TI_VERSION_CHECK(15,12,0) || \ +(LIBRG_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +LIBRG_TI_ARMCL_VERSION_CHECK(5,2,0) || \ +(LIBRG_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +LIBRG_TI_CL2000_VERSION_CHECK(6,4,0) || \ +(LIBRG_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +LIBRG_TI_CL430_VERSION_CHECK(4,3,0) || \ +(LIBRG_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +LIBRG_TI_CL6X_VERSION_CHECK(7,5,0) || \ +LIBRG_TI_CL7X_VERSION_CHECK(1,2,0) || \ +LIBRG_TI_CLPRU_VERSION_CHECK(2,1,0) # define LIBRG_ALWAYS_INLINE __attribute__((__always_inline__)) LIBRG_INLINE #elif LIBRG_MSVC_VERSION_CHECK(12,0,0) # define LIBRG_ALWAYS_INLINE __forceinline #elif defined(__cplusplus) && \ - ( \ - LIBRG_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - LIBRG_TI_CL430_VERSION_CHECK(4,3,0) || \ - LIBRG_TI_CL2000_VERSION_CHECK(6,4,0) || \ - LIBRG_TI_CL6X_VERSION_CHECK(6,1,0) || \ - LIBRG_TI_CL7X_VERSION_CHECK(1,2,0) || \ - LIBRG_TI_CLPRU_VERSION_CHECK(2,1,0) \ - ) +( \ +LIBRG_TI_ARMCL_VERSION_CHECK(5,2,0) || \ +LIBRG_TI_CL430_VERSION_CHECK(4,3,0) || \ +LIBRG_TI_CL2000_VERSION_CHECK(6,4,0) || \ +LIBRG_TI_CL6X_VERSION_CHECK(6,1,0) || \ +LIBRG_TI_CL7X_VERSION_CHECK(1,2,0) || \ +LIBRG_TI_CLPRU_VERSION_CHECK(2,1,0) \ +) # define LIBRG_ALWAYS_INLINE _Pragma("FUNC_ALWAYS_INLINE;") #elif LIBRG_IAR_VERSION_CHECK(8,0,0) # define LIBRG_ALWAYS_INLINE _Pragma("inline=forced") @@ -1642,23 +1642,23 @@ LIBRG_DIAGNOSTIC_POP # undef LIBRG_NEVER_INLINE #endif #if \ - LIBRG_HAS_ATTRIBUTE(noinline) || \ - LIBRG_GCC_VERSION_CHECK(4,0,0) || \ - LIBRG_INTEL_VERSION_CHECK(13,0,0) || \ - LIBRG_SUNPRO_VERSION_CHECK(5,11,0) || \ - LIBRG_ARM_VERSION_CHECK(4,1,0) || \ - LIBRG_IBM_VERSION_CHECK(10,1,0) || \ - LIBRG_TI_VERSION_CHECK(15,12,0) || \ - (LIBRG_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - LIBRG_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (LIBRG_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - LIBRG_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (LIBRG_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - LIBRG_TI_CL430_VERSION_CHECK(4,3,0) || \ - (LIBRG_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - LIBRG_TI_CL6X_VERSION_CHECK(7,5,0) || \ - LIBRG_TI_CL7X_VERSION_CHECK(1,2,0) || \ - LIBRG_TI_CLPRU_VERSION_CHECK(2,1,0) +LIBRG_HAS_ATTRIBUTE(noinline) || \ +LIBRG_GCC_VERSION_CHECK(4,0,0) || \ +LIBRG_INTEL_VERSION_CHECK(13,0,0) || \ +LIBRG_SUNPRO_VERSION_CHECK(5,11,0) || \ +LIBRG_ARM_VERSION_CHECK(4,1,0) || \ +LIBRG_IBM_VERSION_CHECK(10,1,0) || \ +LIBRG_TI_VERSION_CHECK(15,12,0) || \ +(LIBRG_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +LIBRG_TI_ARMCL_VERSION_CHECK(5,2,0) || \ +(LIBRG_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +LIBRG_TI_CL2000_VERSION_CHECK(6,4,0) || \ +(LIBRG_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +LIBRG_TI_CL430_VERSION_CHECK(4,3,0) || \ +(LIBRG_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +LIBRG_TI_CL6X_VERSION_CHECK(7,5,0) || \ +LIBRG_TI_CL7X_VERSION_CHECK(1,2,0) || \ +LIBRG_TI_CLPRU_VERSION_CHECK(2,1,0) # define LIBRG_NEVER_INLINE __attribute__((__noinline__)) #elif LIBRG_MSVC_VERSION_CHECK(13,10,0) # define LIBRG_NEVER_INLINE __declspec(noinline) @@ -1691,19 +1691,19 @@ LIBRG_DIAGNOSTIC_POP # define LIBRG_IMPORT __declspec(dllimport) #else # if \ - LIBRG_HAS_ATTRIBUTE(visibility) || \ - LIBRG_GCC_VERSION_CHECK(3,3,0) || \ - LIBRG_SUNPRO_VERSION_CHECK(5,11,0) || \ - LIBRG_INTEL_VERSION_CHECK(13,0,0) || \ - LIBRG_ARM_VERSION_CHECK(4,1,0) || \ - LIBRG_IBM_VERSION_CHECK(13,1,0) || \ - ( \ - defined(__TI_EABI__) && \ - ( \ - (LIBRG_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - LIBRG_TI_CL6X_VERSION_CHECK(7,5,0) \ - ) \ - ) +LIBRG_HAS_ATTRIBUTE(visibility) || \ +LIBRG_GCC_VERSION_CHECK(3,3,0) || \ +LIBRG_SUNPRO_VERSION_CHECK(5,11,0) || \ +LIBRG_INTEL_VERSION_CHECK(13,0,0) || \ +LIBRG_ARM_VERSION_CHECK(4,1,0) || \ +LIBRG_IBM_VERSION_CHECK(13,1,0) || \ +( \ +defined(__TI_EABI__) && \ +( \ +(LIBRG_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +LIBRG_TI_CL6X_VERSION_CHECK(7,5,0) \ +) \ +) # define LIBRG_PRIVATE __attribute__((__visibility__("hidden"))) # define LIBRG_PUBLIC __attribute__((__visibility__("default"))) # else @@ -1717,13 +1717,13 @@ LIBRG_DIAGNOSTIC_POP # undef LIBRG_NO_THROW #endif #if \ - LIBRG_HAS_ATTRIBUTE(nothrow) || \ - LIBRG_GCC_VERSION_CHECK(3,3,0) || \ - LIBRG_INTEL_VERSION_CHECK(13,0,0) +LIBRG_HAS_ATTRIBUTE(nothrow) || \ +LIBRG_GCC_VERSION_CHECK(3,3,0) || \ +LIBRG_INTEL_VERSION_CHECK(13,0,0) # define LIBRG_NO_THROW __attribute__((__nothrow__)) #elif \ - LIBRG_MSVC_VERSION_CHECK(13,1,0) || \ - LIBRG_ARM_VERSION_CHECK(4,1,0) +LIBRG_MSVC_VERSION_CHECK(13,1,0) || \ +LIBRG_ARM_VERSION_CHECK(4,1,0) # define LIBRG_NO_THROW __declspec(nothrow) #else # define LIBRG_NO_THROW @@ -1733,8 +1733,8 @@ LIBRG_DIAGNOSTIC_POP # undef LIBRG_FALL_THROUGH #endif #if \ - LIBRG_HAS_ATTRIBUTE(fallthrough) || \ - LIBRG_GCC_VERSION_CHECK(7,0,0) +LIBRG_HAS_ATTRIBUTE(fallthrough) || \ +LIBRG_GCC_VERSION_CHECK(7,0,0) # define LIBRG_FALL_THROUGH __attribute__((__fallthrough__)) #elif LIBRG_HAS_CPP_ATTRIBUTE_NS(clang,fallthrough) # define LIBRG_FALL_THROUGH LIBRG_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[clang::fallthrough]]) @@ -1750,8 +1750,8 @@ LIBRG_DIAGNOSTIC_POP # undef LIBRG_RETURNS_NON_NULL #endif #if \ - LIBRG_HAS_ATTRIBUTE(returns_nonnull) || \ - LIBRG_GCC_VERSION_CHECK(4,9,0) +LIBRG_HAS_ATTRIBUTE(returns_nonnull) || \ +LIBRG_GCC_VERSION_CHECK(4,9,0) # define LIBRG_RETURNS_NON_NULL __attribute__((__returns_nonnull__)) #elif defined(_Ret_notnull_) /* SAL */ # define LIBRG_RETURNS_NON_NULL _Ret_notnull_ @@ -1763,11 +1763,11 @@ LIBRG_DIAGNOSTIC_POP # undef LIBRG_ARRAY_PARAM #endif #if \ - defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ - !defined(__STDC_NO_VLA__) && \ - !defined(__cplusplus) && \ - !defined(LIBRG_PGI_VERSION) && \ - !defined(LIBRG_TINYC_VERSION) +defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ +!defined(__STDC_NO_VLA__) && \ +!defined(__cplusplus) && \ +!defined(LIBRG_PGI_VERSION) && \ +!defined(LIBRG_TINYC_VERSION) # define LIBRG_ARRAY_PARAM(name) (name) #else # define LIBRG_ARRAY_PARAM(name) @@ -1785,26 +1785,26 @@ LIBRG_DIAGNOSTIC_POP # undef LIBRG_IS_CONSTEXPR_ #endif #if \ - LIBRG_HAS_BUILTIN(__builtin_constant_p) || \ - LIBRG_GCC_VERSION_CHECK(3,4,0) || \ - LIBRG_INTEL_VERSION_CHECK(13,0,0) || \ - LIBRG_TINYC_VERSION_CHECK(0,9,19) || \ - LIBRG_ARM_VERSION_CHECK(4,1,0) || \ - LIBRG_IBM_VERSION_CHECK(13,1,0) || \ - LIBRG_TI_CL6X_VERSION_CHECK(6,1,0) || \ - (LIBRG_SUNPRO_VERSION_CHECK(5,10,0) && !defined(__cplusplus)) || \ - LIBRG_CRAY_VERSION_CHECK(8,1,0) +LIBRG_HAS_BUILTIN(__builtin_constant_p) || \ +LIBRG_GCC_VERSION_CHECK(3,4,0) || \ +LIBRG_INTEL_VERSION_CHECK(13,0,0) || \ +LIBRG_TINYC_VERSION_CHECK(0,9,19) || \ +LIBRG_ARM_VERSION_CHECK(4,1,0) || \ +LIBRG_IBM_VERSION_CHECK(13,1,0) || \ +LIBRG_TI_CL6X_VERSION_CHECK(6,1,0) || \ +(LIBRG_SUNPRO_VERSION_CHECK(5,10,0) && !defined(__cplusplus)) || \ +LIBRG_CRAY_VERSION_CHECK(8,1,0) # define LIBRG_IS_CONSTANT(expr) __builtin_constant_p(expr) #endif #if !defined(__cplusplus) # if \ - LIBRG_HAS_BUILTIN(__builtin_types_compatible_p) || \ - LIBRG_GCC_VERSION_CHECK(3,4,0) || \ - LIBRG_INTEL_VERSION_CHECK(13,0,0) || \ - LIBRG_IBM_VERSION_CHECK(13,1,0) || \ - LIBRG_CRAY_VERSION_CHECK(8,1,0) || \ - LIBRG_ARM_VERSION_CHECK(5,4,0) || \ - LIBRG_TINYC_VERSION_CHECK(0,9,24) +LIBRG_HAS_BUILTIN(__builtin_types_compatible_p) || \ +LIBRG_GCC_VERSION_CHECK(3,4,0) || \ +LIBRG_INTEL_VERSION_CHECK(13,0,0) || \ +LIBRG_IBM_VERSION_CHECK(13,1,0) || \ +LIBRG_CRAY_VERSION_CHECK(8,1,0) || \ +LIBRG_ARM_VERSION_CHECK(5,4,0) || \ +LIBRG_TINYC_VERSION_CHECK(0,9,24) # if defined(__INTPTR_TYPE__) # define LIBRG_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0)), int*) # else @@ -1812,16 +1812,16 @@ LIBRG_DIAGNOSTIC_POP # define LIBRG_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((intptr_t) ((expr) * 0)) : (int*) 0)), int*) # endif # elif \ - ( \ - defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && \ - !defined(LIBRG_SUNPRO_VERSION) && \ - !defined(LIBRG_PGI_VERSION) && \ - !defined(LIBRG_IAR_VERSION)) || \ - LIBRG_HAS_EXTENSION(c_generic_selections) || \ - LIBRG_GCC_VERSION_CHECK(4,9,0) || \ - LIBRG_INTEL_VERSION_CHECK(17,0,0) || \ - LIBRG_IBM_VERSION_CHECK(12,1,0) || \ - LIBRG_ARM_VERSION_CHECK(5,3,0) +( \ +defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && \ +!defined(LIBRG_SUNPRO_VERSION) && \ +!defined(LIBRG_PGI_VERSION) && \ +!defined(LIBRG_IAR_VERSION)) || \ +LIBRG_HAS_EXTENSION(c_generic_selections) || \ +LIBRG_GCC_VERSION_CHECK(4,9,0) || \ +LIBRG_INTEL_VERSION_CHECK(17,0,0) || \ +LIBRG_IBM_VERSION_CHECK(12,1,0) || \ +LIBRG_ARM_VERSION_CHECK(5,3,0) # if defined(__INTPTR_TYPE__) # define LIBRG_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0), int*: 1, void*: 0) # else @@ -1829,25 +1829,25 @@ LIBRG_DIAGNOSTIC_POP # define LIBRG_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((intptr_t) * 0) : (int*) 0), int*: 1, void*: 0) # endif # elif \ - defined(LIBRG_GCC_VERSION) || \ - defined(LIBRG_INTEL_VERSION) || \ - defined(LIBRG_TINYC_VERSION) || \ - defined(LIBRG_TI_ARMCL_VERSION) || \ - LIBRG_TI_CL430_VERSION_CHECK(18,12,0) || \ - defined(LIBRG_TI_CL2000_VERSION) || \ - defined(LIBRG_TI_CL6X_VERSION) || \ - defined(LIBRG_TI_CL7X_VERSION) || \ - defined(LIBRG_TI_CLPRU_VERSION) || \ - defined(__clang__) +defined(LIBRG_GCC_VERSION) || \ +defined(LIBRG_INTEL_VERSION) || \ +defined(LIBRG_TINYC_VERSION) || \ +defined(LIBRG_TI_ARMCL_VERSION) || \ +LIBRG_TI_CL430_VERSION_CHECK(18,12,0) || \ +defined(LIBRG_TI_CL2000_VERSION) || \ +defined(LIBRG_TI_CL6X_VERSION) || \ +defined(LIBRG_TI_CL7X_VERSION) || \ +defined(LIBRG_TI_CLPRU_VERSION) || \ +defined(__clang__) # define LIBRG_IS_CONSTEXPR_(expr) ( \ - sizeof(void) != \ - sizeof(*( \ - 1 ? \ - ((void*) ((expr) * 0L) ) : \ - ((struct { char v[sizeof(void) * 2]; } *) 1) \ - ) \ - ) \ - ) +sizeof(void) != \ +sizeof(*( \ +1 ? \ +((void*) ((expr) * 0L) ) : \ +((struct { char v[sizeof(void) * 2]; } *) 1) \ +) \ +) \ +) # endif #endif #if defined(LIBRG_IS_CONSTEXPR_) @@ -1885,17 +1885,17 @@ LIBRG_DIAGNOSTIC_POP # undef LIBRG_STATIC_ASSERT #endif #if \ - !defined(__cplusplus) && ( \ - (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || \ - LIBRG_HAS_FEATURE(c_static_assert) || \ - LIBRG_GCC_VERSION_CHECK(6,0,0) || \ - LIBRG_INTEL_VERSION_CHECK(13,0,0) || \ - defined(_Static_assert) \ - ) +!defined(__cplusplus) && ( \ +(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || \ +LIBRG_HAS_FEATURE(c_static_assert) || \ +LIBRG_GCC_VERSION_CHECK(6,0,0) || \ +LIBRG_INTEL_VERSION_CHECK(13,0,0) || \ +defined(_Static_assert) \ +) # define LIBRG_STATIC_ASSERT(expr, message) _Static_assert(expr, message) #elif \ - (defined(__cplusplus) && (__cplusplus >= 201103L)) || \ - LIBRG_MSVC_VERSION_CHECK(16,0,0) +(defined(__cplusplus) && (__cplusplus >= 201103L)) || \ +LIBRG_MSVC_VERSION_CHECK(16,0,0) # define LIBRG_STATIC_ASSERT(expr, message) LIBRG_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(static_assert(expr, message)) #else # define LIBRG_STATIC_ASSERT(expr, message) @@ -1923,13 +1923,13 @@ LIBRG_DIAGNOSTIC_POP #endif #if LIBRG_HAS_WARNING("-Wunknown-pragmas") # define LIBRG_MESSAGE(msg) \ - LIBRG_DIAGNOSTIC_PUSH \ - LIBRG_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ - LIBRG_PRAGMA(message msg) \ - LIBRG_DIAGNOSTIC_POP +LIBRG_DIAGNOSTIC_PUSH \ +LIBRG_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ +LIBRG_PRAGMA(message msg) \ +LIBRG_DIAGNOSTIC_POP #elif \ - LIBRG_GCC_VERSION_CHECK(4,4,0) || \ - LIBRG_INTEL_VERSION_CHECK(13,0,0) +LIBRG_GCC_VERSION_CHECK(4,4,0) || \ +LIBRG_INTEL_VERSION_CHECK(13,0,0) # define LIBRG_MESSAGE(msg) LIBRG_PRAGMA(message msg) #elif LIBRG_CRAY_VERSION_CHECK(5,0,0) # define LIBRG_MESSAGE(msg) LIBRG_PRAGMA(_CRI message msg) @@ -1946,14 +1946,14 @@ LIBRG_DIAGNOSTIC_POP #endif #if LIBRG_HAS_WARNING("-Wunknown-pragmas") # define LIBRG_WARNING(msg) \ - LIBRG_DIAGNOSTIC_PUSH \ - LIBRG_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ - LIBRG_PRAGMA(clang warning msg) \ - LIBRG_DIAGNOSTIC_POP +LIBRG_DIAGNOSTIC_PUSH \ +LIBRG_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ +LIBRG_PRAGMA(clang warning msg) \ +LIBRG_DIAGNOSTIC_POP #elif \ - LIBRG_GCC_VERSION_CHECK(4,8,0) || \ - LIBRG_PGI_VERSION_CHECK(18,4,0) || \ - LIBRG_INTEL_VERSION_CHECK(13,0,0) +LIBRG_GCC_VERSION_CHECK(4,8,0) || \ +LIBRG_PGI_VERSION_CHECK(18,4,0) || \ +LIBRG_INTEL_VERSION_CHECK(13,0,0) # define LIBRG_WARNING(msg) LIBRG_PRAGMA(GCC warning msg) #elif LIBRG_MSVC_VERSION_CHECK(15,0,0) # define LIBRG_WARNING(msg) LIBRG_PRAGMA(message(msg)) @@ -1970,15 +1970,15 @@ LIBRG_DIAGNOSTIC_POP #if LIBRG_HAS_ATTRIBUTE(diagnose_if) # if LIBRG_HAS_WARNING("-Wgcc-compat") # define LIBRG_REQUIRE(expr) \ - LIBRG_DIAGNOSTIC_PUSH \ - _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ - __attribute__((diagnose_if(!(expr), #expr, "error"))) \ - LIBRG_DIAGNOSTIC_POP +LIBRG_DIAGNOSTIC_PUSH \ +_Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ +__attribute__((diagnose_if(!(expr), #expr, "error"))) \ +LIBRG_DIAGNOSTIC_POP # define LIBRG_REQUIRE_MSG(expr,msg) \ - LIBRG_DIAGNOSTIC_PUSH \ - _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ - __attribute__((diagnose_if(!(expr), msg, "error"))) \ - LIBRG_DIAGNOSTIC_POP +LIBRG_DIAGNOSTIC_PUSH \ +_Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ +__attribute__((diagnose_if(!(expr), msg, "error"))) \ +LIBRG_DIAGNOSTIC_POP # else # define LIBRG_REQUIRE(expr) __attribute__((diagnose_if(!(expr), #expr, "error"))) # define LIBRG_REQUIRE_MSG(expr,msg) __attribute__((diagnose_if(!(expr), msg, "error"))) @@ -2000,11 +2000,11 @@ LIBRG_DIAGNOSTIC_POP #endif #if LIBRG_INTEL_VERSION_CHECK(19,0,0) # define LIBRG_FLAGS_CAST(T, expr) (__extension__ ({ \ - LIBRG_DIAGNOSTIC_PUSH \ - _Pragma("warning(disable:188)") \ - ((T) (expr)); \ - LIBRG_DIAGNOSTIC_POP \ - })) +LIBRG_DIAGNOSTIC_PUSH \ +_Pragma("warning(disable:188)") \ +((T) (expr)); \ +LIBRG_DIAGNOSTIC_POP \ +})) #else # define LIBRG_FLAGS_CAST(T, expr) LIBRG_STATIC_CAST(T, expr) #endif @@ -2069,44 +2069,44 @@ LIBRG_DIAGNOSTIC_POP #define LIBRG_VERSION LIBRG_VERSION_ENCODE(LIBRG_VERSION_MAJOR, LIBRG_VERSION_MINOR, LIBRG_VERSION_PATCH) #ifdef LIBRG_IMPL - #ifndef LIBRG_IMPLEMENTATION - #define LIBRG_IMPLEMENTATION - #endif +#ifndef LIBRG_IMPLEMENTATION +#define LIBRG_IMPLEMENTATION +#endif #endif #if defined(__cplusplus) && !defined(LIBRG_EXTERN) - #define LIBRG_EXTERN extern "C" +#define LIBRG_EXTERN extern "C" #else - #define LIBRG_EXTERN extern +#define LIBRG_EXTERN extern #endif #ifndef LIBRG_API - #if defined(LIBRG_SHARED_LIB) - #ifdef LIBRG_IMPLEMENTATION - #define LIBRG_API LIBRG_PUBLIC - #else - #define LIBRG_API LIBRG_IMPORT - #endif - #elif defined(LIBRG_STATIC_LIB) - #ifdef LIBRG_IMPLEMENTATION - #define LIBRG_API - #else - #define LIBRG_API LIBRG_EXTERN - #endif - #elif defined(LIBRG_STATIC) - #define LIBRG_API static - #elif defined(LIBRG_EMSCRIPTEN) - #define LIBRG_API EMSCRIPTEN_KEEPALIVE - #else - #define LIBRG_API LIBRG_EXTERN - #endif +#if defined(LIBRG_SHARED_LIB) +#ifdef LIBRG_IMPLEMENTATION +#define LIBRG_API LIBRG_PUBLIC +#else +#define LIBRG_API LIBRG_IMPORT +#endif +#elif defined(LIBRG_STATIC_LIB) +#ifdef LIBRG_IMPLEMENTATION +#define LIBRG_API +#else +#define LIBRG_API LIBRG_EXTERN +#endif +#elif defined(LIBRG_STATIC) +#define LIBRG_API static +#elif defined(LIBRG_EMSCRIPTEN) +#define LIBRG_API EMSCRIPTEN_KEEPALIVE +#else +#define LIBRG_API LIBRG_EXTERN +#endif #endif #include #include #if defined(__EMSCRIPTEN__) - #include +#include #endif // file: header/types.h @@ -2139,11 +2139,11 @@ typedef enum librg_event_type { LIBRG_WRITE_CREATE, LIBRG_WRITE_UPDATE, LIBRG_WRITE_REMOVE, - + LIBRG_READ_CREATE, LIBRG_READ_UPDATE, LIBRG_READ_REMOVE, - + LIBRG_ERROR_CREATE, LIBRG_ERROR_UPDATE, LIBRG_ERROR_REMOVE, @@ -2342,17232 +2342,17232 @@ LIBRG_END_C_DECLS #define LIBRG_IMPLEMENTATION_DONE #ifndef LIBRG_CUSTOM_ZPL - #define ZPL_NANO - #define ZPL_IMPL - - /** - ZPL - Your (almost) C99 Powerkit - - Usage: - #define ZPL_IMPLEMENTATION exactly in ONE source file right BEFORE including the library, like: - - #define ZPL_IMPLEMENTATION - #include "zpl.h" - - You can also use a freestanding version of ZPL by using ZPL_NANO, like: - - #define ZPL_IMPLEMENTATION - #define ZPL_NANO - #include "zpl.h" - - Options: - - ZPL_EDITOR - This macro should be used by the IDE's Intellisense to parse ZPL correctly. It can NEVER be used for actual compilation of the library! - ZPL_EXPOSE_TYPES - exposes all ZPL defined types to the global namespace. This means type such as `zpl_u32` is now available as `u32` globally. - ZPL_DEFINE_NULL_MACRO - to let ZPL define what NULL stands for in case it is undefined. - ZPL_NO_MATH_H - disables the use of math.h library and replaces it with custom routines or SIMD. - - Credits: - Read AUTHORS.md - - GitHub: - https://github.com/zpl-c/zpl - - Version History: - 10.13.0 - Initial ARM threading support - 10.12.1 - Fix missing zpL_alloc_str - 10.12.0 - Add zpl_crc64 - 10.11.1 - Fix zpl_time_utc_ms on 32-bit OSes - 10.11.0 - Added zpl_file_stream_buf - 10.10.3 - Math type-punning fixes - 10.10.1 - Fix memory writing issue + new write-only in-situ flag - 10.10.0 - Implement memory streaming API - 10.9.1 - Support ARMv6, ARMv7 and ARMv8-a builds - 10.9.0 - Improve the time API - 10.8.3 - zpl_file_close tempfile Windows fixes - 10.8.2 - zpl_file_temp disallow some operations - 10.8.1 - zpl_file_temp Windows fixes - 10.8.0 - Implemented zpl_json_write_string - 10.7.1 - Fix zpl_file_temp platform bug - 10.7.0 - Add zpl_file_write_contents - 10.6.6 - Fix type mismatch in Jobs system - 10.6.0 - Remove event system - 10.5.8 - Remove zpl__memcpy_4byte - 10.5.7 - zpl_file_new is now OS-agnostic constructor - 10.5.6 - Fix coroutine creation - 10.5.5 - Jobs system uses zpl_f32 for priority setting - 10.5.4 - zpl_buffer_free no longer takes the 2nd argument (allocator) - 10.5.3 - Removed crc64 and annotated some hashing methods - 10.5.2 - Don't expose ZPL types anymore - 10.5.1 - Fixed zpl_rdtsc for Emscripten - 10.5.0 - Changed casts to memcopy in random methods, added embed cmd - 10.4.1 - Jobs system now enqueues jobs with def priority of 1.0 - 10.4.0 - [META] version bump - 10.3.0 - Pool allocator now supports zpl_free_all - 10.2.0 - [META] version bump - 10.1.0 - Additional math methods (thanks to funZX and msmshazan) - 10.0.15 - WIP Emscripten fixes - 10.0.14 - FreeBSD support - 10.0.13 - OpenBSD support - 10.0.12 - Cygwin fixes - 10.0.11 - Tweak module dependencies - 10.0.10 - Fix zero-allocation regression in filesystem module - 10.0.9 - Fix multi-compilation unit builds - 10.0.8 - Fix zpl_printf "%0d" format specifier - 10.0.4 - Flush tester output to fix ordering - 10.0.3 - Fix ZPL_STATIC_ASSERT under MSVC - 10.0.0 - Major overhaul of the library - - 9.8.10 - JSON fix array-based documents with objects - 9.8.9 - JSON document structured as array now properly recognizes the root object as array. - 9.8.8 - Fixed an incorrect parsing of empty array nodes. - 9.8.7 - Improve FreeBSD support - 9.8.6 - WIP: Handle inlined methods properly - 9.8.5 - Fix incorrect usage of EOF and opts dependency on JSON5 module's methods - 9.8.4 - Fix MSVC ZPL_NO_MATH_H code branch using incorrect methods internally - 9.8.3 - Fix MinGW GCC related issue with zpl_printf %lld format - 9.8.2 - Fix VS C4190 issue - 9.8.1 - Fix several C++ type casting quirks - 9.8.0 - Incorporated OpenGL into ZPL core as an optional module - 9.7.0 - Added co-routine module - 9.6.0 - Added process module for creation and manipulation - 9.5.2 - zpl_printf family now prints (null) on NULL string arguments - 9.5.1 - Fixed JSON5 real number export support + indentation fixes - 9.5.0 - Added base64 encode/decode methods - 9.4.10- Small enum style changes - 9.4.9 - Remove #undef for cast and hard_cast (sorry) - 9.4.8 - Fix quote-less JSON node name resolution - 9.4.7 - Additional change to the code - 9.4.6 - Fix issue where zpl_json_find would have false match on substrings - 9.4.5 - Mistakes were made, fixed compilation errors - 9.4.3 - Fix old API shenanigans - 9.4.2 - Fix small API typos - 9.4.1 - Reordered JSON5 constants to integrate better with conditions - 9.4.0 - JSON5 API changes made to zpl_json_find - 9.3.0 - Change how zpl uses basic types internally - 9.2.0 - Directory listing was added. Check dirlist_api.c test for more info - 9.1.1 - Fix WIN32_LEAN_AND_MEAN redefinition properly - 9.1.0 - get_env rework and fixes - 9.0.3 - Small fixes and removals - 9.0.0 - New documentation format, removed deprecated code, changed styles - - 8.14.1 - Fix string library - 8.14.0 - Added zpl_re_match_all - 8.13.0 - Update system command API - 8.12.6 - Fix warning in CLI options parser - 8.12.5 - Support parametric options preceding positionals - 8.12.4 - Fixed opts positionals ordering - 8.12.3 - Fixed incorrect handling of flags preceding positionals - 8.12.2 - JSON parsing remark added - 8.12.1 - Fixed a lot of important stuff - 8.12.0 - Added helper constructors for containers - 8.11.2 - Fix bug in opts module - 8.11.1 - Small code improvements - 8.11.0 - Ported regex processor from https://github.com/gingerBill/gb/ and applied fixes on top of it - 8.10.2 - Fix zpl_strtok - 8.10.1 - Replace zpl_strchr by zpl_char_last_occurence - 8.10.0 - Added zpl_strchr - 8.9.0 - API improvements for JSON5 parser - 8.8.4 - Add support for SJSON formatting http://bitsquid.blogspot.com/2009/10/simplified-json-notation.html - - 6.8.3 - JSON5 exp fix - 6.8.2 - Bugfixes applied from gb - 6.8.1 - Performance improvements for JSON5 parser - 6.8.0 - zpl.h is now generated by build.py - 6.7.0 - Several fixes and added switches - 6.6.0 - Several significant changes made to the repository - 6.5.0 - Ported platform layer from https://github.com/gingerBill/gb/ - 6.4.1 - Use zpl_strlen in zpl_strdup - 6.4.0 - Deprecated zpl_buffer_free and added zpl_array_end, zpl_buffer_end - 6.3.0 - Added zpl_strdup - 6.2.1 - Remove math redundancies - 6.2.0 - Integrated zpl_math.h into zpl.h - 6.1.1 - Added direct.h include for win c++ dir methods - 6.1.0 - Added zpl_path_mkdir, zpl_path_rmdir, and few new zplFileErrors - 6.0.4 - More MSVC(++) satisfaction by fixing warnings - 6.0.3 - Satisfy MSVC by fixing a warning - 6.0.2 - Fixed warnings for json5 i64 printfs - 6.0.1 - Fixed warnings for particual win compiler in dirlist method - 6.0.0 - New build, include/ was renamed to code/ - - 5.8.3 - Naming fixes - 5.8.2 - Job system now supports prioritized tasks - 5.8.1 - Renames zpl_pad to zpl_ring - 5.8.0 - Added instantiated scratch pad (circular buffer) - 5.7.2 - Added Windows support for zpl_path_dirlist - 5.7.1 - Fixed few things in job system + macOS support for zpl_path_dirlist - 5.7.0 - Added a job system (zpl_thread_pool) - 5.6.5 - Fixes extra error cases for zpl_opts when input is: - - missing a value for an option, - - having an extra value for a flag (e.g. --enable-log shouldn't get a value.) - 5.6.4 - Several tweaks to the zpl_opts API - 5.6.3 - Added support for flags without values - 5.6.2 - Improve error handling for zpl_opts - 5.6.1 - Added support for strings with spaces in zpl_opts - 5.6.0 - Added zpl_opts for CLI argument parsing - 5.5.1 - Fixed time method for win - 5.5.0 - Integrate JSON5 writer into the core - 5.4.0 - Improved storage support for numbers in JSON5 parser - 5.3.0 - Integrated zpl_json into ZPL - 5.2.0 - Added zpl_string_sprintf - 5.1.1 - Added zpl_system_command_nores for output-less execution - 5.1.0 - Added event handler - 5.0.4 - Fix alias for zpl_list - 5.0.3 - Finalizing syntax changes - 5.0.2 - Fix segfault when using zpl_stack_memory - 5.0.1 - Small code improvements - 5.0.0 - Project structure changes - - 4.7.2 - Got rid of size arg for zpl_str_split_lines - 4.7.1 - Added an example - 4.7.0 - Added zpl_path_dirlist - 4.6.1 - zpl_memcopy x86 patch from upstream - 4.6.0 - Added few string-related functions - 4.5.9 - Error fixes - 4.5.8 - Warning fixes - 4.5.7 - Fixed timer loops. zpl_time* related functions work with seconds now - 4.5.6 - Fixed zpl_time_now() for Windows and Linux - 4.5.5 - Small cosmetic changes - 4.5.4 - Fixed issue when zpl_list_add would break the links - - when adding a new item between nodes - 4.5.3 - Fixed malformed enum values - 4.5.1 - Fixed some warnings - 4.5.0 - Added zpl_array_append_at - 4.4.0 - Added zpl_array_back, zpl_array_front - 4.3.0 - Added zpl_list - 4.2.0 - Added zpl_system_command_str - 4.1.2 - GG, fixed small compilation error - 4.1.1 - Fixed possible security issue in zpl_system_command - 4.1.0 - Added zpl_string_make_reserve and small fixes - 4.0.2 - Warning fix for _LARGEFILE64_SOURCE - 4.0.1 - include stdlib.h for getenv (temp) - 4.0.0 - ARM support, coding style changes and various improvements - - 3.4.1 - zpl_memcopy now uses memcpy for ARM arch-family - 3.4.0 - Removed obsolete code - 3.3.4 - Added Travis CI config - 3.3.3 - Small macro formatting changes + ZPL_SYSTEM_IOS - 3.3.2 - Fixes for android arm - 3.3.1 - Fixed some type cast warnings - 3.3.0 - Added Android support - 3.1.5 - Renamed userptr to user_data in timer - 3.1.4 - Fix for zpl_buffer not allocating correctly - 3.1.2 - Small fix in zpl_memcompare - 3.1.1 - Added char* conversion for data field in zpl_array_header - 3.1.0 - Added data field to zpl_array_header - 3.0.7 - Added timer userptr as argument to callback - 3.0.6 - Small changes - 3.0.5 - Fixed compilation for emscripten - 3.0.4 - Small fixes for tiny cpp warnings - 3.0.3 - Small fixes for various cpp warnings and errors - 3.0.2 - Fixed linux part, and removed trailing spaces - 3.0.1 - Small bugfix in zpl_file_open - 3.0.0 - Added several fixes and features - - 2.4.0 - Added remove to hash table - 2.3.3 - Removed redundant code - 2.3.2 - Eliminated extra warnings - 2.3.1 - Warning hunt - 2.3.0 - Added the ability to copy array/buffer and fixed bug in hash table. - 2.2.1 - Used tmpfile() for Windows - 2.2.0 - Added zpl_file_temp - 2.1.1 - Very small fix (forgive me) - 2.1.0 - Added the ability to resize bitstream - 2.0.8 - Small adjustments - 2.0.7 - MinGW related fixes - 2.0.0 - New NPM based version - - 1.2.2 - Small fix - 1.2.1 - Macro fixes - 1.2.0 - Added zpl_async macro - 1.1.0 - Added timer feature - 1.0.0 - Initial version - - This Software is dual licensed under the following licenses: - - Unlicense - This is free and unencumbered software released into the public domain. - - Anyone is free to copy, modify, publish, use, compile, sell, or - distribute this software, either in source code form or as a compiled - binary, for any purpose, commercial or non-commercial, and by any - means. - - In jurisdictions that recognize copyright laws, the author or authors - of this software dedicate any and all copyright interest in the - software to the public domain. We make this dedication for the benefit - of the public at large and to the detriment of our heirs and - successors. We intend this dedication to be an overt act of - relinquishment in perpetuity of all present and future rights to this - software under copyright law. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR - OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - OTHER DEALINGS IN THE SOFTWARE. - - For more information, please refer to - - BSD 3-Clause - - Copyright (c) 2016-2021 Dominik Madarász. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - 3. Neither the name of the copyright holder nor the names of its contributors - may be used to endorse or promote products derived from this software without - specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - - */ - - #ifndef ZPL_H - #define ZPL_H - - #define ZPL_VERSION_MAJOR 10 - #define ZPL_VERSION_MINOR 13 - #define ZPL_VERSION_PATCH 2 - #define ZPL_VERSION_PRE "" - - // file: zpl_hedley.h - - /* Hedley - https://nemequ.github.io/hedley - * Created by Evan Nemerson - * - * To the extent possible under law, the author(s) have dedicated all - * copyright and related and neighboring rights to this software to - * the public domain worldwide. This software is distributed without - * any warranty. - * - * For details, see . - * SPDX-License-Identifier: CC0-1.0 - */ - - #if !defined(ZPL_HEDLEY_VERSION) || (ZPL_HEDLEY_VERSION < 12) - #if defined(ZPL_HEDLEY_VERSION) - # undef ZPL_HEDLEY_VERSION - #endif - #define ZPL_HEDLEY_VERSION 12 - - #if defined(ZPL_STRINGIFY_EX) - # undef ZPL_STRINGIFY_EX - #endif - #define ZPL_STRINGIFY_EX(x) #x - - #if defined(ZPL_STRINGIFY) - # undef ZPL_STRINGIFY - #endif - #define ZPL_STRINGIFY(x) ZPL_STRINGIFY_EX(x) - - #if defined(ZPL_CONCAT_EX) - # undef ZPL_CONCAT_EX - #endif - #define ZPL_CONCAT_EX(a,b) a##b - - #if defined(ZPL_CONCAT) - # undef ZPL_CONCAT - #endif - #define ZPL_CONCAT(a,b) ZPL_CONCAT_EX(a,b) - - #if defined(ZPL_VERSION_ENCODE) - # undef ZPL_VERSION_ENCODE - #endif - #define ZPL_VERSION_ENCODE(major,minor,patch) (((major) * 1000000) + ((minor) * 1000) + (patch)) - - #if defined(ZPL_VERSION_DECODE_MAJOR) - # undef ZPL_VERSION_DECODE_MAJOR - #endif - #define ZPL_VERSION_DECODE_MAJOR(version) ((version) / 1000000) - - #if defined(ZPL_VERSION_DECODE_MINOR) - # undef ZPL_VERSION_DECODE_MINOR - #endif - #define ZPL_VERSION_DECODE_MINOR(version) (((version) % 1000000) / 1000) - - #if defined(ZPL_VERSION_DECODE_PATCH) - # undef ZPL_VERSION_DECODE_PATCH - #endif - #define ZPL_VERSION_DECODE_PATCH(version) ((version) % 1000) - - #if defined(ZPL_GNUC_VERSION) - # undef ZPL_GNUC_VERSION - #endif - #if defined(__GNUC__) && defined(__GNUC_PATCHLEVEL__) - # define ZPL_GNUC_VERSION ZPL_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) - #elif defined(__GNUC__) - # define ZPL_GNUC_VERSION ZPL_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, 0) - #endif - - #if defined(ZPL_GNUC_VERSION_CHECK) - # undef ZPL_GNUC_VERSION_CHECK - #endif - #if defined(ZPL_GNUC_VERSION) - # define ZPL_GNUC_VERSION_CHECK(major,minor,patch) (ZPL_GNUC_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) - #else - # define ZPL_GNUC_VERSION_CHECK(major,minor,patch) (0) - #endif - - #if defined(ZPL_MSVC_VERSION) - # undef ZPL_MSVC_VERSION - #endif - #if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140000000) - # define ZPL_MSVC_VERSION ZPL_VERSION_ENCODE(_MSC_FULL_VER / 10000000, (_MSC_FULL_VER % 10000000) / 100000, (_MSC_FULL_VER % 100000) / 100) - #elif defined(_MSC_FULL_VER) - # define ZPL_MSVC_VERSION ZPL_VERSION_ENCODE(_MSC_FULL_VER / 1000000, (_MSC_FULL_VER % 1000000) / 10000, (_MSC_FULL_VER % 10000) / 10) - #elif defined(_MSC_VER) - # define ZPL_MSVC_VERSION ZPL_VERSION_ENCODE(_MSC_VER / 100, _MSC_VER % 100, 0) - #endif - - #if defined(ZPL_MSVC_VERSION_CHECK) - # undef ZPL_MSVC_VERSION_CHECK - #endif - #if !defined(_MSC_VER) - # define ZPL_MSVC_VERSION_CHECK(major,minor,patch) (0) - #elif defined(_MSC_VER) && (_MSC_VER >= 1400) - # define ZPL_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch))) - #elif defined(_MSC_VER) && (_MSC_VER >= 1200) - # define ZPL_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 1000000) + (minor * 10000) + (patch))) - #else - # define ZPL_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_VER >= ((major * 100) + (minor))) - #endif - - #if defined(ZPL_INTEL_VERSION) - # undef ZPL_INTEL_VERSION - #endif - #if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) - # define ZPL_INTEL_VERSION ZPL_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, __INTEL_COMPILER_UPDATE) - #elif defined(__INTEL_COMPILER) - # define ZPL_INTEL_VERSION ZPL_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0) - #endif - - #if defined(ZPL_INTEL_VERSION_CHECK) - # undef ZPL_INTEL_VERSION_CHECK - #endif - #if defined(ZPL_INTEL_VERSION) - # define ZPL_INTEL_VERSION_CHECK(major,minor,patch) (ZPL_INTEL_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) - #else - # define ZPL_INTEL_VERSION_CHECK(major,minor,patch) (0) - #endif - - #if defined(ZPL_PGI_VERSION) - # undef ZPL_PGI_VERSION - #endif - #if defined(__PGI) && defined(__PGIC__) && defined(__PGIC_MINOR__) && defined(__PGIC_PATCHLEVEL__) - # define ZPL_PGI_VERSION ZPL_VERSION_ENCODE(__PGIC__, __PGIC_MINOR__, __PGIC_PATCHLEVEL__) - #endif - - #if defined(ZPL_PGI_VERSION_CHECK) - # undef ZPL_PGI_VERSION_CHECK - #endif - #if defined(ZPL_PGI_VERSION) - # define ZPL_PGI_VERSION_CHECK(major,minor,patch) (ZPL_PGI_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) - #else - # define ZPL_PGI_VERSION_CHECK(major,minor,patch) (0) - #endif - - #if defined(ZPL_SUNPRO_VERSION) - # undef ZPL_SUNPRO_VERSION - #endif - #if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000) - # define ZPL_SUNPRO_VERSION ZPL_VERSION_ENCODE((((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), (__SUNPRO_C & 0xf) * 10) - #elif defined(__SUNPRO_C) - # define ZPL_SUNPRO_VERSION ZPL_VERSION_ENCODE((__SUNPRO_C >> 8) & 0xf, (__SUNPRO_C >> 4) & 0xf, (__SUNPRO_C) & 0xf) - #elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000) - # define ZPL_SUNPRO_VERSION ZPL_VERSION_ENCODE((((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), (__SUNPRO_CC & 0xf) * 10) - #elif defined(__SUNPRO_CC) - # define ZPL_SUNPRO_VERSION ZPL_VERSION_ENCODE((__SUNPRO_CC >> 8) & 0xf, (__SUNPRO_CC >> 4) & 0xf, (__SUNPRO_CC) & 0xf) - #endif - - #if defined(ZPL_SUNPRO_VERSION_CHECK) - # undef ZPL_SUNPRO_VERSION_CHECK - #endif - #if defined(ZPL_SUNPRO_VERSION) - # define ZPL_SUNPRO_VERSION_CHECK(major,minor,patch) (ZPL_SUNPRO_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) - #else - # define ZPL_SUNPRO_VERSION_CHECK(major,minor,patch) (0) - #endif - - #if defined(ZPL_EMSCRIPTEN_VERSION) - # undef ZPL_EMSCRIPTEN_VERSION - #endif - #if defined(__EMSCRIPTEN__) - # define ZPL_EMSCRIPTEN_VERSION ZPL_VERSION_ENCODE(__EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__) - #endif - - #if defined(ZPL_EMSCRIPTEN_VERSION_CHECK) - # undef ZPL_EMSCRIPTEN_VERSION_CHECK - #endif - #if defined(ZPL_EMSCRIPTEN_VERSION) - # define ZPL_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (ZPL_EMSCRIPTEN_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) - #else - # define ZPL_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (0) - #endif - - #if defined(ZPL_ARM_VERSION) - # undef ZPL_ARM_VERSION - #endif - #if defined(__CC_ARM) && defined(__ARMCOMPILER_VERSION) - # define ZPL_ARM_VERSION ZPL_VERSION_ENCODE(__ARMCOMPILER_VERSION / 1000000, (__ARMCOMPILER_VERSION % 1000000) / 10000, (__ARMCOMPILER_VERSION % 10000) / 100) - #elif defined(__CC_ARM) && defined(__ARMCC_VERSION) - # define ZPL_ARM_VERSION ZPL_VERSION_ENCODE(__ARMCC_VERSION / 1000000, (__ARMCC_VERSION % 1000000) / 10000, (__ARMCC_VERSION % 10000) / 100) - #endif - - #if defined(ZPL_ARM_VERSION_CHECK) - # undef ZPL_ARM_VERSION_CHECK - #endif - #if defined(ZPL_ARM_VERSION) - # define ZPL_ARM_VERSION_CHECK(major,minor,patch) (ZPL_ARM_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) - #else - # define ZPL_ARM_VERSION_CHECK(major,minor,patch) (0) - #endif - - #if defined(ZPL_IBM_VERSION) - # undef ZPL_IBM_VERSION - #endif - #if defined(__ibmxl__) - # define ZPL_IBM_VERSION ZPL_VERSION_ENCODE(__ibmxl_version__, __ibmxl_release__, __ibmxl_modification__) - #elif defined(__xlC__) && defined(__xlC_ver__) - # define ZPL_IBM_VERSION ZPL_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, (__xlC_ver__ >> 8) & 0xff) - #elif defined(__xlC__) - # define ZPL_IBM_VERSION ZPL_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, 0) - #endif - - #if defined(ZPL_IBM_VERSION_CHECK) - # undef ZPL_IBM_VERSION_CHECK - #endif - #if defined(ZPL_IBM_VERSION) - # define ZPL_IBM_VERSION_CHECK(major,minor,patch) (ZPL_IBM_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) - #else - # define ZPL_IBM_VERSION_CHECK(major,minor,patch) (0) - #endif - - #if defined(ZPL_TI_VERSION) - # undef ZPL_TI_VERSION - #endif - #if \ - defined(__TI_COMPILER_VERSION__) && \ - ( \ - defined(__TMS470__) || defined(__TI_ARM__) || \ - defined(__MSP430__) || \ - defined(__TMS320C2000__) \ - ) - # if (__TI_COMPILER_VERSION__ >= 16000000) - # define ZPL_TI_VERSION ZPL_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) - # endif - #endif - - #if defined(ZPL_TI_VERSION_CHECK) - # undef ZPL_TI_VERSION_CHECK - #endif - #if defined(ZPL_TI_VERSION) - # define ZPL_TI_VERSION_CHECK(major,minor,patch) (ZPL_TI_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) - #else - # define ZPL_TI_VERSION_CHECK(major,minor,patch) (0) - #endif - - #if defined(ZPL_TI_CL2000_VERSION) - # undef ZPL_TI_CL2000_VERSION - #endif - #if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C2000__) - # define ZPL_TI_CL2000_VERSION ZPL_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) - #endif - - #if defined(ZPL_TI_CL2000_VERSION_CHECK) - # undef ZPL_TI_CL2000_VERSION_CHECK - #endif - #if defined(ZPL_TI_CL2000_VERSION) - # define ZPL_TI_CL2000_VERSION_CHECK(major,minor,patch) (ZPL_TI_CL2000_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) - #else - # define ZPL_TI_CL2000_VERSION_CHECK(major,minor,patch) (0) - #endif - - #if defined(ZPL_TI_CL430_VERSION) - # undef ZPL_TI_CL430_VERSION - #endif - #if defined(__TI_COMPILER_VERSION__) && defined(__MSP430__) - # define ZPL_TI_CL430_VERSION ZPL_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) - #endif - - #if defined(ZPL_TI_CL430_VERSION_CHECK) - # undef ZPL_TI_CL430_VERSION_CHECK - #endif - #if defined(ZPL_TI_CL430_VERSION) - # define ZPL_TI_CL430_VERSION_CHECK(major,minor,patch) (ZPL_TI_CL430_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) - #else - # define ZPL_TI_CL430_VERSION_CHECK(major,minor,patch) (0) - #endif - - #if defined(ZPL_TI_ARMCL_VERSION) - # undef ZPL_TI_ARMCL_VERSION - #endif - #if defined(__TI_COMPILER_VERSION__) && (defined(__TMS470__) || defined(__TI_ARM__)) - # define ZPL_TI_ARMCL_VERSION ZPL_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) - #endif - - #if defined(ZPL_TI_ARMCL_VERSION_CHECK) - # undef ZPL_TI_ARMCL_VERSION_CHECK - #endif - #if defined(ZPL_TI_ARMCL_VERSION) - # define ZPL_TI_ARMCL_VERSION_CHECK(major,minor,patch) (ZPL_TI_ARMCL_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) - #else - # define ZPL_TI_ARMCL_VERSION_CHECK(major,minor,patch) (0) - #endif - - #if defined(ZPL_TI_CL6X_VERSION) - # undef ZPL_TI_CL6X_VERSION - #endif - #if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C6X__) - # define ZPL_TI_CL6X_VERSION ZPL_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) - #endif - - #if defined(ZPL_TI_CL6X_VERSION_CHECK) - # undef ZPL_TI_CL6X_VERSION_CHECK - #endif - #if defined(ZPL_TI_CL6X_VERSION) - # define ZPL_TI_CL6X_VERSION_CHECK(major,minor,patch) (ZPL_TI_CL6X_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) - #else - # define ZPL_TI_CL6X_VERSION_CHECK(major,minor,patch) (0) - #endif - - #if defined(ZPL_TI_CL7X_VERSION) - # undef ZPL_TI_CL7X_VERSION - #endif - #if defined(__TI_COMPILER_VERSION__) && defined(__C7000__) - # define ZPL_TI_CL7X_VERSION ZPL_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) - #endif - - #if defined(ZPL_TI_CL7X_VERSION_CHECK) - # undef ZPL_TI_CL7X_VERSION_CHECK - #endif - #if defined(ZPL_TI_CL7X_VERSION) - # define ZPL_TI_CL7X_VERSION_CHECK(major,minor,patch) (ZPL_TI_CL7X_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) - #else - # define ZPL_TI_CL7X_VERSION_CHECK(major,minor,patch) (0) - #endif - - #if defined(ZPL_TI_CLPRU_VERSION) - # undef ZPL_TI_CLPRU_VERSION - #endif - #if defined(__TI_COMPILER_VERSION__) && defined(__PRU__) - # define ZPL_TI_CLPRU_VERSION ZPL_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) - #endif - - #if defined(ZPL_TI_CLPRU_VERSION_CHECK) - # undef ZPL_TI_CLPRU_VERSION_CHECK - #endif - #if defined(ZPL_TI_CLPRU_VERSION) - # define ZPL_TI_CLPRU_VERSION_CHECK(major,minor,patch) (ZPL_TI_CLPRU_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) - #else - # define ZPL_TI_CLPRU_VERSION_CHECK(major,minor,patch) (0) - #endif - - #if defined(ZPL_CRAY_VERSION) - # undef ZPL_CRAY_VERSION - #endif - #if defined(_CRAYC) - # if defined(_RELEASE_PATCHLEVEL) - # define ZPL_CRAY_VERSION ZPL_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, _RELEASE_PATCHLEVEL) - # else - # define ZPL_CRAY_VERSION ZPL_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, 0) - # endif - #endif - - #if defined(ZPL_CRAY_VERSION_CHECK) - # undef ZPL_CRAY_VERSION_CHECK - #endif - #if defined(ZPL_CRAY_VERSION) - # define ZPL_CRAY_VERSION_CHECK(major,minor,patch) (ZPL_CRAY_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) - #else - # define ZPL_CRAY_VERSION_CHECK(major,minor,patch) (0) - #endif - - #if defined(ZPL_IAR_VERSION) - # undef ZPL_IAR_VERSION - #endif - #if defined(__IAR_SYSTEMS_ICC__) - # if __VER__ > 1000 - # define ZPL_IAR_VERSION ZPL_VERSION_ENCODE((__VER__ / 1000000), ((__VER__ / 1000) % 1000), (__VER__ % 1000)) - # else - # define ZPL_IAR_VERSION ZPL_VERSION_ENCODE(VER / 100, __VER__ % 100, 0) - # endif - #endif - - #if defined(ZPL_IAR_VERSION_CHECK) - # undef ZPL_IAR_VERSION_CHECK - #endif - #if defined(ZPL_IAR_VERSION) - # define ZPL_IAR_VERSION_CHECK(major,minor,patch) (ZPL_IAR_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) - #else - # define ZPL_IAR_VERSION_CHECK(major,minor,patch) (0) - #endif - - #if defined(ZPL_TINYC_VERSION) - # undef ZPL_TINYC_VERSION - #endif - #if defined(__TINYC__) - # define ZPL_TINYC_VERSION ZPL_VERSION_ENCODE(__TINYC__ / 1000, (__TINYC__ / 100) % 10, __TINYC__ % 100) - #endif - - #if defined(ZPL_TINYC_VERSION_CHECK) - # undef ZPL_TINYC_VERSION_CHECK - #endif - #if defined(ZPL_TINYC_VERSION) - # define ZPL_TINYC_VERSION_CHECK(major,minor,patch) (ZPL_TINYC_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) - #else - # define ZPL_TINYC_VERSION_CHECK(major,minor,patch) (0) - #endif - - #if defined(ZPL_DMC_VERSION) - # undef ZPL_DMC_VERSION - #endif - #if defined(__DMC__) - # define ZPL_DMC_VERSION ZPL_VERSION_ENCODE(__DMC__ >> 8, (__DMC__ >> 4) & 0xf, __DMC__ & 0xf) - #endif - - #if defined(ZPL_DMC_VERSION_CHECK) - # undef ZPL_DMC_VERSION_CHECK - #endif - #if defined(ZPL_DMC_VERSION) - # define ZPL_DMC_VERSION_CHECK(major,minor,patch) (ZPL_DMC_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) - #else - # define ZPL_DMC_VERSION_CHECK(major,minor,patch) (0) - #endif - - #if defined(ZPL_COMPCERT_VERSION) - # undef ZPL_COMPCERT_VERSION - #endif - #if defined(__COMPCERT_VERSION__) - # define ZPL_COMPCERT_VERSION ZPL_VERSION_ENCODE(__COMPCERT_VERSION__ / 10000, (__COMPCERT_VERSION__ / 100) % 100, __COMPCERT_VERSION__ % 100) - #endif - - #if defined(ZPL_COMPCERT_VERSION_CHECK) - # undef ZPL_COMPCERT_VERSION_CHECK - #endif - #if defined(ZPL_COMPCERT_VERSION) - # define ZPL_COMPCERT_VERSION_CHECK(major,minor,patch) (ZPL_COMPCERT_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) - #else - # define ZPL_COMPCERT_VERSION_CHECK(major,minor,patch) (0) - #endif - - #if defined(ZPL_PELLES_VERSION) - # undef ZPL_PELLES_VERSION - #endif - #if defined(__POCC__) - # define ZPL_PELLES_VERSION ZPL_VERSION_ENCODE(__POCC__ / 100, __POCC__ % 100, 0) - #endif - - #if defined(ZPL_PELLES_VERSION_CHECK) - # undef ZPL_PELLES_VERSION_CHECK - #endif - #if defined(ZPL_PELLES_VERSION) - # define ZPL_PELLES_VERSION_CHECK(major,minor,patch) (ZPL_PELLES_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) - #else - # define ZPL_PELLES_VERSION_CHECK(major,minor,patch) (0) - #endif - - #if defined(ZPL_GCC_VERSION) - # undef ZPL_GCC_VERSION - #endif - #if \ - defined(ZPL_GNUC_VERSION) && \ - !defined(__clang__) && \ - !defined(ZPL_INTEL_VERSION) && \ - !defined(ZPL_PGI_VERSION) && \ - !defined(ZPL_ARM_VERSION) && \ - !defined(ZPL_TI_VERSION) && \ - !defined(ZPL_TI_ARMCL_VERSION) && \ - !defined(ZPL_TI_CL430_VERSION) && \ - !defined(ZPL_TI_CL2000_VERSION) && \ - !defined(ZPL_TI_CL6X_VERSION) && \ - !defined(ZPL_TI_CL7X_VERSION) && \ - !defined(ZPL_TI_CLPRU_VERSION) && \ - !defined(__COMPCERT__) - # define ZPL_GCC_VERSION ZPL_GNUC_VERSION - #endif - - #if defined(ZPL_GCC_VERSION_CHECK) - # undef ZPL_GCC_VERSION_CHECK - #endif - #if defined(ZPL_GCC_VERSION) - # define ZPL_GCC_VERSION_CHECK(major,minor,patch) (ZPL_GCC_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) - #else - # define ZPL_GCC_VERSION_CHECK(major,minor,patch) (0) - #endif - - #if defined(ZPL_HAS_ATTRIBUTE) - # undef ZPL_HAS_ATTRIBUTE - #endif - #if defined(__has_attribute) - # define ZPL_HAS_ATTRIBUTE(attribute) __has_attribute(attribute) - #else - # define ZPL_HAS_ATTRIBUTE(attribute) (0) - #endif - - #if defined(ZPL_GNUC_HAS_ATTRIBUTE) - # undef ZPL_GNUC_HAS_ATTRIBUTE - #endif - #if defined(__has_attribute) - # define ZPL_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) __has_attribute(attribute) - #else - # define ZPL_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) ZPL_GNUC_VERSION_CHECK(major,minor,patch) - #endif - - #if defined(ZPL_GCC_HAS_ATTRIBUTE) - # undef ZPL_GCC_HAS_ATTRIBUTE - #endif - #if defined(__has_attribute) - # define ZPL_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) __has_attribute(attribute) - #else - # define ZPL_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) ZPL_GCC_VERSION_CHECK(major,minor,patch) - #endif - - #if defined(ZPL_HAS_CPP_ATTRIBUTE) - # undef ZPL_HAS_CPP_ATTRIBUTE - #endif - #if \ - defined(__has_cpp_attribute) && \ - defined(__cplusplus) && \ - (!defined(ZPL_SUNPRO_VERSION) || ZPL_SUNPRO_VERSION_CHECK(5,15,0)) - # define ZPL_HAS_CPP_ATTRIBUTE(attribute) __has_cpp_attribute(attribute) - #else - # define ZPL_HAS_CPP_ATTRIBUTE(attribute) (0) - #endif - - #if defined(ZPL_HAS_CPP_ATTRIBUTE_NS) - # undef ZPL_HAS_CPP_ATTRIBUTE_NS - #endif - #if !defined(__cplusplus) || !defined(__has_cpp_attribute) - # define ZPL_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) - #elif \ - !defined(ZPL_PGI_VERSION) && \ - !defined(ZPL_IAR_VERSION) && \ - (!defined(ZPL_SUNPRO_VERSION) || ZPL_SUNPRO_VERSION_CHECK(5,15,0)) && \ - (!defined(ZPL_MSVC_VERSION) || ZPL_MSVC_VERSION_CHECK(19,20,0)) - # define ZPL_HAS_CPP_ATTRIBUTE_NS(ns,attribute) ZPL_HAS_CPP_ATTRIBUTE(ns::attribute) - #else - # define ZPL_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) - #endif - - #if defined(ZPL_GNUC_HAS_CPP_ATTRIBUTE) - # undef ZPL_GNUC_HAS_CPP_ATTRIBUTE - #endif - #if defined(__has_cpp_attribute) && defined(__cplusplus) - # define ZPL_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) - #else - # define ZPL_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) ZPL_GNUC_VERSION_CHECK(major,minor,patch) - #endif - - #if defined(ZPL_GCC_HAS_CPP_ATTRIBUTE) - # undef ZPL_GCC_HAS_CPP_ATTRIBUTE - #endif - #if defined(__has_cpp_attribute) && defined(__cplusplus) - # define ZPL_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) - #else - # define ZPL_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) ZPL_GCC_VERSION_CHECK(major,minor,patch) - #endif - - #if defined(ZPL_HAS_BUILTIN) - # undef ZPL_HAS_BUILTIN - #endif - #if defined(__has_builtin) - # define ZPL_HAS_BUILTIN(builtin) __has_builtin(builtin) - #else - # define ZPL_HAS_BUILTIN(builtin) (0) - #endif - - #if defined(ZPL_GNUC_HAS_BUILTIN) - # undef ZPL_GNUC_HAS_BUILTIN - #endif - #if defined(__has_builtin) - # define ZPL_GNUC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) - #else - # define ZPL_GNUC_HAS_BUILTIN(builtin,major,minor,patch) ZPL_GNUC_VERSION_CHECK(major,minor,patch) - #endif - - #if defined(ZPL_GCC_HAS_BUILTIN) - # undef ZPL_GCC_HAS_BUILTIN - #endif - #if defined(__has_builtin) - # define ZPL_GCC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) - #else - # define ZPL_GCC_HAS_BUILTIN(builtin,major,minor,patch) ZPL_GCC_VERSION_CHECK(major,minor,patch) - #endif - - #if defined(ZPL_HAS_FEATURE) - # undef ZPL_HAS_FEATURE - #endif - #if defined(__has_feature) - # define ZPL_HAS_FEATURE(feature) __has_feature(feature) - #else - # define ZPL_HAS_FEATURE(feature) (0) - #endif - - #if defined(ZPL_GNUC_HAS_FEATURE) - # undef ZPL_GNUC_HAS_FEATURE - #endif - #if defined(__has_feature) - # define ZPL_GNUC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) - #else - # define ZPL_GNUC_HAS_FEATURE(feature,major,minor,patch) ZPL_GNUC_VERSION_CHECK(major,minor,patch) - #endif - - #if defined(ZPL_GCC_HAS_FEATURE) - # undef ZPL_GCC_HAS_FEATURE - #endif - #if defined(__has_feature) - # define ZPL_GCC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) - #else - # define ZPL_GCC_HAS_FEATURE(feature,major,minor,patch) ZPL_GCC_VERSION_CHECK(major,minor,patch) - #endif - - #if defined(ZPL_HAS_EXTENSION) - # undef ZPL_HAS_EXTENSION - #endif - #if defined(__has_extension) - # define ZPL_HAS_EXTENSION(extension) __has_extension(extension) - #else - # define ZPL_HAS_EXTENSION(extension) (0) - #endif - - #if defined(ZPL_GNUC_HAS_EXTENSION) - # undef ZPL_GNUC_HAS_EXTENSION - #endif - #if defined(__has_extension) - # define ZPL_GNUC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) - #else - # define ZPL_GNUC_HAS_EXTENSION(extension,major,minor,patch) ZPL_GNUC_VERSION_CHECK(major,minor,patch) - #endif - - #if defined(ZPL_GCC_HAS_EXTENSION) - # undef ZPL_GCC_HAS_EXTENSION - #endif - #if defined(__has_extension) - # define ZPL_GCC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) - #else - # define ZPL_GCC_HAS_EXTENSION(extension,major,minor,patch) ZPL_GCC_VERSION_CHECK(major,minor,patch) - #endif - - #if defined(ZPL_HAS_DECLSPEC_ATTRIBUTE) - # undef ZPL_HAS_DECLSPEC_ATTRIBUTE - #endif - #if defined(__has_declspec_attribute) - # define ZPL_HAS_DECLSPEC_ATTRIBUTE(attribute) __has_declspec_attribute(attribute) - #else - # define ZPL_HAS_DECLSPEC_ATTRIBUTE(attribute) (0) - #endif - - #if defined(ZPL_GNUC_HAS_DECLSPEC_ATTRIBUTE) - # undef ZPL_GNUC_HAS_DECLSPEC_ATTRIBUTE - #endif - #if defined(__has_declspec_attribute) - # define ZPL_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) - #else - # define ZPL_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) ZPL_GNUC_VERSION_CHECK(major,minor,patch) - #endif - - #if defined(ZPL_GCC_HAS_DECLSPEC_ATTRIBUTE) - # undef ZPL_GCC_HAS_DECLSPEC_ATTRIBUTE - #endif - #if defined(__has_declspec_attribute) - # define ZPL_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) - #else - # define ZPL_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) ZPL_GCC_VERSION_CHECK(major,minor,patch) - #endif - - #if defined(ZPL_HAS_WARNING) - # undef ZPL_HAS_WARNING - #endif - #if defined(__has_warning) - # define ZPL_HAS_WARNING(warning) __has_warning(warning) - #else - # define ZPL_HAS_WARNING(warning) (0) - #endif - - #if defined(ZPL_GNUC_HAS_WARNING) - # undef ZPL_GNUC_HAS_WARNING - #endif - #if defined(__has_warning) - # define ZPL_GNUC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) - #else - # define ZPL_GNUC_HAS_WARNING(warning,major,minor,patch) ZPL_GNUC_VERSION_CHECK(major,minor,patch) - #endif - - #if defined(ZPL_GCC_HAS_WARNING) - # undef ZPL_GCC_HAS_WARNING - #endif - #if defined(__has_warning) - # define ZPL_GCC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) - #else - # define ZPL_GCC_HAS_WARNING(warning,major,minor,patch) ZPL_GCC_VERSION_CHECK(major,minor,patch) - #endif - - /* ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ is for - ZPL INTERNAL USE ONLY. API subject to change without notice. */ - #if defined(ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) - # undef ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ - #endif - #if defined(__cplusplus) - # if ZPL_HAS_WARNING("-Wc++98-compat") - # if ZPL_HAS_WARNING("-Wc++17-extensions") - # define ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ - ZPL_DIAGNOSTIC_PUSH \ - _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ - _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \ - xpr \ - ZPL_DIAGNOSTIC_POP - # else - # define ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ - ZPL_DIAGNOSTIC_PUSH \ - _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ - xpr \ - ZPL_DIAGNOSTIC_POP - # endif - # endif - #endif - #if !defined(ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) - # define ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(x) x - #endif - - #if defined(ZPL_CONST_CAST) - # undef ZPL_CONST_CAST - #endif - #if defined(__cplusplus) - # define ZPL_CONST_CAST(T, expr) (const_cast(expr)) - #elif \ - ZPL_HAS_WARNING("-Wcast-qual") || \ - ZPL_GCC_VERSION_CHECK(4,6,0) || \ - ZPL_INTEL_VERSION_CHECK(13,0,0) - # define ZPL_CONST_CAST(T, expr) (__extension__ ({ \ - ZPL_DIAGNOSTIC_PUSH \ - ZPL_DIAGNOSTIC_DISABLE_CAST_QUAL \ - ((T) (expr)); \ - ZPL_DIAGNOSTIC_POP \ - })) - #else - # define ZPL_CONST_CAST(T, expr) ((T) (expr)) - #endif - - #if defined(ZPL_REINTERPRET_CAST) - # undef ZPL_REINTERPRET_CAST - #endif - #if defined(__cplusplus) - # define ZPL_REINTERPRET_CAST(T, expr) (reinterpret_cast(expr)) - #else - # define ZPL_REINTERPRET_CAST(T, expr) ((T) (expr)) - #endif - - #if defined(ZPL_STATIC_CAST) - # undef ZPL_STATIC_CAST - #endif - #if defined(__cplusplus) - # define ZPL_STATIC_CAST(T, expr) (static_cast(expr)) - #else - # define ZPL_STATIC_CAST(T, expr) ((T) (expr)) - #endif - - #if defined(ZPL_CPP_CAST) - # undef ZPL_CPP_CAST - #endif - #if defined(__cplusplus) - # if ZPL_HAS_WARNING("-Wold-style-cast") - # define ZPL_CPP_CAST(T, expr) \ - ZPL_DIAGNOSTIC_PUSH \ - _Pragma("clang diagnostic ignored \"-Wold-style-cast\"") \ - ((T) (expr)) \ - ZPL_DIAGNOSTIC_POP - # elif ZPL_IAR_VERSION_CHECK(8,3,0) - # define ZPL_CPP_CAST(T, expr) \ - ZPL_DIAGNOSTIC_PUSH \ - _Pragma("diag_suppress=Pe137") \ - ZPL_DIAGNOSTIC_POP \ - # else - # define ZPL_CPP_CAST(T, expr) ((T) (expr)) - # endif - #else - # define ZPL_CPP_CAST(T, expr) (expr) - #endif - - #if \ - (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ - defined(__clang__) || \ - ZPL_GCC_VERSION_CHECK(3,0,0) || \ - ZPL_INTEL_VERSION_CHECK(13,0,0) || \ - ZPL_IAR_VERSION_CHECK(8,0,0) || \ - ZPL_PGI_VERSION_CHECK(18,4,0) || \ - ZPL_ARM_VERSION_CHECK(4,1,0) || \ - ZPL_TI_VERSION_CHECK(15,12,0) || \ - ZPL_TI_ARMCL_VERSION_CHECK(4,7,0) || \ - ZPL_TI_CL430_VERSION_CHECK(2,0,1) || \ - ZPL_TI_CL2000_VERSION_CHECK(6,1,0) || \ - ZPL_TI_CL6X_VERSION_CHECK(7,0,0) || \ - ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ - ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - ZPL_CRAY_VERSION_CHECK(5,0,0) || \ - ZPL_TINYC_VERSION_CHECK(0,9,17) || \ - ZPL_SUNPRO_VERSION_CHECK(8,0,0) || \ - (ZPL_IBM_VERSION_CHECK(10,1,0) && defined(__C99_PRAGMA_OPERATOR)) - # define ZPL_PRAGMA(value) _Pragma(#value) - #elif ZPL_MSVC_VERSION_CHECK(15,0,0) - # define ZPL_PRAGMA(value) __pragma(value) - #else - # define ZPL_PRAGMA(value) - #endif - - #if defined(ZPL_DIAGNOSTIC_PUSH) - # undef ZPL_DIAGNOSTIC_PUSH - #endif - #if defined(ZPL_DIAGNOSTIC_POP) - # undef ZPL_DIAGNOSTIC_POP - #endif - #if defined(__clang__) - # define ZPL_DIAGNOSTIC_PUSH _Pragma("clang diagnostic push") - # define ZPL_DIAGNOSTIC_POP _Pragma("clang diagnostic pop") - #elif ZPL_INTEL_VERSION_CHECK(13,0,0) - # define ZPL_DIAGNOSTIC_PUSH _Pragma("warning(push)") - # define ZPL_DIAGNOSTIC_POP _Pragma("warning(pop)") - #elif ZPL_GCC_VERSION_CHECK(4,6,0) - # define ZPL_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push") - # define ZPL_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop") - #elif ZPL_MSVC_VERSION_CHECK(15,0,0) - # define ZPL_DIAGNOSTIC_PUSH __pragma(warning(push)) - # define ZPL_DIAGNOSTIC_POP __pragma(warning(pop)) - #elif ZPL_ARM_VERSION_CHECK(5,6,0) - # define ZPL_DIAGNOSTIC_PUSH _Pragma("push") - # define ZPL_DIAGNOSTIC_POP _Pragma("pop") - #elif \ - ZPL_TI_VERSION_CHECK(15,12,0) || \ - ZPL_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - ZPL_TI_CL430_VERSION_CHECK(4,4,0) || \ - ZPL_TI_CL6X_VERSION_CHECK(8,1,0) || \ - ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ - ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) - # define ZPL_DIAGNOSTIC_PUSH _Pragma("diag_push") - # define ZPL_DIAGNOSTIC_POP _Pragma("diag_pop") - #elif ZPL_PELLES_VERSION_CHECK(2,90,0) - # define ZPL_DIAGNOSTIC_PUSH _Pragma("warning(push)") - # define ZPL_DIAGNOSTIC_POP _Pragma("warning(pop)") - #else - # define ZPL_DIAGNOSTIC_PUSH - # define ZPL_DIAGNOSTIC_POP - #endif - - #if defined(ZPL_DIAGNOSTIC_DISABLE_DEPRECATED) - # undef ZPL_DIAGNOSTIC_DISABLE_DEPRECATED - #endif - #if ZPL_HAS_WARNING("-Wdeprecated-declarations") - # define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") - #elif ZPL_INTEL_VERSION_CHECK(13,0,0) - # define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warning(disable:1478 1786)") - #elif ZPL_PGI_VERSION_CHECK(17,10,0) - # define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") - #elif ZPL_GCC_VERSION_CHECK(4,3,0) - # define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") - #elif ZPL_MSVC_VERSION_CHECK(15,0,0) - # define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:4996)) - #elif \ - ZPL_TI_VERSION_CHECK(15,12,0) || \ - (ZPL_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (ZPL_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (ZPL_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL430_VERSION_CHECK(4,3,0) || \ - (ZPL_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL6X_VERSION_CHECK(7,5,0) || \ - ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ - ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) - # define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1291,1718") - #elif ZPL_SUNPRO_VERSION_CHECK(5,13,0) && !defined(__cplusplus) - # define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)") - #elif ZPL_SUNPRO_VERSION_CHECK(5,13,0) && defined(__cplusplus) - # define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,symdeprecated,symdeprecated2)") - #elif ZPL_IAR_VERSION_CHECK(8,0,0) - # define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress=Pe1444,Pe1215") - #elif ZPL_PELLES_VERSION_CHECK(2,90,0) - # define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warn(disable:2241)") - #else - # define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED - #endif - - #if defined(ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS) - # undef ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS - #endif - #if ZPL_HAS_WARNING("-Wunknown-pragmas") - # define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"") - #elif ZPL_INTEL_VERSION_CHECK(13,0,0) - # define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("warning(disable:161)") - #elif ZPL_PGI_VERSION_CHECK(17,10,0) - # define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 1675") - #elif ZPL_GCC_VERSION_CHECK(4,3,0) - # define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("GCC diagnostic ignored \"-Wunknown-pragmas\"") - #elif ZPL_MSVC_VERSION_CHECK(15,0,0) - # define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:4068)) - #elif \ - ZPL_TI_VERSION_CHECK(16,9,0) || \ - ZPL_TI_CL6X_VERSION_CHECK(8,0,0) || \ - ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ - ZPL_TI_CLPRU_VERSION_CHECK(2,3,0) - # define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") - #elif ZPL_TI_CL6X_VERSION_CHECK(8,0,0) - # define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") - #elif ZPL_IAR_VERSION_CHECK(8,0,0) - # define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress=Pe161") - #else - # define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS - #endif - - #if defined(ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES) - # undef ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES - #endif - #if ZPL_HAS_WARNING("-Wunknown-attributes") - # define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("clang diagnostic ignored \"-Wunknown-attributes\"") - #elif ZPL_GCC_VERSION_CHECK(4,6,0) - # define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") - #elif ZPL_INTEL_VERSION_CHECK(17,0,0) - # define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("warning(disable:1292)") - #elif ZPL_MSVC_VERSION_CHECK(19,0,0) - # define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:5030)) - #elif ZPL_PGI_VERSION_CHECK(17,10,0) - # define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097") - #elif ZPL_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus) - # define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("error_messages(off,attrskipunsup)") - #elif \ - ZPL_TI_VERSION_CHECK(18,1,0) || \ - ZPL_TI_CL6X_VERSION_CHECK(8,3,0) || \ - ZPL_TI_CL7X_VERSION_CHECK(1,2,0) - # define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1173") - #elif ZPL_IAR_VERSION_CHECK(8,0,0) - # define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress=Pe1097") - #else - # define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES - #endif - - #if defined(ZPL_DIAGNOSTIC_DISABLE_CAST_QUAL) - # undef ZPL_DIAGNOSTIC_DISABLE_CAST_QUAL - #endif - #if ZPL_HAS_WARNING("-Wcast-qual") - # define ZPL_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("clang diagnostic ignored \"-Wcast-qual\"") - #elif ZPL_INTEL_VERSION_CHECK(13,0,0) - # define ZPL_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("warning(disable:2203 2331)") - #elif ZPL_GCC_VERSION_CHECK(3,0,0) - # define ZPL_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") - #else - # define ZPL_DIAGNOSTIC_DISABLE_CAST_QUAL - #endif - - #if defined(ZPL_DEPRECATED) - # undef ZPL_DEPRECATED - #endif - #if defined(ZPL_DEPRECATED_FOR) - # undef ZPL_DEPRECATED_FOR - #endif - #if defined(__cplusplus) && (__cplusplus >= 201402L) - # define ZPL_DEPRECATED(since) ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since)]]) - # define ZPL_DEPRECATED_FOR(since, replacement) ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since "; use " #replacement)]]) - #elif \ - ZPL_HAS_EXTENSION(attribute_deprecated_with_message) || \ - ZPL_GCC_VERSION_CHECK(4,5,0) || \ - ZPL_INTEL_VERSION_CHECK(13,0,0) || \ - ZPL_ARM_VERSION_CHECK(5,6,0) || \ - ZPL_SUNPRO_VERSION_CHECK(5,13,0) || \ - ZPL_PGI_VERSION_CHECK(17,10,0) || \ - ZPL_TI_VERSION_CHECK(18,1,0) || \ - ZPL_TI_ARMCL_VERSION_CHECK(18,1,0) || \ - ZPL_TI_CL6X_VERSION_CHECK(8,3,0) || \ - ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ - ZPL_TI_CLPRU_VERSION_CHECK(2,3,0) - # define ZPL_DEPRECATED(since) __attribute__((__deprecated__("Since " #since))) - # define ZPL_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__("Since " #since "; use " #replacement))) - #elif \ - ZPL_HAS_ATTRIBUTE(deprecated) || \ - ZPL_GCC_VERSION_CHECK(3,1,0) || \ - ZPL_ARM_VERSION_CHECK(4,1,0) || \ - ZPL_TI_VERSION_CHECK(15,12,0) || \ - (ZPL_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (ZPL_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (ZPL_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL430_VERSION_CHECK(4,3,0) || \ - (ZPL_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL6X_VERSION_CHECK(7,5,0) || \ - ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ - ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) - # define ZPL_DEPRECATED(since) __attribute__((__deprecated__)) - # define ZPL_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__)) - #elif ZPL_MSVC_VERSION_CHECK(14,0,0) - # define ZPL_DEPRECATED(since) __declspec(deprecated("Since " # since)) - # define ZPL_DEPRECATED_FOR(since, replacement) __declspec(deprecated("Since " #since "; use " #replacement)) - #elif \ - ZPL_MSVC_VERSION_CHECK(13,10,0) || \ - ZPL_PELLES_VERSION_CHECK(6,50,0) - # define ZPL_DEPRECATED(since) __declspec(deprecated) - # define ZPL_DEPRECATED_FOR(since, replacement) __declspec(deprecated) - #elif ZPL_IAR_VERSION_CHECK(8,0,0) - # define ZPL_DEPRECATED(since) _Pragma("deprecated") - # define ZPL_DEPRECATED_FOR(since, replacement) _Pragma("deprecated") - #else - # define ZPL_DEPRECATED(since) - # define ZPL_DEPRECATED_FOR(since, replacement) - #endif - - #if defined(ZPL_UNAVAILABLE) - # undef ZPL_UNAVAILABLE - #endif - #if \ - ZPL_HAS_ATTRIBUTE(warning) || \ - ZPL_GCC_VERSION_CHECK(4,3,0) || \ - ZPL_INTEL_VERSION_CHECK(13,0,0) - # define ZPL_UNAVAILABLE(available_since) __attribute__((__warning__("Not available until " #available_since))) - #else - # define ZPL_UNAVAILABLE(available_since) - #endif - - #if defined(ZPL_WARN_UNUSED_RESULT) - # undef ZPL_WARN_UNUSED_RESULT - #endif - #if defined(ZPL_WARN_UNUSED_RESULT_MSG) - # undef ZPL_WARN_UNUSED_RESULT_MSG - #endif - #if (ZPL_HAS_CPP_ATTRIBUTE(nodiscard) >= 201907L) - # define ZPL_WARN_UNUSED_RESULT ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) - # define ZPL_WARN_UNUSED_RESULT_MSG(msg) ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard(msg)]]) - #elif ZPL_HAS_CPP_ATTRIBUTE(nodiscard) - # define ZPL_WARN_UNUSED_RESULT ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) - # define ZPL_WARN_UNUSED_RESULT_MSG(msg) ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) - #elif \ - ZPL_HAS_ATTRIBUTE(warn_unused_result) || \ - ZPL_GCC_VERSION_CHECK(3,4,0) || \ - ZPL_INTEL_VERSION_CHECK(13,0,0) || \ - ZPL_TI_VERSION_CHECK(15,12,0) || \ - (ZPL_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (ZPL_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (ZPL_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL430_VERSION_CHECK(4,3,0) || \ - (ZPL_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL6X_VERSION_CHECK(7,5,0) || \ - ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ - ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - (ZPL_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ - ZPL_PGI_VERSION_CHECK(17,10,0) - # define ZPL_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__)) - # define ZPL_WARN_UNUSED_RESULT_MSG(msg) __attribute__((__warn_unused_result__)) - #elif defined(_Check_return_) /* SAL */ - # define ZPL_WARN_UNUSED_RESULT _Check_return_ - # define ZPL_WARN_UNUSED_RESULT_MSG(msg) _Check_return_ - #else - # define ZPL_WARN_UNUSED_RESULT - # define ZPL_WARN_UNUSED_RESULT_MSG(msg) - #endif - - #if defined(ZPL_SENTINEL) - # undef ZPL_SENTINEL - #endif - #if \ - ZPL_HAS_ATTRIBUTE(sentinel) || \ - ZPL_GCC_VERSION_CHECK(4,0,0) || \ - ZPL_INTEL_VERSION_CHECK(13,0,0) || \ - ZPL_ARM_VERSION_CHECK(5,4,0) - # define ZPL_SENTINEL(position) __attribute__((__sentinel__(position))) - #else - # define ZPL_SENTINEL(position) - #endif - - #if defined(ZPL_NO_RETURN) - # undef ZPL_NO_RETURN - #endif - #if ZPL_IAR_VERSION_CHECK(8,0,0) - # define ZPL_NO_RETURN __noreturn - #elif ZPL_INTEL_VERSION_CHECK(13,0,0) - # define ZPL_NO_RETURN __attribute__((__noreturn__)) - #elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L - # define ZPL_NO_RETURN _Noreturn - #elif defined(__cplusplus) && (__cplusplus >= 201103L) - # define ZPL_NO_RETURN ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[noreturn]]) - #elif \ - ZPL_HAS_ATTRIBUTE(noreturn) || \ - ZPL_GCC_VERSION_CHECK(3,2,0) || \ - ZPL_SUNPRO_VERSION_CHECK(5,11,0) || \ - ZPL_ARM_VERSION_CHECK(4,1,0) || \ - ZPL_IBM_VERSION_CHECK(10,1,0) || \ - ZPL_TI_VERSION_CHECK(15,12,0) || \ - (ZPL_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (ZPL_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (ZPL_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL430_VERSION_CHECK(4,3,0) || \ - (ZPL_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL6X_VERSION_CHECK(7,5,0) || \ - ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ - ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) - # define ZPL_NO_RETURN __attribute__((__noreturn__)) - #elif ZPL_SUNPRO_VERSION_CHECK(5,10,0) - # define ZPL_NO_RETURN _Pragma("does_not_return") - #elif ZPL_MSVC_VERSION_CHECK(13,10,0) - # define ZPL_NO_RETURN __declspec(noreturn) - #elif ZPL_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus) - # define ZPL_NO_RETURN _Pragma("FUNC_NEVER_RETURNS;") - #elif ZPL_COMPCERT_VERSION_CHECK(3,2,0) - # define ZPL_NO_RETURN __attribute((noreturn)) - #elif ZPL_PELLES_VERSION_CHECK(9,0,0) - # define ZPL_NO_RETURN __declspec(noreturn) - #else - # define ZPL_NO_RETURN - #endif - - #if defined(ZPL_NO_ESCAPE) - # undef ZPL_NO_ESCAPE - #endif - #if ZPL_HAS_ATTRIBUTE(noescape) - # define ZPL_NO_ESCAPE __attribute__((__noescape__)) - #else - # define ZPL_NO_ESCAPE - #endif - - #if defined(ZPL_UNREACHABLE) - # undef ZPL_UNREACHABLE - #endif - #if defined(ZPL_UNREACHABLE_RETURN) - # undef ZPL_UNREACHABLE_RETURN - #endif - #if defined(ZPL_ASSUME) - # undef ZPL_ASSUME - #endif - #if \ - ZPL_MSVC_VERSION_CHECK(13,10,0) || \ - ZPL_INTEL_VERSION_CHECK(13,0,0) - # define ZPL_ASSUME(expr) __assume(expr) - #elif ZPL_HAS_BUILTIN(__builtin_assume) - # define ZPL_ASSUME(expr) __builtin_assume(expr) - #elif \ - ZPL_TI_CL2000_VERSION_CHECK(6,2,0) || \ - ZPL_TI_CL6X_VERSION_CHECK(4,0,0) - # if defined(__cplusplus) - # define ZPL_ASSUME(expr) std::_nassert(expr) - # else - # define ZPL_ASSUME(expr) _nassert(expr) - # endif - #endif - #if \ - (ZPL_HAS_BUILTIN(__builtin_unreachable) && (!defined(ZPL_ARM_VERSION))) || \ - ZPL_GCC_VERSION_CHECK(4,5,0) || \ - ZPL_PGI_VERSION_CHECK(18,10,0) || \ - ZPL_INTEL_VERSION_CHECK(13,0,0) || \ - ZPL_IBM_VERSION_CHECK(13,1,5) - # define ZPL_UNREACHABLE() __builtin_unreachable() - #elif defined(ZPL_ASSUME) - # define ZPL_UNREACHABLE() ZPL_ASSUME(0) - #endif - #if !defined(ZPL_ASSUME) - # if defined(ZPL_UNREACHABLE) - # define ZPL_ASSUME(expr) ZPL_STATIC_CAST(void, ((expr) ? 1 : (ZPL_UNREACHABLE(), 1))) - # else - # define ZPL_ASSUME(expr) ZPL_STATIC_CAST(void, expr) - # endif - #endif - #if defined(ZPL_UNREACHABLE) - # if \ - ZPL_TI_CL2000_VERSION_CHECK(6,2,0) || \ - ZPL_TI_CL6X_VERSION_CHECK(4,0,0) - # define ZPL_UNREACHABLE_RETURN(value) return (ZPL_STATIC_CAST(void, ZPL_ASSUME(0)), (value)) - # else - # define ZPL_UNREACHABLE_RETURN(value) ZPL_UNREACHABLE() - # endif - #else - # define ZPL_UNREACHABLE_RETURN(value) return (value) - #endif - #if !defined(ZPL_UNREACHABLE) - # define ZPL_UNREACHABLE() ZPL_ASSUME(0) - #endif - - ZPL_DIAGNOSTIC_PUSH - #if ZPL_HAS_WARNING("-Wpedantic") - # pragma clang diagnostic ignored "-Wpedantic" - #endif - #if ZPL_HAS_WARNING("-Wc++98-compat-pedantic") && defined(__cplusplus) - # pragma clang diagnostic ignored "-Wc++98-compat-pedantic" - #endif - #if ZPL_GCC_HAS_WARNING("-Wvariadic-macros",4,0,0) - # if defined(__clang__) - # pragma clang diagnostic ignored "-Wvariadic-macros" - # elif defined(ZPL_GCC_VERSION) - # pragma GCC diagnostic ignored "-Wvariadic-macros" - # endif - #endif - #if defined(ZPL_NON_NULL) - # undef ZPL_NON_NULL - #endif - #if \ - ZPL_HAS_ATTRIBUTE(nonnull) || \ - ZPL_GCC_VERSION_CHECK(3,3,0) || \ - ZPL_INTEL_VERSION_CHECK(13,0,0) || \ - ZPL_ARM_VERSION_CHECK(4,1,0) - # define ZPL_NON_NULL(...) __attribute__((__nonnull__(__VA_ARGS__))) - #else - # define ZPL_NON_NULL(...) - #endif - ZPL_DIAGNOSTIC_POP - - #if defined(ZPL_PRINTF_FORMAT) - # undef ZPL_PRINTF_FORMAT - #endif - #if defined(__MINGW32__) && ZPL_GCC_HAS_ATTRIBUTE(format,4,4,0) && !defined(__USE_MINGW_ANSI_STDIO) - # define ZPL_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(ms_printf, string_idx, first_to_check))) - #elif defined(__MINGW32__) && ZPL_GCC_HAS_ATTRIBUTE(format,4,4,0) && defined(__USE_MINGW_ANSI_STDIO) - # define ZPL_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(gnu_printf, string_idx, first_to_check))) - #elif \ - ZPL_HAS_ATTRIBUTE(format) || \ - ZPL_GCC_VERSION_CHECK(3,1,0) || \ - ZPL_INTEL_VERSION_CHECK(13,0,0) || \ - ZPL_ARM_VERSION_CHECK(5,6,0) || \ - ZPL_IBM_VERSION_CHECK(10,1,0) || \ - ZPL_TI_VERSION_CHECK(15,12,0) || \ - (ZPL_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (ZPL_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (ZPL_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL430_VERSION_CHECK(4,3,0) || \ - (ZPL_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL6X_VERSION_CHECK(7,5,0) || \ - ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ - ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) - # define ZPL_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(__printf__, string_idx, first_to_check))) - #elif ZPL_PELLES_VERSION_CHECK(6,0,0) - # define ZPL_PRINTF_FORMAT(string_idx,first_to_check) __declspec(vaformat(printf,string_idx,first_to_check)) - #else - # define ZPL_PRINTF_FORMAT(string_idx,first_to_check) - #endif - - #if defined(ZPL_CONSTEXPR) - # undef ZPL_CONSTEXPR - #endif - #if defined(__cplusplus) - # if __cplusplus >= 201103L - # define ZPL_CONSTEXPR ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(constexpr) - # endif - #endif - #if !defined(ZPL_CONSTEXPR) - # define ZPL_CONSTEXPR - #endif - - #if defined(ZPL_PREDICT) - # undef ZPL_PREDICT - #endif - #if defined(ZPL_LIKELY) - # undef ZPL_LIKELY - #endif - #if defined(ZPL_UNLIKELY) - # undef ZPL_UNLIKELY - #endif - #if defined(ZPL_UNPREDICTABLE) - # undef ZPL_UNPREDICTABLE - #endif - #if ZPL_HAS_BUILTIN(__builtin_unpredictable) - # define ZPL_UNPREDICTABLE(expr) __builtin_unpredictable((expr)) - #endif - #if \ - ZPL_HAS_BUILTIN(__builtin_expect_with_probability) || \ - ZPL_GCC_VERSION_CHECK(9,0,0) - # define ZPL_PREDICT(expr, value, probability) __builtin_expect_with_probability( (expr), (value), (probability)) - # define ZPL_PREDICT_TRUE(expr, probability) __builtin_expect_with_probability(!!(expr), 1 , (probability)) - # define ZPL_PREDICT_FALSE(expr, probability) __builtin_expect_with_probability(!!(expr), 0 , (probability)) - # define ZPL_LIKELY(expr) __builtin_expect (!!(expr), 1 ) - # define ZPL_UNLIKELY(expr) __builtin_expect (!!(expr), 0 ) - #elif \ - ZPL_HAS_BUILTIN(__builtin_expect) || \ - ZPL_GCC_VERSION_CHECK(3,0,0) || \ - ZPL_INTEL_VERSION_CHECK(13,0,0) || \ - (ZPL_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ - ZPL_ARM_VERSION_CHECK(4,1,0) || \ - ZPL_IBM_VERSION_CHECK(10,1,0) || \ - ZPL_TI_VERSION_CHECK(15,12,0) || \ - ZPL_TI_ARMCL_VERSION_CHECK(4,7,0) || \ - ZPL_TI_CL430_VERSION_CHECK(3,1,0) || \ - ZPL_TI_CL2000_VERSION_CHECK(6,1,0) || \ - ZPL_TI_CL6X_VERSION_CHECK(6,1,0) || \ - ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ - ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - ZPL_TINYC_VERSION_CHECK(0,9,27) || \ - ZPL_CRAY_VERSION_CHECK(8,1,0) - # define ZPL_PREDICT(expr, expected, probability) \ - (((probability) >= 0.9) ? __builtin_expect((expr), (expected)) : (ZPL_STATIC_CAST(void, expected), (expr))) - # define ZPL_PREDICT_TRUE(expr, probability) \ - (__extension__ ({ \ - double zpl_probability_ = (probability); \ - ((zpl_probability_ >= 0.9) ? __builtin_expect(!!(expr), 1) : ((zpl_probability_ <= 0.1) ? __builtin_expect(!!(expr), 0) : !!(expr))); \ - })) - # define ZPL_PREDICT_FALSE(expr, probability) \ - (__extension__ ({ \ - double zpl_probability_ = (probability); \ - ((zpl_probability_ >= 0.9) ? __builtin_expect(!!(expr), 0) : ((zpl_probability_ <= 0.1) ? __builtin_expect(!!(expr), 1) : !!(expr))); \ - })) - # define ZPL_LIKELY(expr) __builtin_expect(!!(expr), 1) - # define ZPL_UNLIKELY(expr) __builtin_expect(!!(expr), 0) - #else - # define ZPL_PREDICT(expr, expected, probability) (ZPL_STATIC_CAST(void, expected), (expr)) - # define ZPL_PREDICT_TRUE(expr, probability) (!!(expr)) - # define ZPL_PREDICT_FALSE(expr, probability) (!!(expr)) - # define ZPL_LIKELY(expr) (!!(expr)) - # define ZPL_UNLIKELY(expr) (!!(expr)) - #endif - #if !defined(ZPL_UNPREDICTABLE) - # define ZPL_UNPREDICTABLE(expr) ZPL_PREDICT(expr, 1, 0.5) - #endif - - #if defined(ZPL_MALLOC) - # undef ZPL_MALLOC - #endif - #if \ - ZPL_HAS_ATTRIBUTE(malloc) || \ - ZPL_GCC_VERSION_CHECK(3,1,0) || \ - ZPL_INTEL_VERSION_CHECK(13,0,0) || \ - ZPL_SUNPRO_VERSION_CHECK(5,11,0) || \ - ZPL_ARM_VERSION_CHECK(4,1,0) || \ - ZPL_IBM_VERSION_CHECK(12,1,0) || \ - ZPL_TI_VERSION_CHECK(15,12,0) || \ - (ZPL_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (ZPL_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (ZPL_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL430_VERSION_CHECK(4,3,0) || \ - (ZPL_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL6X_VERSION_CHECK(7,5,0) || \ - ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ - ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) - # define ZPL_MALLOC __attribute__((__malloc__)) - #elif ZPL_SUNPRO_VERSION_CHECK(5,10,0) - # define ZPL_MALLOC _Pragma("returns_new_memory") - #elif ZPL_MSVC_VERSION_CHECK(14, 0, 0) - # define ZPL_MALLOC __declspec(restrict) - #else - # define ZPL_MALLOC - #endif - - #if defined(ZPL_PURE) - # undef ZPL_PURE - #endif - #if \ - ZPL_HAS_ATTRIBUTE(pure) || \ - ZPL_GCC_VERSION_CHECK(2,96,0) || \ - ZPL_INTEL_VERSION_CHECK(13,0,0) || \ - ZPL_SUNPRO_VERSION_CHECK(5,11,0) || \ - ZPL_ARM_VERSION_CHECK(4,1,0) || \ - ZPL_IBM_VERSION_CHECK(10,1,0) || \ - ZPL_TI_VERSION_CHECK(15,12,0) || \ - (ZPL_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (ZPL_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (ZPL_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL430_VERSION_CHECK(4,3,0) || \ - (ZPL_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL6X_VERSION_CHECK(7,5,0) || \ - ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ - ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - ZPL_PGI_VERSION_CHECK(17,10,0) - # define ZPL_PURE __attribute__((__pure__)) - #elif ZPL_SUNPRO_VERSION_CHECK(5,10,0) - # define ZPL_PURE _Pragma("does_not_write_global_data") - #elif defined(__cplusplus) && \ - ( \ - ZPL_TI_CL430_VERSION_CHECK(2,0,1) || \ - ZPL_TI_CL6X_VERSION_CHECK(4,0,0) || \ - ZPL_TI_CL7X_VERSION_CHECK(1,2,0) \ - ) - # define ZPL_PURE _Pragma("FUNC_IS_PURE;") - #else - # define ZPL_PURE - #endif - - #if defined(ZPL_CONST) - # undef ZPL_CONST - #endif - #if \ - ZPL_HAS_ATTRIBUTE(const) || \ - ZPL_GCC_VERSION_CHECK(2,5,0) || \ - ZPL_INTEL_VERSION_CHECK(13,0,0) || \ - ZPL_SUNPRO_VERSION_CHECK(5,11,0) || \ - ZPL_ARM_VERSION_CHECK(4,1,0) || \ - ZPL_IBM_VERSION_CHECK(10,1,0) || \ - ZPL_TI_VERSION_CHECK(15,12,0) || \ - (ZPL_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (ZPL_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (ZPL_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL430_VERSION_CHECK(4,3,0) || \ - (ZPL_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL6X_VERSION_CHECK(7,5,0) || \ - ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ - ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - ZPL_PGI_VERSION_CHECK(17,10,0) - # define ZPL_CONST __attribute__((__const__)) - #elif \ - ZPL_SUNPRO_VERSION_CHECK(5,10,0) - # define ZPL_CONST _Pragma("no_side_effect") - #else - # define ZPL_CONST ZPL_PURE - #endif - - #if defined(ZPL_RESTRICT) - # undef ZPL_RESTRICT - #endif - #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && !defined(__cplusplus) - # define ZPL_RESTRICT restrict - #elif \ - ZPL_GCC_VERSION_CHECK(3,1,0) || \ - ZPL_MSVC_VERSION_CHECK(14,0,0) || \ - ZPL_INTEL_VERSION_CHECK(13,0,0) || \ - ZPL_ARM_VERSION_CHECK(4,1,0) || \ - ZPL_IBM_VERSION_CHECK(10,1,0) || \ - ZPL_PGI_VERSION_CHECK(17,10,0) || \ - ZPL_TI_CL430_VERSION_CHECK(4,3,0) || \ - ZPL_TI_CL2000_VERSION_CHECK(6,2,4) || \ - ZPL_TI_CL6X_VERSION_CHECK(8,1,0) || \ - ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ - (ZPL_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)) || \ - ZPL_IAR_VERSION_CHECK(8,0,0) || \ - defined(__clang__) - # define ZPL_RESTRICT __restrict - #elif ZPL_SUNPRO_VERSION_CHECK(5,3,0) && !defined(__cplusplus) - # define ZPL_RESTRICT _Restrict - #else - # define ZPL_RESTRICT - #endif - - #if defined(ZPL_INLINE) - # undef ZPL_INLINE - #endif - #if \ - (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ - (defined(__cplusplus) && (__cplusplus >= 199711L)) - # define ZPL_INLINE inline - #elif \ - defined(ZPL_GCC_VERSION) || \ - ZPL_ARM_VERSION_CHECK(6,2,0) - # define ZPL_INLINE __inline__ - #elif \ - ZPL_MSVC_VERSION_CHECK(12,0,0) || \ - ZPL_ARM_VERSION_CHECK(4,1,0) || \ - ZPL_TI_ARMCL_VERSION_CHECK(5,1,0) || \ - ZPL_TI_CL430_VERSION_CHECK(3,1,0) || \ - ZPL_TI_CL2000_VERSION_CHECK(6,2,0) || \ - ZPL_TI_CL6X_VERSION_CHECK(8,0,0) || \ - ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ - ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) - # define ZPL_INLINE __inline - #else - # define ZPL_INLINE - #endif - - #if defined(ZPL_ALWAYS_INLINE) - # undef ZPL_ALWAYS_INLINE - #endif - #if \ - ZPL_HAS_ATTRIBUTE(always_inline) || \ - ZPL_GCC_VERSION_CHECK(4,0,0) || \ - ZPL_INTEL_VERSION_CHECK(13,0,0) || \ - ZPL_SUNPRO_VERSION_CHECK(5,11,0) || \ - ZPL_ARM_VERSION_CHECK(4,1,0) || \ - ZPL_IBM_VERSION_CHECK(10,1,0) || \ - ZPL_TI_VERSION_CHECK(15,12,0) || \ - (ZPL_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (ZPL_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (ZPL_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL430_VERSION_CHECK(4,3,0) || \ - (ZPL_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL6X_VERSION_CHECK(7,5,0) || \ - ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ - ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) - # define ZPL_ALWAYS_INLINE __attribute__((__always_inline__)) ZPL_INLINE - #elif ZPL_MSVC_VERSION_CHECK(12,0,0) - # define ZPL_ALWAYS_INLINE __forceinline - #elif defined(__cplusplus) && \ - ( \ - ZPL_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - ZPL_TI_CL430_VERSION_CHECK(4,3,0) || \ - ZPL_TI_CL2000_VERSION_CHECK(6,4,0) || \ - ZPL_TI_CL6X_VERSION_CHECK(6,1,0) || \ - ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ - ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) \ - ) - # define ZPL_ALWAYS_INLINE _Pragma("FUNC_ALWAYS_INLINE;") - #elif ZPL_IAR_VERSION_CHECK(8,0,0) - # define ZPL_ALWAYS_INLINE _Pragma("inline=forced") - #else - # define ZPL_ALWAYS_INLINE ZPL_INLINE - #endif - - #if defined(ZPL_NEVER_INLINE) - # undef ZPL_NEVER_INLINE - #endif - #if \ - ZPL_HAS_ATTRIBUTE(noinline) || \ - ZPL_GCC_VERSION_CHECK(4,0,0) || \ - ZPL_INTEL_VERSION_CHECK(13,0,0) || \ - ZPL_SUNPRO_VERSION_CHECK(5,11,0) || \ - ZPL_ARM_VERSION_CHECK(4,1,0) || \ - ZPL_IBM_VERSION_CHECK(10,1,0) || \ - ZPL_TI_VERSION_CHECK(15,12,0) || \ - (ZPL_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (ZPL_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (ZPL_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL430_VERSION_CHECK(4,3,0) || \ - (ZPL_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL6X_VERSION_CHECK(7,5,0) || \ - ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ - ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) - # define ZPL_NEVER_INLINE __attribute__((__noinline__)) - #elif ZPL_MSVC_VERSION_CHECK(13,10,0) - # define ZPL_NEVER_INLINE __declspec(noinline) - #elif ZPL_PGI_VERSION_CHECK(10,2,0) - # define ZPL_NEVER_INLINE _Pragma("noinline") - #elif ZPL_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus) - # define ZPL_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;") - #elif ZPL_IAR_VERSION_CHECK(8,0,0) - # define ZPL_NEVER_INLINE _Pragma("inline=never") - #elif ZPL_COMPCERT_VERSION_CHECK(3,2,0) - # define ZPL_NEVER_INLINE __attribute((noinline)) - #elif ZPL_PELLES_VERSION_CHECK(9,0,0) - # define ZPL_NEVER_INLINE __declspec(noinline) - #else - # define ZPL_NEVER_INLINE - #endif - - #if defined(ZPL_PRIVATE) - # undef ZPL_PRIVATE - #endif - #if defined(ZPL_PUBLIC) - # undef ZPL_PUBLIC - #endif - #if defined(ZPL_IMPORT) - # undef ZPL_IMPORT - #endif - #if defined(_WIN32) || defined(__CYGWIN__) - # define ZPL_PRIVATE - # define ZPL_PUBLIC __declspec(dllexport) - # define ZPL_IMPORT __declspec(dllimport) - #else - # if \ - ZPL_HAS_ATTRIBUTE(visibility) || \ - ZPL_GCC_VERSION_CHECK(3,3,0) || \ - ZPL_SUNPRO_VERSION_CHECK(5,11,0) || \ - ZPL_INTEL_VERSION_CHECK(13,0,0) || \ - ZPL_ARM_VERSION_CHECK(4,1,0) || \ - ZPL_IBM_VERSION_CHECK(13,1,0) || \ - ( \ - defined(__TI_EABI__) && \ - ( \ - (ZPL_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL6X_VERSION_CHECK(7,5,0) \ - ) \ - ) - # define ZPL_PRIVATE __attribute__((__visibility__("hidden"))) - # define ZPL_PUBLIC __attribute__((__visibility__("default"))) - # else - # define ZPL_PRIVATE - # define ZPL_PUBLIC - # endif - # define ZPL_IMPORT extern - #endif - - #if defined(ZPL_NO_THROW) - # undef ZPL_NO_THROW - #endif - #if \ - ZPL_HAS_ATTRIBUTE(nothrow) || \ - ZPL_GCC_VERSION_CHECK(3,3,0) || \ - ZPL_INTEL_VERSION_CHECK(13,0,0) - # define ZPL_NO_THROW __attribute__((__nothrow__)) - #elif \ - ZPL_MSVC_VERSION_CHECK(13,1,0) || \ - ZPL_ARM_VERSION_CHECK(4,1,0) - # define ZPL_NO_THROW __declspec(nothrow) - #else - # define ZPL_NO_THROW - #endif - - #if defined(ZPL_FALL_THROUGH) - # undef ZPL_FALL_THROUGH - #endif - #if ZPL_GNUC_HAS_ATTRIBUTE(fallthrough,7,0,0) && !defined(ZPL_PGI_VERSION) - # define ZPL_FALL_THROUGH __attribute__((__fallthrough__)) - #elif ZPL_HAS_CPP_ATTRIBUTE_NS(clang,fallthrough) - # define ZPL_FALL_THROUGH ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[clang::fallthrough]]) - #elif ZPL_HAS_CPP_ATTRIBUTE(fallthrough) - # define ZPL_FALL_THROUGH ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[fallthrough]]) - #elif defined(__fallthrough) /* SAL */ - # define ZPL_FALL_THROUGH __fallthrough - #else - # define ZPL_FALL_THROUGH - #endif - - #if defined(ZPL_RETURNS_NON_NULL) - # undef ZPL_RETURNS_NON_NULL - #endif - #if \ - ZPL_HAS_ATTRIBUTE(returns_nonnull) || \ - ZPL_GCC_VERSION_CHECK(4,9,0) - # define ZPL_RETURNS_NON_NULL __attribute__((__returns_nonnull__)) - #elif defined(_Ret_notnull_) /* SAL */ - # define ZPL_RETURNS_NON_NULL _Ret_notnull_ - #else - # define ZPL_RETURNS_NON_NULL - #endif - - #if defined(ZPL_ARRAY_PARAM) - # undef ZPL_ARRAY_PARAM - #endif - #if \ - defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ - !defined(__STDC_NO_VLA__) && \ - !defined(__cplusplus) && \ - !defined(ZPL_PGI_VERSION) && \ - !defined(ZPL_TINYC_VERSION) - # define ZPL_ARRAY_PARAM(name) (name) - #else - # define ZPL_ARRAY_PARAM(name) - #endif - - #if defined(ZPL_IS_CONSTANT) - # undef ZPL_IS_CONSTANT - #endif - #if defined(ZPL_REQUIRE_CONSTEXPR) - # undef ZPL_REQUIRE_CONSTEXPR - #endif - /* ZPL_IS_CONSTEXPR_ is for - ZPL INTERNAL USE ONLY. API subject to change without notice. */ - #if defined(ZPL_IS_CONSTEXPR_) - # undef ZPL_IS_CONSTEXPR_ - #endif - #if \ - ZPL_HAS_BUILTIN(__builtin_constant_p) || \ - ZPL_GCC_VERSION_CHECK(3,4,0) || \ - ZPL_INTEL_VERSION_CHECK(13,0,0) || \ - ZPL_TINYC_VERSION_CHECK(0,9,19) || \ - ZPL_ARM_VERSION_CHECK(4,1,0) || \ - ZPL_IBM_VERSION_CHECK(13,1,0) || \ - ZPL_TI_CL6X_VERSION_CHECK(6,1,0) || \ - (ZPL_SUNPRO_VERSION_CHECK(5,10,0) && !defined(__cplusplus)) || \ - ZPL_CRAY_VERSION_CHECK(8,1,0) - # define ZPL_IS_CONSTANT(expr) __builtin_constant_p(expr) - #endif - #if !defined(__cplusplus) - # if \ - ZPL_HAS_BUILTIN(__builtin_types_compatible_p) || \ - ZPL_GCC_VERSION_CHECK(3,4,0) || \ - ZPL_INTEL_VERSION_CHECK(13,0,0) || \ - ZPL_IBM_VERSION_CHECK(13,1,0) || \ - ZPL_CRAY_VERSION_CHECK(8,1,0) || \ - ZPL_ARM_VERSION_CHECK(5,4,0) || \ - ZPL_TINYC_VERSION_CHECK(0,9,24) - # if defined(__INTPTR_TYPE__) - # define ZPL_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0)), int*) - # else - # include - # define ZPL_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((intptr_t) ((expr) * 0)) : (int*) 0)), int*) - # endif - # elif \ - ( \ - defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && \ - !defined(ZPL_SUNPRO_VERSION) && \ - !defined(ZPL_PGI_VERSION) && \ - !defined(ZPL_IAR_VERSION)) || \ - ZPL_HAS_EXTENSION(c_generic_selections) || \ - ZPL_GCC_VERSION_CHECK(4,9,0) || \ - ZPL_INTEL_VERSION_CHECK(17,0,0) || \ - ZPL_IBM_VERSION_CHECK(12,1,0) || \ - ZPL_ARM_VERSION_CHECK(5,3,0) - # if defined(__INTPTR_TYPE__) - # define ZPL_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0), int*: 1, void*: 0) - # else - # include - # define ZPL_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((intptr_t) * 0) : (int*) 0), int*: 1, void*: 0) - # endif - # elif \ - defined(ZPL_GCC_VERSION) || \ - defined(ZPL_INTEL_VERSION) || \ - defined(ZPL_TINYC_VERSION) || \ - defined(ZPL_TI_ARMCL_VERSION) || \ - ZPL_TI_CL430_VERSION_CHECK(18,12,0) || \ - defined(ZPL_TI_CL2000_VERSION) || \ - defined(ZPL_TI_CL6X_VERSION) || \ - defined(ZPL_TI_CL7X_VERSION) || \ - defined(ZPL_TI_CLPRU_VERSION) || \ - defined(__clang__) - # define ZPL_IS_CONSTEXPR_(expr) ( \ - sizeof(void) != \ - sizeof(*( \ - 1 ? \ - ((void*) ((expr) * 0L) ) : \ - ((struct { char v[sizeof(void) * 2]; } *) 1) \ - ) \ - ) \ - ) - # endif - #endif - #if defined(ZPL_IS_CONSTEXPR_) - # if !defined(ZPL_IS_CONSTANT) - # define ZPL_IS_CONSTANT(expr) ZPL_IS_CONSTEXPR_(expr) - # endif - # define ZPL_REQUIRE_CONSTEXPR(expr) (ZPL_IS_CONSTEXPR_(expr) ? (expr) : (-1)) - #else - # if !defined(ZPL_IS_CONSTANT) - # define ZPL_IS_CONSTANT(expr) (0) - # endif - # define ZPL_REQUIRE_CONSTEXPR(expr) (expr) - #endif - - #if defined(ZPL_BEGIN_C_DECLS) - # undef ZPL_BEGIN_C_DECLS - #endif - #if defined(ZPL_END_C_DECLS) - # undef ZPL_END_C_DECLS - #endif - #if defined(ZPL_C_DECL) - # undef ZPL_C_DECL - #endif - #if defined(__cplusplus) - # define ZPL_BEGIN_C_DECLS extern "C" { - # define ZPL_END_C_DECLS } - # define ZPL_C_DECL extern "C" - #else - # define ZPL_BEGIN_C_DECLS - # define ZPL_END_C_DECLS - # define ZPL_C_DECL - #endif - - #if defined(ZPL_STATIC_ASSERT) - # undef ZPL_STATIC_ASSERT - #endif - #if \ - !defined(__cplusplus) && ( \ - (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || \ - ZPL_HAS_FEATURE(c_static_assert) || \ - ZPL_GCC_VERSION_CHECK(6,0,0) || \ - ZPL_INTEL_VERSION_CHECK(13,0,0) || \ - defined(_Static_assert) \ - ) - # define ZPL_STATIC_ASSERT(expr, message) _Static_assert(expr, message) - #elif \ - (defined(__cplusplus) && (__cplusplus >= 201103L)) || \ - ZPL_MSVC_VERSION_CHECK(16,0,0) - # define ZPL_STATIC_ASSERT(expr, message) ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(static_assert(expr, message)) - #else - #define ZPL_STATIC_ASSERT3(cond, msg) typedef char static_assertion_##msg[(!!(cond)) * 2 - 1] - #define ZPL_STATIC_ASSERT2(cond, line) ZPL_STATIC_ASSERT3(cond, static_assertion_at_line_##line) - #define ZPL_STATIC_ASSERT1(cond, line) ZPL_STATIC_ASSERT2(cond, line) - #define ZPL_STATIC_ASSERT(cond, unused) ZPL_STATIC_ASSERT1(cond, __LINE__) - #endif - - #if defined(ZPL_NULL) - # undef ZPL_NULL - #endif - #if defined(__cplusplus) - # if __cplusplus >= 201103L - # define ZPL_NULL ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(nullptr) - # elif defined(NULL) - # define ZPL_NULL NULL - # else - # define ZPL_NULL ZPL_STATIC_CAST(void*, 0) - # endif - #elif defined(NULL) - # define ZPL_NULL NULL - #else - # define ZPL_NULL ((void*) 0) - #endif - - #if defined(ZPL_MESSAGE) - # undef ZPL_MESSAGE - #endif - #if ZPL_HAS_WARNING("-Wunknown-pragmas") - # define ZPL_MESSAGE(msg) \ - ZPL_DIAGNOSTIC_PUSH \ - ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ - ZPL_PRAGMA(message msg) \ - ZPL_DIAGNOSTIC_POP - #elif \ - ZPL_GCC_VERSION_CHECK(4,4,0) || \ - ZPL_INTEL_VERSION_CHECK(13,0,0) - # define ZPL_MESSAGE(msg) ZPL_PRAGMA(message msg) - #elif ZPL_CRAY_VERSION_CHECK(5,0,0) - # define ZPL_MESSAGE(msg) ZPL_PRAGMA(_CRI message msg) - #elif ZPL_IAR_VERSION_CHECK(8,0,0) - # define ZPL_MESSAGE(msg) ZPL_PRAGMA(message(msg)) - #elif ZPL_PELLES_VERSION_CHECK(2,0,0) - # define ZPL_MESSAGE(msg) ZPL_PRAGMA(message(msg)) - #else - # define ZPL_MESSAGE(msg) - #endif - - #if defined(ZPL_WARNING) - # undef ZPL_WARNING - #endif - #if ZPL_HAS_WARNING("-Wunknown-pragmas") - # define ZPL_WARNING(msg) \ - ZPL_DIAGNOSTIC_PUSH \ - ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ - ZPL_PRAGMA(clang warning msg) \ - ZPL_DIAGNOSTIC_POP - #elif \ - ZPL_GCC_VERSION_CHECK(4,8,0) || \ - ZPL_PGI_VERSION_CHECK(18,4,0) || \ - ZPL_INTEL_VERSION_CHECK(13,0,0) - # define ZPL_WARNING(msg) ZPL_PRAGMA(GCC warning msg) - #elif ZPL_MSVC_VERSION_CHECK(15,0,0) - # define ZPL_WARNING(msg) ZPL_PRAGMA(message(msg)) - #else - # define ZPL_WARNING(msg) ZPL_MESSAGE(msg) - #endif - - #if defined(ZPL_REQUIRE) - # undef ZPL_REQUIRE - #endif - #if defined(ZPL_REQUIRE_MSG) - # undef ZPL_REQUIRE_MSG - #endif - #if ZPL_HAS_ATTRIBUTE(diagnose_if) - # if ZPL_HAS_WARNING("-Wgcc-compat") - # define ZPL_REQUIRE(expr) \ - ZPL_DIAGNOSTIC_PUSH \ - _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ - __attribute__((diagnose_if(!(expr), #expr, "error"))) \ - ZPL_DIAGNOSTIC_POP - # define ZPL_REQUIRE_MSG(expr,msg) \ - ZPL_DIAGNOSTIC_PUSH \ - _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ - __attribute__((diagnose_if(!(expr), msg, "error"))) \ - ZPL_DIAGNOSTIC_POP - # else - # define ZPL_REQUIRE(expr) __attribute__((diagnose_if(!(expr), #expr, "error"))) - # define ZPL_REQUIRE_MSG(expr,msg) __attribute__((diagnose_if(!(expr), msg, "error"))) - # endif - #else - # define ZPL_REQUIRE(expr) - # define ZPL_REQUIRE_MSG(expr,msg) - #endif - - #if defined(ZPL_FLAGS) - # undef ZPL_FLAGS - #endif - #if ZPL_HAS_ATTRIBUTE(flag_enum) - # define ZPL_FLAGS __attribute__((__flag_enum__)) - #endif - - #if defined(ZPL_FLAGS_CAST) - # undef ZPL_FLAGS_CAST - #endif - #if ZPL_INTEL_VERSION_CHECK(19,0,0) - # define ZPL_FLAGS_CAST(T, expr) (__extension__ ({ \ - ZPL_DIAGNOSTIC_PUSH \ - _Pragma("warning(disable:188)") \ - ((T) (expr)); \ - ZPL_DIAGNOSTIC_POP \ - })) - #else - # define ZPL_FLAGS_CAST(T, expr) ZPL_STATIC_CAST(T, expr) - #endif - - #if defined(ZPL_EMPTY_BASES) - # undef ZPL_EMPTY_BASES - #endif - #if ZPL_MSVC_VERSION_CHECK(19,0,23918) && !ZPL_MSVC_VERSION_CHECK(20,0,0) - # define ZPL_EMPTY_BASES __declspec(empty_bases) - #else - # define ZPL_EMPTY_BASES - #endif - - /* Remaining macros are deprecated. */ - - #if defined(ZPL_GCC_NOT_CLANG_VERSION_CHECK) - # undef ZPL_GCC_NOT_CLANG_VERSION_CHECK - #endif - #if defined(__clang__) - # define ZPL_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) (0) - #else - # define ZPL_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) ZPL_GCC_VERSION_CHECK(major,minor,patch) - #endif - - #if defined(ZPL_CLANG_HAS_ATTRIBUTE) - # undef ZPL_CLANG_HAS_ATTRIBUTE - #endif - #define ZPL_CLANG_HAS_ATTRIBUTE(attribute) ZPL_HAS_ATTRIBUTE(attribute) - - #if defined(ZPL_CLANG_HAS_CPP_ATTRIBUTE) - # undef ZPL_CLANG_HAS_CPP_ATTRIBUTE - #endif - #define ZPL_CLANG_HAS_CPP_ATTRIBUTE(attribute) ZPL_HAS_CPP_ATTRIBUTE(attribute) - - #if defined(ZPL_CLANG_HAS_BUILTIN) - # undef ZPL_CLANG_HAS_BUILTIN - #endif - #define ZPL_CLANG_HAS_BUILTIN(builtin) ZPL_HAS_BUILTIN(builtin) - - #if defined(ZPL_CLANG_HAS_FEATURE) - # undef ZPL_CLANG_HAS_FEATURE - #endif - #define ZPL_CLANG_HAS_FEATURE(feature) ZPL_HAS_FEATURE(feature) - - #if defined(ZPL_CLANG_HAS_EXTENSION) - # undef ZPL_CLANG_HAS_EXTENSION - #endif - #define ZPL_CLANG_HAS_EXTENSION(extension) ZPL_HAS_EXTENSION(extension) - - #if defined(ZPL_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE) - # undef ZPL_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE - #endif - #define ZPL_CLANG_HAS_DECLSPEC_ATTRIBUTE(attribute) ZPL_HAS_DECLSPEC_ATTRIBUTE(attribute) - - #if defined(ZPL_CLANG_HAS_WARNING) - # undef ZPL_CLANG_HAS_WARNING - #endif - #define ZPL_CLANG_HAS_WARNING(warning) ZPL_HAS_WARNING(warning) - - #endif /* !defined(ZPL_HEDLEY_VERSION) || (ZPL_HEDLEY_VERSION < X) */ - - #define ZPL_VERSION ZPL_VERSION_ENCODE(ZPL_VERSION_MAJOR, ZPL_VERSION_MINOR, ZPL_VERSION_PATCH) - - #ifdef ZPL_IMPL - #ifndef ZPL_IMPLEMENTATION - #define ZPL_IMPLEMENTATION - #endif - #endif - - #if defined(__cplusplus) && !defined(ZPL_EXTERN) - #define ZPL_EXTERN extern "C" - #else - #define ZPL_EXTERN extern - #endif - - #ifndef ZPL_DEF - #if defined(ZPL_SHARED_LIB) - #ifdef ZPL_IMPLEMENTATION - #define ZPL_DEF ZPL_PUBLIC - #else - #define ZPL_DEF ZPL_IMPORT - #endif - #elif defined(ZPL_STATIC_LIB) - #ifdef ZPL_IMPLEMENTATION - #define ZPL_DEF - #else - #define ZPL_DEF ZPL_EXTERN - #endif - #elif defined(ZPL_STATIC) - #define ZPL_DEF static - #else - #define ZPL_DEF ZPL_EXTERN - #endif - #endif - - #ifndef ZPL_DEF_INLINE - #if defined(ZPL_STATIC) - #define ZPL_DEF_INLINE - #define ZPL_IMPL_INLINE - #else - #define ZPL_DEF_INLINE ZPL_ALWAYS_INLINE - #define ZPL_IMPL_INLINE ZPL_INLINE - #endif - #endif - - /* Architecture-specific overrides */ - #if defined(__ARM_ARCH) && defined(__cplusplus) - #define ZPL_DISABLE_THREADING - #endif - - /* Distributions */ - #ifndef ZPL_CUSTOM_MODULES - /* default distribution */ - #define ZPL_MODULE_CORE - #define ZPL_MODULE_TIMER - #define ZPL_MODULE_HASHING - #define ZPL_MODULE_REGEX - #define ZPL_MODULE_EVENT - #define ZPL_MODULE_DLL - #define ZPL_MODULE_OPTS - #define ZPL_MODULE_PROCESS - #define ZPL_MODULE_MATH - #define ZPL_MODULE_JSON - #define ZPL_MODULE_THREADING - #define ZPL_MODULE_JOBS - #define ZPL_MODULE_COROUTINES - - /* zpl nano distribution */ - #if defined(ZPL_NANO) - #undef ZPL_MODULE_TIMER - #undef ZPL_MODULE_HASHING - #undef ZPL_MODULE_REGEX - #undef ZPL_MODULE_EVENT - #undef ZPL_MODULE_DLL - #undef ZPL_MODULE_OPTS - #undef ZPL_MODULE_PROCESS - #undef ZPL_MODULE_MATH - #undef ZPL_MODULE_JSON - #undef ZPL_MODULE_THREADING - #undef ZPL_MODULE_JOBS - #undef ZPL_MODULE_COROUTINES - #endif - - /* module enabling overrides */ - #if defined(ZPL_ENABLE_CORE) && !defined(ZPL_MODULE_CORE) - #define ZPL_MODULE_CORE - #endif - #if defined(ZPL_ENABLE_TIMER) && !defined(ZPL_MODULE_TIMER) - #define ZPL_MODULE_TIMER - #endif - #if defined(ZPL_ENABLE_HASHING) && !defined(ZPL_MODULE_HASHING) - #define ZPL_MODULE_HASHING - #endif - #if defined(ZPL_ENABLE_REGEX) && !defined(ZPL_MODULE_REGEX) - #define ZPL_MODULE_REGEX - #endif - #if defined(ZPL_ENABLE_DLL) && !defined(ZPL_MODULE_DLL) - #define ZPL_MODULE_DLL - #endif - #if defined(ZPL_ENABLE_OPTS) && !defined(ZPL_MODULE_OPTS) - #define ZPL_MODULE_OPTS - #endif - #if defined(ZPL_ENABLE_PROCESS) && !defined(ZPL_MODULE_PROCESS) - #define ZPL_MODULE_PROCESS - #endif - #if defined(ZPL_ENABLE_MATH) && !defined(ZPL_MODULE_MATH) - #define ZPL_MODULE_MATH - #endif - #if defined(ZPL_ENABLE_JSON) && !defined(ZPL_MODULE_JSON) - #define ZPL_MODULE_JSON - #endif - #if defined(ZPL_ENABLE_THREADING) && !defined(ZPL_MODULE_THREADING) - #define ZPL_MODULE_THREADING - #endif - #if defined(ZPL_ENABLE_JOBS) && !defined(ZPL_MODULE_JOBS) - #ifndef ZPL_MODULE_THREADING - #define ZPL_MODULE_THREADING /* dependency */ - #endif - #define ZPL_MODULE_JOBS - #endif - #if defined(ZPL_ENABLE_COROUTINES) && !defined(ZPL_MODULE_COROUTINES) - #ifndef ZPL_MODULE_THREADING - #define ZPL_MODULE_THREADING /* dependency */ - #endif - - #ifndef ZPL_MODULE_JOBS - #define ZPL_MODULE_JOBS /* dependency */ - #endif - - #define ZPL_MODULE_COROUTINES - #endif - - /* module disabling overrides */ - #if defined(ZPL_DISABLE_CORE) && defined(ZPL_MODULE_CORE) - #undef ZPL_MODULE_CORE - #endif - #if defined(ZPL_DISABLE_TIMER) && defined(ZPL_MODULE_TIMER) - #undef ZPL_MODULE_TIMER - #endif - #if defined(ZPL_DISABLE_HASHING) && defined(ZPL_MODULE_HASHING) - #undef ZPL_MODULE_HASHING - #endif - #if defined(ZPL_DISABLE_REGEX) && defined(ZPL_MODULE_REGEX) - #undef ZPL_MODULE_REGEX - #endif - #if defined(ZPL_DISABLE_DLL) && defined(ZPL_MODULE_DLL) - #undef ZPL_MODULE_DLL - #endif - #if defined(ZPL_DISABLE_OPTS) && defined(ZPL_MODULE_OPTS) - #undef ZPL_MODULE_OPTS - #endif - #if defined(ZPL_DISABLE_PROCESS) && defined(ZPL_MODULE_PROCESS) - #undef ZPL_MODULE_PROCESS - #endif - #if defined(ZPL_DISABLE_MATH) && defined(ZPL_MODULE_MATH) - #undef ZPL_MODULE_MATH - #endif - #if defined(ZPL_DISABLE_JSON) && defined(ZPL_MODULE_JSON) - #undef ZPL_MODULE_JSON - #endif - #if defined(ZPL_DISABLE_THREADING) && defined(ZPL_MODULE_THREADING) - #ifdef ZPL_MODULE_JOBS - #undef ZPL_MODULE_JOBS /* user */ - #endif - - #ifdef ZPL_MODULE_COROUTINES - #undef ZPL_MODULE_COROUTINES /* user */ - #endif - - #undef ZPL_MODULE_THREADING - #endif - #if defined(ZPL_DISABLE_JOBS) && defined(ZPL_MODULE_JOBS) - #ifdef ZPL_MODULE_COROUTINES - #undef ZPL_MODULE_COROUTINES /* user */ - #endif - - #undef ZPL_MODULE_JOBS - #endif - #if defined(ZPL_DISABLE_COROUTINES) && defined(ZPL_MODULE_COROUTINES) - #undef ZPL_MODULE_COROUTINES - #endif - #endif - - #if defined(__GCC__) || defined(__GNUC__) || defined(__clang__) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wunused-function" - #pragma GCC diagnostic ignored "-Wmissing-field-initializers" - #pragma GCC diagnostic ignored "-Wimplicit-fallthrough" - #endif - - #if defined(_MSC_VER) - #pragma warning(push) - #pragma warning(disable : 4201) - #pragma warning(disable : 4127) // Conditional expression is constant - #endif - - /* general purpose includes */ - - // file: header/core/system.h - - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - /* Platform architecture */ - - #if defined(_WIN64) || defined(__x86_64__) || defined(_M_X64) || defined(__64BIT__) || defined(__powerpc64__) || \ - defined(__ppc64__) || defined(__aarch64__) - #ifndef ZPL_ARCH_64_BIT - #define ZPL_ARCH_64_BIT 1 - #endif - #else - #ifndef ZPL_ARCH_32_BIT - #define ZPL_ARCH_32_BIT 1 - #endif - #endif - - /* Platform endiannes */ - - #ifndef ZPL_ENDIAN_ORDER - #define ZPL_ENDIAN_ORDER - #define ZPL_IS_BIG_ENDIAN (!*(zpl_u8 *)&(zpl_u16){ 1 }) - #define ZPL_IS_LITTLE_ENDIAN (!ZPL_IS_BIG_ENDIAN) - #endif - - /* Platform OS */ - - #if defined(_WIN32) || defined(_WIN64) - #ifndef ZPL_SYSTEM_WINDOWS - #define ZPL_SYSTEM_WINDOWS 1 - #endif - #elif defined(__APPLE__) && defined(__MACH__) - #ifndef ZPL_SYSTEM_OSX - #define ZPL_SYSTEM_OSX 1 - #endif - #ifndef ZPL_SYSTEM_MACOS - #define ZPL_SYSTEM_MACOS 1 - #endif - #include - #if TARGET_IPHONE_SIMULATOR == 1 || TARGET_OS_IPHONE == 1 - #ifndef ZPL_SYSTEM_IOS - #define ZPL_SYSTEM_IOS 1 - #endif - #endif - #elif defined(__unix__) - #ifndef ZPL_SYSTEM_UNIX - #define ZPL_SYSTEM_UNIX 1 - #endif - #if defined(ANDROID) || defined(__ANDROID__) - #ifndef ZPL_SYSTEM_ANDROID - #define ZPL_SYSTEM_ANDROID 1 - #endif - #ifndef ZPL_SYSTEM_LINUX - #define ZPL_SYSTEM_LINUX 1 - #endif - #elif defined(__linux__) - #ifndef ZPL_SYSTEM_LINUX - #define ZPL_SYSTEM_LINUX 1 - #endif - #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) - #ifndef ZPL_SYSTEM_FREEBSD - #define ZPL_SYSTEM_FREEBSD 1 - #endif - #elif defined(__OpenBSD__) - #ifndef ZPL_SYSTEM_OPENBSD - #define ZPL_SYSTEM_OPENBSD 1 - #endif - #elif defined(__EMSCRIPTEN__) - #ifndef ZPL_SYSTEM_EMSCRIPTEN - #define ZPL_SYSTEM_EMSCRIPTEN 1 - #endif - #elif defined(__CYGWIN__) - #ifndef ZPL_SYSTEM_CYGWIN - #define ZPL_SYSTEM_CYGWIN 1 - #endif - #else - #error This UNIX operating system is not supported - #endif - #else - #error This operating system is not supported - #endif - - /* Platform compiler */ - - #if defined(_MSC_VER) - #define ZPL_COMPILER_MSVC 1 - #elif defined(__GNUC__) - #define ZPL_COMPILER_GCC 1 - #elif defined(__clang__) - #define ZPL_COMPILER_CLANG 1 - #elif defined(__MINGW32__) - #define ZPL_COMPILER_MINGW 1 - #else - #error Unknown compiler - #endif - - /* Platform CPU */ - - #if defined(__arm__) || defined(__aarch64__) || defined(__ARM_ARCH) - #ifndef ZPL_CPU_ARM - #define ZPL_CPU_ARM 1 - #endif - #ifndef ZPL_CACHE_LINE_SIZE - #define ZPL_CACHE_LINE_SIZE 64 - #endif - #elif defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__x86_64__) || defined(ZPL_SYSTEM_EMSCRIPTEN) - #ifndef ZPL_CPU_X86 - #define ZPL_CPU_X86 1 - #endif - #ifndef ZPL_CACHE_LINE_SIZE - #define ZPL_CACHE_LINE_SIZE 64 - #endif - #elif defined(_M_PPC) || defined(__powerpc__) || defined(__powerpc64__) - #ifndef ZPL_CPU_PPC - #define ZPL_CPU_PPC 1 - #endif - #ifndef ZPL_CACHE_LINE_SIZE - #define ZPL_CACHE_LINE_SIZE 128 - #endif - #elif defined(__MIPSEL__) || defined(__mips_isa_rev) - #ifndef ZPL_CPU_MIPS - #define ZPL_CPU_MIPS 1 - #endif - #ifndef ZPL_CACHE_LINE_SIZE - #define ZPL_CACHE_LINE_SIZE 64 - #endif - #else - #error Unknown CPU Type - #endif - - // TODO(ZaKlaus): Find a better way to get this flag in MinGW. - #if defined(ZPL_COMPILER_GCC) && !defined(WC_ERR_INVALID_CHARS) - #define WC_ERR_INVALID_CHARS 0x0080 - #endif - - #if defined(ZPL_COMPILER_GCC) && defined(ZPL_SYSTEM_WINDOWS) - #ifndef ZPL_COMPILER_MINGW - #define ZPL_COMPILER_MINGW // assume we use mingw as a compiler - #endif - #endif - - #if defined(ZPL_SYSTEM_UNIX) - #ifndef _GNU_SOURCE - #define _GNU_SOURCE - #endif - - #ifndef _LARGEFILE64_SOURCE - #define _LARGEFILE64_SOURCE - #endif - #endif - - ZPL_END_C_DECLS - - #include - #include - - #if defined(ZPL_SYSTEM_WINDOWS) - #include - #endif - - // file: header/core/types.h - - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - /* Basic types */ - - #if defined(ZPL_COMPILER_MSVC) - #if _MSC_VER < 1300 - typedef unsigned char zpl_u8; - typedef signed char zpl_i8; - typedef unsigned short zpl_u16; - typedef signed short zpl_i16; - typedef unsigned int zpl_u32; - typedef signed int zpl_i32; - #else - typedef unsigned __int8 zpl_u8; - typedef signed __int8 zpl_i8; - typedef unsigned __int16 zpl_u16; - typedef signed __int16 zpl_i16; - typedef unsigned __int32 zpl_u32; - typedef signed __int32 zpl_i32; - #endif - typedef unsigned __int64 zpl_u64; - typedef signed __int64 zpl_i64; - #else - #include - - typedef uint8_t zpl_u8; - typedef int8_t zpl_i8; - typedef uint16_t zpl_u16; - typedef int16_t zpl_i16; - typedef uint32_t zpl_u32; - typedef int32_t zpl_i32; - typedef uint64_t zpl_u64; - typedef int64_t zpl_i64; - #endif - - ZPL_STATIC_ASSERT(sizeof(zpl_u8) == sizeof(zpl_i8), "sizeof(zpl_u8) != sizeof(zpl_i8)"); - ZPL_STATIC_ASSERT(sizeof(zpl_u16) == sizeof(zpl_i16), "sizeof(zpl_u16) != sizeof(zpl_i16)"); - ZPL_STATIC_ASSERT(sizeof(zpl_u32) == sizeof(zpl_i32), "sizeof(zpl_u32) != sizeof(zpl_i32)"); - ZPL_STATIC_ASSERT(sizeof(zpl_u64) == sizeof(zpl_i64), "sizeof(zpl_u64) != sizeof(zpl_i64)"); - - ZPL_STATIC_ASSERT(sizeof(zpl_u8) == 1, "sizeof(zpl_u8) != 1"); - ZPL_STATIC_ASSERT(sizeof(zpl_u16) == 2, "sizeof(zpl_u16) != 2"); - ZPL_STATIC_ASSERT(sizeof(zpl_u32) == 4, "sizeof(zpl_u32) != 4"); - ZPL_STATIC_ASSERT(sizeof(zpl_u64) == 8, "sizeof(zpl_u64) != 8"); - - typedef size_t zpl_usize; - typedef ptrdiff_t zpl_isize; - - ZPL_STATIC_ASSERT(sizeof(zpl_usize) == sizeof(zpl_isize), "sizeof(zpl_usize) != sizeof(zpl_isize)"); - - // NOTE: (u)zpl_intptr is only here for semantic reasons really as this library will only support 32/64 bit OSes. - #if defined(_WIN64) - typedef signed __int64 zpl_intptr; - typedef unsigned __int64 zpl_uintptr; - #elif defined(_WIN32) - // NOTE; To mark types changing their size, e.g. zpl_intptr - #ifndef _W64 - #if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 - #define _W64 __w64 - #else - #define _W64 - #endif - #endif - typedef _W64 signed int zpl_intptr; - typedef _W64 unsigned int zpl_uintptr; - #else - typedef uintptr_t zpl_uintptr; - typedef intptr_t zpl_intptr; - #endif - - ZPL_STATIC_ASSERT(sizeof(zpl_uintptr) == sizeof(zpl_intptr), "sizeof(zpl_uintptr) != sizeof(zpl_intptr)"); - - typedef float zpl_f32; - typedef double zpl_f64; - - ZPL_STATIC_ASSERT(sizeof(zpl_f32) == 4, "sizeof(zpl_f32) != 4"); - ZPL_STATIC_ASSERT(sizeof(zpl_f64) == 8, "sizeof(zpl_f64) != 8"); - - typedef zpl_i32 zpl_rune; // NOTE: Unicode codepoint - typedef zpl_i32 zpl_char32; - #define ZPL_RUNE_INVALID cast(zpl_rune)(0xfffd) - #define ZPL_RUNE_MAX cast(zpl_rune)(0x0010ffff) - #define ZPL_RUNE_BOM cast(zpl_rune)(0xfeff) - #define ZPL_RUNE_EOF cast(zpl_rune)(-1) - - typedef zpl_i8 zpl_b8; - typedef zpl_i16 zpl_b16; - typedef zpl_i32 zpl_b32; - - #if !defined(__cplusplus) - #if (defined(_MSC_VER) && _MSC_VER < 1800) || (!defined(_MSC_VER) && !defined(__STDC_VERSION__)) - #ifndef true - #define true(0 == 0) - #endif - #ifndef false - #define false(0 != 0) - #endif - - typedef zpl_b8 bool; - #else - #include - #endif - #endif - - #if __cplusplus > 199711L - #define register // Deprecated in C++11. - #endif // #if __cplusplus > 199711L - - #ifndef ZPL_U8_MIN - #define ZPL_U8_MIN 0u - #define ZPL_U8_MAX 0xffu - #define ZPL_I8_MIN (-0x7f - 1) - #define ZPL_I8_MAX 0x7f - - #define ZPL_U16_MIN 0u - #define ZPL_U16_MAX 0xffffu - #define ZPL_I16_MIN (-0x7fff - 1) - #define ZPL_I16_MAX 0x7fff - - #define ZPL_U32_MIN 0u - #define ZPL_U32_MAX 0xffffffffu - #define ZPL_I32_MIN (-0x7fffffff - 1) - #define ZPL_I32_MAX 0x7fffffff - - #define ZPL_U64_MIN 0ull - #define ZPL_U64_MAX 0xffffffffffffffffull - #define ZPL_I64_MIN (-0x7fffffffffffffffll - 1) - #define ZPL_I64_MAX 0x7fffffffffffffffll - - #if defined(ZPL_ARCH_32_BIT) - #define ZPL_USIZE_MIN ZPL_U32_MIN - #define ZPL_USIZE_MAX ZPL_U32_MAX - #define ZPL_ISIZE_MIN ZPL_S32_MIN - #define ZPL_ISIZE_MAX ZPL_S32_MAX - #elif defined(ZPL_ARCH_64_BIT) - #define ZPL_USIZE_MIN ZPL_U64_MIN - #define ZPL_USIZE_MAX ZPL_U64_MAX - #define ZPL_ISIZE_MIN ZPL_I64_MIN - #define ZPL_ISIZE_MAX ZPL_I64_MAX - #else - #error Unknown architecture size. This library only supports 32 bit and 64 bit architectures. - #endif - - #define ZPL_F32_MIN 1.17549435e-38f - #define ZPL_F32_MAX 3.40282347e+38f - - #define ZPL_F64_MIN 2.2250738585072014e-308 - #define ZPL_F64_MAX 1.7976931348623157e+308 - #endif - - #ifdef ZPL_DEFINE_NULL_MACRO - #ifndef NULL - #define NULL ZPL_NULL - #endif - #endif - - ZPL_END_C_DECLS - // file: header/core/helpers.h - - /* Various macro based helpers */ - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - #ifndef cast - #define cast(Type) (Type) - #endif - - #ifndef zpl_size_of - #define zpl_size_of(x) (zpl_isize)(sizeof(x)) - #endif - - #ifndef zpl_count_of - #define zpl_count_of(x) ((zpl_size_of(x) / zpl_size_of(0 [x])) / ((zpl_isize)(!(zpl_size_of(x) % zpl_size_of(0 [x]))))) - #endif - - #ifndef zpl_offset_of - #ifdef _MSC_VER - #define zpl_offset_of(Type, element) ((zpl_isize) & (((Type *)0)->element)) - #else - #define zpl_offset_of(Type, element) __builtin_offsetof(Type, element) - #endif - #endif - - #if defined(__cplusplus) - #ifndef zpl_align_of - #if __cplusplus >= 201103L - #define zpl_align_of(Type) (zpl_isize)alignof(Type) - #else - extern "C++" { - template struct zpl_alignment_trick { - char c; - T member; - }; - } - #define zpl_align_of(Type) zpl_offset_of(zpl_alignment_trick, member) - #endif - #endif - #else - #ifndef zpl_align_of - #define zpl_align_of(Type) \ - zpl_offset_of( \ - struct { \ - char c; \ - Type member; \ - }, \ - member) - #endif - #endif - - #ifndef zpl_swap - #define zpl_swap(Type, a, b) \ - do { \ - Type tmp = (a); \ - (a) = (b); \ - (b) = tmp; \ - } while (0) - #endif - - - - #ifndef zpl_global - #define zpl_global static // Global variables - #endif - - #ifndef zpl_internal - #define zpl_internal static // Internal linkage - #endif - - #ifndef zpl_local_persist - #define zpl_local_persist static // Local Persisting variables - #endif - - #ifndef zpl_unused - #if defined(_MSC_VER) - #define zpl_unused(x) (__pragma(warning(suppress : 4100))(x)) - #elif defined(__GCC__) - #define zpl_unused(x) __attribute__((__unused__))(x) - #else - #define zpl_unused(x) ((void)(zpl_size_of(x))) - #endif - #endif - - - #ifndef ZPL_JOIN_MACROS - #define ZPL_JOIN_MACROS - - #define ZPL_JOIN2 ZPL_CONCAT - #define ZPL_JOIN3(a, b, c) ZPL_JOIN2(ZPL_JOIN2(a, b), c) - #define ZPL_JOIN4(a, b, c, d) ZPL_JOIN2(ZPL_JOIN2(ZPL_JOIN2(a, b), c), d) - #endif - - #ifndef ZPL_BIT - #define ZPL_BIT(x) (1 << (x)) - #endif - - #ifndef zpl_min - #define zpl_min(a, b) ((a) < (b) ? (a) : (b)) - #endif - - #ifndef zpl_max - #define zpl_max(a, b) ((a) > (b) ? (a) : (b)) - #endif - - #ifndef zpl_min3 - #define zpl_min3(a, b, c) zpl_min(zpl_min(a, b), c) - #endif - - #ifndef zpl_max3 - #define zpl_max3(a, b, c) zpl_max(zpl_max(a, b), c) - #endif - - #ifndef zpl_clamp - #define zpl_clamp(x, lower, upper) zpl_min(zpl_max((x), (lower)), (upper)) - #endif - - #ifndef zpl_clamp01 - #define zpl_clamp01(x) zpl_clamp((x), 0, 1) - #endif - - #ifndef zpl_is_between - #define zpl_is_between(x, lower, upper) (((lower) <= (x)) && ((x) <= (upper))) - #endif - - #ifndef zpl_abs - #define zpl_abs(x) ((x) < 0 ? -(x) : (x)) - #endif - - #ifndef hard_cast - #define hard_cast(type) *cast(type) & - #endif - - // WARN(ZaKlaus): Supported only on GCC via GNU extensions!!! - #ifndef zpl_lambda - #define zpl_lambda(b_) ({ b_ _; }) - #endif - - #ifndef zpl_when - #define zpl_when(init, type, name) \ - type name = init; \ - if (name) - #endif - - /* NOTE: Very useful bit setting */ - #ifndef ZPL_MASK_SET - #define ZPL_MASK_SET(var, set, mask) \ - do { \ - if (set) \ - (var) |= (mask); \ - else \ - (var) &= ~(mask); \ - } while (0) - #endif - - // Multiline string literals in C99! - #ifndef ZPL_MULTILINE - #define ZPL_MULTILINE(...) #__VA_ARGS__ - #endif - - ZPL_END_C_DECLS - - #if defined(ZPL_MODULE_CORE) - // file: header/core/debug.h - - /* Debugging stuff */ - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - #ifndef ZPL_DEBUG_TRAP - #if defined(_MSC_VER) - #if _MSC_VER < 1300 - #define ZPL_DEBUG_TRAP( ) __asm int 3 /* Trap to debugger! */ - #else - #define ZPL_DEBUG_TRAP( ) __debugbreak( ) - #endif - #else - #define ZPL_DEBUG_TRAP( ) __builtin_trap( ) - #endif - #endif +#define ZPL_NANO +#define ZPL_IMPL + +/** + ZPL - Your (almost) C99 Powerkit + +Usage: + #define ZPL_IMPLEMENTATION exactly in ONE source file right BEFORE including the library, like: + + #define ZPL_IMPLEMENTATION + #include "zpl.h" + + You can also use a freestanding version of ZPL by using ZPL_NANO, like: + + #define ZPL_IMPLEMENTATION + #define ZPL_NANO + #include "zpl.h" + +Options: + + ZPL_EDITOR - This macro should be used by the IDE's Intellisense to parse ZPL correctly. It can NEVER be used for actual compilation of the library! + ZPL_EXPOSE_TYPES - exposes all ZPL defined types to the global namespace. This means type such as `zpl_u32` is now available as `u32` globally. + ZPL_DEFINE_NULL_MACRO - to let ZPL define what NULL stands for in case it is undefined. + ZPL_NO_MATH_H - disables the use of math.h library and replaces it with custom routines or SIMD. + +Credits: + Read AUTHORS.md + +GitHub: + https://github.com/zpl-c/zpl + +Version History: + 10.13.0 - Initial ARM threading support + 10.12.1 - Fix missing zpL_alloc_str + 10.12.0 - Add zpl_crc64 + 10.11.1 - Fix zpl_time_utc_ms on 32-bit OSes + 10.11.0 - Added zpl_file_stream_buf + 10.10.3 - Math type-punning fixes + 10.10.1 - Fix memory writing issue + new write-only in-situ flag + 10.10.0 - Implement memory streaming API + 10.9.1 - Support ARMv6, ARMv7 and ARMv8-a builds + 10.9.0 - Improve the time API + 10.8.3 - zpl_file_close tempfile Windows fixes + 10.8.2 - zpl_file_temp disallow some operations + 10.8.1 - zpl_file_temp Windows fixes + 10.8.0 - Implemented zpl_json_write_string + 10.7.1 - Fix zpl_file_temp platform bug + 10.7.0 - Add zpl_file_write_contents + 10.6.6 - Fix type mismatch in Jobs system + 10.6.0 - Remove event system + 10.5.8 - Remove zpl__memcpy_4byte + 10.5.7 - zpl_file_new is now OS-agnostic constructor + 10.5.6 - Fix coroutine creation + 10.5.5 - Jobs system uses zpl_f32 for priority setting + 10.5.4 - zpl_buffer_free no longer takes the 2nd argument (allocator) + 10.5.3 - Removed crc64 and annotated some hashing methods + 10.5.2 - Don't expose ZPL types anymore + 10.5.1 - Fixed zpl_rdtsc for Emscripten + 10.5.0 - Changed casts to memcopy in random methods, added embed cmd + 10.4.1 - Jobs system now enqueues jobs with def priority of 1.0 + 10.4.0 - [META] version bump + 10.3.0 - Pool allocator now supports zpl_free_all + 10.2.0 - [META] version bump + 10.1.0 - Additional math methods (thanks to funZX and msmshazan) + 10.0.15 - WIP Emscripten fixes + 10.0.14 - FreeBSD support + 10.0.13 - OpenBSD support + 10.0.12 - Cygwin fixes + 10.0.11 - Tweak module dependencies + 10.0.10 - Fix zero-allocation regression in filesystem module + 10.0.9 - Fix multi-compilation unit builds + 10.0.8 - Fix zpl_printf "%0d" format specifier + 10.0.4 - Flush tester output to fix ordering + 10.0.3 - Fix ZPL_STATIC_ASSERT under MSVC + 10.0.0 - Major overhaul of the library + + 9.8.10 - JSON fix array-based documents with objects + 9.8.9 - JSON document structured as array now properly recognizes the root object as array. + 9.8.8 - Fixed an incorrect parsing of empty array nodes. + 9.8.7 - Improve FreeBSD support + 9.8.6 - WIP: Handle inlined methods properly + 9.8.5 - Fix incorrect usage of EOF and opts dependency on JSON5 module's methods + 9.8.4 - Fix MSVC ZPL_NO_MATH_H code branch using incorrect methods internally + 9.8.3 - Fix MinGW GCC related issue with zpl_printf %lld format + 9.8.2 - Fix VS C4190 issue + 9.8.1 - Fix several C++ type casting quirks + 9.8.0 - Incorporated OpenGL into ZPL core as an optional module + 9.7.0 - Added co-routine module + 9.6.0 - Added process module for creation and manipulation + 9.5.2 - zpl_printf family now prints (null) on NULL string arguments + 9.5.1 - Fixed JSON5 real number export support + indentation fixes + 9.5.0 - Added base64 encode/decode methods + 9.4.10- Small enum style changes + 9.4.9 - Remove #undef for cast and hard_cast (sorry) + 9.4.8 - Fix quote-less JSON node name resolution + 9.4.7 - Additional change to the code + 9.4.6 - Fix issue where zpl_json_find would have false match on substrings + 9.4.5 - Mistakes were made, fixed compilation errors + 9.4.3 - Fix old API shenanigans + 9.4.2 - Fix small API typos + 9.4.1 - Reordered JSON5 constants to integrate better with conditions + 9.4.0 - JSON5 API changes made to zpl_json_find + 9.3.0 - Change how zpl uses basic types internally + 9.2.0 - Directory listing was added. Check dirlist_api.c test for more info + 9.1.1 - Fix WIN32_LEAN_AND_MEAN redefinition properly + 9.1.0 - get_env rework and fixes + 9.0.3 - Small fixes and removals + 9.0.0 - New documentation format, removed deprecated code, changed styles + + 8.14.1 - Fix string library + 8.14.0 - Added zpl_re_match_all + 8.13.0 - Update system command API + 8.12.6 - Fix warning in CLI options parser + 8.12.5 - Support parametric options preceding positionals + 8.12.4 - Fixed opts positionals ordering + 8.12.3 - Fixed incorrect handling of flags preceding positionals + 8.12.2 - JSON parsing remark added + 8.12.1 - Fixed a lot of important stuff + 8.12.0 - Added helper constructors for containers + 8.11.2 - Fix bug in opts module + 8.11.1 - Small code improvements + 8.11.0 - Ported regex processor from https://github.com/gingerBill/gb/ and applied fixes on top of it + 8.10.2 - Fix zpl_strtok + 8.10.1 - Replace zpl_strchr by zpl_char_last_occurence + 8.10.0 - Added zpl_strchr + 8.9.0 - API improvements for JSON5 parser + 8.8.4 - Add support for SJSON formatting http://bitsquid.blogspot.com/2009/10/simplified-json-notation.html + + 6.8.3 - JSON5 exp fix + 6.8.2 - Bugfixes applied from gb + 6.8.1 - Performance improvements for JSON5 parser + 6.8.0 - zpl.h is now generated by build.py + 6.7.0 - Several fixes and added switches + 6.6.0 - Several significant changes made to the repository + 6.5.0 - Ported platform layer from https://github.com/gingerBill/gb/ + 6.4.1 - Use zpl_strlen in zpl_strdup + 6.4.0 - Deprecated zpl_buffer_free and added zpl_array_end, zpl_buffer_end + 6.3.0 - Added zpl_strdup + 6.2.1 - Remove math redundancies + 6.2.0 - Integrated zpl_math.h into zpl.h + 6.1.1 - Added direct.h include for win c++ dir methods + 6.1.0 - Added zpl_path_mkdir, zpl_path_rmdir, and few new zplFileErrors + 6.0.4 - More MSVC(++) satisfaction by fixing warnings + 6.0.3 - Satisfy MSVC by fixing a warning + 6.0.2 - Fixed warnings for json5 i64 printfs + 6.0.1 - Fixed warnings for particual win compiler in dirlist method + 6.0.0 - New build, include/ was renamed to code/ + + 5.8.3 - Naming fixes + 5.8.2 - Job system now supports prioritized tasks + 5.8.1 - Renames zpl_pad to zpl_ring + 5.8.0 - Added instantiated scratch pad (circular buffer) + 5.7.2 - Added Windows support for zpl_path_dirlist + 5.7.1 - Fixed few things in job system + macOS support for zpl_path_dirlist + 5.7.0 - Added a job system (zpl_thread_pool) + 5.6.5 - Fixes extra error cases for zpl_opts when input is: + - missing a value for an option, + - having an extra value for a flag (e.g. --enable-log shouldn't get a value.) + 5.6.4 - Several tweaks to the zpl_opts API + 5.6.3 - Added support for flags without values + 5.6.2 - Improve error handling for zpl_opts + 5.6.1 - Added support for strings with spaces in zpl_opts + 5.6.0 - Added zpl_opts for CLI argument parsing + 5.5.1 - Fixed time method for win + 5.5.0 - Integrate JSON5 writer into the core + 5.4.0 - Improved storage support for numbers in JSON5 parser + 5.3.0 - Integrated zpl_json into ZPL + 5.2.0 - Added zpl_string_sprintf + 5.1.1 - Added zpl_system_command_nores for output-less execution + 5.1.0 - Added event handler + 5.0.4 - Fix alias for zpl_list + 5.0.3 - Finalizing syntax changes + 5.0.2 - Fix segfault when using zpl_stack_memory + 5.0.1 - Small code improvements + 5.0.0 - Project structure changes + + 4.7.2 - Got rid of size arg for zpl_str_split_lines + 4.7.1 - Added an example + 4.7.0 - Added zpl_path_dirlist + 4.6.1 - zpl_memcopy x86 patch from upstream + 4.6.0 - Added few string-related functions + 4.5.9 - Error fixes + 4.5.8 - Warning fixes + 4.5.7 - Fixed timer loops. zpl_time* related functions work with seconds now + 4.5.6 - Fixed zpl_time_now() for Windows and Linux + 4.5.5 - Small cosmetic changes + 4.5.4 - Fixed issue when zpl_list_add would break the links + - when adding a new item between nodes + 4.5.3 - Fixed malformed enum values + 4.5.1 - Fixed some warnings + 4.5.0 - Added zpl_array_append_at + 4.4.0 - Added zpl_array_back, zpl_array_front + 4.3.0 - Added zpl_list + 4.2.0 - Added zpl_system_command_str + 4.1.2 - GG, fixed small compilation error + 4.1.1 - Fixed possible security issue in zpl_system_command + 4.1.0 - Added zpl_string_make_reserve and small fixes + 4.0.2 - Warning fix for _LARGEFILE64_SOURCE + 4.0.1 - include stdlib.h for getenv (temp) + 4.0.0 - ARM support, coding style changes and various improvements + + 3.4.1 - zpl_memcopy now uses memcpy for ARM arch-family + 3.4.0 - Removed obsolete code + 3.3.4 - Added Travis CI config + 3.3.3 - Small macro formatting changes + ZPL_SYSTEM_IOS + 3.3.2 - Fixes for android arm + 3.3.1 - Fixed some type cast warnings + 3.3.0 - Added Android support + 3.1.5 - Renamed userptr to user_data in timer + 3.1.4 - Fix for zpl_buffer not allocating correctly + 3.1.2 - Small fix in zpl_memcompare + 3.1.1 - Added char* conversion for data field in zpl_array_header + 3.1.0 - Added data field to zpl_array_header + 3.0.7 - Added timer userptr as argument to callback + 3.0.6 - Small changes + 3.0.5 - Fixed compilation for emscripten + 3.0.4 - Small fixes for tiny cpp warnings + 3.0.3 - Small fixes for various cpp warnings and errors + 3.0.2 - Fixed linux part, and removed trailing spaces + 3.0.1 - Small bugfix in zpl_file_open + 3.0.0 - Added several fixes and features + + 2.4.0 - Added remove to hash table + 2.3.3 - Removed redundant code + 2.3.2 - Eliminated extra warnings + 2.3.1 - Warning hunt + 2.3.0 - Added the ability to copy array/buffer and fixed bug in hash table. + 2.2.1 - Used tmpfile() for Windows + 2.2.0 - Added zpl_file_temp + 2.1.1 - Very small fix (forgive me) + 2.1.0 - Added the ability to resize bitstream + 2.0.8 - Small adjustments + 2.0.7 - MinGW related fixes + 2.0.0 - New NPM based version + + 1.2.2 - Small fix + 1.2.1 - Macro fixes + 1.2.0 - Added zpl_async macro + 1.1.0 - Added timer feature + 1.0.0 - Initial version + + This Software is dual licensed under the following licenses: + + Unlicense + This is free and unencumbered software released into the public domain. + + Anyone is free to copy, modify, publish, use, compile, sell, or + distribute this software, either in source code form or as a compiled + binary, for any purpose, commercial or non-commercial, and by any + means. + + In jurisdictions that recognize copyright laws, the author or authors + of this software dedicate any and all copyright interest in the + software to the public domain. We make this dedication for the benefit + of the public at large and to the detriment of our heirs and + successors. We intend this dedication to be an overt act of + relinquishment in perpetuity of all present and future rights to this + software under copyright law. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + + For more information, please refer to + + BSD 3-Clause + + Copyright (c) 2016-2021 Dominik Madarász. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +*/ + +#ifndef ZPL_H +#define ZPL_H + +#define ZPL_VERSION_MAJOR 10 +#define ZPL_VERSION_MINOR 13 +#define ZPL_VERSION_PATCH 2 +#define ZPL_VERSION_PRE "" + +// file: zpl_hedley.h + +/* Hedley - https://nemequ.github.io/hedley + * Created by Evan Nemerson + * + * To the extent possible under law, the author(s) have dedicated all + * copyright and related and neighboring rights to this software to + * the public domain worldwide. This software is distributed without + * any warranty. + * + * For details, see . + * SPDX-License-Identifier: CC0-1.0 + */ + +#if !defined(ZPL_HEDLEY_VERSION) || (ZPL_HEDLEY_VERSION < 12) +#if defined(ZPL_HEDLEY_VERSION) +# undef ZPL_HEDLEY_VERSION +#endif +#define ZPL_HEDLEY_VERSION 12 + +#if defined(ZPL_STRINGIFY_EX) +# undef ZPL_STRINGIFY_EX +#endif +#define ZPL_STRINGIFY_EX(x) #x + +#if defined(ZPL_STRINGIFY) +# undef ZPL_STRINGIFY +#endif +#define ZPL_STRINGIFY(x) ZPL_STRINGIFY_EX(x) + +#if defined(ZPL_CONCAT_EX) +# undef ZPL_CONCAT_EX +#endif +#define ZPL_CONCAT_EX(a,b) a##b + +#if defined(ZPL_CONCAT) +# undef ZPL_CONCAT +#endif +#define ZPL_CONCAT(a,b) ZPL_CONCAT_EX(a,b) + +#if defined(ZPL_VERSION_ENCODE) +# undef ZPL_VERSION_ENCODE +#endif +#define ZPL_VERSION_ENCODE(major,minor,patch) (((major) * 1000000) + ((minor) * 1000) + (patch)) + +#if defined(ZPL_VERSION_DECODE_MAJOR) +# undef ZPL_VERSION_DECODE_MAJOR +#endif +#define ZPL_VERSION_DECODE_MAJOR(version) ((version) / 1000000) + +#if defined(ZPL_VERSION_DECODE_MINOR) +# undef ZPL_VERSION_DECODE_MINOR +#endif +#define ZPL_VERSION_DECODE_MINOR(version) (((version) % 1000000) / 1000) + +#if defined(ZPL_VERSION_DECODE_PATCH) +# undef ZPL_VERSION_DECODE_PATCH +#endif +#define ZPL_VERSION_DECODE_PATCH(version) ((version) % 1000) + +#if defined(ZPL_GNUC_VERSION) +# undef ZPL_GNUC_VERSION +#endif +#if defined(__GNUC__) && defined(__GNUC_PATCHLEVEL__) +# define ZPL_GNUC_VERSION ZPL_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) +#elif defined(__GNUC__) +# define ZPL_GNUC_VERSION ZPL_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, 0) +#endif + +#if defined(ZPL_GNUC_VERSION_CHECK) +# undef ZPL_GNUC_VERSION_CHECK +#endif +#if defined(ZPL_GNUC_VERSION) +# define ZPL_GNUC_VERSION_CHECK(major,minor,patch) (ZPL_GNUC_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) +#else +# define ZPL_GNUC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(ZPL_MSVC_VERSION) +# undef ZPL_MSVC_VERSION +#endif +#if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140000000) +# define ZPL_MSVC_VERSION ZPL_VERSION_ENCODE(_MSC_FULL_VER / 10000000, (_MSC_FULL_VER % 10000000) / 100000, (_MSC_FULL_VER % 100000) / 100) +#elif defined(_MSC_FULL_VER) +# define ZPL_MSVC_VERSION ZPL_VERSION_ENCODE(_MSC_FULL_VER / 1000000, (_MSC_FULL_VER % 1000000) / 10000, (_MSC_FULL_VER % 10000) / 10) +#elif defined(_MSC_VER) +# define ZPL_MSVC_VERSION ZPL_VERSION_ENCODE(_MSC_VER / 100, _MSC_VER % 100, 0) +#endif + +#if defined(ZPL_MSVC_VERSION_CHECK) +# undef ZPL_MSVC_VERSION_CHECK +#endif +#if !defined(_MSC_VER) +# define ZPL_MSVC_VERSION_CHECK(major,minor,patch) (0) +#elif defined(_MSC_VER) && (_MSC_VER >= 1400) +# define ZPL_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch))) +#elif defined(_MSC_VER) && (_MSC_VER >= 1200) +# define ZPL_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 1000000) + (minor * 10000) + (patch))) +#else +# define ZPL_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_VER >= ((major * 100) + (minor))) +#endif + +#if defined(ZPL_INTEL_VERSION) +# undef ZPL_INTEL_VERSION +#endif +#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) +# define ZPL_INTEL_VERSION ZPL_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, __INTEL_COMPILER_UPDATE) +#elif defined(__INTEL_COMPILER) +# define ZPL_INTEL_VERSION ZPL_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0) +#endif + +#if defined(ZPL_INTEL_VERSION_CHECK) +# undef ZPL_INTEL_VERSION_CHECK +#endif +#if defined(ZPL_INTEL_VERSION) +# define ZPL_INTEL_VERSION_CHECK(major,minor,patch) (ZPL_INTEL_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) +#else +# define ZPL_INTEL_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(ZPL_PGI_VERSION) +# undef ZPL_PGI_VERSION +#endif +#if defined(__PGI) && defined(__PGIC__) && defined(__PGIC_MINOR__) && defined(__PGIC_PATCHLEVEL__) +# define ZPL_PGI_VERSION ZPL_VERSION_ENCODE(__PGIC__, __PGIC_MINOR__, __PGIC_PATCHLEVEL__) +#endif + +#if defined(ZPL_PGI_VERSION_CHECK) +# undef ZPL_PGI_VERSION_CHECK +#endif +#if defined(ZPL_PGI_VERSION) +# define ZPL_PGI_VERSION_CHECK(major,minor,patch) (ZPL_PGI_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) +#else +# define ZPL_PGI_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(ZPL_SUNPRO_VERSION) +# undef ZPL_SUNPRO_VERSION +#endif +#if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000) +# define ZPL_SUNPRO_VERSION ZPL_VERSION_ENCODE((((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), (__SUNPRO_C & 0xf) * 10) +#elif defined(__SUNPRO_C) +# define ZPL_SUNPRO_VERSION ZPL_VERSION_ENCODE((__SUNPRO_C >> 8) & 0xf, (__SUNPRO_C >> 4) & 0xf, (__SUNPRO_C) & 0xf) +#elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000) +# define ZPL_SUNPRO_VERSION ZPL_VERSION_ENCODE((((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), (__SUNPRO_CC & 0xf) * 10) +#elif defined(__SUNPRO_CC) +# define ZPL_SUNPRO_VERSION ZPL_VERSION_ENCODE((__SUNPRO_CC >> 8) & 0xf, (__SUNPRO_CC >> 4) & 0xf, (__SUNPRO_CC) & 0xf) +#endif + +#if defined(ZPL_SUNPRO_VERSION_CHECK) +# undef ZPL_SUNPRO_VERSION_CHECK +#endif +#if defined(ZPL_SUNPRO_VERSION) +# define ZPL_SUNPRO_VERSION_CHECK(major,minor,patch) (ZPL_SUNPRO_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) +#else +# define ZPL_SUNPRO_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(ZPL_EMSCRIPTEN_VERSION) +# undef ZPL_EMSCRIPTEN_VERSION +#endif +#if defined(__EMSCRIPTEN__) +# define ZPL_EMSCRIPTEN_VERSION ZPL_VERSION_ENCODE(__EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__) +#endif + +#if defined(ZPL_EMSCRIPTEN_VERSION_CHECK) +# undef ZPL_EMSCRIPTEN_VERSION_CHECK +#endif +#if defined(ZPL_EMSCRIPTEN_VERSION) +# define ZPL_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (ZPL_EMSCRIPTEN_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) +#else +# define ZPL_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(ZPL_ARM_VERSION) +# undef ZPL_ARM_VERSION +#endif +#if defined(__CC_ARM) && defined(__ARMCOMPILER_VERSION) +# define ZPL_ARM_VERSION ZPL_VERSION_ENCODE(__ARMCOMPILER_VERSION / 1000000, (__ARMCOMPILER_VERSION % 1000000) / 10000, (__ARMCOMPILER_VERSION % 10000) / 100) +#elif defined(__CC_ARM) && defined(__ARMCC_VERSION) +# define ZPL_ARM_VERSION ZPL_VERSION_ENCODE(__ARMCC_VERSION / 1000000, (__ARMCC_VERSION % 1000000) / 10000, (__ARMCC_VERSION % 10000) / 100) +#endif + +#if defined(ZPL_ARM_VERSION_CHECK) +# undef ZPL_ARM_VERSION_CHECK +#endif +#if defined(ZPL_ARM_VERSION) +# define ZPL_ARM_VERSION_CHECK(major,minor,patch) (ZPL_ARM_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) +#else +# define ZPL_ARM_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(ZPL_IBM_VERSION) +# undef ZPL_IBM_VERSION +#endif +#if defined(__ibmxl__) +# define ZPL_IBM_VERSION ZPL_VERSION_ENCODE(__ibmxl_version__, __ibmxl_release__, __ibmxl_modification__) +#elif defined(__xlC__) && defined(__xlC_ver__) +# define ZPL_IBM_VERSION ZPL_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, (__xlC_ver__ >> 8) & 0xff) +#elif defined(__xlC__) +# define ZPL_IBM_VERSION ZPL_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, 0) +#endif + +#if defined(ZPL_IBM_VERSION_CHECK) +# undef ZPL_IBM_VERSION_CHECK +#endif +#if defined(ZPL_IBM_VERSION) +# define ZPL_IBM_VERSION_CHECK(major,minor,patch) (ZPL_IBM_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) +#else +# define ZPL_IBM_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(ZPL_TI_VERSION) +# undef ZPL_TI_VERSION +#endif +#if \ +defined(__TI_COMPILER_VERSION__) && \ +( \ +defined(__TMS470__) || defined(__TI_ARM__) || \ +defined(__MSP430__) || \ +defined(__TMS320C2000__) \ +) +# if (__TI_COMPILER_VERSION__ >= 16000000) +# define ZPL_TI_VERSION ZPL_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +# endif +#endif + +#if defined(ZPL_TI_VERSION_CHECK) +# undef ZPL_TI_VERSION_CHECK +#endif +#if defined(ZPL_TI_VERSION) +# define ZPL_TI_VERSION_CHECK(major,minor,patch) (ZPL_TI_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) +#else +# define ZPL_TI_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(ZPL_TI_CL2000_VERSION) +# undef ZPL_TI_CL2000_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C2000__) +# define ZPL_TI_CL2000_VERSION ZPL_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(ZPL_TI_CL2000_VERSION_CHECK) +# undef ZPL_TI_CL2000_VERSION_CHECK +#endif +#if defined(ZPL_TI_CL2000_VERSION) +# define ZPL_TI_CL2000_VERSION_CHECK(major,minor,patch) (ZPL_TI_CL2000_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) +#else +# define ZPL_TI_CL2000_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(ZPL_TI_CL430_VERSION) +# undef ZPL_TI_CL430_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__MSP430__) +# define ZPL_TI_CL430_VERSION ZPL_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(ZPL_TI_CL430_VERSION_CHECK) +# undef ZPL_TI_CL430_VERSION_CHECK +#endif +#if defined(ZPL_TI_CL430_VERSION) +# define ZPL_TI_CL430_VERSION_CHECK(major,minor,patch) (ZPL_TI_CL430_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) +#else +# define ZPL_TI_CL430_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(ZPL_TI_ARMCL_VERSION) +# undef ZPL_TI_ARMCL_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && (defined(__TMS470__) || defined(__TI_ARM__)) +# define ZPL_TI_ARMCL_VERSION ZPL_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(ZPL_TI_ARMCL_VERSION_CHECK) +# undef ZPL_TI_ARMCL_VERSION_CHECK +#endif +#if defined(ZPL_TI_ARMCL_VERSION) +# define ZPL_TI_ARMCL_VERSION_CHECK(major,minor,patch) (ZPL_TI_ARMCL_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) +#else +# define ZPL_TI_ARMCL_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(ZPL_TI_CL6X_VERSION) +# undef ZPL_TI_CL6X_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C6X__) +# define ZPL_TI_CL6X_VERSION ZPL_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(ZPL_TI_CL6X_VERSION_CHECK) +# undef ZPL_TI_CL6X_VERSION_CHECK +#endif +#if defined(ZPL_TI_CL6X_VERSION) +# define ZPL_TI_CL6X_VERSION_CHECK(major,minor,patch) (ZPL_TI_CL6X_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) +#else +# define ZPL_TI_CL6X_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(ZPL_TI_CL7X_VERSION) +# undef ZPL_TI_CL7X_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__C7000__) +# define ZPL_TI_CL7X_VERSION ZPL_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(ZPL_TI_CL7X_VERSION_CHECK) +# undef ZPL_TI_CL7X_VERSION_CHECK +#endif +#if defined(ZPL_TI_CL7X_VERSION) +# define ZPL_TI_CL7X_VERSION_CHECK(major,minor,patch) (ZPL_TI_CL7X_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) +#else +# define ZPL_TI_CL7X_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(ZPL_TI_CLPRU_VERSION) +# undef ZPL_TI_CLPRU_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__PRU__) +# define ZPL_TI_CLPRU_VERSION ZPL_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(ZPL_TI_CLPRU_VERSION_CHECK) +# undef ZPL_TI_CLPRU_VERSION_CHECK +#endif +#if defined(ZPL_TI_CLPRU_VERSION) +# define ZPL_TI_CLPRU_VERSION_CHECK(major,minor,patch) (ZPL_TI_CLPRU_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) +#else +# define ZPL_TI_CLPRU_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(ZPL_CRAY_VERSION) +# undef ZPL_CRAY_VERSION +#endif +#if defined(_CRAYC) +# if defined(_RELEASE_PATCHLEVEL) +# define ZPL_CRAY_VERSION ZPL_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, _RELEASE_PATCHLEVEL) +# else +# define ZPL_CRAY_VERSION ZPL_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, 0) +# endif +#endif + +#if defined(ZPL_CRAY_VERSION_CHECK) +# undef ZPL_CRAY_VERSION_CHECK +#endif +#if defined(ZPL_CRAY_VERSION) +# define ZPL_CRAY_VERSION_CHECK(major,minor,patch) (ZPL_CRAY_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) +#else +# define ZPL_CRAY_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(ZPL_IAR_VERSION) +# undef ZPL_IAR_VERSION +#endif +#if defined(__IAR_SYSTEMS_ICC__) +# if __VER__ > 1000 +# define ZPL_IAR_VERSION ZPL_VERSION_ENCODE((__VER__ / 1000000), ((__VER__ / 1000) % 1000), (__VER__ % 1000)) +# else +# define ZPL_IAR_VERSION ZPL_VERSION_ENCODE(VER / 100, __VER__ % 100, 0) +# endif +#endif + +#if defined(ZPL_IAR_VERSION_CHECK) +# undef ZPL_IAR_VERSION_CHECK +#endif +#if defined(ZPL_IAR_VERSION) +# define ZPL_IAR_VERSION_CHECK(major,minor,patch) (ZPL_IAR_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) +#else +# define ZPL_IAR_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(ZPL_TINYC_VERSION) +# undef ZPL_TINYC_VERSION +#endif +#if defined(__TINYC__) +# define ZPL_TINYC_VERSION ZPL_VERSION_ENCODE(__TINYC__ / 1000, (__TINYC__ / 100) % 10, __TINYC__ % 100) +#endif + +#if defined(ZPL_TINYC_VERSION_CHECK) +# undef ZPL_TINYC_VERSION_CHECK +#endif +#if defined(ZPL_TINYC_VERSION) +# define ZPL_TINYC_VERSION_CHECK(major,minor,patch) (ZPL_TINYC_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) +#else +# define ZPL_TINYC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(ZPL_DMC_VERSION) +# undef ZPL_DMC_VERSION +#endif +#if defined(__DMC__) +# define ZPL_DMC_VERSION ZPL_VERSION_ENCODE(__DMC__ >> 8, (__DMC__ >> 4) & 0xf, __DMC__ & 0xf) +#endif + +#if defined(ZPL_DMC_VERSION_CHECK) +# undef ZPL_DMC_VERSION_CHECK +#endif +#if defined(ZPL_DMC_VERSION) +# define ZPL_DMC_VERSION_CHECK(major,minor,patch) (ZPL_DMC_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) +#else +# define ZPL_DMC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(ZPL_COMPCERT_VERSION) +# undef ZPL_COMPCERT_VERSION +#endif +#if defined(__COMPCERT_VERSION__) +# define ZPL_COMPCERT_VERSION ZPL_VERSION_ENCODE(__COMPCERT_VERSION__ / 10000, (__COMPCERT_VERSION__ / 100) % 100, __COMPCERT_VERSION__ % 100) +#endif + +#if defined(ZPL_COMPCERT_VERSION_CHECK) +# undef ZPL_COMPCERT_VERSION_CHECK +#endif +#if defined(ZPL_COMPCERT_VERSION) +# define ZPL_COMPCERT_VERSION_CHECK(major,minor,patch) (ZPL_COMPCERT_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) +#else +# define ZPL_COMPCERT_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(ZPL_PELLES_VERSION) +# undef ZPL_PELLES_VERSION +#endif +#if defined(__POCC__) +# define ZPL_PELLES_VERSION ZPL_VERSION_ENCODE(__POCC__ / 100, __POCC__ % 100, 0) +#endif + +#if defined(ZPL_PELLES_VERSION_CHECK) +# undef ZPL_PELLES_VERSION_CHECK +#endif +#if defined(ZPL_PELLES_VERSION) +# define ZPL_PELLES_VERSION_CHECK(major,minor,patch) (ZPL_PELLES_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) +#else +# define ZPL_PELLES_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(ZPL_GCC_VERSION) +# undef ZPL_GCC_VERSION +#endif +#if \ +defined(ZPL_GNUC_VERSION) && \ +!defined(__clang__) && \ +!defined(ZPL_INTEL_VERSION) && \ +!defined(ZPL_PGI_VERSION) && \ +!defined(ZPL_ARM_VERSION) && \ +!defined(ZPL_TI_VERSION) && \ +!defined(ZPL_TI_ARMCL_VERSION) && \ +!defined(ZPL_TI_CL430_VERSION) && \ +!defined(ZPL_TI_CL2000_VERSION) && \ +!defined(ZPL_TI_CL6X_VERSION) && \ +!defined(ZPL_TI_CL7X_VERSION) && \ +!defined(ZPL_TI_CLPRU_VERSION) && \ +!defined(__COMPCERT__) +# define ZPL_GCC_VERSION ZPL_GNUC_VERSION +#endif + +#if defined(ZPL_GCC_VERSION_CHECK) +# undef ZPL_GCC_VERSION_CHECK +#endif +#if defined(ZPL_GCC_VERSION) +# define ZPL_GCC_VERSION_CHECK(major,minor,patch) (ZPL_GCC_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) +#else +# define ZPL_GCC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(ZPL_HAS_ATTRIBUTE) +# undef ZPL_HAS_ATTRIBUTE +#endif +#if defined(__has_attribute) +# define ZPL_HAS_ATTRIBUTE(attribute) __has_attribute(attribute) +#else +# define ZPL_HAS_ATTRIBUTE(attribute) (0) +#endif + +#if defined(ZPL_GNUC_HAS_ATTRIBUTE) +# undef ZPL_GNUC_HAS_ATTRIBUTE +#endif +#if defined(__has_attribute) +# define ZPL_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) __has_attribute(attribute) +#else +# define ZPL_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) ZPL_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(ZPL_GCC_HAS_ATTRIBUTE) +# undef ZPL_GCC_HAS_ATTRIBUTE +#endif +#if defined(__has_attribute) +# define ZPL_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) __has_attribute(attribute) +#else +# define ZPL_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) ZPL_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(ZPL_HAS_CPP_ATTRIBUTE) +# undef ZPL_HAS_CPP_ATTRIBUTE +#endif +#if \ +defined(__has_cpp_attribute) && \ +defined(__cplusplus) && \ +(!defined(ZPL_SUNPRO_VERSION) || ZPL_SUNPRO_VERSION_CHECK(5,15,0)) +# define ZPL_HAS_CPP_ATTRIBUTE(attribute) __has_cpp_attribute(attribute) +#else +# define ZPL_HAS_CPP_ATTRIBUTE(attribute) (0) +#endif + +#if defined(ZPL_HAS_CPP_ATTRIBUTE_NS) +# undef ZPL_HAS_CPP_ATTRIBUTE_NS +#endif +#if !defined(__cplusplus) || !defined(__has_cpp_attribute) +# define ZPL_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) +#elif \ +!defined(ZPL_PGI_VERSION) && \ +!defined(ZPL_IAR_VERSION) && \ +(!defined(ZPL_SUNPRO_VERSION) || ZPL_SUNPRO_VERSION_CHECK(5,15,0)) && \ +(!defined(ZPL_MSVC_VERSION) || ZPL_MSVC_VERSION_CHECK(19,20,0)) +# define ZPL_HAS_CPP_ATTRIBUTE_NS(ns,attribute) ZPL_HAS_CPP_ATTRIBUTE(ns::attribute) +#else +# define ZPL_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) +#endif + +#if defined(ZPL_GNUC_HAS_CPP_ATTRIBUTE) +# undef ZPL_GNUC_HAS_CPP_ATTRIBUTE +#endif +#if defined(__has_cpp_attribute) && defined(__cplusplus) +# define ZPL_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) +#else +# define ZPL_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) ZPL_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(ZPL_GCC_HAS_CPP_ATTRIBUTE) +# undef ZPL_GCC_HAS_CPP_ATTRIBUTE +#endif +#if defined(__has_cpp_attribute) && defined(__cplusplus) +# define ZPL_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) +#else +# define ZPL_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) ZPL_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(ZPL_HAS_BUILTIN) +# undef ZPL_HAS_BUILTIN +#endif +#if defined(__has_builtin) +# define ZPL_HAS_BUILTIN(builtin) __has_builtin(builtin) +#else +# define ZPL_HAS_BUILTIN(builtin) (0) +#endif + +#if defined(ZPL_GNUC_HAS_BUILTIN) +# undef ZPL_GNUC_HAS_BUILTIN +#endif +#if defined(__has_builtin) +# define ZPL_GNUC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) +#else +# define ZPL_GNUC_HAS_BUILTIN(builtin,major,minor,patch) ZPL_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(ZPL_GCC_HAS_BUILTIN) +# undef ZPL_GCC_HAS_BUILTIN +#endif +#if defined(__has_builtin) +# define ZPL_GCC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) +#else +# define ZPL_GCC_HAS_BUILTIN(builtin,major,minor,patch) ZPL_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(ZPL_HAS_FEATURE) +# undef ZPL_HAS_FEATURE +#endif +#if defined(__has_feature) +# define ZPL_HAS_FEATURE(feature) __has_feature(feature) +#else +# define ZPL_HAS_FEATURE(feature) (0) +#endif + +#if defined(ZPL_GNUC_HAS_FEATURE) +# undef ZPL_GNUC_HAS_FEATURE +#endif +#if defined(__has_feature) +# define ZPL_GNUC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) +#else +# define ZPL_GNUC_HAS_FEATURE(feature,major,minor,patch) ZPL_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(ZPL_GCC_HAS_FEATURE) +# undef ZPL_GCC_HAS_FEATURE +#endif +#if defined(__has_feature) +# define ZPL_GCC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) +#else +# define ZPL_GCC_HAS_FEATURE(feature,major,minor,patch) ZPL_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(ZPL_HAS_EXTENSION) +# undef ZPL_HAS_EXTENSION +#endif +#if defined(__has_extension) +# define ZPL_HAS_EXTENSION(extension) __has_extension(extension) +#else +# define ZPL_HAS_EXTENSION(extension) (0) +#endif + +#if defined(ZPL_GNUC_HAS_EXTENSION) +# undef ZPL_GNUC_HAS_EXTENSION +#endif +#if defined(__has_extension) +# define ZPL_GNUC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) +#else +# define ZPL_GNUC_HAS_EXTENSION(extension,major,minor,patch) ZPL_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(ZPL_GCC_HAS_EXTENSION) +# undef ZPL_GCC_HAS_EXTENSION +#endif +#if defined(__has_extension) +# define ZPL_GCC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) +#else +# define ZPL_GCC_HAS_EXTENSION(extension,major,minor,patch) ZPL_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(ZPL_HAS_DECLSPEC_ATTRIBUTE) +# undef ZPL_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) +# define ZPL_HAS_DECLSPEC_ATTRIBUTE(attribute) __has_declspec_attribute(attribute) +#else +# define ZPL_HAS_DECLSPEC_ATTRIBUTE(attribute) (0) +#endif + +#if defined(ZPL_GNUC_HAS_DECLSPEC_ATTRIBUTE) +# undef ZPL_GNUC_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) +# define ZPL_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) +#else +# define ZPL_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) ZPL_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(ZPL_GCC_HAS_DECLSPEC_ATTRIBUTE) +# undef ZPL_GCC_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) +# define ZPL_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) +#else +# define ZPL_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) ZPL_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(ZPL_HAS_WARNING) +# undef ZPL_HAS_WARNING +#endif +#if defined(__has_warning) +# define ZPL_HAS_WARNING(warning) __has_warning(warning) +#else +# define ZPL_HAS_WARNING(warning) (0) +#endif + +#if defined(ZPL_GNUC_HAS_WARNING) +# undef ZPL_GNUC_HAS_WARNING +#endif +#if defined(__has_warning) +# define ZPL_GNUC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) +#else +# define ZPL_GNUC_HAS_WARNING(warning,major,minor,patch) ZPL_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(ZPL_GCC_HAS_WARNING) +# undef ZPL_GCC_HAS_WARNING +#endif +#if defined(__has_warning) +# define ZPL_GCC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) +#else +# define ZPL_GCC_HAS_WARNING(warning,major,minor,patch) ZPL_GCC_VERSION_CHECK(major,minor,patch) +#endif + +/* ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ is for + ZPL INTERNAL USE ONLY. API subject to change without notice. */ +#if defined(ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) +# undef ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ +#endif +#if defined(__cplusplus) +# if ZPL_HAS_WARNING("-Wc++98-compat") +# if ZPL_HAS_WARNING("-Wc++17-extensions") +# define ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ +ZPL_DIAGNOSTIC_PUSH \ +_Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ +_Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \ +xpr \ +ZPL_DIAGNOSTIC_POP +# else +# define ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ +ZPL_DIAGNOSTIC_PUSH \ +_Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ +xpr \ +ZPL_DIAGNOSTIC_POP +# endif +# endif +#endif +#if !defined(ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) +# define ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(x) x +#endif + +#if defined(ZPL_CONST_CAST) +# undef ZPL_CONST_CAST +#endif +#if defined(__cplusplus) +# define ZPL_CONST_CAST(T, expr) (const_cast(expr)) +#elif \ +ZPL_HAS_WARNING("-Wcast-qual") || \ +ZPL_GCC_VERSION_CHECK(4,6,0) || \ +ZPL_INTEL_VERSION_CHECK(13,0,0) +# define ZPL_CONST_CAST(T, expr) (__extension__ ({ \ +ZPL_DIAGNOSTIC_PUSH \ +ZPL_DIAGNOSTIC_DISABLE_CAST_QUAL \ +((T) (expr)); \ +ZPL_DIAGNOSTIC_POP \ +})) +#else +# define ZPL_CONST_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(ZPL_REINTERPRET_CAST) +# undef ZPL_REINTERPRET_CAST +#endif +#if defined(__cplusplus) +# define ZPL_REINTERPRET_CAST(T, expr) (reinterpret_cast(expr)) +#else +# define ZPL_REINTERPRET_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(ZPL_STATIC_CAST) +# undef ZPL_STATIC_CAST +#endif +#if defined(__cplusplus) +# define ZPL_STATIC_CAST(T, expr) (static_cast(expr)) +#else +# define ZPL_STATIC_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(ZPL_CPP_CAST) +# undef ZPL_CPP_CAST +#endif +#if defined(__cplusplus) +# if ZPL_HAS_WARNING("-Wold-style-cast") +# define ZPL_CPP_CAST(T, expr) \ +ZPL_DIAGNOSTIC_PUSH \ +_Pragma("clang diagnostic ignored \"-Wold-style-cast\"") \ +((T) (expr)) \ +ZPL_DIAGNOSTIC_POP +# elif ZPL_IAR_VERSION_CHECK(8,3,0) +# define ZPL_CPP_CAST(T, expr) \ +ZPL_DIAGNOSTIC_PUSH \ +_Pragma("diag_suppress=Pe137") \ +ZPL_DIAGNOSTIC_POP \ +# else +# define ZPL_CPP_CAST(T, expr) ((T) (expr)) +# endif +#else +# define ZPL_CPP_CAST(T, expr) (expr) +#endif + +#if \ +(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ +defined(__clang__) || \ +ZPL_GCC_VERSION_CHECK(3,0,0) || \ +ZPL_INTEL_VERSION_CHECK(13,0,0) || \ +ZPL_IAR_VERSION_CHECK(8,0,0) || \ +ZPL_PGI_VERSION_CHECK(18,4,0) || \ +ZPL_ARM_VERSION_CHECK(4,1,0) || \ +ZPL_TI_VERSION_CHECK(15,12,0) || \ +ZPL_TI_ARMCL_VERSION_CHECK(4,7,0) || \ +ZPL_TI_CL430_VERSION_CHECK(2,0,1) || \ +ZPL_TI_CL2000_VERSION_CHECK(6,1,0) || \ +ZPL_TI_CL6X_VERSION_CHECK(7,0,0) || \ +ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ +ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) || \ +ZPL_CRAY_VERSION_CHECK(5,0,0) || \ +ZPL_TINYC_VERSION_CHECK(0,9,17) || \ +ZPL_SUNPRO_VERSION_CHECK(8,0,0) || \ +(ZPL_IBM_VERSION_CHECK(10,1,0) && defined(__C99_PRAGMA_OPERATOR)) +# define ZPL_PRAGMA(value) _Pragma(#value) +#elif ZPL_MSVC_VERSION_CHECK(15,0,0) +# define ZPL_PRAGMA(value) __pragma(value) +#else +# define ZPL_PRAGMA(value) +#endif + +#if defined(ZPL_DIAGNOSTIC_PUSH) +# undef ZPL_DIAGNOSTIC_PUSH +#endif +#if defined(ZPL_DIAGNOSTIC_POP) +# undef ZPL_DIAGNOSTIC_POP +#endif +#if defined(__clang__) +# define ZPL_DIAGNOSTIC_PUSH _Pragma("clang diagnostic push") +# define ZPL_DIAGNOSTIC_POP _Pragma("clang diagnostic pop") +#elif ZPL_INTEL_VERSION_CHECK(13,0,0) +# define ZPL_DIAGNOSTIC_PUSH _Pragma("warning(push)") +# define ZPL_DIAGNOSTIC_POP _Pragma("warning(pop)") +#elif ZPL_GCC_VERSION_CHECK(4,6,0) +# define ZPL_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push") +# define ZPL_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop") +#elif ZPL_MSVC_VERSION_CHECK(15,0,0) +# define ZPL_DIAGNOSTIC_PUSH __pragma(warning(push)) +# define ZPL_DIAGNOSTIC_POP __pragma(warning(pop)) +#elif ZPL_ARM_VERSION_CHECK(5,6,0) +# define ZPL_DIAGNOSTIC_PUSH _Pragma("push") +# define ZPL_DIAGNOSTIC_POP _Pragma("pop") +#elif \ +ZPL_TI_VERSION_CHECK(15,12,0) || \ +ZPL_TI_ARMCL_VERSION_CHECK(5,2,0) || \ +ZPL_TI_CL430_VERSION_CHECK(4,4,0) || \ +ZPL_TI_CL6X_VERSION_CHECK(8,1,0) || \ +ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ +ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) +# define ZPL_DIAGNOSTIC_PUSH _Pragma("diag_push") +# define ZPL_DIAGNOSTIC_POP _Pragma("diag_pop") +#elif ZPL_PELLES_VERSION_CHECK(2,90,0) +# define ZPL_DIAGNOSTIC_PUSH _Pragma("warning(push)") +# define ZPL_DIAGNOSTIC_POP _Pragma("warning(pop)") +#else +# define ZPL_DIAGNOSTIC_PUSH +# define ZPL_DIAGNOSTIC_POP +#endif + +#if defined(ZPL_DIAGNOSTIC_DISABLE_DEPRECATED) +# undef ZPL_DIAGNOSTIC_DISABLE_DEPRECATED +#endif +#if ZPL_HAS_WARNING("-Wdeprecated-declarations") +# define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") +#elif ZPL_INTEL_VERSION_CHECK(13,0,0) +# define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warning(disable:1478 1786)") +#elif ZPL_PGI_VERSION_CHECK(17,10,0) +# define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") +#elif ZPL_GCC_VERSION_CHECK(4,3,0) +# define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +#elif ZPL_MSVC_VERSION_CHECK(15,0,0) +# define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:4996)) +#elif \ +ZPL_TI_VERSION_CHECK(15,12,0) || \ +(ZPL_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_ARMCL_VERSION_CHECK(5,2,0) || \ +(ZPL_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL2000_VERSION_CHECK(6,4,0) || \ +(ZPL_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL430_VERSION_CHECK(4,3,0) || \ +(ZPL_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL6X_VERSION_CHECK(7,5,0) || \ +ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ +ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) +# define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1291,1718") +#elif ZPL_SUNPRO_VERSION_CHECK(5,13,0) && !defined(__cplusplus) +# define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)") +#elif ZPL_SUNPRO_VERSION_CHECK(5,13,0) && defined(__cplusplus) +# define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,symdeprecated,symdeprecated2)") +#elif ZPL_IAR_VERSION_CHECK(8,0,0) +# define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress=Pe1444,Pe1215") +#elif ZPL_PELLES_VERSION_CHECK(2,90,0) +# define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warn(disable:2241)") +#else +# define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED +#endif + +#if defined(ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS) +# undef ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS +#endif +#if ZPL_HAS_WARNING("-Wunknown-pragmas") +# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"") +#elif ZPL_INTEL_VERSION_CHECK(13,0,0) +# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("warning(disable:161)") +#elif ZPL_PGI_VERSION_CHECK(17,10,0) +# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 1675") +#elif ZPL_GCC_VERSION_CHECK(4,3,0) +# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("GCC diagnostic ignored \"-Wunknown-pragmas\"") +#elif ZPL_MSVC_VERSION_CHECK(15,0,0) +# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:4068)) +#elif \ +ZPL_TI_VERSION_CHECK(16,9,0) || \ +ZPL_TI_CL6X_VERSION_CHECK(8,0,0) || \ +ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ +ZPL_TI_CLPRU_VERSION_CHECK(2,3,0) +# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") +#elif ZPL_TI_CL6X_VERSION_CHECK(8,0,0) +# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") +#elif ZPL_IAR_VERSION_CHECK(8,0,0) +# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress=Pe161") +#else +# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS +#endif + +#if defined(ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES) +# undef ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES +#endif +#if ZPL_HAS_WARNING("-Wunknown-attributes") +# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("clang diagnostic ignored \"-Wunknown-attributes\"") +#elif ZPL_GCC_VERSION_CHECK(4,6,0) +# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +#elif ZPL_INTEL_VERSION_CHECK(17,0,0) +# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("warning(disable:1292)") +#elif ZPL_MSVC_VERSION_CHECK(19,0,0) +# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:5030)) +#elif ZPL_PGI_VERSION_CHECK(17,10,0) +# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097") +#elif ZPL_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus) +# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("error_messages(off,attrskipunsup)") +#elif \ +ZPL_TI_VERSION_CHECK(18,1,0) || \ +ZPL_TI_CL6X_VERSION_CHECK(8,3,0) || \ +ZPL_TI_CL7X_VERSION_CHECK(1,2,0) +# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1173") +#elif ZPL_IAR_VERSION_CHECK(8,0,0) +# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress=Pe1097") +#else +# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES +#endif + +#if defined(ZPL_DIAGNOSTIC_DISABLE_CAST_QUAL) +# undef ZPL_DIAGNOSTIC_DISABLE_CAST_QUAL +#endif +#if ZPL_HAS_WARNING("-Wcast-qual") +# define ZPL_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("clang diagnostic ignored \"-Wcast-qual\"") +#elif ZPL_INTEL_VERSION_CHECK(13,0,0) +# define ZPL_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("warning(disable:2203 2331)") +#elif ZPL_GCC_VERSION_CHECK(3,0,0) +# define ZPL_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") +#else +# define ZPL_DIAGNOSTIC_DISABLE_CAST_QUAL +#endif + +#if defined(ZPL_DEPRECATED) +# undef ZPL_DEPRECATED +#endif +#if defined(ZPL_DEPRECATED_FOR) +# undef ZPL_DEPRECATED_FOR +#endif +#if defined(__cplusplus) && (__cplusplus >= 201402L) +# define ZPL_DEPRECATED(since) ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since)]]) +# define ZPL_DEPRECATED_FOR(since, replacement) ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since "; use " #replacement)]]) +#elif \ +ZPL_HAS_EXTENSION(attribute_deprecated_with_message) || \ +ZPL_GCC_VERSION_CHECK(4,5,0) || \ +ZPL_INTEL_VERSION_CHECK(13,0,0) || \ +ZPL_ARM_VERSION_CHECK(5,6,0) || \ +ZPL_SUNPRO_VERSION_CHECK(5,13,0) || \ +ZPL_PGI_VERSION_CHECK(17,10,0) || \ +ZPL_TI_VERSION_CHECK(18,1,0) || \ +ZPL_TI_ARMCL_VERSION_CHECK(18,1,0) || \ +ZPL_TI_CL6X_VERSION_CHECK(8,3,0) || \ +ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ +ZPL_TI_CLPRU_VERSION_CHECK(2,3,0) +# define ZPL_DEPRECATED(since) __attribute__((__deprecated__("Since " #since))) +# define ZPL_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__("Since " #since "; use " #replacement))) +#elif \ +ZPL_HAS_ATTRIBUTE(deprecated) || \ +ZPL_GCC_VERSION_CHECK(3,1,0) || \ +ZPL_ARM_VERSION_CHECK(4,1,0) || \ +ZPL_TI_VERSION_CHECK(15,12,0) || \ +(ZPL_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_ARMCL_VERSION_CHECK(5,2,0) || \ +(ZPL_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL2000_VERSION_CHECK(6,4,0) || \ +(ZPL_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL430_VERSION_CHECK(4,3,0) || \ +(ZPL_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL6X_VERSION_CHECK(7,5,0) || \ +ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ +ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) +# define ZPL_DEPRECATED(since) __attribute__((__deprecated__)) +# define ZPL_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__)) +#elif ZPL_MSVC_VERSION_CHECK(14,0,0) +# define ZPL_DEPRECATED(since) __declspec(deprecated("Since " # since)) +# define ZPL_DEPRECATED_FOR(since, replacement) __declspec(deprecated("Since " #since "; use " #replacement)) +#elif \ +ZPL_MSVC_VERSION_CHECK(13,10,0) || \ +ZPL_PELLES_VERSION_CHECK(6,50,0) +# define ZPL_DEPRECATED(since) __declspec(deprecated) +# define ZPL_DEPRECATED_FOR(since, replacement) __declspec(deprecated) +#elif ZPL_IAR_VERSION_CHECK(8,0,0) +# define ZPL_DEPRECATED(since) _Pragma("deprecated") +# define ZPL_DEPRECATED_FOR(since, replacement) _Pragma("deprecated") +#else +# define ZPL_DEPRECATED(since) +# define ZPL_DEPRECATED_FOR(since, replacement) +#endif + +#if defined(ZPL_UNAVAILABLE) +# undef ZPL_UNAVAILABLE +#endif +#if \ +ZPL_HAS_ATTRIBUTE(warning) || \ +ZPL_GCC_VERSION_CHECK(4,3,0) || \ +ZPL_INTEL_VERSION_CHECK(13,0,0) +# define ZPL_UNAVAILABLE(available_since) __attribute__((__warning__("Not available until " #available_since))) +#else +# define ZPL_UNAVAILABLE(available_since) +#endif + +#if defined(ZPL_WARN_UNUSED_RESULT) +# undef ZPL_WARN_UNUSED_RESULT +#endif +#if defined(ZPL_WARN_UNUSED_RESULT_MSG) +# undef ZPL_WARN_UNUSED_RESULT_MSG +#endif +#if (ZPL_HAS_CPP_ATTRIBUTE(nodiscard) >= 201907L) +# define ZPL_WARN_UNUSED_RESULT ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) +# define ZPL_WARN_UNUSED_RESULT_MSG(msg) ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard(msg)]]) +#elif ZPL_HAS_CPP_ATTRIBUTE(nodiscard) +# define ZPL_WARN_UNUSED_RESULT ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) +# define ZPL_WARN_UNUSED_RESULT_MSG(msg) ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) +#elif \ +ZPL_HAS_ATTRIBUTE(warn_unused_result) || \ +ZPL_GCC_VERSION_CHECK(3,4,0) || \ +ZPL_INTEL_VERSION_CHECK(13,0,0) || \ +ZPL_TI_VERSION_CHECK(15,12,0) || \ +(ZPL_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_ARMCL_VERSION_CHECK(5,2,0) || \ +(ZPL_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL2000_VERSION_CHECK(6,4,0) || \ +(ZPL_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL430_VERSION_CHECK(4,3,0) || \ +(ZPL_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL6X_VERSION_CHECK(7,5,0) || \ +ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ +ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) || \ +(ZPL_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ +ZPL_PGI_VERSION_CHECK(17,10,0) +# define ZPL_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__)) +# define ZPL_WARN_UNUSED_RESULT_MSG(msg) __attribute__((__warn_unused_result__)) +#elif defined(_Check_return_) /* SAL */ +# define ZPL_WARN_UNUSED_RESULT _Check_return_ +# define ZPL_WARN_UNUSED_RESULT_MSG(msg) _Check_return_ +#else +# define ZPL_WARN_UNUSED_RESULT +# define ZPL_WARN_UNUSED_RESULT_MSG(msg) +#endif + +#if defined(ZPL_SENTINEL) +# undef ZPL_SENTINEL +#endif +#if \ +ZPL_HAS_ATTRIBUTE(sentinel) || \ +ZPL_GCC_VERSION_CHECK(4,0,0) || \ +ZPL_INTEL_VERSION_CHECK(13,0,0) || \ +ZPL_ARM_VERSION_CHECK(5,4,0) +# define ZPL_SENTINEL(position) __attribute__((__sentinel__(position))) +#else +# define ZPL_SENTINEL(position) +#endif + +#if defined(ZPL_NO_RETURN) +# undef ZPL_NO_RETURN +#endif +#if ZPL_IAR_VERSION_CHECK(8,0,0) +# define ZPL_NO_RETURN __noreturn +#elif ZPL_INTEL_VERSION_CHECK(13,0,0) +# define ZPL_NO_RETURN __attribute__((__noreturn__)) +#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L +# define ZPL_NO_RETURN _Noreturn +#elif defined(__cplusplus) && (__cplusplus >= 201103L) +# define ZPL_NO_RETURN ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[noreturn]]) +#elif \ +ZPL_HAS_ATTRIBUTE(noreturn) || \ +ZPL_GCC_VERSION_CHECK(3,2,0) || \ +ZPL_SUNPRO_VERSION_CHECK(5,11,0) || \ +ZPL_ARM_VERSION_CHECK(4,1,0) || \ +ZPL_IBM_VERSION_CHECK(10,1,0) || \ +ZPL_TI_VERSION_CHECK(15,12,0) || \ +(ZPL_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_ARMCL_VERSION_CHECK(5,2,0) || \ +(ZPL_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL2000_VERSION_CHECK(6,4,0) || \ +(ZPL_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL430_VERSION_CHECK(4,3,0) || \ +(ZPL_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL6X_VERSION_CHECK(7,5,0) || \ +ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ +ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) +# define ZPL_NO_RETURN __attribute__((__noreturn__)) +#elif ZPL_SUNPRO_VERSION_CHECK(5,10,0) +# define ZPL_NO_RETURN _Pragma("does_not_return") +#elif ZPL_MSVC_VERSION_CHECK(13,10,0) +# define ZPL_NO_RETURN __declspec(noreturn) +#elif ZPL_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus) +# define ZPL_NO_RETURN _Pragma("FUNC_NEVER_RETURNS;") +#elif ZPL_COMPCERT_VERSION_CHECK(3,2,0) +# define ZPL_NO_RETURN __attribute((noreturn)) +#elif ZPL_PELLES_VERSION_CHECK(9,0,0) +# define ZPL_NO_RETURN __declspec(noreturn) +#else +# define ZPL_NO_RETURN +#endif + +#if defined(ZPL_NO_ESCAPE) +# undef ZPL_NO_ESCAPE +#endif +#if ZPL_HAS_ATTRIBUTE(noescape) +# define ZPL_NO_ESCAPE __attribute__((__noescape__)) +#else +# define ZPL_NO_ESCAPE +#endif + +#if defined(ZPL_UNREACHABLE) +# undef ZPL_UNREACHABLE +#endif +#if defined(ZPL_UNREACHABLE_RETURN) +# undef ZPL_UNREACHABLE_RETURN +#endif +#if defined(ZPL_ASSUME) +# undef ZPL_ASSUME +#endif +#if \ +ZPL_MSVC_VERSION_CHECK(13,10,0) || \ +ZPL_INTEL_VERSION_CHECK(13,0,0) +# define ZPL_ASSUME(expr) __assume(expr) +#elif ZPL_HAS_BUILTIN(__builtin_assume) +# define ZPL_ASSUME(expr) __builtin_assume(expr) +#elif \ +ZPL_TI_CL2000_VERSION_CHECK(6,2,0) || \ +ZPL_TI_CL6X_VERSION_CHECK(4,0,0) +# if defined(__cplusplus) +# define ZPL_ASSUME(expr) std::_nassert(expr) +# else +# define ZPL_ASSUME(expr) _nassert(expr) +# endif +#endif +#if \ +(ZPL_HAS_BUILTIN(__builtin_unreachable) && (!defined(ZPL_ARM_VERSION))) || \ +ZPL_GCC_VERSION_CHECK(4,5,0) || \ +ZPL_PGI_VERSION_CHECK(18,10,0) || \ +ZPL_INTEL_VERSION_CHECK(13,0,0) || \ +ZPL_IBM_VERSION_CHECK(13,1,5) +# define ZPL_UNREACHABLE() __builtin_unreachable() +#elif defined(ZPL_ASSUME) +# define ZPL_UNREACHABLE() ZPL_ASSUME(0) +#endif +#if !defined(ZPL_ASSUME) +# if defined(ZPL_UNREACHABLE) +# define ZPL_ASSUME(expr) ZPL_STATIC_CAST(void, ((expr) ? 1 : (ZPL_UNREACHABLE(), 1))) +# else +# define ZPL_ASSUME(expr) ZPL_STATIC_CAST(void, expr) +# endif +#endif +#if defined(ZPL_UNREACHABLE) +# if \ +ZPL_TI_CL2000_VERSION_CHECK(6,2,0) || \ +ZPL_TI_CL6X_VERSION_CHECK(4,0,0) +# define ZPL_UNREACHABLE_RETURN(value) return (ZPL_STATIC_CAST(void, ZPL_ASSUME(0)), (value)) +# else +# define ZPL_UNREACHABLE_RETURN(value) ZPL_UNREACHABLE() +# endif +#else +# define ZPL_UNREACHABLE_RETURN(value) return (value) +#endif +#if !defined(ZPL_UNREACHABLE) +# define ZPL_UNREACHABLE() ZPL_ASSUME(0) +#endif + +ZPL_DIAGNOSTIC_PUSH +#if ZPL_HAS_WARNING("-Wpedantic") +# pragma clang diagnostic ignored "-Wpedantic" +#endif +#if ZPL_HAS_WARNING("-Wc++98-compat-pedantic") && defined(__cplusplus) +# pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +#endif +#if ZPL_GCC_HAS_WARNING("-Wvariadic-macros",4,0,0) +# if defined(__clang__) +# pragma clang diagnostic ignored "-Wvariadic-macros" +# elif defined(ZPL_GCC_VERSION) +# pragma GCC diagnostic ignored "-Wvariadic-macros" +# endif +#endif +#if defined(ZPL_NON_NULL) +# undef ZPL_NON_NULL +#endif +#if \ +ZPL_HAS_ATTRIBUTE(nonnull) || \ +ZPL_GCC_VERSION_CHECK(3,3,0) || \ +ZPL_INTEL_VERSION_CHECK(13,0,0) || \ +ZPL_ARM_VERSION_CHECK(4,1,0) +# define ZPL_NON_NULL(...) __attribute__((__nonnull__(__VA_ARGS__))) +#else +# define ZPL_NON_NULL(...) +#endif +ZPL_DIAGNOSTIC_POP + +#if defined(ZPL_PRINTF_FORMAT) +# undef ZPL_PRINTF_FORMAT +#endif +#if defined(__MINGW32__) && ZPL_GCC_HAS_ATTRIBUTE(format,4,4,0) && !defined(__USE_MINGW_ANSI_STDIO) +# define ZPL_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(ms_printf, string_idx, first_to_check))) +#elif defined(__MINGW32__) && ZPL_GCC_HAS_ATTRIBUTE(format,4,4,0) && defined(__USE_MINGW_ANSI_STDIO) +# define ZPL_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(gnu_printf, string_idx, first_to_check))) +#elif \ +ZPL_HAS_ATTRIBUTE(format) || \ +ZPL_GCC_VERSION_CHECK(3,1,0) || \ +ZPL_INTEL_VERSION_CHECK(13,0,0) || \ +ZPL_ARM_VERSION_CHECK(5,6,0) || \ +ZPL_IBM_VERSION_CHECK(10,1,0) || \ +ZPL_TI_VERSION_CHECK(15,12,0) || \ +(ZPL_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_ARMCL_VERSION_CHECK(5,2,0) || \ +(ZPL_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL2000_VERSION_CHECK(6,4,0) || \ +(ZPL_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL430_VERSION_CHECK(4,3,0) || \ +(ZPL_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL6X_VERSION_CHECK(7,5,0) || \ +ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ +ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) +# define ZPL_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(__printf__, string_idx, first_to_check))) +#elif ZPL_PELLES_VERSION_CHECK(6,0,0) +# define ZPL_PRINTF_FORMAT(string_idx,first_to_check) __declspec(vaformat(printf,string_idx,first_to_check)) +#else +# define ZPL_PRINTF_FORMAT(string_idx,first_to_check) +#endif + +#if defined(ZPL_CONSTEXPR) +# undef ZPL_CONSTEXPR +#endif +#if defined(__cplusplus) +# if __cplusplus >= 201103L +# define ZPL_CONSTEXPR ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(constexpr) +# endif +#endif +#if !defined(ZPL_CONSTEXPR) +# define ZPL_CONSTEXPR +#endif + +#if defined(ZPL_PREDICT) +# undef ZPL_PREDICT +#endif +#if defined(ZPL_LIKELY) +# undef ZPL_LIKELY +#endif +#if defined(ZPL_UNLIKELY) +# undef ZPL_UNLIKELY +#endif +#if defined(ZPL_UNPREDICTABLE) +# undef ZPL_UNPREDICTABLE +#endif +#if ZPL_HAS_BUILTIN(__builtin_unpredictable) +# define ZPL_UNPREDICTABLE(expr) __builtin_unpredictable((expr)) +#endif +#if \ +ZPL_HAS_BUILTIN(__builtin_expect_with_probability) || \ +ZPL_GCC_VERSION_CHECK(9,0,0) +# define ZPL_PREDICT(expr, value, probability) __builtin_expect_with_probability( (expr), (value), (probability)) +# define ZPL_PREDICT_TRUE(expr, probability) __builtin_expect_with_probability(!!(expr), 1 , (probability)) +# define ZPL_PREDICT_FALSE(expr, probability) __builtin_expect_with_probability(!!(expr), 0 , (probability)) +# define ZPL_LIKELY(expr) __builtin_expect (!!(expr), 1 ) +# define ZPL_UNLIKELY(expr) __builtin_expect (!!(expr), 0 ) +#elif \ +ZPL_HAS_BUILTIN(__builtin_expect) || \ +ZPL_GCC_VERSION_CHECK(3,0,0) || \ +ZPL_INTEL_VERSION_CHECK(13,0,0) || \ +(ZPL_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ +ZPL_ARM_VERSION_CHECK(4,1,0) || \ +ZPL_IBM_VERSION_CHECK(10,1,0) || \ +ZPL_TI_VERSION_CHECK(15,12,0) || \ +ZPL_TI_ARMCL_VERSION_CHECK(4,7,0) || \ +ZPL_TI_CL430_VERSION_CHECK(3,1,0) || \ +ZPL_TI_CL2000_VERSION_CHECK(6,1,0) || \ +ZPL_TI_CL6X_VERSION_CHECK(6,1,0) || \ +ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ +ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) || \ +ZPL_TINYC_VERSION_CHECK(0,9,27) || \ +ZPL_CRAY_VERSION_CHECK(8,1,0) +# define ZPL_PREDICT(expr, expected, probability) \ +(((probability) >= 0.9) ? __builtin_expect((expr), (expected)) : (ZPL_STATIC_CAST(void, expected), (expr))) +# define ZPL_PREDICT_TRUE(expr, probability) \ +(__extension__ ({ \ +double zpl_probability_ = (probability); \ +((zpl_probability_ >= 0.9) ? __builtin_expect(!!(expr), 1) : ((zpl_probability_ <= 0.1) ? __builtin_expect(!!(expr), 0) : !!(expr))); \ +})) +# define ZPL_PREDICT_FALSE(expr, probability) \ +(__extension__ ({ \ +double zpl_probability_ = (probability); \ +((zpl_probability_ >= 0.9) ? __builtin_expect(!!(expr), 0) : ((zpl_probability_ <= 0.1) ? __builtin_expect(!!(expr), 1) : !!(expr))); \ +})) +# define ZPL_LIKELY(expr) __builtin_expect(!!(expr), 1) +# define ZPL_UNLIKELY(expr) __builtin_expect(!!(expr), 0) +#else +# define ZPL_PREDICT(expr, expected, probability) (ZPL_STATIC_CAST(void, expected), (expr)) +# define ZPL_PREDICT_TRUE(expr, probability) (!!(expr)) +# define ZPL_PREDICT_FALSE(expr, probability) (!!(expr)) +# define ZPL_LIKELY(expr) (!!(expr)) +# define ZPL_UNLIKELY(expr) (!!(expr)) +#endif +#if !defined(ZPL_UNPREDICTABLE) +# define ZPL_UNPREDICTABLE(expr) ZPL_PREDICT(expr, 1, 0.5) +#endif + +#if defined(ZPL_MALLOC) +# undef ZPL_MALLOC +#endif +#if \ +ZPL_HAS_ATTRIBUTE(malloc) || \ +ZPL_GCC_VERSION_CHECK(3,1,0) || \ +ZPL_INTEL_VERSION_CHECK(13,0,0) || \ +ZPL_SUNPRO_VERSION_CHECK(5,11,0) || \ +ZPL_ARM_VERSION_CHECK(4,1,0) || \ +ZPL_IBM_VERSION_CHECK(12,1,0) || \ +ZPL_TI_VERSION_CHECK(15,12,0) || \ +(ZPL_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_ARMCL_VERSION_CHECK(5,2,0) || \ +(ZPL_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL2000_VERSION_CHECK(6,4,0) || \ +(ZPL_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL430_VERSION_CHECK(4,3,0) || \ +(ZPL_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL6X_VERSION_CHECK(7,5,0) || \ +ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ +ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) +# define ZPL_MALLOC __attribute__((__malloc__)) +#elif ZPL_SUNPRO_VERSION_CHECK(5,10,0) +# define ZPL_MALLOC _Pragma("returns_new_memory") +#elif ZPL_MSVC_VERSION_CHECK(14, 0, 0) +# define ZPL_MALLOC __declspec(restrict) +#else +# define ZPL_MALLOC +#endif + +#if defined(ZPL_PURE) +# undef ZPL_PURE +#endif +#if \ +ZPL_HAS_ATTRIBUTE(pure) || \ +ZPL_GCC_VERSION_CHECK(2,96,0) || \ +ZPL_INTEL_VERSION_CHECK(13,0,0) || \ +ZPL_SUNPRO_VERSION_CHECK(5,11,0) || \ +ZPL_ARM_VERSION_CHECK(4,1,0) || \ +ZPL_IBM_VERSION_CHECK(10,1,0) || \ +ZPL_TI_VERSION_CHECK(15,12,0) || \ +(ZPL_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_ARMCL_VERSION_CHECK(5,2,0) || \ +(ZPL_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL2000_VERSION_CHECK(6,4,0) || \ +(ZPL_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL430_VERSION_CHECK(4,3,0) || \ +(ZPL_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL6X_VERSION_CHECK(7,5,0) || \ +ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ +ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) || \ +ZPL_PGI_VERSION_CHECK(17,10,0) +# define ZPL_PURE __attribute__((__pure__)) +#elif ZPL_SUNPRO_VERSION_CHECK(5,10,0) +# define ZPL_PURE _Pragma("does_not_write_global_data") +#elif defined(__cplusplus) && \ +( \ +ZPL_TI_CL430_VERSION_CHECK(2,0,1) || \ +ZPL_TI_CL6X_VERSION_CHECK(4,0,0) || \ +ZPL_TI_CL7X_VERSION_CHECK(1,2,0) \ +) +# define ZPL_PURE _Pragma("FUNC_IS_PURE;") +#else +# define ZPL_PURE +#endif + +#if defined(ZPL_CONST) +# undef ZPL_CONST +#endif +#if \ +ZPL_HAS_ATTRIBUTE(const) || \ +ZPL_GCC_VERSION_CHECK(2,5,0) || \ +ZPL_INTEL_VERSION_CHECK(13,0,0) || \ +ZPL_SUNPRO_VERSION_CHECK(5,11,0) || \ +ZPL_ARM_VERSION_CHECK(4,1,0) || \ +ZPL_IBM_VERSION_CHECK(10,1,0) || \ +ZPL_TI_VERSION_CHECK(15,12,0) || \ +(ZPL_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_ARMCL_VERSION_CHECK(5,2,0) || \ +(ZPL_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL2000_VERSION_CHECK(6,4,0) || \ +(ZPL_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL430_VERSION_CHECK(4,3,0) || \ +(ZPL_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL6X_VERSION_CHECK(7,5,0) || \ +ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ +ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) || \ +ZPL_PGI_VERSION_CHECK(17,10,0) +# define ZPL_CONST __attribute__((__const__)) +#elif \ +ZPL_SUNPRO_VERSION_CHECK(5,10,0) +# define ZPL_CONST _Pragma("no_side_effect") +#else +# define ZPL_CONST ZPL_PURE +#endif + +#if defined(ZPL_RESTRICT) +# undef ZPL_RESTRICT +#endif +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && !defined(__cplusplus) +# define ZPL_RESTRICT restrict +#elif \ +ZPL_GCC_VERSION_CHECK(3,1,0) || \ +ZPL_MSVC_VERSION_CHECK(14,0,0) || \ +ZPL_INTEL_VERSION_CHECK(13,0,0) || \ +ZPL_ARM_VERSION_CHECK(4,1,0) || \ +ZPL_IBM_VERSION_CHECK(10,1,0) || \ +ZPL_PGI_VERSION_CHECK(17,10,0) || \ +ZPL_TI_CL430_VERSION_CHECK(4,3,0) || \ +ZPL_TI_CL2000_VERSION_CHECK(6,2,4) || \ +ZPL_TI_CL6X_VERSION_CHECK(8,1,0) || \ +ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ +(ZPL_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)) || \ +ZPL_IAR_VERSION_CHECK(8,0,0) || \ +defined(__clang__) +# define ZPL_RESTRICT __restrict +#elif ZPL_SUNPRO_VERSION_CHECK(5,3,0) && !defined(__cplusplus) +# define ZPL_RESTRICT _Restrict +#else +# define ZPL_RESTRICT +#endif + +#if defined(ZPL_INLINE) +# undef ZPL_INLINE +#endif +#if \ +(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ +(defined(__cplusplus) && (__cplusplus >= 199711L)) +# define ZPL_INLINE inline +#elif \ +defined(ZPL_GCC_VERSION) || \ +ZPL_ARM_VERSION_CHECK(6,2,0) +# define ZPL_INLINE __inline__ +#elif \ +ZPL_MSVC_VERSION_CHECK(12,0,0) || \ +ZPL_ARM_VERSION_CHECK(4,1,0) || \ +ZPL_TI_ARMCL_VERSION_CHECK(5,1,0) || \ +ZPL_TI_CL430_VERSION_CHECK(3,1,0) || \ +ZPL_TI_CL2000_VERSION_CHECK(6,2,0) || \ +ZPL_TI_CL6X_VERSION_CHECK(8,0,0) || \ +ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ +ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) +# define ZPL_INLINE __inline +#else +# define ZPL_INLINE +#endif + +#if defined(ZPL_ALWAYS_INLINE) +# undef ZPL_ALWAYS_INLINE +#endif +#if \ +ZPL_HAS_ATTRIBUTE(always_inline) || \ +ZPL_GCC_VERSION_CHECK(4,0,0) || \ +ZPL_INTEL_VERSION_CHECK(13,0,0) || \ +ZPL_SUNPRO_VERSION_CHECK(5,11,0) || \ +ZPL_ARM_VERSION_CHECK(4,1,0) || \ +ZPL_IBM_VERSION_CHECK(10,1,0) || \ +ZPL_TI_VERSION_CHECK(15,12,0) || \ +(ZPL_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_ARMCL_VERSION_CHECK(5,2,0) || \ +(ZPL_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL2000_VERSION_CHECK(6,4,0) || \ +(ZPL_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL430_VERSION_CHECK(4,3,0) || \ +(ZPL_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL6X_VERSION_CHECK(7,5,0) || \ +ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ +ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) +# define ZPL_ALWAYS_INLINE __attribute__((__always_inline__)) ZPL_INLINE +#elif ZPL_MSVC_VERSION_CHECK(12,0,0) +# define ZPL_ALWAYS_INLINE __forceinline +#elif defined(__cplusplus) && \ +( \ +ZPL_TI_ARMCL_VERSION_CHECK(5,2,0) || \ +ZPL_TI_CL430_VERSION_CHECK(4,3,0) || \ +ZPL_TI_CL2000_VERSION_CHECK(6,4,0) || \ +ZPL_TI_CL6X_VERSION_CHECK(6,1,0) || \ +ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ +ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) \ +) +# define ZPL_ALWAYS_INLINE _Pragma("FUNC_ALWAYS_INLINE;") +#elif ZPL_IAR_VERSION_CHECK(8,0,0) +# define ZPL_ALWAYS_INLINE _Pragma("inline=forced") +#else +# define ZPL_ALWAYS_INLINE ZPL_INLINE +#endif + +#if defined(ZPL_NEVER_INLINE) +# undef ZPL_NEVER_INLINE +#endif +#if \ +ZPL_HAS_ATTRIBUTE(noinline) || \ +ZPL_GCC_VERSION_CHECK(4,0,0) || \ +ZPL_INTEL_VERSION_CHECK(13,0,0) || \ +ZPL_SUNPRO_VERSION_CHECK(5,11,0) || \ +ZPL_ARM_VERSION_CHECK(4,1,0) || \ +ZPL_IBM_VERSION_CHECK(10,1,0) || \ +ZPL_TI_VERSION_CHECK(15,12,0) || \ +(ZPL_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_ARMCL_VERSION_CHECK(5,2,0) || \ +(ZPL_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL2000_VERSION_CHECK(6,4,0) || \ +(ZPL_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL430_VERSION_CHECK(4,3,0) || \ +(ZPL_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL6X_VERSION_CHECK(7,5,0) || \ +ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ +ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) +# define ZPL_NEVER_INLINE __attribute__((__noinline__)) +#elif ZPL_MSVC_VERSION_CHECK(13,10,0) +# define ZPL_NEVER_INLINE __declspec(noinline) +#elif ZPL_PGI_VERSION_CHECK(10,2,0) +# define ZPL_NEVER_INLINE _Pragma("noinline") +#elif ZPL_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus) +# define ZPL_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;") +#elif ZPL_IAR_VERSION_CHECK(8,0,0) +# define ZPL_NEVER_INLINE _Pragma("inline=never") +#elif ZPL_COMPCERT_VERSION_CHECK(3,2,0) +# define ZPL_NEVER_INLINE __attribute((noinline)) +#elif ZPL_PELLES_VERSION_CHECK(9,0,0) +# define ZPL_NEVER_INLINE __declspec(noinline) +#else +# define ZPL_NEVER_INLINE +#endif + +#if defined(ZPL_PRIVATE) +# undef ZPL_PRIVATE +#endif +#if defined(ZPL_PUBLIC) +# undef ZPL_PUBLIC +#endif +#if defined(ZPL_IMPORT) +# undef ZPL_IMPORT +#endif +#if defined(_WIN32) || defined(__CYGWIN__) +# define ZPL_PRIVATE +# define ZPL_PUBLIC __declspec(dllexport) +# define ZPL_IMPORT __declspec(dllimport) +#else +# if \ +ZPL_HAS_ATTRIBUTE(visibility) || \ +ZPL_GCC_VERSION_CHECK(3,3,0) || \ +ZPL_SUNPRO_VERSION_CHECK(5,11,0) || \ +ZPL_INTEL_VERSION_CHECK(13,0,0) || \ +ZPL_ARM_VERSION_CHECK(4,1,0) || \ +ZPL_IBM_VERSION_CHECK(13,1,0) || \ +( \ +defined(__TI_EABI__) && \ +( \ +(ZPL_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL6X_VERSION_CHECK(7,5,0) \ +) \ +) +# define ZPL_PRIVATE __attribute__((__visibility__("hidden"))) +# define ZPL_PUBLIC __attribute__((__visibility__("default"))) +# else +# define ZPL_PRIVATE +# define ZPL_PUBLIC +# endif +# define ZPL_IMPORT extern +#endif + +#if defined(ZPL_NO_THROW) +# undef ZPL_NO_THROW +#endif +#if \ +ZPL_HAS_ATTRIBUTE(nothrow) || \ +ZPL_GCC_VERSION_CHECK(3,3,0) || \ +ZPL_INTEL_VERSION_CHECK(13,0,0) +# define ZPL_NO_THROW __attribute__((__nothrow__)) +#elif \ +ZPL_MSVC_VERSION_CHECK(13,1,0) || \ +ZPL_ARM_VERSION_CHECK(4,1,0) +# define ZPL_NO_THROW __declspec(nothrow) +#else +# define ZPL_NO_THROW +#endif + +#if defined(ZPL_FALL_THROUGH) +# undef ZPL_FALL_THROUGH +#endif +#if ZPL_GNUC_HAS_ATTRIBUTE(fallthrough,7,0,0) && !defined(ZPL_PGI_VERSION) +# define ZPL_FALL_THROUGH __attribute__((__fallthrough__)) +#elif ZPL_HAS_CPP_ATTRIBUTE_NS(clang,fallthrough) +# define ZPL_FALL_THROUGH ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[clang::fallthrough]]) +#elif ZPL_HAS_CPP_ATTRIBUTE(fallthrough) +# define ZPL_FALL_THROUGH ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[fallthrough]]) +#elif defined(__fallthrough) /* SAL */ +# define ZPL_FALL_THROUGH __fallthrough +#else +# define ZPL_FALL_THROUGH +#endif + +#if defined(ZPL_RETURNS_NON_NULL) +# undef ZPL_RETURNS_NON_NULL +#endif +#if \ +ZPL_HAS_ATTRIBUTE(returns_nonnull) || \ +ZPL_GCC_VERSION_CHECK(4,9,0) +# define ZPL_RETURNS_NON_NULL __attribute__((__returns_nonnull__)) +#elif defined(_Ret_notnull_) /* SAL */ +# define ZPL_RETURNS_NON_NULL _Ret_notnull_ +#else +# define ZPL_RETURNS_NON_NULL +#endif + +#if defined(ZPL_ARRAY_PARAM) +# undef ZPL_ARRAY_PARAM +#endif +#if \ +defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ +!defined(__STDC_NO_VLA__) && \ +!defined(__cplusplus) && \ +!defined(ZPL_PGI_VERSION) && \ +!defined(ZPL_TINYC_VERSION) +# define ZPL_ARRAY_PARAM(name) (name) +#else +# define ZPL_ARRAY_PARAM(name) +#endif + +#if defined(ZPL_IS_CONSTANT) +# undef ZPL_IS_CONSTANT +#endif +#if defined(ZPL_REQUIRE_CONSTEXPR) +# undef ZPL_REQUIRE_CONSTEXPR +#endif +/* ZPL_IS_CONSTEXPR_ is for + ZPL INTERNAL USE ONLY. API subject to change without notice. */ +#if defined(ZPL_IS_CONSTEXPR_) +# undef ZPL_IS_CONSTEXPR_ +#endif +#if \ +ZPL_HAS_BUILTIN(__builtin_constant_p) || \ +ZPL_GCC_VERSION_CHECK(3,4,0) || \ +ZPL_INTEL_VERSION_CHECK(13,0,0) || \ +ZPL_TINYC_VERSION_CHECK(0,9,19) || \ +ZPL_ARM_VERSION_CHECK(4,1,0) || \ +ZPL_IBM_VERSION_CHECK(13,1,0) || \ +ZPL_TI_CL6X_VERSION_CHECK(6,1,0) || \ +(ZPL_SUNPRO_VERSION_CHECK(5,10,0) && !defined(__cplusplus)) || \ +ZPL_CRAY_VERSION_CHECK(8,1,0) +# define ZPL_IS_CONSTANT(expr) __builtin_constant_p(expr) +#endif +#if !defined(__cplusplus) +# if \ +ZPL_HAS_BUILTIN(__builtin_types_compatible_p) || \ +ZPL_GCC_VERSION_CHECK(3,4,0) || \ +ZPL_INTEL_VERSION_CHECK(13,0,0) || \ +ZPL_IBM_VERSION_CHECK(13,1,0) || \ +ZPL_CRAY_VERSION_CHECK(8,1,0) || \ +ZPL_ARM_VERSION_CHECK(5,4,0) || \ +ZPL_TINYC_VERSION_CHECK(0,9,24) +# if defined(__INTPTR_TYPE__) +# define ZPL_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0)), int*) +# else +# include +# define ZPL_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((intptr_t) ((expr) * 0)) : (int*) 0)), int*) +# endif +# elif \ +( \ +defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && \ +!defined(ZPL_SUNPRO_VERSION) && \ +!defined(ZPL_PGI_VERSION) && \ +!defined(ZPL_IAR_VERSION)) || \ +ZPL_HAS_EXTENSION(c_generic_selections) || \ +ZPL_GCC_VERSION_CHECK(4,9,0) || \ +ZPL_INTEL_VERSION_CHECK(17,0,0) || \ +ZPL_IBM_VERSION_CHECK(12,1,0) || \ +ZPL_ARM_VERSION_CHECK(5,3,0) +# if defined(__INTPTR_TYPE__) +# define ZPL_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0), int*: 1, void*: 0) +# else +# include +# define ZPL_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((intptr_t) * 0) : (int*) 0), int*: 1, void*: 0) +# endif +# elif \ +defined(ZPL_GCC_VERSION) || \ +defined(ZPL_INTEL_VERSION) || \ +defined(ZPL_TINYC_VERSION) || \ +defined(ZPL_TI_ARMCL_VERSION) || \ +ZPL_TI_CL430_VERSION_CHECK(18,12,0) || \ +defined(ZPL_TI_CL2000_VERSION) || \ +defined(ZPL_TI_CL6X_VERSION) || \ +defined(ZPL_TI_CL7X_VERSION) || \ +defined(ZPL_TI_CLPRU_VERSION) || \ +defined(__clang__) +# define ZPL_IS_CONSTEXPR_(expr) ( \ +sizeof(void) != \ +sizeof(*( \ +1 ? \ +((void*) ((expr) * 0L) ) : \ +((struct { char v[sizeof(void) * 2]; } *) 1) \ +) \ +) \ +) +# endif +#endif +#if defined(ZPL_IS_CONSTEXPR_) +# if !defined(ZPL_IS_CONSTANT) +# define ZPL_IS_CONSTANT(expr) ZPL_IS_CONSTEXPR_(expr) +# endif +# define ZPL_REQUIRE_CONSTEXPR(expr) (ZPL_IS_CONSTEXPR_(expr) ? (expr) : (-1)) +#else +# if !defined(ZPL_IS_CONSTANT) +# define ZPL_IS_CONSTANT(expr) (0) +# endif +# define ZPL_REQUIRE_CONSTEXPR(expr) (expr) +#endif + +#if defined(ZPL_BEGIN_C_DECLS) +# undef ZPL_BEGIN_C_DECLS +#endif +#if defined(ZPL_END_C_DECLS) +# undef ZPL_END_C_DECLS +#endif +#if defined(ZPL_C_DECL) +# undef ZPL_C_DECL +#endif +#if defined(__cplusplus) +# define ZPL_BEGIN_C_DECLS extern "C" { +# define ZPL_END_C_DECLS } +# define ZPL_C_DECL extern "C" +#else +# define ZPL_BEGIN_C_DECLS +# define ZPL_END_C_DECLS +# define ZPL_C_DECL +#endif + +#if defined(ZPL_STATIC_ASSERT) +# undef ZPL_STATIC_ASSERT +#endif +#if \ +!defined(__cplusplus) && ( \ +(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || \ +ZPL_HAS_FEATURE(c_static_assert) || \ +ZPL_GCC_VERSION_CHECK(6,0,0) || \ +ZPL_INTEL_VERSION_CHECK(13,0,0) || \ +defined(_Static_assert) \ +) +# define ZPL_STATIC_ASSERT(expr, message) _Static_assert(expr, message) +#elif \ +(defined(__cplusplus) && (__cplusplus >= 201103L)) || \ +ZPL_MSVC_VERSION_CHECK(16,0,0) +# define ZPL_STATIC_ASSERT(expr, message) ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(static_assert(expr, message)) +#else +#define ZPL_STATIC_ASSERT3(cond, msg) typedef char static_assertion_##msg[(!!(cond)) * 2 - 1] +#define ZPL_STATIC_ASSERT2(cond, line) ZPL_STATIC_ASSERT3(cond, static_assertion_at_line_##line) +#define ZPL_STATIC_ASSERT1(cond, line) ZPL_STATIC_ASSERT2(cond, line) +#define ZPL_STATIC_ASSERT(cond, unused) ZPL_STATIC_ASSERT1(cond, __LINE__) +#endif + +#if defined(ZPL_NULL) +# undef ZPL_NULL +#endif +#if defined(__cplusplus) +# if __cplusplus >= 201103L +# define ZPL_NULL ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(nullptr) +# elif defined(NULL) +# define ZPL_NULL NULL +# else +# define ZPL_NULL ZPL_STATIC_CAST(void*, 0) +# endif +#elif defined(NULL) +# define ZPL_NULL NULL +#else +# define ZPL_NULL ((void*) 0) +#endif + +#if defined(ZPL_MESSAGE) +# undef ZPL_MESSAGE +#endif +#if ZPL_HAS_WARNING("-Wunknown-pragmas") +# define ZPL_MESSAGE(msg) \ +ZPL_DIAGNOSTIC_PUSH \ +ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ +ZPL_PRAGMA(message msg) \ +ZPL_DIAGNOSTIC_POP +#elif \ +ZPL_GCC_VERSION_CHECK(4,4,0) || \ +ZPL_INTEL_VERSION_CHECK(13,0,0) +# define ZPL_MESSAGE(msg) ZPL_PRAGMA(message msg) +#elif ZPL_CRAY_VERSION_CHECK(5,0,0) +# define ZPL_MESSAGE(msg) ZPL_PRAGMA(_CRI message msg) +#elif ZPL_IAR_VERSION_CHECK(8,0,0) +# define ZPL_MESSAGE(msg) ZPL_PRAGMA(message(msg)) +#elif ZPL_PELLES_VERSION_CHECK(2,0,0) +# define ZPL_MESSAGE(msg) ZPL_PRAGMA(message(msg)) +#else +# define ZPL_MESSAGE(msg) +#endif + +#if defined(ZPL_WARNING) +# undef ZPL_WARNING +#endif +#if ZPL_HAS_WARNING("-Wunknown-pragmas") +# define ZPL_WARNING(msg) \ +ZPL_DIAGNOSTIC_PUSH \ +ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ +ZPL_PRAGMA(clang warning msg) \ +ZPL_DIAGNOSTIC_POP +#elif \ +ZPL_GCC_VERSION_CHECK(4,8,0) || \ +ZPL_PGI_VERSION_CHECK(18,4,0) || \ +ZPL_INTEL_VERSION_CHECK(13,0,0) +# define ZPL_WARNING(msg) ZPL_PRAGMA(GCC warning msg) +#elif ZPL_MSVC_VERSION_CHECK(15,0,0) +# define ZPL_WARNING(msg) ZPL_PRAGMA(message(msg)) +#else +# define ZPL_WARNING(msg) ZPL_MESSAGE(msg) +#endif + +#if defined(ZPL_REQUIRE) +# undef ZPL_REQUIRE +#endif +#if defined(ZPL_REQUIRE_MSG) +# undef ZPL_REQUIRE_MSG +#endif +#if ZPL_HAS_ATTRIBUTE(diagnose_if) +# if ZPL_HAS_WARNING("-Wgcc-compat") +# define ZPL_REQUIRE(expr) \ +ZPL_DIAGNOSTIC_PUSH \ +_Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ +__attribute__((diagnose_if(!(expr), #expr, "error"))) \ +ZPL_DIAGNOSTIC_POP +# define ZPL_REQUIRE_MSG(expr,msg) \ +ZPL_DIAGNOSTIC_PUSH \ +_Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ +__attribute__((diagnose_if(!(expr), msg, "error"))) \ +ZPL_DIAGNOSTIC_POP +# else +# define ZPL_REQUIRE(expr) __attribute__((diagnose_if(!(expr), #expr, "error"))) +# define ZPL_REQUIRE_MSG(expr,msg) __attribute__((diagnose_if(!(expr), msg, "error"))) +# endif +#else +# define ZPL_REQUIRE(expr) +# define ZPL_REQUIRE_MSG(expr,msg) +#endif + +#if defined(ZPL_FLAGS) +# undef ZPL_FLAGS +#endif +#if ZPL_HAS_ATTRIBUTE(flag_enum) +# define ZPL_FLAGS __attribute__((__flag_enum__)) +#endif + +#if defined(ZPL_FLAGS_CAST) +# undef ZPL_FLAGS_CAST +#endif +#if ZPL_INTEL_VERSION_CHECK(19,0,0) +# define ZPL_FLAGS_CAST(T, expr) (__extension__ ({ \ +ZPL_DIAGNOSTIC_PUSH \ +_Pragma("warning(disable:188)") \ +((T) (expr)); \ +ZPL_DIAGNOSTIC_POP \ +})) +#else +# define ZPL_FLAGS_CAST(T, expr) ZPL_STATIC_CAST(T, expr) +#endif + +#if defined(ZPL_EMPTY_BASES) +# undef ZPL_EMPTY_BASES +#endif +#if ZPL_MSVC_VERSION_CHECK(19,0,23918) && !ZPL_MSVC_VERSION_CHECK(20,0,0) +# define ZPL_EMPTY_BASES __declspec(empty_bases) +#else +# define ZPL_EMPTY_BASES +#endif + +/* Remaining macros are deprecated. */ + +#if defined(ZPL_GCC_NOT_CLANG_VERSION_CHECK) +# undef ZPL_GCC_NOT_CLANG_VERSION_CHECK +#endif +#if defined(__clang__) +# define ZPL_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) (0) +#else +# define ZPL_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) ZPL_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(ZPL_CLANG_HAS_ATTRIBUTE) +# undef ZPL_CLANG_HAS_ATTRIBUTE +#endif +#define ZPL_CLANG_HAS_ATTRIBUTE(attribute) ZPL_HAS_ATTRIBUTE(attribute) + +#if defined(ZPL_CLANG_HAS_CPP_ATTRIBUTE) +# undef ZPL_CLANG_HAS_CPP_ATTRIBUTE +#endif +#define ZPL_CLANG_HAS_CPP_ATTRIBUTE(attribute) ZPL_HAS_CPP_ATTRIBUTE(attribute) + +#if defined(ZPL_CLANG_HAS_BUILTIN) +# undef ZPL_CLANG_HAS_BUILTIN +#endif +#define ZPL_CLANG_HAS_BUILTIN(builtin) ZPL_HAS_BUILTIN(builtin) + +#if defined(ZPL_CLANG_HAS_FEATURE) +# undef ZPL_CLANG_HAS_FEATURE +#endif +#define ZPL_CLANG_HAS_FEATURE(feature) ZPL_HAS_FEATURE(feature) + +#if defined(ZPL_CLANG_HAS_EXTENSION) +# undef ZPL_CLANG_HAS_EXTENSION +#endif +#define ZPL_CLANG_HAS_EXTENSION(extension) ZPL_HAS_EXTENSION(extension) + +#if defined(ZPL_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE) +# undef ZPL_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE +#endif +#define ZPL_CLANG_HAS_DECLSPEC_ATTRIBUTE(attribute) ZPL_HAS_DECLSPEC_ATTRIBUTE(attribute) + +#if defined(ZPL_CLANG_HAS_WARNING) +# undef ZPL_CLANG_HAS_WARNING +#endif +#define ZPL_CLANG_HAS_WARNING(warning) ZPL_HAS_WARNING(warning) + +#endif /* !defined(ZPL_HEDLEY_VERSION) || (ZPL_HEDLEY_VERSION < X) */ + +#define ZPL_VERSION ZPL_VERSION_ENCODE(ZPL_VERSION_MAJOR, ZPL_VERSION_MINOR, ZPL_VERSION_PATCH) + +#ifdef ZPL_IMPL +#ifndef ZPL_IMPLEMENTATION +#define ZPL_IMPLEMENTATION +#endif +#endif + +#if defined(__cplusplus) && !defined(ZPL_EXTERN) +#define ZPL_EXTERN extern "C" +#else +#define ZPL_EXTERN extern +#endif + +#ifndef ZPL_DEF +#if defined(ZPL_SHARED_LIB) +#ifdef ZPL_IMPLEMENTATION +#define ZPL_DEF ZPL_PUBLIC +#else +#define ZPL_DEF ZPL_IMPORT +#endif +#elif defined(ZPL_STATIC_LIB) +#ifdef ZPL_IMPLEMENTATION +#define ZPL_DEF +#else +#define ZPL_DEF ZPL_EXTERN +#endif +#elif defined(ZPL_STATIC) +#define ZPL_DEF static +#else +#define ZPL_DEF ZPL_EXTERN +#endif +#endif + +#ifndef ZPL_DEF_INLINE +#if defined(ZPL_STATIC) +#define ZPL_DEF_INLINE +#define ZPL_IMPL_INLINE +#else +#define ZPL_DEF_INLINE ZPL_ALWAYS_INLINE +#define ZPL_IMPL_INLINE ZPL_INLINE +#endif +#endif + +/* Architecture-specific overrides */ +#if defined(__ARM_ARCH) && defined(__cplusplus) +#define ZPL_DISABLE_THREADING +#endif + +/* Distributions */ +#ifndef ZPL_CUSTOM_MODULES +/* default distribution */ +#define ZPL_MODULE_CORE +#define ZPL_MODULE_TIMER +#define ZPL_MODULE_HASHING +#define ZPL_MODULE_REGEX +#define ZPL_MODULE_EVENT +#define ZPL_MODULE_DLL +#define ZPL_MODULE_OPTS +#define ZPL_MODULE_PROCESS +#define ZPL_MODULE_MATH +#define ZPL_MODULE_JSON +#define ZPL_MODULE_THREADING +#define ZPL_MODULE_JOBS +#define ZPL_MODULE_COROUTINES + +/* zpl nano distribution */ +#if defined(ZPL_NANO) +#undef ZPL_MODULE_TIMER +#undef ZPL_MODULE_HASHING +#undef ZPL_MODULE_REGEX +#undef ZPL_MODULE_EVENT +#undef ZPL_MODULE_DLL +#undef ZPL_MODULE_OPTS +#undef ZPL_MODULE_PROCESS +#undef ZPL_MODULE_MATH +#undef ZPL_MODULE_JSON +#undef ZPL_MODULE_THREADING +#undef ZPL_MODULE_JOBS +#undef ZPL_MODULE_COROUTINES +#endif + +/* module enabling overrides */ +#if defined(ZPL_ENABLE_CORE) && !defined(ZPL_MODULE_CORE) +#define ZPL_MODULE_CORE +#endif +#if defined(ZPL_ENABLE_TIMER) && !defined(ZPL_MODULE_TIMER) +#define ZPL_MODULE_TIMER +#endif +#if defined(ZPL_ENABLE_HASHING) && !defined(ZPL_MODULE_HASHING) +#define ZPL_MODULE_HASHING +#endif +#if defined(ZPL_ENABLE_REGEX) && !defined(ZPL_MODULE_REGEX) +#define ZPL_MODULE_REGEX +#endif +#if defined(ZPL_ENABLE_DLL) && !defined(ZPL_MODULE_DLL) +#define ZPL_MODULE_DLL +#endif +#if defined(ZPL_ENABLE_OPTS) && !defined(ZPL_MODULE_OPTS) +#define ZPL_MODULE_OPTS +#endif +#if defined(ZPL_ENABLE_PROCESS) && !defined(ZPL_MODULE_PROCESS) +#define ZPL_MODULE_PROCESS +#endif +#if defined(ZPL_ENABLE_MATH) && !defined(ZPL_MODULE_MATH) +#define ZPL_MODULE_MATH +#endif +#if defined(ZPL_ENABLE_JSON) && !defined(ZPL_MODULE_JSON) +#define ZPL_MODULE_JSON +#endif +#if defined(ZPL_ENABLE_THREADING) && !defined(ZPL_MODULE_THREADING) +#define ZPL_MODULE_THREADING +#endif +#if defined(ZPL_ENABLE_JOBS) && !defined(ZPL_MODULE_JOBS) +#ifndef ZPL_MODULE_THREADING +#define ZPL_MODULE_THREADING /* dependency */ +#endif +#define ZPL_MODULE_JOBS +#endif +#if defined(ZPL_ENABLE_COROUTINES) && !defined(ZPL_MODULE_COROUTINES) +#ifndef ZPL_MODULE_THREADING +#define ZPL_MODULE_THREADING /* dependency */ +#endif + +#ifndef ZPL_MODULE_JOBS +#define ZPL_MODULE_JOBS /* dependency */ +#endif + +#define ZPL_MODULE_COROUTINES +#endif + +/* module disabling overrides */ +#if defined(ZPL_DISABLE_CORE) && defined(ZPL_MODULE_CORE) +#undef ZPL_MODULE_CORE +#endif +#if defined(ZPL_DISABLE_TIMER) && defined(ZPL_MODULE_TIMER) +#undef ZPL_MODULE_TIMER +#endif +#if defined(ZPL_DISABLE_HASHING) && defined(ZPL_MODULE_HASHING) +#undef ZPL_MODULE_HASHING +#endif +#if defined(ZPL_DISABLE_REGEX) && defined(ZPL_MODULE_REGEX) +#undef ZPL_MODULE_REGEX +#endif +#if defined(ZPL_DISABLE_DLL) && defined(ZPL_MODULE_DLL) +#undef ZPL_MODULE_DLL +#endif +#if defined(ZPL_DISABLE_OPTS) && defined(ZPL_MODULE_OPTS) +#undef ZPL_MODULE_OPTS +#endif +#if defined(ZPL_DISABLE_PROCESS) && defined(ZPL_MODULE_PROCESS) +#undef ZPL_MODULE_PROCESS +#endif +#if defined(ZPL_DISABLE_MATH) && defined(ZPL_MODULE_MATH) +#undef ZPL_MODULE_MATH +#endif +#if defined(ZPL_DISABLE_JSON) && defined(ZPL_MODULE_JSON) +#undef ZPL_MODULE_JSON +#endif +#if defined(ZPL_DISABLE_THREADING) && defined(ZPL_MODULE_THREADING) +#ifdef ZPL_MODULE_JOBS +#undef ZPL_MODULE_JOBS /* user */ +#endif + +#ifdef ZPL_MODULE_COROUTINES +#undef ZPL_MODULE_COROUTINES /* user */ +#endif + +#undef ZPL_MODULE_THREADING +#endif +#if defined(ZPL_DISABLE_JOBS) && defined(ZPL_MODULE_JOBS) +#ifdef ZPL_MODULE_COROUTINES +#undef ZPL_MODULE_COROUTINES /* user */ +#endif + +#undef ZPL_MODULE_JOBS +#endif +#if defined(ZPL_DISABLE_COROUTINES) && defined(ZPL_MODULE_COROUTINES) +#undef ZPL_MODULE_COROUTINES +#endif +#endif + +#if defined(__GCC__) || defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-function" +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" +#pragma GCC diagnostic ignored "-Wimplicit-fallthrough" +#endif + +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4201) +#pragma warning(disable : 4127) // Conditional expression is constant +#endif + +/* general purpose includes */ + +// file: header/core/system.h + +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +/* Platform architecture */ + +#if defined(_WIN64) || defined(__x86_64__) || defined(_M_X64) || defined(__64BIT__) || defined(__powerpc64__) || \ +defined(__ppc64__) || defined(__aarch64__) +#ifndef ZPL_ARCH_64_BIT +#define ZPL_ARCH_64_BIT 1 +#endif +#else +#ifndef ZPL_ARCH_32_BIT +#define ZPL_ARCH_32_BIT 1 +#endif +#endif + +/* Platform endiannes */ + +#ifndef ZPL_ENDIAN_ORDER +#define ZPL_ENDIAN_ORDER +#define ZPL_IS_BIG_ENDIAN (!*(zpl_u8 *)&(zpl_u16){ 1 }) +#define ZPL_IS_LITTLE_ENDIAN (!ZPL_IS_BIG_ENDIAN) +#endif + +/* Platform OS */ + +#if defined(_WIN32) || defined(_WIN64) +#ifndef ZPL_SYSTEM_WINDOWS +#define ZPL_SYSTEM_WINDOWS 1 +#endif +#elif defined(__APPLE__) && defined(__MACH__) +#ifndef ZPL_SYSTEM_OSX +#define ZPL_SYSTEM_OSX 1 +#endif +#ifndef ZPL_SYSTEM_MACOS +#define ZPL_SYSTEM_MACOS 1 +#endif +#include +#if TARGET_IPHONE_SIMULATOR == 1 || TARGET_OS_IPHONE == 1 +#ifndef ZPL_SYSTEM_IOS +#define ZPL_SYSTEM_IOS 1 +#endif +#endif +#elif defined(__unix__) +#ifndef ZPL_SYSTEM_UNIX +#define ZPL_SYSTEM_UNIX 1 +#endif +#if defined(ANDROID) || defined(__ANDROID__) +#ifndef ZPL_SYSTEM_ANDROID +#define ZPL_SYSTEM_ANDROID 1 +#endif +#ifndef ZPL_SYSTEM_LINUX +#define ZPL_SYSTEM_LINUX 1 +#endif +#elif defined(__linux__) +#ifndef ZPL_SYSTEM_LINUX +#define ZPL_SYSTEM_LINUX 1 +#endif +#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) +#ifndef ZPL_SYSTEM_FREEBSD +#define ZPL_SYSTEM_FREEBSD 1 +#endif +#elif defined(__OpenBSD__) +#ifndef ZPL_SYSTEM_OPENBSD +#define ZPL_SYSTEM_OPENBSD 1 +#endif +#elif defined(__EMSCRIPTEN__) +#ifndef ZPL_SYSTEM_EMSCRIPTEN +#define ZPL_SYSTEM_EMSCRIPTEN 1 +#endif +#elif defined(__CYGWIN__) +#ifndef ZPL_SYSTEM_CYGWIN +#define ZPL_SYSTEM_CYGWIN 1 +#endif +#else +#error This UNIX operating system is not supported +#endif +#else +#error This operating system is not supported +#endif + +/* Platform compiler */ + +#if defined(_MSC_VER) +#define ZPL_COMPILER_MSVC 1 +#elif defined(__GNUC__) +#define ZPL_COMPILER_GCC 1 +#elif defined(__clang__) +#define ZPL_COMPILER_CLANG 1 +#elif defined(__MINGW32__) +#define ZPL_COMPILER_MINGW 1 +#else +#error Unknown compiler +#endif + +/* Platform CPU */ + +#if defined(__arm__) || defined(__aarch64__) || defined(__ARM_ARCH) +#ifndef ZPL_CPU_ARM +#define ZPL_CPU_ARM 1 +#endif +#ifndef ZPL_CACHE_LINE_SIZE +#define ZPL_CACHE_LINE_SIZE 64 +#endif +#elif defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__x86_64__) || defined(ZPL_SYSTEM_EMSCRIPTEN) +#ifndef ZPL_CPU_X86 +#define ZPL_CPU_X86 1 +#endif +#ifndef ZPL_CACHE_LINE_SIZE +#define ZPL_CACHE_LINE_SIZE 64 +#endif +#elif defined(_M_PPC) || defined(__powerpc__) || defined(__powerpc64__) +#ifndef ZPL_CPU_PPC +#define ZPL_CPU_PPC 1 +#endif +#ifndef ZPL_CACHE_LINE_SIZE +#define ZPL_CACHE_LINE_SIZE 128 +#endif +#elif defined(__MIPSEL__) || defined(__mips_isa_rev) +#ifndef ZPL_CPU_MIPS +#define ZPL_CPU_MIPS 1 +#endif +#ifndef ZPL_CACHE_LINE_SIZE +#define ZPL_CACHE_LINE_SIZE 64 +#endif +#else +#error Unknown CPU Type +#endif + +// TODO(ZaKlaus): Find a better way to get this flag in MinGW. +#if defined(ZPL_COMPILER_GCC) && !defined(WC_ERR_INVALID_CHARS) +#define WC_ERR_INVALID_CHARS 0x0080 +#endif + +#if defined(ZPL_COMPILER_GCC) && defined(ZPL_SYSTEM_WINDOWS) +#ifndef ZPL_COMPILER_MINGW +#define ZPL_COMPILER_MINGW // assume we use mingw as a compiler +#endif +#endif + +#if defined(ZPL_SYSTEM_UNIX) +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#ifndef _LARGEFILE64_SOURCE +#define _LARGEFILE64_SOURCE +#endif +#endif + +ZPL_END_C_DECLS + +#include +#include + +#if defined(ZPL_SYSTEM_WINDOWS) +#include +#endif + +// file: header/core/types.h + +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +/* Basic types */ + +#if defined(ZPL_COMPILER_MSVC) +#if _MSC_VER < 1300 +typedef unsigned char zpl_u8; +typedef signed char zpl_i8; +typedef unsigned short zpl_u16; +typedef signed short zpl_i16; +typedef unsigned int zpl_u32; +typedef signed int zpl_i32; +#else +typedef unsigned __int8 zpl_u8; +typedef signed __int8 zpl_i8; +typedef unsigned __int16 zpl_u16; +typedef signed __int16 zpl_i16; +typedef unsigned __int32 zpl_u32; +typedef signed __int32 zpl_i32; +#endif +typedef unsigned __int64 zpl_u64; +typedef signed __int64 zpl_i64; +#else +#include + +typedef uint8_t zpl_u8; +typedef int8_t zpl_i8; +typedef uint16_t zpl_u16; +typedef int16_t zpl_i16; +typedef uint32_t zpl_u32; +typedef int32_t zpl_i32; +typedef uint64_t zpl_u64; +typedef int64_t zpl_i64; +#endif + +ZPL_STATIC_ASSERT(sizeof(zpl_u8) == sizeof(zpl_i8), "sizeof(zpl_u8) != sizeof(zpl_i8)"); +ZPL_STATIC_ASSERT(sizeof(zpl_u16) == sizeof(zpl_i16), "sizeof(zpl_u16) != sizeof(zpl_i16)"); +ZPL_STATIC_ASSERT(sizeof(zpl_u32) == sizeof(zpl_i32), "sizeof(zpl_u32) != sizeof(zpl_i32)"); +ZPL_STATIC_ASSERT(sizeof(zpl_u64) == sizeof(zpl_i64), "sizeof(zpl_u64) != sizeof(zpl_i64)"); + +ZPL_STATIC_ASSERT(sizeof(zpl_u8) == 1, "sizeof(zpl_u8) != 1"); +ZPL_STATIC_ASSERT(sizeof(zpl_u16) == 2, "sizeof(zpl_u16) != 2"); +ZPL_STATIC_ASSERT(sizeof(zpl_u32) == 4, "sizeof(zpl_u32) != 4"); +ZPL_STATIC_ASSERT(sizeof(zpl_u64) == 8, "sizeof(zpl_u64) != 8"); + +typedef size_t zpl_usize; +typedef ptrdiff_t zpl_isize; + +ZPL_STATIC_ASSERT(sizeof(zpl_usize) == sizeof(zpl_isize), "sizeof(zpl_usize) != sizeof(zpl_isize)"); + +// NOTE: (u)zpl_intptr is only here for semantic reasons really as this library will only support 32/64 bit OSes. +#if defined(_WIN64) +typedef signed __int64 zpl_intptr; +typedef unsigned __int64 zpl_uintptr; +#elif defined(_WIN32) +// NOTE; To mark types changing their size, e.g. zpl_intptr +#ifndef _W64 +#if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 +#define _W64 __w64 +#else +#define _W64 +#endif +#endif +typedef _W64 signed int zpl_intptr; +typedef _W64 unsigned int zpl_uintptr; +#else +typedef uintptr_t zpl_uintptr; +typedef intptr_t zpl_intptr; +#endif + +ZPL_STATIC_ASSERT(sizeof(zpl_uintptr) == sizeof(zpl_intptr), "sizeof(zpl_uintptr) != sizeof(zpl_intptr)"); + +typedef float zpl_f32; +typedef double zpl_f64; + +ZPL_STATIC_ASSERT(sizeof(zpl_f32) == 4, "sizeof(zpl_f32) != 4"); +ZPL_STATIC_ASSERT(sizeof(zpl_f64) == 8, "sizeof(zpl_f64) != 8"); + +typedef zpl_i32 zpl_rune; // NOTE: Unicode codepoint +typedef zpl_i32 zpl_char32; +#define ZPL_RUNE_INVALID cast(zpl_rune)(0xfffd) +#define ZPL_RUNE_MAX cast(zpl_rune)(0x0010ffff) +#define ZPL_RUNE_BOM cast(zpl_rune)(0xfeff) +#define ZPL_RUNE_EOF cast(zpl_rune)(-1) + +typedef zpl_i8 zpl_b8; +typedef zpl_i16 zpl_b16; +typedef zpl_i32 zpl_b32; + +#if !defined(__cplusplus) +#if (defined(_MSC_VER) && _MSC_VER < 1800) || (!defined(_MSC_VER) && !defined(__STDC_VERSION__)) +#ifndef true +#define true(0 == 0) +#endif +#ifndef false +#define false(0 != 0) +#endif + +typedef zpl_b8 bool; +#else +#include +#endif +#endif + +#if __cplusplus > 199711L +#define register // Deprecated in C++11. +#endif // #if __cplusplus > 199711L + +#ifndef ZPL_U8_MIN +#define ZPL_U8_MIN 0u +#define ZPL_U8_MAX 0xffu +#define ZPL_I8_MIN (-0x7f - 1) +#define ZPL_I8_MAX 0x7f + +#define ZPL_U16_MIN 0u +#define ZPL_U16_MAX 0xffffu +#define ZPL_I16_MIN (-0x7fff - 1) +#define ZPL_I16_MAX 0x7fff + +#define ZPL_U32_MIN 0u +#define ZPL_U32_MAX 0xffffffffu +#define ZPL_I32_MIN (-0x7fffffff - 1) +#define ZPL_I32_MAX 0x7fffffff + +#define ZPL_U64_MIN 0ull +#define ZPL_U64_MAX 0xffffffffffffffffull +#define ZPL_I64_MIN (-0x7fffffffffffffffll - 1) +#define ZPL_I64_MAX 0x7fffffffffffffffll + +#if defined(ZPL_ARCH_32_BIT) +#define ZPL_USIZE_MIN ZPL_U32_MIN +#define ZPL_USIZE_MAX ZPL_U32_MAX +#define ZPL_ISIZE_MIN ZPL_S32_MIN +#define ZPL_ISIZE_MAX ZPL_S32_MAX +#elif defined(ZPL_ARCH_64_BIT) +#define ZPL_USIZE_MIN ZPL_U64_MIN +#define ZPL_USIZE_MAX ZPL_U64_MAX +#define ZPL_ISIZE_MIN ZPL_I64_MIN +#define ZPL_ISIZE_MAX ZPL_I64_MAX +#else +#error Unknown architecture size. This library only supports 32 bit and 64 bit architectures. +#endif + +#define ZPL_F32_MIN 1.17549435e-38f +#define ZPL_F32_MAX 3.40282347e+38f + +#define ZPL_F64_MIN 2.2250738585072014e-308 +#define ZPL_F64_MAX 1.7976931348623157e+308 +#endif + +#ifdef ZPL_DEFINE_NULL_MACRO +#ifndef NULL +#define NULL ZPL_NULL +#endif +#endif + +ZPL_END_C_DECLS +// file: header/core/helpers.h + +/* Various macro based helpers */ +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +#ifndef cast +#define cast(Type) (Type) +#endif + +#ifndef zpl_size_of +#define zpl_size_of(x) (zpl_isize)(sizeof(x)) +#endif + +#ifndef zpl_count_of +#define zpl_count_of(x) ((zpl_size_of(x) / zpl_size_of(0 [x])) / ((zpl_isize)(!(zpl_size_of(x) % zpl_size_of(0 [x]))))) +#endif + +#ifndef zpl_offset_of +#ifdef _MSC_VER +#define zpl_offset_of(Type, element) ((zpl_isize) & (((Type *)0)->element)) +#else +#define zpl_offset_of(Type, element) __builtin_offsetof(Type, element) +#endif +#endif + +#if defined(__cplusplus) +#ifndef zpl_align_of +#if __cplusplus >= 201103L +#define zpl_align_of(Type) (zpl_isize)alignof(Type) +#else +extern "C++" { + template struct zpl_alignment_trick { + char c; + T member; + }; +} +#define zpl_align_of(Type) zpl_offset_of(zpl_alignment_trick, member) +#endif +#endif +#else +#ifndef zpl_align_of +#define zpl_align_of(Type) \ +zpl_offset_of( \ +struct { \ +char c; \ +Type member; \ +}, \ +member) +#endif +#endif + +#ifndef zpl_swap +#define zpl_swap(Type, a, b) \ +do { \ +Type tmp = (a); \ +(a) = (b); \ +(b) = tmp; \ +} while (0) +#endif + + + +#ifndef zpl_global +#define zpl_global static // Global variables +#endif + +#ifndef zpl_internal +#define zpl_internal static // Internal linkage +#endif + +#ifndef zpl_local_persist +#define zpl_local_persist static // Local Persisting variables +#endif + +#ifndef zpl_unused +#if defined(_MSC_VER) +#define zpl_unused(x) (__pragma(warning(suppress : 4100))(x)) +#elif defined(__GCC__) +#define zpl_unused(x) __attribute__((__unused__))(x) +#else +#define zpl_unused(x) ((void)(zpl_size_of(x))) +#endif +#endif + + +#ifndef ZPL_JOIN_MACROS +#define ZPL_JOIN_MACROS + +#define ZPL_JOIN2 ZPL_CONCAT +#define ZPL_JOIN3(a, b, c) ZPL_JOIN2(ZPL_JOIN2(a, b), c) +#define ZPL_JOIN4(a, b, c, d) ZPL_JOIN2(ZPL_JOIN2(ZPL_JOIN2(a, b), c), d) +#endif + +#ifndef ZPL_BIT +#define ZPL_BIT(x) (1 << (x)) +#endif + +#ifndef zpl_min +#define zpl_min(a, b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef zpl_max +#define zpl_max(a, b) ((a) > (b) ? (a) : (b)) +#endif + +#ifndef zpl_min3 +#define zpl_min3(a, b, c) zpl_min(zpl_min(a, b), c) +#endif + +#ifndef zpl_max3 +#define zpl_max3(a, b, c) zpl_max(zpl_max(a, b), c) +#endif + +#ifndef zpl_clamp +#define zpl_clamp(x, lower, upper) zpl_min(zpl_max((x), (lower)), (upper)) +#endif + +#ifndef zpl_clamp01 +#define zpl_clamp01(x) zpl_clamp((x), 0, 1) +#endif + +#ifndef zpl_is_between +#define zpl_is_between(x, lower, upper) (((lower) <= (x)) && ((x) <= (upper))) +#endif + +#ifndef zpl_abs +#define zpl_abs(x) ((x) < 0 ? -(x) : (x)) +#endif + +#ifndef hard_cast +#define hard_cast(type) *cast(type) & +#endif + +// WARN(ZaKlaus): Supported only on GCC via GNU extensions!!! +#ifndef zpl_lambda +#define zpl_lambda(b_) ({ b_ _; }) +#endif + +#ifndef zpl_when +#define zpl_when(init, type, name) \ +type name = init; \ +if (name) +#endif + +/* NOTE: Very useful bit setting */ +#ifndef ZPL_MASK_SET +#define ZPL_MASK_SET(var, set, mask) \ +do { \ +if (set) \ +(var) |= (mask); \ +else \ +(var) &= ~(mask); \ +} while (0) +#endif + +// Multiline string literals in C99! +#ifndef ZPL_MULTILINE +#define ZPL_MULTILINE(...) #__VA_ARGS__ +#endif + +ZPL_END_C_DECLS + +#if defined(ZPL_MODULE_CORE) +// file: header/core/debug.h + +/* Debugging stuff */ +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +#ifndef ZPL_DEBUG_TRAP +#if defined(_MSC_VER) +#if _MSC_VER < 1300 +#define ZPL_DEBUG_TRAP( ) __asm int 3 /* Trap to debugger! */ +#else +#define ZPL_DEBUG_TRAP( ) __debugbreak( ) +#endif +#else +#define ZPL_DEBUG_TRAP( ) __builtin_trap( ) +#endif +#endif - #ifndef ZPL_ASSERT_MSG - #define ZPL_ASSERT_MSG(cond, msg, ...) \ - do { \ - if (!(cond)) { \ - zpl_assert_handler(#cond, __FILE__, cast(zpl_i64) __LINE__, msg, ##__VA_ARGS__); \ - ZPL_DEBUG_TRAP( ); \ - } \ - } while (0) - #endif - - #ifndef ZPL_ASSERT - #define ZPL_ASSERT(cond) ZPL_ASSERT_MSG(cond, NULL) - #endif +#ifndef ZPL_ASSERT_MSG +#define ZPL_ASSERT_MSG(cond, msg, ...) \ +do { \ +if (!(cond)) { \ +zpl_assert_handler(#cond, __FILE__, cast(zpl_i64) __LINE__, msg, ##__VA_ARGS__); \ +ZPL_DEBUG_TRAP( ); \ +} \ +} while (0) +#endif + +#ifndef ZPL_ASSERT +#define ZPL_ASSERT(cond) ZPL_ASSERT_MSG(cond, NULL) +#endif - #ifndef ZPL_ASSERT_NOT_NULL - #define ZPL_ASSERT_NOT_NULL(ptr) ZPL_ASSERT_MSG((ptr) != NULL, #ptr " must not be NULL") - #endif +#ifndef ZPL_ASSERT_NOT_NULL +#define ZPL_ASSERT_NOT_NULL(ptr) ZPL_ASSERT_MSG((ptr) != NULL, #ptr " must not be NULL") +#endif - // NOTE: Things that shouldn't happen with a message! - #ifndef ZPL_PANIC - #define ZPL_PANIC(msg, ...) ZPL_ASSERT_MSG(0, msg, ##__VA_ARGS__) - #endif +// NOTE: Things that shouldn't happen with a message! +#ifndef ZPL_PANIC +#define ZPL_PANIC(msg, ...) ZPL_ASSERT_MSG(0, msg, ##__VA_ARGS__) +#endif - #ifndef ZPL_NOT_IMPLEMENTED - #define ZPL_NOT_IMPLEMENTED ZPL_PANIC("not implemented") - #endif - - /* Functions */ - - ZPL_DEF void zpl_assert_handler(char const *condition, char const *file, zpl_i32 line, char const *msg, ...); - ZPL_DEF zpl_i32 zpl_assert_crash(char const *condition); - - ZPL_END_C_DECLS - // file: header/core/memory.h - - /** @file mem.c - @brief Memory manipulation and helpers. - @defgroup memman Memory management - - Consists of pointer arithmetic methods, virtual memory management and custom memory allocators. +#ifndef ZPL_NOT_IMPLEMENTED +#define ZPL_NOT_IMPLEMENTED ZPL_PANIC("not implemented") +#endif + +/* Functions */ + +ZPL_DEF void zpl_assert_handler(char const *condition, char const *file, zpl_i32 line, char const *msg, ...); +ZPL_DEF zpl_i32 zpl_assert_crash(char const *condition); + +ZPL_END_C_DECLS +// file: header/core/memory.h + +/** @file mem.c +@brief Memory manipulation and helpers. +@defgroup memman Memory management + + Consists of pointer arithmetic methods, virtual memory management and custom memory allocators. - @{ - */ - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - //! Checks if value is power of 2. - ZPL_DEF_INLINE zpl_b32 zpl_is_power_of_two(zpl_isize x); - - //! Aligns address to specified alignment. - ZPL_DEF_INLINE void *zpl_align_forward(void *ptr, zpl_isize alignment); - - //! Moves pointer forward by bytes. - ZPL_DEF_INLINE void *zpl_pointer_add(void *ptr, zpl_isize bytes); - - //! Moves pointer backward by bytes. - ZPL_DEF_INLINE void *zpl_pointer_sub(void *ptr, zpl_isize bytes); - - //! Moves pointer forward by bytes. - ZPL_DEF_INLINE void const *zpl_pointer_add_const(void const *ptr, zpl_isize bytes); - - //! Moves pointer backward by bytes. - ZPL_DEF_INLINE void const *zpl_pointer_sub_const(void const *ptr, zpl_isize bytes); - - //! Calculates difference between two addresses. - ZPL_DEF_INLINE zpl_isize zpl_pointer_diff(void const *begin, void const *end); - - #define zpl_ptr_add zpl_pointer_add - #define zpl_ptr_sub zpl_pointer_sub - #define zpl_ptr_add_const zpl_pointer_add_const - #define zpl_ptr_sub_const zpl_pointer_sub_const - #define zpl_ptr_diff zpl_pointer_diff - - //! Clears up memory at location by specified size. - - //! @param ptr Memory location to clear up. - //! @param size The size to clear up with. - ZPL_DEF_INLINE void zpl_zero_size(void *ptr, zpl_isize size); - - #ifndef zpl_zero_item - //! Clears up an item. - #define zpl_zero_item(t) zpl_zero_size((t), zpl_size_of(*(t))) // NOTE: Pass pointer of struct - - //! Clears up an array. - #define zpl_zero_array(a, count) zpl_zero_size((a), zpl_size_of(*(a)) * count) - #endif - - //! Copy memory from source to destination. - ZPL_DEF_INLINE void *zpl_memmove(void *dest, void const *source, zpl_isize size); - - //! Set constant value at memory location with specified size. - ZPL_DEF_INLINE void *zpl_memset(void *data, zpl_u8 byte_value, zpl_isize size); - - //! Compare two memory locations with specified size. - ZPL_DEF_INLINE zpl_i32 zpl_memcompare(void const *s1, void const *s2, zpl_isize size); - - //! Swap memory contents between 2 locations with size. - ZPL_DEF void zpl_memswap(void *i, void *j, zpl_isize size); - - //! Search for a constant value within the size limit at memory location. - ZPL_DEF void const *zpl_memchr(void const *data, zpl_u8 byte_value, zpl_isize size); - - //! Search for a constant value within the size limit at memory location in backwards. - ZPL_DEF void const *zpl_memrchr(void const *data, zpl_u8 byte_value, zpl_isize size); - - //! Copy non-overlapping memory from source to destination. - ZPL_DEF void *zpl_memcopy(void *dest, void const *source, zpl_isize size); - - #ifndef zpl_memcopy_array - - //! Copy non-overlapping array. - #define zpl_memcopy_array(dst, src, count) zpl_memcopy((dst), (src), zpl_size_of(*(dst)) * (count)) - #endif - - //! Copy an array. - #ifndef zpl_memmove_array - #define zpl_memmove_array(dst, src, count) zpl_memmove((dst), (src), zpl_size_of(*(dst)) * (count)) - #endif - - #ifndef ZPL_BIT_CAST - #define ZPL_BIT_CAST(dest, source) \ - do { \ - ZPL_STATIC_ASSERT(zpl_size_of(*(dest)) <= zpl_size_of(source), "zpl_size_of(*(dest)) !<= zpl_size_of(source)");\ - zpl_memcopy((dest), &(source), zpl_size_of(*dest)); \ - } while (0) - #endif - - #ifndef zpl_kilobytes - #define zpl_kilobytes(x) ((x) * (zpl_i64)(1024)) - #define zpl_megabytes(x) (zpl_kilobytes(x) * (zpl_i64)(1024)) - #define zpl_gigabytes(x) (zpl_megabytes(x) * (zpl_i64)(1024)) - #define zpl_terabytes(x) (zpl_gigabytes(x) * (zpl_i64)(1024)) - #endif - - - /* inlines */ - - #define ZPL__ONES (cast(zpl_usize) - 1 / ZPL_U8_MAX) - #define ZPL__HIGHS (ZPL__ONES * (ZPL_U8_MAX / 2 + 1)) - #define ZPL__HAS_ZERO(x) (((x)-ZPL__ONES) & ~(x)&ZPL__HIGHS) - - ZPL_IMPL_INLINE void *zpl_align_forward(void *ptr, zpl_isize alignment) { - zpl_uintptr p; - - ZPL_ASSERT(zpl_is_power_of_two(alignment)); - - p = cast(zpl_uintptr) ptr; - return cast(void *)((p + (alignment - 1)) & ~(alignment - 1)); - } - - ZPL_IMPL_INLINE void *zpl_pointer_add(void *ptr, zpl_isize bytes) { return cast(void *)(cast(zpl_u8 *) ptr + bytes); } - ZPL_IMPL_INLINE void *zpl_pointer_sub(void *ptr, zpl_isize bytes) { return cast(void *)(cast(zpl_u8 *) ptr - bytes); } - ZPL_IMPL_INLINE void const *zpl_pointer_add_const(void const *ptr, zpl_isize bytes) { - return cast(void const *)(cast(zpl_u8 const *) ptr + bytes); - } - ZPL_IMPL_INLINE void const *zpl_pointer_sub_const(void const *ptr, zpl_isize bytes) { - return cast(void const *)(cast(zpl_u8 const *) ptr - bytes); - } - ZPL_IMPL_INLINE zpl_isize zpl_pointer_diff(void const *begin, void const *end) { - return cast(zpl_isize)(cast(zpl_u8 const *) end - cast(zpl_u8 const *) begin); - } - - ZPL_IMPL_INLINE void zpl_zero_size(void *ptr, zpl_isize size) { zpl_memset(ptr, 0, size); } - - #if defined(_MSC_VER) && !defined(__clang__) - #pragma intrinsic(__movsb) - #endif - - ZPL_IMPL_INLINE void *zpl_memmove(void *dest, void const *source, zpl_isize n) { - if (dest == NULL) { return NULL; } - - zpl_u8 *d = cast(zpl_u8 *) dest; - zpl_u8 const *s = cast(zpl_u8 const *) source; - - if (d == s) return d; - if (s + n <= d || d + n <= s) // NOTE: Non-overlapping - return zpl_memcopy(d, s, n); - - if (d < s) { - if (cast(zpl_uintptr) s % zpl_size_of(zpl_isize) == cast(zpl_uintptr) d % zpl_size_of(zpl_isize)) { - while (cast(zpl_uintptr) d % zpl_size_of(zpl_isize)) { - if (!n--) return dest; - *d++ = *s++; - } - while (n >= zpl_size_of(zpl_isize)) { - *cast(zpl_isize *) d = *cast(zpl_isize *) s; - n -= zpl_size_of(zpl_isize); - d += zpl_size_of(zpl_isize); - s += zpl_size_of(zpl_isize); - } - } - for (; n; n--) *d++ = *s++; - } else { - if ((cast(zpl_uintptr) s % zpl_size_of(zpl_isize)) == (cast(zpl_uintptr) d % zpl_size_of(zpl_isize))) { - while (cast(zpl_uintptr)(d + n) % zpl_size_of(zpl_isize)) { - if (!n--) return dest; - d[n] = s[n]; - } - while (n >= zpl_size_of(zpl_isize)) { - n -= zpl_size_of(zpl_isize); - *cast(zpl_isize *)(d + n) = *cast(zpl_isize *)(s + n); - } - } - while (n) n--, d[n] = s[n]; + @{ + */ +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +//! Checks if value is power of 2. +ZPL_DEF_INLINE zpl_b32 zpl_is_power_of_two(zpl_isize x); + +//! Aligns address to specified alignment. +ZPL_DEF_INLINE void *zpl_align_forward(void *ptr, zpl_isize alignment); + +//! Moves pointer forward by bytes. +ZPL_DEF_INLINE void *zpl_pointer_add(void *ptr, zpl_isize bytes); + +//! Moves pointer backward by bytes. +ZPL_DEF_INLINE void *zpl_pointer_sub(void *ptr, zpl_isize bytes); + +//! Moves pointer forward by bytes. +ZPL_DEF_INLINE void const *zpl_pointer_add_const(void const *ptr, zpl_isize bytes); + +//! Moves pointer backward by bytes. +ZPL_DEF_INLINE void const *zpl_pointer_sub_const(void const *ptr, zpl_isize bytes); + +//! Calculates difference between two addresses. +ZPL_DEF_INLINE zpl_isize zpl_pointer_diff(void const *begin, void const *end); + +#define zpl_ptr_add zpl_pointer_add +#define zpl_ptr_sub zpl_pointer_sub +#define zpl_ptr_add_const zpl_pointer_add_const +#define zpl_ptr_sub_const zpl_pointer_sub_const +#define zpl_ptr_diff zpl_pointer_diff + +//! Clears up memory at location by specified size. + +//! @param ptr Memory location to clear up. +//! @param size The size to clear up with. +ZPL_DEF_INLINE void zpl_zero_size(void *ptr, zpl_isize size); + +#ifndef zpl_zero_item +//! Clears up an item. +#define zpl_zero_item(t) zpl_zero_size((t), zpl_size_of(*(t))) // NOTE: Pass pointer of struct + +//! Clears up an array. +#define zpl_zero_array(a, count) zpl_zero_size((a), zpl_size_of(*(a)) * count) +#endif + +//! Copy memory from source to destination. +ZPL_DEF_INLINE void *zpl_memmove(void *dest, void const *source, zpl_isize size); + +//! Set constant value at memory location with specified size. +ZPL_DEF_INLINE void *zpl_memset(void *data, zpl_u8 byte_value, zpl_isize size); + +//! Compare two memory locations with specified size. +ZPL_DEF_INLINE zpl_i32 zpl_memcompare(void const *s1, void const *s2, zpl_isize size); + +//! Swap memory contents between 2 locations with size. +ZPL_DEF void zpl_memswap(void *i, void *j, zpl_isize size); + +//! Search for a constant value within the size limit at memory location. +ZPL_DEF void const *zpl_memchr(void const *data, zpl_u8 byte_value, zpl_isize size); + +//! Search for a constant value within the size limit at memory location in backwards. +ZPL_DEF void const *zpl_memrchr(void const *data, zpl_u8 byte_value, zpl_isize size); + +//! Copy non-overlapping memory from source to destination. +ZPL_DEF void *zpl_memcopy(void *dest, void const *source, zpl_isize size); + +#ifndef zpl_memcopy_array + +//! Copy non-overlapping array. +#define zpl_memcopy_array(dst, src, count) zpl_memcopy((dst), (src), zpl_size_of(*(dst)) * (count)) +#endif + +//! Copy an array. +#ifndef zpl_memmove_array +#define zpl_memmove_array(dst, src, count) zpl_memmove((dst), (src), zpl_size_of(*(dst)) * (count)) +#endif + +#ifndef ZPL_BIT_CAST +#define ZPL_BIT_CAST(dest, source) \ +do { \ +ZPL_STATIC_ASSERT(zpl_size_of(*(dest)) <= zpl_size_of(source), "zpl_size_of(*(dest)) !<= zpl_size_of(source)");\ +zpl_memcopy((dest), &(source), zpl_size_of(*dest)); \ +} while (0) +#endif + +#ifndef zpl_kilobytes +#define zpl_kilobytes(x) ((x) * (zpl_i64)(1024)) +#define zpl_megabytes(x) (zpl_kilobytes(x) * (zpl_i64)(1024)) +#define zpl_gigabytes(x) (zpl_megabytes(x) * (zpl_i64)(1024)) +#define zpl_terabytes(x) (zpl_gigabytes(x) * (zpl_i64)(1024)) +#endif + + +/* inlines */ + +#define ZPL__ONES (cast(zpl_usize) - 1 / ZPL_U8_MAX) +#define ZPL__HIGHS (ZPL__ONES * (ZPL_U8_MAX / 2 + 1)) +#define ZPL__HAS_ZERO(x) (((x)-ZPL__ONES) & ~(x)&ZPL__HIGHS) + +ZPL_IMPL_INLINE void *zpl_align_forward(void *ptr, zpl_isize alignment) { + zpl_uintptr p; + + ZPL_ASSERT(zpl_is_power_of_two(alignment)); + + p = cast(zpl_uintptr) ptr; + return cast(void *)((p + (alignment - 1)) & ~(alignment - 1)); +} + +ZPL_IMPL_INLINE void *zpl_pointer_add(void *ptr, zpl_isize bytes) { return cast(void *)(cast(zpl_u8 *) ptr + bytes); } +ZPL_IMPL_INLINE void *zpl_pointer_sub(void *ptr, zpl_isize bytes) { return cast(void *)(cast(zpl_u8 *) ptr - bytes); } +ZPL_IMPL_INLINE void const *zpl_pointer_add_const(void const *ptr, zpl_isize bytes) { + return cast(void const *)(cast(zpl_u8 const *) ptr + bytes); +} +ZPL_IMPL_INLINE void const *zpl_pointer_sub_const(void const *ptr, zpl_isize bytes) { + return cast(void const *)(cast(zpl_u8 const *) ptr - bytes); +} +ZPL_IMPL_INLINE zpl_isize zpl_pointer_diff(void const *begin, void const *end) { + return cast(zpl_isize)(cast(zpl_u8 const *) end - cast(zpl_u8 const *) begin); +} + +ZPL_IMPL_INLINE void zpl_zero_size(void *ptr, zpl_isize size) { zpl_memset(ptr, 0, size); } + +#if defined(_MSC_VER) && !defined(__clang__) +#pragma intrinsic(__movsb) +#endif + +ZPL_IMPL_INLINE void *zpl_memmove(void *dest, void const *source, zpl_isize n) { + if (dest == NULL) { return NULL; } + + zpl_u8 *d = cast(zpl_u8 *) dest; + zpl_u8 const *s = cast(zpl_u8 const *) source; + + if (d == s) return d; + if (s + n <= d || d + n <= s) // NOTE: Non-overlapping + return zpl_memcopy(d, s, n); + + if (d < s) { + if (cast(zpl_uintptr) s % zpl_size_of(zpl_isize) == cast(zpl_uintptr) d % zpl_size_of(zpl_isize)) { + while (cast(zpl_uintptr) d % zpl_size_of(zpl_isize)) { + if (!n--) return dest; + *d++ = *s++; } - - return dest; - } - - ZPL_IMPL_INLINE void *zpl_memset(void *dest, zpl_u8 c, zpl_isize n) { - if (dest == NULL) { return NULL; } - - zpl_u8 *s = cast(zpl_u8 *) dest; - zpl_isize k; - zpl_u32 c32 = ((zpl_u32)-1) / 255 * c; - - if (n == 0) return dest; - s[0] = s[n - 1] = c; - if (n < 3) return dest; - s[1] = s[n - 2] = c; - s[2] = s[n - 3] = c; - if (n < 7) return dest; - s[3] = s[n - 4] = c; - if (n < 9) return dest; - - k = -cast(zpl_intptr) s & 3; - s += k; - n -= k; - n &= -4; - - *cast(zpl_u32 *)(s + 0) = c32; - *cast(zpl_u32 *)(s + n - 4) = c32; - if (n < 9) return dest; - *cast(zpl_u32 *)(s + 4) = c32; - *cast(zpl_u32 *)(s + 8) = c32; - *cast(zpl_u32 *)(s + n - 12) = c32; - *cast(zpl_u32 *)(s + n - 8) = c32; - if (n < 25) return dest; - *cast(zpl_u32 *)(s + 12) = c32; - *cast(zpl_u32 *)(s + 16) = c32; - *cast(zpl_u32 *)(s + 20) = c32; - *cast(zpl_u32 *)(s + 24) = c32; - *cast(zpl_u32 *)(s + n - 28) = c32; - *cast(zpl_u32 *)(s + n - 24) = c32; - *cast(zpl_u32 *)(s + n - 20) = c32; - *cast(zpl_u32 *)(s + n - 16) = c32; - - k = 24 + (cast(zpl_uintptr) s & 4); - s += k; - n -= k; - - { - zpl_u64 c64 = (cast(zpl_u64) c32 << 32) | c32; - while (n > 31) { - *cast(zpl_u64 *)(s + 0) = c64; - *cast(zpl_u64 *)(s + 8) = c64; - *cast(zpl_u64 *)(s + 16) = c64; - *cast(zpl_u64 *)(s + 24) = c64; - - n -= 32; - s += 32; - } + while (n >= zpl_size_of(zpl_isize)) { + *cast(zpl_isize *) d = *cast(zpl_isize *) s; + n -= zpl_size_of(zpl_isize); + d += zpl_size_of(zpl_isize); + s += zpl_size_of(zpl_isize); } - - return dest; } - - ZPL_IMPL_INLINE zpl_i32 zpl_memcompare(void const *s1, void const *s2, zpl_isize size) { - zpl_u8 const *s1p8 = cast(zpl_u8 const *) s1; - zpl_u8 const *s2p8 = cast(zpl_u8 const *) s2; - - if (s1 == NULL || s2 == NULL) { return 0; } - - while (size--) { - zpl_isize d; - if ((d = (*s1p8++ - *s2p8++)) != 0) return cast(zpl_i32) d; + for (; n; n--) *d++ = *s++; + } else { + if ((cast(zpl_uintptr) s % zpl_size_of(zpl_isize)) == (cast(zpl_uintptr) d % zpl_size_of(zpl_isize))) { + while (cast(zpl_uintptr)(d + n) % zpl_size_of(zpl_isize)) { + if (!n--) return dest; + d[n] = s[n]; } + while (n >= zpl_size_of(zpl_isize)) { + n -= zpl_size_of(zpl_isize); + *cast(zpl_isize *)(d + n) = *cast(zpl_isize *)(s + n); + } + } + while (n) n--, d[n] = s[n]; + } + + return dest; +} + +ZPL_IMPL_INLINE void *zpl_memset(void *dest, zpl_u8 c, zpl_isize n) { + if (dest == NULL) { return NULL; } + + zpl_u8 *s = cast(zpl_u8 *) dest; + zpl_isize k; + zpl_u32 c32 = ((zpl_u32)-1) / 255 * c; + + if (n == 0) return dest; + s[0] = s[n - 1] = c; + if (n < 3) return dest; + s[1] = s[n - 2] = c; + s[2] = s[n - 3] = c; + if (n < 7) return dest; + s[3] = s[n - 4] = c; + if (n < 9) return dest; + + k = -cast(zpl_intptr) s & 3; + s += k; + n -= k; + n &= -4; + + *cast(zpl_u32 *)(s + 0) = c32; + *cast(zpl_u32 *)(s + n - 4) = c32; + if (n < 9) return dest; + *cast(zpl_u32 *)(s + 4) = c32; + *cast(zpl_u32 *)(s + 8) = c32; + *cast(zpl_u32 *)(s + n - 12) = c32; + *cast(zpl_u32 *)(s + n - 8) = c32; + if (n < 25) return dest; + *cast(zpl_u32 *)(s + 12) = c32; + *cast(zpl_u32 *)(s + 16) = c32; + *cast(zpl_u32 *)(s + 20) = c32; + *cast(zpl_u32 *)(s + 24) = c32; + *cast(zpl_u32 *)(s + n - 28) = c32; + *cast(zpl_u32 *)(s + n - 24) = c32; + *cast(zpl_u32 *)(s + n - 20) = c32; + *cast(zpl_u32 *)(s + n - 16) = c32; + + k = 24 + (cast(zpl_uintptr) s & 4); + s += k; + n -= k; + + { + zpl_u64 c64 = (cast(zpl_u64) c32 << 32) | c32; + while (n > 31) { + *cast(zpl_u64 *)(s + 0) = c64; + *cast(zpl_u64 *)(s + 8) = c64; + *cast(zpl_u64 *)(s + 16) = c64; + *cast(zpl_u64 *)(s + 24) = c64; + + n -= 32; + s += 32; + } + } + + return dest; +} + +ZPL_IMPL_INLINE zpl_i32 zpl_memcompare(void const *s1, void const *s2, zpl_isize size) { + zpl_u8 const *s1p8 = cast(zpl_u8 const *) s1; + zpl_u8 const *s2p8 = cast(zpl_u8 const *) s2; + + if (s1 == NULL || s2 == NULL) { return 0; } + + while (size--) { + zpl_isize d; + if ((d = (*s1p8++ - *s2p8++)) != 0) return cast(zpl_i32) d; + } + return 0; +} + +ZPL_IMPL_INLINE zpl_b32 zpl_is_power_of_two(zpl_isize x) { + if (x <= 0) return false; + return !(x & (x - 1)); +} + +ZPL_END_C_DECLS +// file: header/core/memory_virtual.h + + +//////////////////////////////////////////////////////////////// +// +// Virtual Memory +// +// +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +typedef struct zpl_virtual_memory { + void *data; + zpl_isize size; +} zpl_virtual_memory; + +//! Initialize virtual memory from existing data. +ZPL_DEF zpl_virtual_memory zpl_vm(void *data, zpl_isize size); + +//! Allocate virtual memory at address with size. + +//! @param addr The starting address of the region to reserve. If NULL, it lets operating system to decide where to allocate it. +//! @param size The size to server. +ZPL_DEF zpl_virtual_memory zpl_vm_alloc(void *addr, zpl_isize size); + +//! Release the virtual memory. +ZPL_DEF zpl_b32 zpl_vm_free(zpl_virtual_memory vm); + +//! Trim virtual memory. +ZPL_DEF zpl_virtual_memory zpl_vm_trim(zpl_virtual_memory vm, zpl_isize lead_size, zpl_isize size); + +//! Purge virtual memory. +ZPL_DEF zpl_b32 zpl_vm_purge(zpl_virtual_memory vm); + +//! Retrieve VM's page size and alignment. +ZPL_DEF zpl_isize zpl_virtual_memory_page_size(zpl_isize *alignment_out); + +ZPL_END_C_DECLS +// file: header/core/memory_custom.h + +//////////////////////////////////////////////////////////////// +// +// Custom Allocation +// +// +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +typedef enum zplAllocationType { + ZPL_ALLOCATION_ALLOC, + ZPL_ALLOCATION_FREE, + ZPL_ALLOCATION_FREE_ALL, + ZPL_ALLOCATION_RESIZE, +} zplAllocationType; + +// NOTE: This is useful so you can define an allocator of the same type and parameters +#define ZPL_ALLOCATOR_PROC(name) \ +void *name(void *allocator_data, zplAllocationType type, zpl_isize size, zpl_isize alignment, void *old_memory, \ +zpl_isize old_size, zpl_u64 flags) +typedef ZPL_ALLOCATOR_PROC(zpl_allocator_proc); + + +typedef struct zpl_allocator { + zpl_allocator_proc *proc; + void *data; +} zpl_allocator; + +typedef enum zplAllocatorFlag { + ZPL_ALLOCATOR_FLAG_CLEAR_TO_ZERO = ZPL_BIT(0), +} zplAllocatorFlag; + +#ifndef ZPL_DEFAULT_MEMORY_ALIGNMENT +#define ZPL_DEFAULT_MEMORY_ALIGNMENT (2 * zpl_size_of(void *)) +#endif + +#ifndef ZPL_DEFAULT_ALLOCATOR_FLAGS +#define ZPL_DEFAULT_ALLOCATOR_FLAGS (ZPL_ALLOCATOR_FLAG_CLEAR_TO_ZERO) +#endif + +//! Allocate memory with specified alignment. +ZPL_DEF_INLINE void *zpl_alloc_align(zpl_allocator a, zpl_isize size, zpl_isize alignment); + +//! Allocate memory with default alignment. +ZPL_DEF_INLINE void *zpl_alloc(zpl_allocator a, zpl_isize size); + +//! Free allocated memory. +ZPL_DEF_INLINE void zpl_free(zpl_allocator a, void *ptr); + +//! Free all memory allocated by an allocator. +ZPL_DEF_INLINE void zpl_free_all(zpl_allocator a); + +//! Resize an allocated memory. +ZPL_DEF_INLINE void *zpl_resize(zpl_allocator a, void *ptr, zpl_isize old_size, zpl_isize new_size); + +//! Resize an allocated memory with specified alignment. +ZPL_DEF_INLINE void *zpl_resize_align(zpl_allocator a, void *ptr, zpl_isize old_size, zpl_isize new_size, zpl_isize alignment); + +//! Allocate memory and copy data into it. +ZPL_DEF_INLINE void *zpl_alloc_copy(zpl_allocator a, void const *src, zpl_isize size); + +//! Allocate memory with specified alignment and copy data into it. +ZPL_DEF_INLINE void *zpl_alloc_copy_align(zpl_allocator a, void const *src, zpl_isize size, zpl_isize alignment); + +//! Allocate memory for null-terminated C-String. +ZPL_DEF char *zpl_alloc_str(zpl_allocator a, char const *str); + +//! Allocate memory for C-String with specified size. +ZPL_DEF_INLINE char *zpl_alloc_str_len(zpl_allocator a, char const *str, zpl_isize len); + +#ifndef zpl_alloc_item + +//! Allocate memory for an item. +#define zpl_alloc_item(allocator_, Type) (Type *)zpl_alloc(allocator_, zpl_size_of(Type)) + +//! Allocate memory for an array of items. +#define zpl_alloc_array(allocator_, Type, count) (Type *)zpl_alloc(allocator_, zpl_size_of(Type) * (count)) +#endif + +//! Allocate/Resize memory using default options. + +//! Use this if you don't need a "fancy" resize allocation +ZPL_DEF_INLINE void *zpl_default_resize_align(zpl_allocator a, void *ptr, zpl_isize old_size, zpl_isize new_size, zpl_isize alignment); + +//! The heap allocator backed by operating system's memory manager. +ZPL_DEF_INLINE zpl_allocator zpl_heap_allocator(void); +ZPL_DEF ZPL_ALLOCATOR_PROC(zpl_heap_allocator_proc); + +#ifndef zpl_malloc + +//! Helper to allocate memory using heap allocator. +#define zpl_malloc(sz) zpl_alloc(zpl_heap_allocator( ), sz) + +//! Helper to free memory allocated by heap allocator. +#define zpl_mfree(ptr) zpl_free(zpl_heap_allocator( ), ptr) + +//! Alias to heap allocator. +#define zpl_heap zpl_heap_allocator +#endif + +// +// Arena Allocator +// + +typedef struct zpl_arena { + zpl_allocator backing; + void *physical_start; + zpl_isize total_size; + zpl_isize total_allocated; + zpl_isize temp_count; +} zpl_arena; + +//! Initialize memory arena from existing memory region. +ZPL_DEF_INLINE void zpl_arena_init_from_memory(zpl_arena *arena, void *start, zpl_isize size); + +//! Initialize memory arena using existing memory allocator. +ZPL_DEF_INLINE void zpl_arena_init_from_allocator(zpl_arena *arena, zpl_allocator backing, zpl_isize size); + +//! Initialize memory arena within an existing parent memory arena. +ZPL_DEF_INLINE void zpl_arena_init_sub(zpl_arena *arena, zpl_arena *parent_arena, zpl_isize size); + +//! Release the memory used by memory arena. +ZPL_DEF_INLINE void zpl_arena_free(zpl_arena *arena); + + +//! Retrieve memory arena's aligned allocation address. +ZPL_DEF_INLINE zpl_isize zpl_arena_alignment_of(zpl_arena *arena, zpl_isize alignment); + +//! Retrieve memory arena's remaining size. +ZPL_DEF_INLINE zpl_isize zpl_arena_size_remaining(zpl_arena *arena, zpl_isize alignment); + +//! Check whether memory arena has any temporary snapshots. +ZPL_DEF_INLINE void zpl_arena_check(zpl_arena *arena); + +//! Allocation Types: alloc, free_all, resize +ZPL_DEF_INLINE zpl_allocator zpl_arena_allocator(zpl_arena *arena); +ZPL_DEF ZPL_ALLOCATOR_PROC(zpl_arena_allocator_proc); + + +typedef struct zpl_temp_arena_memory { + zpl_arena *arena; + zpl_isize original_count; +} zpl_temp_arena_memory; + +//! Capture a snapshot of used memory in a memory arena. +ZPL_DEF_INLINE zpl_temp_arena_memory zpl_temp_arena_memory_begin(zpl_arena *arena); + +//! Reset memory arena's usage by a captured snapshot. +ZPL_DEF_INLINE void zpl_temp_arena_memory_end(zpl_temp_arena_memory tmp_mem); + +// +// Pool Allocator +// + + +typedef struct zpl_pool { + zpl_allocator backing; + void *physical_start; + void *free_list; + zpl_isize block_size; + zpl_isize block_align; + zpl_isize total_size; + zpl_isize num_blocks; +} zpl_pool; + + +//! Initialize pool allocator. +ZPL_DEF_INLINE void zpl_pool_init(zpl_pool *pool, zpl_allocator backing, zpl_isize num_blocks, zpl_isize block_size); + +//! Initialize pool allocator with specific block alignment. +ZPL_DEF void zpl_pool_init_align(zpl_pool *pool, zpl_allocator backing, zpl_isize num_blocks, zpl_isize block_size, + zpl_isize block_align); + +//! Release the resources used by pool allocator. +ZPL_DEF_INLINE void zpl_pool_free(zpl_pool *pool); + +//! Allocation Types: alloc, free +ZPL_DEF_INLINE zpl_allocator zpl_pool_allocator(zpl_pool *pool); +ZPL_DEF ZPL_ALLOCATOR_PROC(zpl_pool_allocator_proc); + + +typedef struct zpl_allocation_header_ev { + zpl_isize size; +} zpl_allocation_header_ev; + +ZPL_DEF_INLINE zpl_allocation_header_ev *zpl_allocation_header(void *data); +ZPL_DEF_INLINE void zpl_allocation_header_fill(zpl_allocation_header_ev *header, void *data, zpl_isize size); + +#if defined(ZPL_ARCH_32_BIT) +#define ZPL_ISIZE_HIGH_BIT 0x80000000 +#elif defined(ZPL_ARCH_64_BIT) +#define ZPL_ISIZE_HIGH_BIT 0x8000000000000000ll +#else +#error +#endif + +// +// Scratch Memory Allocator - Ring Buffer Based Arena +// + + +typedef struct zpl_scratch_memory { + void *physical_start; + zpl_isize total_size; + void *alloc_point; + void *free_point; +} zpl_scratch_memory; + +//! Initialize ring buffer arena. +ZPL_DEF void zpl_scratch_memory_init(zpl_scratch_memory *s, void *start, zpl_isize size); + +//! Check whether ring buffer arena is in use. +ZPL_DEF zpl_b32 zpl_scratch_memory_is_in_use(zpl_scratch_memory *s, void *ptr); + +//! Allocation Types: alloc, free, free_all, resize +ZPL_DEF zpl_allocator zpl_scratch_allocator(zpl_scratch_memory *s); +ZPL_DEF ZPL_ALLOCATOR_PROC(zpl_scratch_allocator_proc); + +// +// Stack Memory Allocator +// + + +typedef struct zpl_stack_memory { + zpl_allocator backing; + + void *physical_start; + zpl_usize total_size; + zpl_usize allocated; +} zpl_stack_memory; + +//! Initialize stack allocator from existing memory. +ZPL_DEF_INLINE void zpl_stack_memory_init_from_memory(zpl_stack_memory *s, void *start, zpl_isize size); + +//! Initialize stack allocator using existing memory allocator. +ZPL_DEF_INLINE void zpl_stack_memory_init(zpl_stack_memory *s, zpl_allocator backing, zpl_isize size); + +//! Check whether stack allocator is in use. +ZPL_DEF_INLINE zpl_b32 zpl_stack_memory_is_in_use(zpl_stack_memory *s, void *ptr); + +//! Release the resources used by stack allocator. +ZPL_DEF_INLINE void zpl_stack_memory_free(zpl_stack_memory *s); + +//! Allocation Types: alloc, free, free_all +ZPL_DEF_INLINE zpl_allocator zpl_stack_allocator(zpl_stack_memory *s); +ZPL_DEF ZPL_ALLOCATOR_PROC(zpl_stack_allocator_proc); + +// TODO: Fixed heap allocator +// TODO: General heap allocator. Maybe a TCMalloc like clone? + + +/* inlines */ + +ZPL_IMPL_INLINE void *zpl_alloc_align(zpl_allocator a, zpl_isize size, zpl_isize alignment) { + return a.proc(a.data, ZPL_ALLOCATION_ALLOC, size, alignment, NULL, 0, ZPL_DEFAULT_ALLOCATOR_FLAGS); +} +ZPL_IMPL_INLINE void *zpl_alloc(zpl_allocator a, zpl_isize size) { + return zpl_alloc_align(a, size, ZPL_DEFAULT_MEMORY_ALIGNMENT); +} +ZPL_IMPL_INLINE void zpl_free(zpl_allocator a, void *ptr) { + if (ptr != NULL) a.proc(a.data, ZPL_ALLOCATION_FREE, 0, 0, ptr, 0, ZPL_DEFAULT_ALLOCATOR_FLAGS); +} +ZPL_IMPL_INLINE void zpl_free_all(zpl_allocator a) { + a.proc(a.data, ZPL_ALLOCATION_FREE_ALL, 0, 0, NULL, 0, ZPL_DEFAULT_ALLOCATOR_FLAGS); +} +ZPL_IMPL_INLINE void *zpl_resize(zpl_allocator a, void *ptr, zpl_isize old_size, zpl_isize new_size) { + return zpl_resize_align(a, ptr, old_size, new_size, ZPL_DEFAULT_MEMORY_ALIGNMENT); +} +ZPL_IMPL_INLINE void *zpl_resize_align(zpl_allocator a, void *ptr, zpl_isize old_size, zpl_isize new_size, zpl_isize alignment) { + return a.proc(a.data, ZPL_ALLOCATION_RESIZE, new_size, alignment, ptr, old_size, ZPL_DEFAULT_ALLOCATOR_FLAGS); +} + +ZPL_IMPL_INLINE void *zpl_alloc_copy(zpl_allocator a, void const *src, zpl_isize size) { + return zpl_memcopy(zpl_alloc(a, size), src, size); +} +ZPL_IMPL_INLINE void *zpl_alloc_copy_align(zpl_allocator a, void const *src, zpl_isize size, zpl_isize alignment) { + return zpl_memcopy(zpl_alloc_align(a, size, alignment), src, size); +} + +ZPL_IMPL_INLINE char *zpl_alloc_str_len(zpl_allocator a, char const *str, zpl_isize len) { + char *result; + result = cast(char *) zpl_alloc_copy(a, str, len + 1); + result[len] = '\0'; + return result; +} + +ZPL_IMPL_INLINE void *zpl_default_resize_align(zpl_allocator a, void *old_memory, zpl_isize old_size, zpl_isize new_size, + zpl_isize alignment) { + if (!old_memory) return zpl_alloc_align(a, new_size, alignment); + + if (new_size == 0) { + zpl_free(a, old_memory); + return NULL; + } + + if (new_size < old_size) new_size = old_size; + + if (old_size == new_size) { + return old_memory; + } else { + void *new_memory = zpl_alloc_align(a, new_size, alignment); + if (!new_memory) return NULL; + zpl_memmove(new_memory, old_memory, zpl_min(new_size, old_size)); + zpl_free(a, old_memory); + return new_memory; + } +} + + +// +// Heap Allocator +// + +ZPL_IMPL_INLINE zpl_allocator zpl_heap_allocator(void) { + zpl_allocator a; + a.proc = zpl_heap_allocator_proc; + a.data = NULL; + return a; +} + +// +// Arena Allocator +// + +ZPL_IMPL_INLINE void zpl_arena_init_from_memory(zpl_arena *arena, void *start, zpl_isize size) { + arena->backing.proc = NULL; + arena->backing.data = NULL; + arena->physical_start = start; + arena->total_size = size; + arena->total_allocated = 0; + arena->temp_count = 0; +} + +ZPL_IMPL_INLINE void zpl_arena_init_from_allocator(zpl_arena *arena, zpl_allocator backing, zpl_isize size) { + arena->backing = backing; + arena->physical_start = zpl_alloc(backing, size); // NOTE: Uses default alignment + arena->total_size = size; + arena->total_allocated = 0; + arena->temp_count = 0; +} + +ZPL_IMPL_INLINE void zpl_arena_init_sub(zpl_arena *arena, zpl_arena *parent_arena, zpl_isize size) { + zpl_arena_init_from_allocator(arena, zpl_arena_allocator(parent_arena), size); +} + +ZPL_IMPL_INLINE void zpl_arena_free(zpl_arena *arena) { + if (arena->backing.proc) { + zpl_free(arena->backing, arena->physical_start); + arena->physical_start = NULL; + } +} + +ZPL_IMPL_INLINE zpl_isize zpl_arena_alignment_of(zpl_arena *arena, zpl_isize alignment) { + zpl_isize alignment_offset, result_pointer, mask; + ZPL_ASSERT(zpl_is_power_of_two(alignment)); + + alignment_offset = 0; + result_pointer = cast(zpl_isize) arena->physical_start + arena->total_allocated; + mask = alignment - 1; + if (result_pointer & mask) alignment_offset = alignment - (result_pointer & mask); + + return alignment_offset; +} + +ZPL_IMPL_INLINE zpl_isize zpl_arena_size_remaining(zpl_arena *arena, zpl_isize alignment) { + zpl_isize result = arena->total_size - (arena->total_allocated + zpl_arena_alignment_of(arena, alignment)); + return result; +} + +ZPL_IMPL_INLINE void zpl_arena_check(zpl_arena *arena) { ZPL_ASSERT(arena->temp_count == 0); } + +ZPL_IMPL_INLINE zpl_allocator zpl_arena_allocator(zpl_arena *arena) { + zpl_allocator allocator; + allocator.proc = zpl_arena_allocator_proc; + allocator.data = arena; + return allocator; +} + +ZPL_IMPL_INLINE zpl_temp_arena_memory zpl_temp_arena_memory_begin(zpl_arena *arena) { + zpl_temp_arena_memory tmp; + tmp.arena = arena; + tmp.original_count = arena->total_allocated; + arena->temp_count++; + return tmp; +} + +ZPL_IMPL_INLINE void zpl_temp_arena_memory_end(zpl_temp_arena_memory tmp) { + ZPL_ASSERT(tmp.arena->total_allocated >= tmp.original_count); + ZPL_ASSERT(tmp.arena->temp_count > 0); + tmp.arena->total_allocated = tmp.original_count; + tmp.arena->temp_count--; +} + +// +// Pool Allocator +// + +ZPL_IMPL_INLINE void zpl_pool_init(zpl_pool *pool, zpl_allocator backing, zpl_isize num_blocks, zpl_isize block_size) { + zpl_pool_init_align(pool, backing, num_blocks, block_size, ZPL_DEFAULT_MEMORY_ALIGNMENT); +} + +ZPL_IMPL_INLINE void zpl_pool_free(zpl_pool *pool) { + if (pool->backing.proc) { zpl_free(pool->backing, pool->physical_start); } +} + +ZPL_IMPL_INLINE zpl_allocator zpl_pool_allocator(zpl_pool *pool) { + zpl_allocator allocator; + allocator.proc = zpl_pool_allocator_proc; + allocator.data = pool; + return allocator; +} + +ZPL_IMPL_INLINE zpl_allocation_header_ev *zpl_allocation_header(void *data) { + zpl_isize *p = cast(zpl_isize *) data; + while (p[-1] == cast(zpl_isize)(-1)) p--; + return cast(zpl_allocation_header_ev *) p - 1; +} + +ZPL_IMPL_INLINE void zpl_allocation_header_fill(zpl_allocation_header_ev *header, void *data, zpl_isize size) { + zpl_isize *ptr; + header->size = size; + ptr = cast(zpl_isize *)(header + 1); + while (cast(void *) ptr < data) *ptr++ = cast(zpl_isize)(-1); +} + +// +// Stack Memory Allocator +// + +#define ZPL_STACK_ALLOC_OFFSET sizeof(zpl_u64) +ZPL_STATIC_ASSERT(ZPL_STACK_ALLOC_OFFSET == 8, "ZPL_STACK_ALLOC_OFFSET != 8"); + +ZPL_IMPL_INLINE void zpl_stack_memory_init_from_memory(zpl_stack_memory *s, void *start, zpl_isize size) { + s->physical_start = start; + s->total_size = size; + s->allocated = 0; +} + +ZPL_IMPL_INLINE void zpl_stack_memory_init(zpl_stack_memory *s, zpl_allocator backing, zpl_isize size) { + s->backing = backing; + s->physical_start = zpl_alloc(backing, size); + s->total_size = size; + s->allocated = 0; +} + +ZPL_IMPL_INLINE zpl_b32 zpl_stack_memory_is_in_use(zpl_stack_memory *s, void *ptr) { + if (s->allocated == 0) return false; + + if (ptr > s->physical_start && ptr < zpl_pointer_add(s->physical_start, s->total_size)) { return true; } + + return false; +} + +ZPL_IMPL_INLINE void zpl_stack_memory_free(zpl_stack_memory *s) { + if (s->backing.proc) { + zpl_free(s->backing, s->physical_start); + s->physical_start = NULL; + } +} + +ZPL_IMPL_INLINE zpl_allocator zpl_stack_allocator(zpl_stack_memory *s) { + zpl_allocator a; + a.proc = zpl_stack_allocator_proc; + a.data = s; + return a; +} + +ZPL_END_C_DECLS +// file: header/core/collections/array.h + +//////////////////////////////////////////////////////////////// +// +// Dynamic Array (POD Types) +// +// zpl_array(Type) works like zpl_string or zpl_buffer where the actual type is just a pointer to the first +// element. +// +// Available Procedures for zpl_array(Type) +// zpl_array_init +// zpl_array_free +// zpl_array_set_capacity +// zpl_array_grow +// zpl_array_append +// zpl_array_appendv +// zpl_array_pop +// zpl_array_clear +// zpl_array_back +// zpl_array_front +// zpl_array_resize +// zpl_array_reserve +// + +#if 0 // Example +void foo(void) { + zpl_isize i; + int test_values[] = {4, 2, 1, 7}; + zpl_allocator a = zpl_heap_allocator(); + zpl_array(int) items; + + zpl_array_init(items, a); + + zpl_array_append(items, 1); + zpl_array_append(items, 4); + zpl_array_append(items, 9); + zpl_array_append(items, 16); + + items[1] = 3; // Manually set value + // NOTE: No array bounds checking + + for (i = 0; i < items.count; i++) + zpl_printf("%d\n", items[i]); + // 1 + // 3 + // 9 + // 16 + + zpl_array_clear(items); + + zpl_array_appendv(items, test_values, zpl_count_of(test_values)); + for (i = 0; i < items.count; i++) + zpl_printf("%d\n", items[i]); + // 4 + // 2 + // 1 + // 7 + + zpl_array_free(items); +} +#endif + +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +typedef struct zpl_array_header { + char *data; + zpl_isize count; + zpl_isize capacity; + zpl_allocator allocator; +} zpl_array_header; + +#define zpl_array(Type) Type * + +#define zpl_array_make(Type, Name, allocator) Type *Name; zpl_array_init(Name, allocator) + +#ifndef ZPL_ARRAY_GROW_FORMULA +#define ZPL_ARRAY_GROW_FORMULA(x) (2 * (x) + 8) +#endif + +ZPL_STATIC_ASSERT(ZPL_ARRAY_GROW_FORMULA(0) > 0, "ZPL_ARRAY_GROW_FORMULA(0) <= 0"); + +#define ZPL_ARRAY_HEADER(x) (cast(zpl_array_header *)(x) - 1) +#define zpl_array_allocator(x) (ZPL_ARRAY_HEADER(x)->allocator) +#define zpl_array_count(x) (ZPL_ARRAY_HEADER(x)->count) +#define zpl_array_capacity(x) (ZPL_ARRAY_HEADER(x)->capacity) +#define zpl_array_end(x) (x + (zpl_array_count(x) - 1)) + +#define zpl_array_init_reserve(x, allocator_, cap) \ +do { \ +void **zpl__array_ = cast(void **) & (x); \ +zpl_array_header *zpl__ah = \ +cast(zpl_array_header *) zpl_alloc(allocator_, zpl_size_of(zpl_array_header) + zpl_size_of(*(x)) * (cap)); \ +zpl__ah->allocator = allocator_; \ +zpl__ah->count = 0; \ +zpl__ah->data = (char *)x; \ +zpl__ah->capacity = cap; \ +*zpl__array_ = cast(void *)(zpl__ah + 1); \ +} while (0) + +// NOTE: Give it an initial default capacity +#define zpl_array_init(x, allocator) zpl_array_init_reserve(x, allocator, ZPL_ARRAY_GROW_FORMULA(0)) + +#define zpl_array_free(x) \ +do { \ +zpl_array_header *zpl__ah = ZPL_ARRAY_HEADER(x); \ +zpl_free(zpl__ah->allocator, zpl__ah); \ +} while (0) + +#define zpl_array_set_capacity(x, capacity) \ +do { \ +if (x) { \ +void **zpl__array_ = cast(void **) & (x); \ +*zpl__array_ = zpl__array_set_capacity((x), (capacity), zpl_size_of(*(x))); \ +} \ +} while (0) + +// NOTE: Do not use the thing below directly, use the macro +ZPL_DEF void *zpl__array_set_capacity(void *array, zpl_isize capacity, zpl_isize element_size); + +#define zpl_array_grow(x, min_capacity) \ +do { \ +zpl_isize new_capacity = ZPL_ARRAY_GROW_FORMULA(zpl_array_capacity(x)); \ +if (new_capacity < (min_capacity)) new_capacity = (min_capacity); \ +zpl_array_set_capacity(x, new_capacity); \ +} while (0) + +#define zpl_array_append(x, item) \ +do { \ +if (zpl_array_capacity(x) < zpl_array_count(x) + 1) zpl_array_grow(x, 0); \ +(x)[zpl_array_count(x)++] = (item); \ +} while (0) + +#define zpl_array_append_at(x, item, ind) \ +do { \ +zpl_array_header *zpl__ah = ZPL_ARRAY_HEADER(x); \ +if (ind == zpl__ah->count) { zpl_array_append(x, item); break; } \ +if (zpl_array_capacity(x) < zpl_array_count(x) + 1) zpl_array_grow(x, 0); \ +zpl_memmove(&(x)[ind + 1], (x + ind), zpl_size_of(x[0]) * (zpl__ah->count - ind)); \ +x[ind] = item; \ +zpl__ah->count++; \ +} while (0) + +#define zpl_array_appendv(x, items, item_count) \ +do { \ +zpl_array_header *zpl__ah = ZPL_ARRAY_HEADER(x); \ +ZPL_ASSERT(zpl_size_of((items)[0]) == zpl_size_of((x)[0])); \ +if (zpl__ah->capacity < zpl__ah->count + (item_count)) zpl_array_grow(x, zpl__ah->count + (item_count)); \ +zpl_memcopy(&(x)[zpl__ah->count], (items), zpl_size_of((x)[0]) * (item_count)); \ +zpl__ah->count += (item_count); \ +} while (0) + +#define zpl_array_remove_at(x, index) \ +do { \ +zpl_array_header *zpl__ah = ZPL_ARRAY_HEADER(x); \ +ZPL_ASSERT(index < zpl__ah->count); \ +zpl_memmove(x + index, x + index + 1, zpl_size_of(x[0]) * (zpl__ah->count - index)); \ +--zpl__ah->count; \ +} while (0) + +#define zpl_array_copy_init(y, x) \ +do { \ +zpl_array_init_reserve(y, zpl_array_allocator(x), zpl_array_capacity(x)); \ +zpl_memcopy(y, x, zpl_array_capacity(x) * zpl_size_of(*x)); \ +zpl_array_count(y) = zpl_array_count(x); \ +} while (0) + +#define zpl_array_pop(x) \ +do { \ +ZPL_ASSERT(ZPL_ARRAY_HEADER(x)->count > 0); \ +ZPL_ARRAY_HEADER(x)->count--; \ +} while (0) +#define zpl_array_back(x) x[ZPL_ARRAY_HEADER(x)->count - 1] +#define zpl_array_front(x) x[0] +#define zpl_array_clear(x) \ +do { ZPL_ARRAY_HEADER(x)->count = 0; } while (0) + +#define zpl_array_resize(x, new_count) \ +do { \ +if (ZPL_ARRAY_HEADER(x)->capacity < (new_count)) zpl_array_grow(x, (new_count)); \ +ZPL_ARRAY_HEADER(x)->count = (new_count); \ +} while (0) + +#define zpl_array_reserve(x, new_capacity) \ +do { \ +if (ZPL_ARRAY_HEADER(x)->capacity < (new_capacity)) zpl_array_set_capacity(x, new_capacity); \ +} while (0) + +ZPL_END_C_DECLS +// file: header/core/collections/buffer.h + +//////////////////////////////////////////////////////////////// +// +// Fixed Capacity Buffer (POD Types) +// +// +// zpl_buffer(Type) works like zpl_string or zpl_array where the actual type is just a pointer to the first +// element. +// +// Available Procedures for zpl_buffer(Type) +// zpl_buffer_init +// zpl_buffer_free +// zpl_buffer_append +// zpl_buffer_appendv +// zpl_buffer_pop +// zpl_buffer_clear + +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +typedef struct zpl_buffer_header { + zpl_allocator backing; + zpl_isize count; + zpl_isize capacity; +} zpl_buffer_header; + +#define zpl_buffer(Type) Type * + +#define zpl_buffer_make(Type, Name, allocator, cap) Type *Name; zpl_buffer_init(Name, allocator, cap) + +#define ZPL_BUFFER_HEADER(x) (cast(zpl_buffer_header *)(x) - 1) +#define zpl_buffer_count(x) (ZPL_BUFFER_HEADER(x)->count) +#define zpl_buffer_capacity(x) (ZPL_BUFFER_HEADER(x)->capacity) +#define zpl_buffer_end(x) (x + (zpl_buffer_count(x) - 1)) + +#define zpl_buffer_init(x, allocator, cap) \ +do { \ +void **nx = cast(void **) & (x); \ +zpl_buffer_header *zpl__bh = \ +cast(zpl_buffer_header *) zpl_alloc((allocator), sizeof(zpl_buffer_header) + (cap)*zpl_size_of(*(x))); \ +zpl__bh->backing = allocator; \ +zpl__bh->count = 0; \ +zpl__bh->capacity = cap; \ +*nx = cast(void *)(zpl__bh + 1); \ +} while (0) + +#define zpl_buffer_free(x) (zpl_free(ZPL_BUFFER_HEADER(x)->backing, ZPL_BUFFER_HEADER(x))) + +#define zpl_buffer_append(x, item) \ +do { (x)[zpl_buffer_count(x)++] = (item); } while (0) + +#define zpl_buffer_appendv(x, items, item_count) \ +do { \ +ZPL_ASSERT(zpl_size_of(*(items)) == zpl_size_of(*(x))); \ +ZPL_ASSERT(zpl_buffer_count(x) + item_count <= zpl_buffer_capacity(x)); \ +zpl_memcopy(&(x)[zpl_buffer_count(x)], (items), zpl_size_of(*(x)) * (item_count)); \ +zpl_buffer_count(x) += (item_count); \ +} while (0) + +#define zpl_buffer_copy_init(y, x) \ +do { \ +zpl_buffer_init_reserve(y, zpl_buffer_allocator(x), zpl_buffer_capacity(x)); \ +zpl_memcopy(y, x, zpl_buffer_capacity(x) * zpl_size_of(*x)); \ +zpl_buffer_count(y) = zpl_buffer_count(x); \ +} while (0) + +#define zpl_buffer_pop(x) \ +do { \ +ZPL_ASSERT(zpl_buffer_count(x) > 0); \ +zpl_buffer_count(x)--; \ +} while (0) +#define zpl_buffer_clear(x) \ +do { zpl_buffer_count(x) = 0; } while (0) + +ZPL_END_C_DECLS +// file: header/core/collections/list.h + +//////////////////////////////////////////////////////////////// +// +// Linked List +// +// zpl_list encapsulates pointer to data and points to the next and the previous element in the list. +// +// Available Procedures for zpl_list +// zpl_list_init +// zpl_list_add +// zpl_list_remove + +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +#if 0 +#define ZPL_IMPLEMENTATION +#include "zpl.h" +int main(void) +{ + zpl_list s, *head, *cursor; + zpl_list_init(&s, "it is optional to call init: "); + head = cursor = &s; + + // since we can construct an element implicitly this way + // the second field gets overwritten once we add it to a list. + zpl_list a = {"hello"}; + cursor = zpl_list_add(cursor, &a); + + zpl_list b = {"world"}; + cursor = zpl_list_add(cursor, &b); + + zpl_list c = {"!!! OK"}; + cursor = zpl_list_add(cursor, &c); + + for (zpl_list *l=head; l; l=l->next) { + zpl_printf("%s ", cast(char *)l->ptr); + } + zpl_printf("\n"); + + return 0; +} +#endif + + +typedef struct zpl__list { + void const *ptr; + struct zpl__list *next, *prev; +} zpl_list; + +ZPL_DEF_INLINE void zpl_list_init(zpl_list *list, void const *ptr); +ZPL_DEF_INLINE zpl_list *zpl_list_add(zpl_list *list, zpl_list *item); + +// NOTE(zaklaus): Returns a pointer to the next node (or NULL if the removed node has no trailing node.) +ZPL_DEF_INLINE zpl_list *zpl_list_remove(zpl_list *list); + + +ZPL_IMPL_INLINE void zpl_list_init(zpl_list *list, void const *ptr) { + zpl_list list_ = { 0 }; + *list = list_; + list->ptr = ptr; +} + +ZPL_IMPL_INLINE zpl_list *zpl_list_add(zpl_list *list, zpl_list *item) { + item->next = NULL; + + if (list->next) { item->next = list->next; } + + list->next = item; + item->prev = list; + return item; +} + +ZPL_IMPL_INLINE zpl_list *zpl_list_remove(zpl_list *list) { + if (list->prev) { list->prev->next = list->next; } + + return list->next; +} + +ZPL_END_C_DECLS +// file: header/core/collections/ring.h + +//////////////////////////////////////////////////////////////// +// +// Instantiated Circular buffer +// +/* +int main() +{ + zpl_ring_zpl_u32 pad={0}; + zpl_ring_zpl_u32_init(&pad, zpl_heap(), 3); + zpl_ring_zpl_u32_append(&pad, 1); + zpl_ring_zpl_u32_append(&pad, 2); + zpl_ring_zpl_u32_append(&pad, 3); + + while (!zpl_ring_zpl_u32_empty(&pad)) { + zpl_printf("Result is %d\n", *zpl_ring_zpl_u32_get(&pad)); + } + + zpl_ring_zpl_u32_free(&pad); + + return 0; +} +*/ + +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +#define ZPL_RING_DECLARE(type) \ +typedef struct { \ +zpl_allocator backing; \ +zpl_buffer(type) buf; \ +zpl_usize head, tail; \ +zpl_usize capacity; \ +} ZPL_JOIN2(zpl_ring_, type); \ +\ +ZPL_DEF void ZPL_JOIN3(zpl_ring_, type, _init)(ZPL_JOIN2(zpl_ring_, type) * pad, zpl_allocator a, zpl_isize max_size); \ +ZPL_DEF void ZPL_JOIN3(zpl_ring_, type, _free)(ZPL_JOIN2(zpl_ring_, type) * pad); \ +ZPL_DEF zpl_b32 ZPL_JOIN3(zpl_ring_, type, _full)(ZPL_JOIN2(zpl_ring_, type) * pad); \ +ZPL_DEF zpl_b32 ZPL_JOIN3(zpl_ring_, type, _empty)(ZPL_JOIN2(zpl_ring_, type) * pad); \ +ZPL_DEF void ZPL_JOIN3(zpl_ring_, type, _append)(ZPL_JOIN2(zpl_ring_, type) * pad, type data); \ +ZPL_DEF void ZPL_JOIN3(zpl_ring_, type, _append_array)(ZPL_JOIN2(zpl_ring_, type) * pad, zpl_array(type) data); \ +ZPL_DEF type *ZPL_JOIN3(zpl_ring_, type, _get)(ZPL_JOIN2(zpl_ring_, type) * pad); \ +ZPL_DEF zpl_array(type) \ +ZPL_JOIN3(zpl_ring_, type, _get_array)(ZPL_JOIN2(zpl_ring_, type) * pad, zpl_usize max_size, zpl_allocator a); + +#define ZPL_RING_DEFINE(type) \ +void ZPL_JOIN3(zpl_ring_, type, _init)(ZPL_JOIN2(zpl_ring_, type) * pad, zpl_allocator a, zpl_isize max_size) { \ +ZPL_JOIN2(zpl_ring_, type) pad_ = { 0 }; \ +*pad = pad_; \ +\ +pad->backing = a; \ +zpl_buffer_init(pad->buf, a, max_size + 1); \ +pad->capacity = max_size + 1; \ +pad->head = pad->tail = 0; \ +} \ +void ZPL_JOIN3(zpl_ring_, type, _free)(ZPL_JOIN2(zpl_ring_, type) * pad) { \ +zpl_buffer_free(pad->buf); \ +} \ +\ +zpl_b32 ZPL_JOIN3(zpl_ring_, type, _full)(ZPL_JOIN2(zpl_ring_, type) * pad) { \ +return ((pad->head + 1) % pad->capacity) == pad->tail; \ +} \ +\ +zpl_b32 ZPL_JOIN3(zpl_ring_, type, _empty)(ZPL_JOIN2(zpl_ring_, type) * pad) { return pad->head == pad->tail; } \ +\ +void ZPL_JOIN3(zpl_ring_, type, _append)(ZPL_JOIN2(zpl_ring_, type) * pad, type data) { \ +pad->buf[pad->head] = data; \ +pad->head = (pad->head + 1) % pad->capacity; \ +\ +if (pad->head == pad->tail) { pad->tail = (pad->tail + 1) % pad->capacity; } \ +} \ +\ +void ZPL_JOIN3(zpl_ring_, type, _append_array)(ZPL_JOIN2(zpl_ring_, type) * pad, zpl_array(type) data) { \ +zpl_usize c = zpl_array_count(data); \ +for (zpl_usize i = 0; i < c; ++i) { ZPL_JOIN3(zpl_ring_, type, _append)(pad, data[i]); } \ +} \ +\ +type *ZPL_JOIN3(zpl_ring_, type, _get)(ZPL_JOIN2(zpl_ring_, type) * pad) { \ +if (ZPL_JOIN3(zpl_ring_, type, _empty)(pad)) { return NULL; } \ +\ +type *data = &pad->buf[pad->tail]; \ +pad->tail = (pad->tail + 1) % pad->capacity; \ +\ +return data; \ +} \ +\ +zpl_array(type) \ +ZPL_JOIN3(zpl_ring_, type, _get_array)(ZPL_JOIN2(zpl_ring_, type) * pad, zpl_usize max_size, zpl_allocator a) { \ +zpl_array(type) vals = 0; \ +zpl_array_init(vals, a); \ +while (--max_size && !ZPL_JOIN3(zpl_ring_, type, _empty)(pad)) { \ +zpl_array_append(vals, *ZPL_JOIN3(zpl_ring_, type, _get)(pad)); \ +} \ +return vals; \ +} + +ZPL_END_C_DECLS +// file: header/core/collections/hashtable.h + +/** @file hashtable.c +@brief Instantiated hash table +@defgroup hashtable Instantiated hash table + +@n +@n This is an attempt to implement a templated hash table +@n NOTE: The key is always a zpl_u64 for simplicity and you will _probably_ _never_ need anything bigger. +@n +@n Hash table type and function declaration, call: ZPL_TABLE_DECLARE(PREFIX, NAME, N, VALUE) +@n Hash table function definitions, call: ZPL_TABLE_DEFINE(NAME, N, VALUE) +@n +@n PREFIX - a prefix for function prototypes e.g. extern, static, etc. +@n NAME - Name of the Hash Table +@n FUNC - the name will prefix function names +@n VALUE - the type of the value to be stored +@n +@n tablename_init(NAME * h, zpl_allocator a); +@n tablename_destroy(NAME * h); +@n tablename_get(NAME * h, zpl_u64 key); +@n tablename_set(NAME * h, zpl_u64 key, VALUE value); +@n tablename_grow(NAME * h); +@n tablename_rehash(NAME * h, zpl_isize new_count); +@n tablename_remove(NAME * h, zpl_u64 key); + + @{ +*/ + +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +typedef struct zpl_hash_table_find_result { + zpl_isize hash_index; + zpl_isize entry_prev; + zpl_isize entry_index; +} zpl_hash_table_find_result; + +#define ZPL_TABLE(PREFIX, NAME, FUNC, VALUE) \ +ZPL_TABLE_DECLARE(PREFIX, NAME, FUNC, VALUE); \ +ZPL_TABLE_DEFINE(NAME, FUNC, VALUE); + +#define ZPL_TABLE_DECLARE(PREFIX, NAME, FUNC, VALUE) \ +typedef struct ZPL_JOIN2(NAME, Entry) { \ +zpl_u64 key; \ +zpl_isize next; \ +VALUE value; \ +} ZPL_JOIN2(NAME, Entry); \ +\ +typedef struct NAME { \ +zpl_array(zpl_isize) hashes; \ +zpl_array(ZPL_JOIN2(NAME, Entry)) entries; \ +} NAME; \ +\ +PREFIX void ZPL_JOIN2(FUNC, init)(NAME * h, zpl_allocator a); \ +PREFIX void ZPL_JOIN2(FUNC, destroy)(NAME * h); \ +PREFIX VALUE *ZPL_JOIN2(FUNC, get)(NAME * h, zpl_u64 key); \ +PREFIX void ZPL_JOIN2(FUNC, set)(NAME * h, zpl_u64 key, VALUE value); \ +PREFIX void ZPL_JOIN2(FUNC, grow)(NAME * h); \ +PREFIX void ZPL_JOIN2(FUNC, rehash)(NAME * h, zpl_isize new_count); \ +PREFIX void ZPL_JOIN2(FUNC, remove)(NAME * h, zpl_u64 key); + +#define ZPL_TABLE_DEFINE(NAME, FUNC, VALUE) \ +void ZPL_JOIN2(FUNC, init)(NAME * h, zpl_allocator a) { \ +zpl_array_init(h->hashes, a); \ +zpl_array_init(h->entries, a); \ +} \ +\ +void ZPL_JOIN2(FUNC, destroy)(NAME * h) { \ +if (h->entries) zpl_array_free(h->entries); \ +if (h->hashes) zpl_array_free(h->hashes); \ +} \ +\ +zpl_internal zpl_isize ZPL_JOIN2(FUNC, _add_entry)(NAME * h, zpl_u64 key) { \ +zpl_isize index; \ +ZPL_JOIN2(NAME, Entry) e = { 0 }; \ +e.key = key; \ +e.next = -1; \ +index = zpl_array_count(h->entries); \ +zpl_array_append(h->entries, e); \ +return index; \ +} \ +\ +zpl_internal zpl_hash_table_find_result ZPL_JOIN2(FUNC, _find)(NAME * h, zpl_u64 key) { \ +zpl_hash_table_find_result r = { -1, -1, -1 }; \ +if (zpl_array_count(h->hashes) > 0) { \ +r.hash_index = key % zpl_array_count(h->hashes); \ +r.entry_index = h->hashes[r.hash_index]; \ +while (r.entry_index >= 0) { \ +if (h->entries[r.entry_index].key == key) return r; \ +r.entry_prev = r.entry_index; \ +r.entry_index = h->entries[r.entry_index].next; \ +} \ +} \ +return r; \ +} \ +\ +zpl_internal zpl_b32 ZPL_JOIN2(FUNC, _full)(NAME * h) { \ +return 0.75f * zpl_array_count(h->hashes) < zpl_array_count(h->entries); \ +} \ +\ +void ZPL_JOIN2(FUNC, grow)(NAME * h) { \ +zpl_isize new_count = ZPL_ARRAY_GROW_FORMULA(zpl_array_count(h->entries)); \ +ZPL_JOIN2(FUNC, rehash)(h, new_count); \ +} \ +\ +void ZPL_JOIN2(FUNC, rehash)(NAME * h, zpl_isize new_count) { \ +zpl_isize i, j; \ +NAME nh = { 0 }; \ +ZPL_JOIN2(FUNC, init)(&nh, zpl_array_allocator(h->hashes)); \ +zpl_array_resize(nh.hashes, new_count); \ +zpl_array_reserve(nh.entries, zpl_array_count(h->entries)); \ +for (i = 0; i < new_count; i++) nh.hashes[i] = -1; \ +for (i = 0; i < zpl_array_count(h->entries); i++) { \ +ZPL_JOIN2(NAME, Entry) * e; \ +zpl_hash_table_find_result fr; \ +if (zpl_array_count(nh.hashes) == 0) ZPL_JOIN2(FUNC, grow)(&nh); \ +e = &h->entries[i]; \ +fr = ZPL_JOIN2(FUNC, _find)(&nh, e->key); \ +j = ZPL_JOIN2(FUNC, _add_entry)(&nh, e->key); \ +if (fr.entry_prev < 0) \ +nh.hashes[fr.hash_index] = j; \ +else \ +nh.entries[fr.entry_prev].next = j; \ +nh.entries[j].next = fr.entry_index; \ +nh.entries[j].value = e->value; \ +} \ +ZPL_JOIN2(FUNC, destroy)(h); \ +h->hashes = nh.hashes; \ +h->entries = nh.entries; \ +} \ +\ +VALUE *ZPL_JOIN2(FUNC, get)(NAME * h, zpl_u64 key) { \ +zpl_isize index = ZPL_JOIN2(FUNC, _find)(h, key).entry_index; \ +if (index >= 0) return &h->entries[index].value; \ +return NULL; \ +} \ +\ +void ZPL_JOIN2(FUNC, remove)(NAME * h, zpl_u64 key) { \ +zpl_hash_table_find_result fr = ZPL_JOIN2(FUNC, _find)(h, key); \ +if (fr.entry_index >= 0) { \ +if (fr.entry_prev >= 0) { \ +h->entries[fr.entry_prev].next = h->entries[fr.entry_index].next; \ +} else { \ +h->hashes[fr.hash_index] = fr.entry_index; \ +} \ +zpl_array_remove_at(h->entries, fr.entry_index); \ +} \ +ZPL_JOIN2(FUNC, rehash)(h, zpl_array_count(h->entries)); \ +} \ +\ +void ZPL_JOIN2(FUNC, set)(NAME * h, zpl_u64 key, VALUE value) { \ +zpl_isize index; \ +zpl_hash_table_find_result fr; \ +if (zpl_array_count(h->hashes) == 0) ZPL_JOIN2(FUNC, grow)(h); \ +fr = ZPL_JOIN2(FUNC, _find)(h, key); \ +if (fr.entry_index >= 0) { \ +index = fr.entry_index; \ +} else { \ +index = ZPL_JOIN2(FUNC, _add_entry)(h, key); \ +if (fr.entry_prev >= 0) { \ +h->entries[fr.entry_prev].next = index; \ +} else { \ +h->hashes[fr.hash_index] = index; \ +} \ +} \ +h->entries[index].value = value; \ +if (ZPL_JOIN2(FUNC, _full)(h)) ZPL_JOIN2(FUNC, grow)(h); \ +}\ + +//! @} + +ZPL_END_C_DECLS +// file: header/core/string.h + +/** @file string.c +@brief String operations and library +@defgroup string String library + +Offers methods for c-string manipulation, but also a string library based on gb_string, which is c-string friendly. + +@{ +*/ + +//////////////////////////////////////////////////////////////// +// +// Char Functions +// +// + +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +ZPL_DEF_INLINE char zpl_char_to_lower(char c); +ZPL_DEF_INLINE char zpl_char_to_upper(char c); +ZPL_DEF_INLINE zpl_b32 zpl_char_is_space(char c); +ZPL_DEF_INLINE zpl_b32 zpl_char_is_digit(char c); +ZPL_DEF_INLINE zpl_b32 zpl_char_is_hex_digit(char c); +ZPL_DEF_INLINE zpl_b32 zpl_char_is_alpha(char c); +ZPL_DEF_INLINE zpl_b32 zpl_char_is_alphanumeric(char c); +ZPL_DEF_INLINE zpl_i32 zpl_digit_to_int(char c); +ZPL_DEF_INLINE zpl_i32 zpl_hex_digit_to_int(char c); +ZPL_DEF_INLINE zpl_u8 zpl_char_to_hex_digit(char c); +ZPL_DEF_INLINE zpl_b32 zpl_char_is_control(char c); + +// NOTE: ASCII only +ZPL_DEF_INLINE void zpl_str_to_lower(char *str); +ZPL_DEF_INLINE void zpl_str_to_upper(char *str); + +ZPL_DEF_INLINE char *zpl_str_trim(char *str, zpl_b32 skip_newline); +ZPL_DEF_INLINE char *zpl_str_skip(char *str, char c); +ZPL_DEF_INLINE char *zpl_str_control_skip(char *str, char c); + +ZPL_DEF_INLINE zpl_isize zpl_strlen(const char *str); +ZPL_DEF_INLINE zpl_isize zpl_strnlen(const char *str, zpl_isize max_len); +ZPL_DEF_INLINE zpl_i32 zpl_strcmp(const char *s1, const char *s2); +ZPL_DEF_INLINE zpl_i32 zpl_strncmp(const char *s1, const char *s2, zpl_isize len); +ZPL_DEF_INLINE char *zpl_strcpy(char *dest, const char *source); +ZPL_DEF_INLINE char *zpl_strncpy(char *dest, const char *source, zpl_isize len); +ZPL_DEF_INLINE zpl_isize zpl_strlcpy(char *dest, const char *source, zpl_isize len); +ZPL_DEF_INLINE char *zpl_strrev(char *str); // NOTE: ASCII only +ZPL_DEF_INLINE const char *zpl_strtok(char *output, const char *src, const char *delimit); + +ZPL_DEF_INLINE char *zpl_strdup(zpl_allocator a, char *src, zpl_isize max_len); +ZPL_DEF_INLINE char **zpl_str_split_lines(zpl_allocator alloc, char *source, zpl_b32 strip_whitespace); + +#define zpl_str_expand(str) str, zpl_strlen(str) + +ZPL_DEF_INLINE zpl_b32 zpl_str_has_prefix(const char *str, const char *prefix); +ZPL_DEF_INLINE zpl_b32 zpl_str_has_suffix(const char *str, const char *suffix); + +ZPL_DEF_INLINE const char *zpl_char_first_occurence(const char *str, char c); +ZPL_DEF_INLINE const char *zpl_char_last_occurence(const char *str, char c); +#define zpl_strchr zpl_char_first_occurence + +ZPL_DEF_INLINE void zpl_str_concat(char *dest, zpl_isize dest_len, const char *src_a, zpl_isize src_a_len, const char *src_b, zpl_isize src_b_len); + +ZPL_DEF zpl_u64 zpl_str_to_u64(const char *str, char **end_ptr, zpl_i32 base); // TODO: Support more than just decimal and hexadecimal +ZPL_DEF zpl_i64 zpl_str_to_i64(const char *str, char **end_ptr, zpl_i32 base); // TODO: Support more than just decimal and hexadecimal +ZPL_DEF zpl_f64 zpl_str_to_f64(const char *str, char **end_ptr); +ZPL_DEF void zpl_i64_to_str(zpl_i64 value, char *string, zpl_i32 base); +ZPL_DEF void zpl_u64_to_str(zpl_u64 value, char *string, zpl_i32 base); + +ZPL_DEF_INLINE zpl_f32 zpl_str_to_f32(const char *str, char **end_ptr); + +//////////////////////////////////////////////////////////////// +// +// UTF-8 Handling +// +// + +// NOTE: Does not check if utf-8 string is valid +ZPL_IMPL_INLINE zpl_isize zpl_utf8_strlen(zpl_u8 const *str); +ZPL_IMPL_INLINE zpl_isize zpl_utf8_strnlen(zpl_u8 const *str, zpl_isize max_len); + +// NOTE: Windows doesn't handle 8 bit filenames well +ZPL_DEF zpl_u16 *zpl_utf8_to_ucs2(zpl_u16 *buffer, zpl_isize len, zpl_u8 const *str); +ZPL_DEF zpl_u8 *zpl_ucs2_to_utf8(zpl_u8 *buffer, zpl_isize len, zpl_u16 const *str); +ZPL_DEF zpl_u16 *zpl_utf8_to_ucs2_buf(zpl_u8 const *str); // NOTE: Uses locally persisting buffer +ZPL_DEF zpl_u8 *zpl_ucs2_to_utf8_buf(zpl_u16 const *str); // NOTE: Uses locally persisting buffer + +// NOTE: Returns size of codepoint in bytes +ZPL_DEF zpl_isize zpl_utf8_decode(zpl_u8 const *str, zpl_isize str_len, zpl_rune *codepoint); +ZPL_DEF zpl_isize zpl_utf8_codepoint_size(zpl_u8 const *str, zpl_isize str_len); +ZPL_DEF zpl_isize zpl_utf8_encode_rune(zpl_u8 buf[4], zpl_rune r); + +/* inlines */ + +ZPL_IMPL_INLINE char zpl_char_to_lower(char c) { + if (c >= 'A' && c <= 'Z') return 'a' + (c - 'A'); + return c; +} + +ZPL_IMPL_INLINE char zpl_char_to_upper(char c) { + if (c >= 'a' && c <= 'z') return 'A' + (c - 'a'); + return c; +} + +ZPL_IMPL_INLINE zpl_b32 zpl_char_is_space(char c) { + if (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v') return true; + return false; +} + +ZPL_IMPL_INLINE zpl_b32 zpl_char_is_digit(char c) { + if (c >= '0' && c <= '9') return true; + return false; +} + +ZPL_IMPL_INLINE zpl_b32 zpl_char_is_hex_digit(char c) { + if (zpl_char_is_digit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) return true; + return false; +} + +ZPL_IMPL_INLINE zpl_b32 zpl_char_is_alpha(char c) { + if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) return true; + return false; +} + +ZPL_IMPL_INLINE zpl_b32 zpl_char_is_alphanumeric(char c) { return zpl_char_is_alpha(c) || zpl_char_is_digit(c); } + +ZPL_IMPL_INLINE zpl_i32 zpl_digit_to_int(char c) { return zpl_char_is_digit(c) ? c - '0' : c - 'W'; } + +ZPL_IMPL_INLINE zpl_i32 zpl_hex_digit_to_int(char c) { + if (zpl_char_is_digit(c)) + return zpl_digit_to_int(c); + else if (zpl_is_between(c, 'a', 'f')) + return c - 'a' + 10; + else if (zpl_is_between(c, 'A', 'F')) + return c - 'A' + 10; + return -1; +} + +ZPL_IMPL_INLINE zpl_u8 zpl_char_to_hex_digit(char c) { + if (c >= '0' && c <= '9') + return (zpl_u8)(c - '0'); + if (c >= 'a' && c <= 'f') + return (zpl_u8)(c - 'a'); + if (c >= 'A' && c <= 'F') + return (zpl_u8)(c - 'A'); + return 0; +} + + +ZPL_IMPL_INLINE void zpl_str_to_lower(char *str) { + if (!str) return; + while (*str) { + *str = zpl_char_to_lower(*str); + str++; + } +} + +ZPL_IMPL_INLINE void zpl_str_to_upper(char *str) { + if (!str) return; + while (*str) { + *str = zpl_char_to_upper(*str); + str++; + } +} + +ZPL_IMPL_INLINE zpl_isize zpl_strlen(const char *str) { + if (str == NULL) { return 0; } + + const char *begin = str; + zpl_isize const *w; + while (cast(zpl_uintptr) str % sizeof(zpl_usize)) { + if (!*str) return str - begin; + str++; + } + w = cast(zpl_isize const *) str; + while (!ZPL__HAS_ZERO(*w)) w++; + str = cast(const char *) w; + while (*str) str++; + return str - begin; +} + +ZPL_IMPL_INLINE zpl_isize zpl_strnlen(const char *str, zpl_isize max_len) { + const char *end = cast(const char *) zpl_memchr(str, 0, max_len); + if (end) return end - str; + return max_len; +} + +ZPL_IMPL_INLINE zpl_isize zpl_utf8_strlen(zpl_u8 const *str) { + zpl_isize count = 0; + for (; *str; count++) { + zpl_u8 c = *str; + zpl_isize inc = 0; + if (c < 0x80) + inc = 1; + else if ((c & 0xe0) == 0xc0) + inc = 2; + else if ((c & 0xf0) == 0xe0) + inc = 3; + else if ((c & 0xf8) == 0xf0) + inc = 4; + else + return -1; + + str += inc; + } + return count; +} + +ZPL_IMPL_INLINE zpl_isize zpl_utf8_strnlen(zpl_u8 const *str, zpl_isize max_len) { + zpl_isize count = 0; + for (; *str && max_len > 0; count++) { + zpl_u8 c = *str; + zpl_isize inc = 0; + if (c < 0x80) + inc = 1; + else if ((c & 0xe0) == 0xc0) + inc = 2; + else if ((c & 0xf0) == 0xe0) + inc = 3; + else if ((c & 0xf8) == 0xf0) + inc = 4; + else + return -1; + + str += inc; + max_len -= inc; + } + return count; +} + +ZPL_IMPL_INLINE zpl_i32 zpl_strcmp(const char *s1, const char *s2) { + while (*s1 && (*s1 == *s2)) { s1++, s2++; } + return *(zpl_u8 *)s1 - *(zpl_u8 *)s2; +} + +ZPL_IMPL_INLINE char *zpl_strcpy(char *dest, const char *source) { + ZPL_ASSERT_NOT_NULL(dest); + if (source) { + char *str = dest; + while (*source) *str++ = *source++; + } + return dest; +} + +ZPL_IMPL_INLINE char *zpl_strncpy(char *dest, const char *source, zpl_isize len) { + ZPL_ASSERT_NOT_NULL(dest); + if (source) { + char *str = dest; + while (len > 0 && *source) { + *str++ = *source++; + len--; + } + while (len > 0) { + *str++ = '\0'; + len--; + } + } + return dest; +} + +ZPL_IMPL_INLINE zpl_isize zpl_strlcpy(char *dest, const char *source, zpl_isize len) { + zpl_isize result = 0; + ZPL_ASSERT_NOT_NULL(dest); + if (source) { + const char *source_start = source; + char *str = dest; + while (len > 0 && *source) { + *str++ = *source++; + len--; + } + while (len > 0) { + *str++ = '\0'; + len--; + } + + result = source - source_start; + } + return result; +} + +ZPL_IMPL_INLINE char *zpl_strrev(char *str) { + zpl_isize len = zpl_strlen(str); + char *a = str + 0; + char *b = str + len - 1; + len /= 2; + while (len--) { + zpl_swap(char, *a, *b); + a++, b--; + } + return str; +} + +ZPL_IMPL_INLINE zpl_i32 zpl_strncmp(const char *s1, const char *s2, zpl_isize len) { + for (; len > 0; s1++, s2++, len--) { + if (*s1 != *s2) + return ((s1 < s2) ? -1 : +1); + else if (*s1 == '\0') return 0; + } + return 0; +} + +ZPL_IMPL_INLINE const char *zpl_strtok(char *output, const char *src, const char *delimit) { + while (*src && zpl_char_first_occurence(delimit, *src) == NULL) *output++ = *src++; + + *output = 0; + return *src ? src + 1 : src; +} + +ZPL_IMPL_INLINE zpl_b32 zpl_char_is_control(char c) { + return !!zpl_strchr("\"\\/bfnrt", c); +} + +ZPL_IMPL_INLINE zpl_b32 zpl__is_special_char(char c) { return !!zpl_strchr("<>:/", c); } +ZPL_IMPL_INLINE zpl_b32 zpl__is_assign_char(char c) { return !!zpl_strchr(":=|", c); } +ZPL_IMPL_INLINE zpl_b32 zpl__is_delim_char(char c) { return !!zpl_strchr(",|\n", c); } + + +ZPL_IMPL_INLINE char *zpl_str_control_skip(char *str, char c) { + while ((*str && *str != c) || (*(str - 1) == '\\' && *str == c && zpl_char_is_control(c))) { ++str; } + + return str; +} + + +ZPL_IMPL_INLINE zpl_b32 zpl_str_has_prefix(const char *str, const char *prefix) { + while (*prefix) { + if (*str++ != *prefix++) return false; + } + return true; +} + +ZPL_IMPL_INLINE zpl_b32 zpl_str_has_suffix(const char *str, const char *suffix) { + zpl_isize i = zpl_strlen(str); + zpl_isize j = zpl_strlen(suffix); + if (j <= i) return zpl_strcmp(str + i - j, suffix) == 0; + return false; +} + +ZPL_IMPL_INLINE const char *zpl_char_first_occurence(const char *s, char c) { + char ch = c; + for (; *s != ch; s++) { + if (*s == '\0') return NULL; + } + return s; +} + +ZPL_IMPL_INLINE const char *zpl_char_last_occurence(const char *s, char c) { + char *result = (char*)NULL; + do { + if (*s == c) result = (char *)s; + } while (*s++); + + return result; +} + +ZPL_IMPL_INLINE char *zpl_str_trim(char *str, zpl_b32 skip_newline) +{ + while (*str && zpl_char_is_space(*str) && (!skip_newline || (skip_newline && *str != '\n'))) { ++str; } + return str; +} + +ZPL_IMPL_INLINE char *zpl_str_skip(char *str, char c) { + while (*str && *str != c) { ++str; } + return str; +} + +ZPL_IMPL_INLINE void zpl_str_concat(char *dest, zpl_isize dest_len, const char *src_a, zpl_isize src_a_len, const char *src_b, + zpl_isize src_b_len) { + ZPL_ASSERT(dest_len >= src_a_len + src_b_len + 1); + if (dest) { + zpl_memcopy(dest, src_a, src_a_len); + zpl_memcopy(dest + src_a_len, src_b, src_b_len); + dest[src_a_len + src_b_len] = '\0'; + } +} + +ZPL_IMPL_INLINE zpl_f32 zpl_str_to_f32(const char *str, char **end_ptr) { + zpl_f64 f = zpl_str_to_f64(str, end_ptr); + zpl_f32 r = cast(zpl_f32) f; + return r; +} + +ZPL_IMPL_INLINE char *zpl_strdup(zpl_allocator a, char *src, zpl_isize max_len) { + ZPL_ASSERT_NOT_NULL(src); + zpl_isize len = zpl_strlen(src); + char *dest = cast(char *) zpl_alloc(a, max_len); + zpl_memset(dest + len, 0, max_len - len); + zpl_strncpy(dest, src, max_len); + + return dest; +} + +ZPL_IMPL_INLINE char **zpl_str_split_lines(zpl_allocator alloc, char *source, zpl_b32 strip_whitespace) { + char **lines = NULL, *p = source, *pd = p; + zpl_array_init(lines, alloc); + + while (*p) { + if (*pd == '\n') { + *pd = 0; + if (*(pd - 1) == '\r') *(pd - 1) = 0; + if (strip_whitespace && (pd - p) == 0) { + p = pd + 1; + continue; + } + zpl_array_append(lines, p); + p = pd + 1; } + ++pd; + } + return lines; +} - ZPL_IMPL_INLINE zpl_b32 zpl_is_power_of_two(zpl_isize x) { - if (x <= 0) return false; - return !(x & (x - 1)); +ZPL_END_C_DECLS +// file: header/core/stringlib.h + +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +typedef char *zpl_string; + +typedef struct zpl_string_header { + zpl_allocator allocator; + zpl_isize length; + zpl_isize capacity; +} zpl_string_header; + +#define ZPL_STRING_HEADER(str) (cast(zpl_string_header *)(str) - 1) + +ZPL_DEF zpl_string zpl_string_make_reserve(zpl_allocator a, zpl_isize capacity); +ZPL_DEF zpl_string zpl_string_make_length(zpl_allocator a, void const *str, zpl_isize num_bytes); +ZPL_DEF zpl_string zpl_string_sprintf(zpl_allocator a, char *buf, zpl_isize num_bytes, const char *fmt, ...); +ZPL_DEF zpl_string zpl_string_sprintf_buf(zpl_allocator a, const char *fmt, ...); // NOTE: Uses locally persistent buffer +ZPL_DEF zpl_string zpl_string_append_length(zpl_string str, void const *other, zpl_isize num_bytes); +ZPL_DEF zpl_string zpl_string_appendc(zpl_string str, const char *other); +ZPL_DEF zpl_string zpl_string_join(zpl_allocator a, const char **parts, zpl_isize count, const char *glue); +ZPL_DEF zpl_string zpl_string_set(zpl_string str, const char *cstr); +ZPL_DEF zpl_string zpl_string_make_space_for(zpl_string str, zpl_isize add_len); +ZPL_DEF zpl_isize zpl_string_allocation_size(zpl_string const str); +ZPL_DEF zpl_b32 zpl_string_are_equal(zpl_string const lhs, zpl_string const rhs); +ZPL_DEF zpl_string zpl_string_trim(zpl_string str, const char *cut_set); +ZPL_DEF zpl_string zpl_string_append_rune(zpl_string str, zpl_rune r); +ZPL_DEF zpl_string zpl_string_append_fmt(zpl_string str, const char *fmt, ...); + +ZPL_DEF_INLINE zpl_string zpl_string_make(zpl_allocator a, const char *str); +ZPL_DEF_INLINE void zpl_string_free(zpl_string str); +ZPL_DEF_INLINE void zpl_string_clear(zpl_string str); +ZPL_DEF_INLINE zpl_string zpl_string_duplicate(zpl_allocator a, zpl_string const str); +ZPL_DEF_INLINE zpl_isize zpl_string_length(zpl_string const str); +ZPL_DEF_INLINE zpl_isize zpl_string_capacity(zpl_string const str); +ZPL_DEF_INLINE zpl_isize zpl_string_available_space(zpl_string const str); +ZPL_DEF_INLINE zpl_string zpl_string_append(zpl_string str, zpl_string const other); +ZPL_DEF_INLINE zpl_string zpl_string_trim_space(zpl_string str); // Whitespace ` \t\r\n\v\f` +ZPL_DEF_INLINE void zpl__set_string_length(zpl_string str, zpl_isize len); +ZPL_DEF_INLINE void zpl__set_string_capacity(zpl_string str, zpl_isize cap); + +ZPL_IMPL_INLINE void zpl__set_string_length(zpl_string str, zpl_isize len) { ZPL_STRING_HEADER(str)->length = len; } +ZPL_IMPL_INLINE void zpl__set_string_capacity(zpl_string str, zpl_isize cap) { ZPL_STRING_HEADER(str)->capacity = cap; } +ZPL_IMPL_INLINE zpl_string zpl_string_make(zpl_allocator a, const char *str) { + zpl_isize len = str ? zpl_strlen(str) : 0; + return zpl_string_make_length(a, str, len); +} + +ZPL_IMPL_INLINE void zpl_string_free(zpl_string str) { + if (str) { + zpl_string_header *header = ZPL_STRING_HEADER(str); + zpl_free(header->allocator, header); + } +} + +ZPL_IMPL_INLINE zpl_string zpl_string_duplicate(zpl_allocator a, zpl_string const str) { + return zpl_string_make_length(a, str, zpl_string_length(str)); +} + +ZPL_IMPL_INLINE zpl_isize zpl_string_length(zpl_string const str) { return ZPL_STRING_HEADER(str)->length; } +ZPL_IMPL_INLINE zpl_isize zpl_string_capacity(zpl_string const str) { return ZPL_STRING_HEADER(str)->capacity; } + +ZPL_IMPL_INLINE zpl_isize zpl_string_available_space(zpl_string const str) { + zpl_string_header *h = ZPL_STRING_HEADER(str); + if (h->capacity > h->length) return h->capacity - h->length; + return 0; +} + +ZPL_IMPL_INLINE void zpl_string_clear(zpl_string str) { + zpl__set_string_length(str, 0); + str[0] = '\0'; +} + +ZPL_IMPL_INLINE zpl_string zpl_string_append(zpl_string str, zpl_string const other) { + return zpl_string_append_length(str, other, zpl_string_length(other)); +} + +ZPL_IMPL_INLINE zpl_string zpl_string_trim_space(zpl_string str) { return zpl_string_trim(str, " \t\r\n\v\f"); } + + +ZPL_END_C_DECLS +// file: header/core/file.h + +/** @file file.c +@brief File handling +@defgroup fileio File handling + +File I/O operations as well as path and folder structure manipulation methods. With threading enabled, it also offers async read/write methods. + +@{ +*/ +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +typedef zpl_u32 zpl_file_mode; + +typedef enum zpl_file_mode_flag { + ZPL_FILE_MODE_READ = ZPL_BIT(0), + ZPL_FILE_MODE_WRITE = ZPL_BIT(1), + ZPL_FILE_MODE_APPEND = ZPL_BIT(2), + ZPL_FILE_MODE_RW = ZPL_BIT(3), + ZPL_FILE_MODES = ZPL_FILE_MODE_READ | ZPL_FILE_MODE_WRITE | ZPL_FILE_MODE_APPEND | ZPL_FILE_MODE_RW, +} zpl_file_mode_flag; + +// NOTE: Only used internally and for the file operations +typedef enum zpl_seek_whence_type { + ZPL_SEEK_WHENCE_BEGIN = 0, + ZPL_SEEK_WHENCE_CURRENT = 1, + ZPL_SEEK_WHENCE_END = 2, +} zpl_seek_whence_type; + +typedef enum zpl_file_error { + ZPL_FILE_ERROR_NONE, + ZPL_FILE_ERROR_INVALID, + ZPL_FILE_ERROR_INVALID_FILENAME, + ZPL_FILE_ERROR_EXISTS, + ZPL_FILE_ERROR_NOT_EXISTS, + ZPL_FILE_ERROR_PERMISSION, + ZPL_FILE_ERROR_TRUNCATION_FAILURE, + ZPL_FILE_ERROR_NOT_EMPTY, + ZPL_FILE_ERROR_NAME_TOO_LONG, + ZPL_FILE_ERROR_UNKNOWN, +} zpl_file_error; + +typedef union zpl_file_descriptor { + void *p; + zpl_intptr i; + zpl_uintptr u; +} zpl_file_descriptor; + +typedef struct zpl_file_operations zpl_file_operations; + +#define ZPL_FILE_OPEN_PROC(name) zpl_file_error name(zpl_file_descriptor *fd, zpl_file_operations *ops, zpl_file_mode mode, char const *filename) +#define ZPL_FILE_READ_AT_PROC(name) zpl_b32 name(zpl_file_descriptor fd, void *buffer, zpl_isize size, zpl_i64 offset, zpl_isize *bytes_read, zpl_b32 stop_at_newline) +#define ZPL_FILE_WRITE_AT_PROC(name) zpl_b32 name(zpl_file_descriptor fd, void const *buffer, zpl_isize size, zpl_i64 offset, zpl_isize *bytes_written) +#define ZPL_FILE_SEEK_PROC(name) zpl_b32 name(zpl_file_descriptor fd, zpl_i64 offset, zpl_seek_whence_type whence, zpl_i64 *new_offset) +#define ZPL_FILE_CLOSE_PROC(name) void name(zpl_file_descriptor fd) + +typedef ZPL_FILE_OPEN_PROC(zpl_file_open_proc); +typedef ZPL_FILE_READ_AT_PROC(zpl_file_read_proc); +typedef ZPL_FILE_WRITE_AT_PROC(zpl_file_write_proc); +typedef ZPL_FILE_SEEK_PROC(zpl_file_seek_proc); +typedef ZPL_FILE_CLOSE_PROC(zpl_file_close_proc); + +struct zpl_file_operations { + zpl_file_read_proc *read_at; + zpl_file_write_proc *write_at; + zpl_file_seek_proc *seek; + zpl_file_close_proc *close; +}; + +extern zpl_file_operations const zpl_default_file_operations; + +typedef zpl_u64 zpl_file_time; +typedef enum zpl_dir_type { + ZPL_DIR_TYPE_FILE, + ZPL_DIR_TYPE_FOLDER, + ZPL_DIR_TYPE_UNKNOWN, +} zpl_dir_type; + +struct zpl_dir_info; + +typedef struct zpl_dir_entry { + char const *filename; + struct zpl_dir_info *dir_info; + zpl_u8 type; +} zpl_dir_entry; + +typedef struct zpl_dir_info { + char const *fullpath; + zpl_dir_entry *entries; // zpl_array + + // Internals + char **filenames; // zpl_array + zpl_string buf; +} zpl_dir_info; + +typedef struct zpl_file { + zpl_file_operations ops; + zpl_file_descriptor fd; + zpl_b32 is_temp; + + char const *filename; + zpl_file_time last_write_time; + zpl_dir_entry *dir; +} zpl_file; + +typedef enum zpl_file_standard_type { + ZPL_FILE_STANDARD_INPUT, + ZPL_FILE_STANDARD_OUTPUT, + ZPL_FILE_STANDARD_ERROR, + + ZPL_FILE_STANDARD_COUNT, +} zpl_file_standard_type; + +/** + * Get standard file I/O. + * @param std Check zpl_file_standard_type + * @return File handle to standard I/O + */ +ZPL_DEF zpl_file *zpl_file_get_standard(zpl_file_standard_type std); + +/** + * Connects a system handle to a ZPL file. + * @param file Pointer to ZPL file + * @param handle Low-level OS handle to connect + */ +ZPL_DEF void zpl_file_connect_handle(zpl_file *file, void *handle); + +/** + * Creates a new file + * @param file + * @param filename + */ +ZPL_DEF zpl_file_error zpl_file_create(zpl_file *file, char const *filename); + +/** + * Opens a file + * @param file + * @param filename + */ +ZPL_DEF zpl_file_error zpl_file_open(zpl_file *file, char const *filename); + +/** + * Opens a file using a specified mode + * @param file + * @param mode Access mode to use + * @param filename + */ +ZPL_DEF zpl_file_error zpl_file_open_mode(zpl_file *file, zpl_file_mode mode, char const *filename); + +/** + * Constructs a new file from data + * @param file + * @param fd Low-level file descriptor to use + * @param ops File operations to rely upon + * @param filename + */ +ZPL_DEF zpl_file_error zpl_file_new(zpl_file *file, zpl_file_descriptor fd, zpl_file_operations ops, char const *filename); + +/** + * Returns a size of the file + * @param file + * @return File size + */ +ZPL_DEF zpl_i64 zpl_file_size(zpl_file *file); + +/** + * Returns the currently opened file's name + * @param file + */ +ZPL_DEF char const *zpl_file_name(zpl_file *file); + +/** + * Truncates the file by a specified size + * @param file + * @param size Size to truncate + */ +ZPL_DEF zpl_file_error zpl_file_truncate(zpl_file *file, zpl_i64 size); + +/** + * Checks whether a file's been changed since the last check + * @param file + */ +ZPL_DEF zpl_b32 zpl_file_has_changed(zpl_file *file); + +/** + * Retrieves a directory listing relative to the file + * @param file + */ +ZPL_DEF void zpl_file_dirinfo_refresh(zpl_file *file); + +/** + * Creates a temporary file + * @param file + */ +zpl_file_error zpl_file_temp(zpl_file *file); + +/** + * Closes the file + * @param file + */ +ZPL_DEF zpl_file_error zpl_file_close(zpl_file *file); + +/** + * Reads file safely + * @param file + * @param buffer Buffer to read to + * @param size Size to read + * @param offset Offset to read from + * @param bytes_read How much data we've actually read + */ +ZPL_DEF_INLINE zpl_b32 zpl_file_read_at_check(zpl_file *file, void *buffer, zpl_isize size, zpl_i64 offset, zpl_isize *bytes_read); + +/** + * Writes to file safely + * @param file + * @param buffer Buffer to read from + * @param size Size to write + * @param offset Offset to write to + * @param bytes_written How much data we've actually written + */ +ZPL_DEF_INLINE zpl_b32 zpl_file_write_at_check(zpl_file *file, void const *buffer, zpl_isize size, zpl_i64 offset, zpl_isize *bytes_written); + + +/** + * Reads file at a specific offset + * @param file + * @param buffer Buffer to read to + * @param size Size to read + * @param offset Offset to read from + * @param bytes_read How much data we've actually read + */ +ZPL_DEF_INLINE zpl_b32 zpl_file_read_at(zpl_file *file, void *buffer, zpl_isize size, zpl_i64 offset); + +/** + * Writes to file at a specific offset + * @param file + * @param buffer Buffer to read from + * @param size Size to write + * @param offset Offset to write to + * @param bytes_written How much data we've actually written + */ +ZPL_DEF_INLINE zpl_b32 zpl_file_write_at(zpl_file *file, void const *buffer, zpl_isize size, zpl_i64 offset); + +/** + * Seeks the file cursor from the beginning of file to a specific position + * @param file + * @param offset Offset to seek to + */ +ZPL_DEF_INLINE zpl_i64 zpl_file_seek(zpl_file *file, zpl_i64 offset); + +/** + * Seeks the file cursor to the end of the file + * @param file + */ +ZPL_DEF_INLINE zpl_i64 zpl_file_seek_to_end(zpl_file *file); + +/** + * Skips N bytes at the current position + * @param file + * @param bytes Bytes to skip + */ +ZPL_DEF_INLINE zpl_i64 zpl_file_skip(zpl_file *file, zpl_i64 bytes); // NOTE: Skips a certain amount of bytes + +/** + * Returns the length from the beginning of the file we've read so far + * @param file + * @return Our current position in file + */ +ZPL_DEF_INLINE zpl_i64 zpl_file_tell(zpl_file *file); + +/** + * Reads from a file + * @param file + * @param buffer Buffer to read to + * @param size Size to read + */ +ZPL_DEF_INLINE zpl_b32 zpl_file_read(zpl_file *file, void *buffer, zpl_isize size); + +/** + * Writes to a file + * @param file + * @param buffer Buffer to read from + * @param size Size to read + */ +ZPL_DEF_INLINE zpl_b32 zpl_file_write(zpl_file *file, void const *buffer, zpl_isize size); + + +typedef struct zpl_file_contents { + zpl_allocator allocator; + void *data; + zpl_isize size; +} zpl_file_contents; + +/** + * Reads the whole file contents + * @param a Allocator to use + * @param zero_terminate End the read data with null terminator + * @param filepath Path to the file + * @return File contents data + */ +ZPL_DEF zpl_file_contents zpl_file_read_contents(zpl_allocator a, zpl_b32 zero_terminate, char const *filepath); + +/** + * Frees the file content data previously read + * @param fc + */ +ZPL_DEF void zpl_file_free_contents(zpl_file_contents *fc); + +/** + * Writes content to a file + */ +ZPL_DEF zpl_b32 zpl_file_write_contents(char const* filepath, void const* buffer, zpl_isize size, zpl_file_error* err); + +/** + * Reads the file as array of lines + * + * Make sure you free both the returned buffer and the lines (zpl_array) + * @param alloc Allocator to use + * @param lines Reference to zpl_array container we store lines to + * @param filename Path to the file + * @param strip_whitespace Strip whitespace when we split to lines? + * @return File content we've read itself + */ +ZPL_DEF char *zpl_file_read_lines(zpl_allocator alloc, zpl_array(char *)*lines, char const *filename, zpl_b32 strip_whitespace); + +//! @} + +/* inlines */ + + +ZPL_IMPL_INLINE zpl_b32 zpl_file_read_at_check(zpl_file *f, void *buffer, zpl_isize size, zpl_i64 offset, zpl_isize *bytes_read) { + if (!f->ops.read_at) f->ops = zpl_default_file_operations; + return f->ops.read_at(f->fd, buffer, size, offset, bytes_read, false); +} + +ZPL_IMPL_INLINE zpl_b32 zpl_file_write_at_check(zpl_file *f, void const *buffer, zpl_isize size, zpl_i64 offset, zpl_isize *bytes_written) { + if (!f->ops.read_at) f->ops = zpl_default_file_operations; + return f->ops.write_at(f->fd, buffer, size, offset, bytes_written); +} + +ZPL_IMPL_INLINE zpl_b32 zpl_file_read_at(zpl_file *f, void *buffer, zpl_isize size, zpl_i64 offset) { + return zpl_file_read_at_check(f, buffer, size, offset, NULL); +} + +ZPL_IMPL_INLINE zpl_b32 zpl_file_write_at(zpl_file *f, void const *buffer, zpl_isize size, zpl_i64 offset) { + return zpl_file_write_at_check(f, buffer, size, offset, NULL); +} + +ZPL_IMPL_INLINE zpl_i64 zpl_file_seek(zpl_file *f, zpl_i64 offset) { + zpl_i64 new_offset = 0; + if (!f->ops.read_at) f->ops = zpl_default_file_operations; + f->ops.seek(f->fd, offset, ZPL_SEEK_WHENCE_BEGIN, &new_offset); + return new_offset; +} + +ZPL_IMPL_INLINE zpl_i64 zpl_file_seek_to_end(zpl_file *f) { + zpl_i64 new_offset = 0; + if (!f->ops.read_at) f->ops = zpl_default_file_operations; + f->ops.seek(f->fd, 0, ZPL_SEEK_WHENCE_END, &new_offset); + return new_offset; +} + +// NOTE: Skips a certain amount of bytes +ZPL_IMPL_INLINE zpl_i64 zpl_file_skip(zpl_file *f, zpl_i64 bytes) { + zpl_i64 new_offset = 0; + if (!f->ops.read_at) f->ops = zpl_default_file_operations; + f->ops.seek(f->fd, bytes, ZPL_SEEK_WHENCE_CURRENT, &new_offset); + return new_offset; +} + +ZPL_IMPL_INLINE zpl_i64 zpl_file_tell(zpl_file *f) { + zpl_i64 new_offset = 0; + if (!f->ops.read_at) f->ops = zpl_default_file_operations; + f->ops.seek(f->fd, 0, ZPL_SEEK_WHENCE_CURRENT, &new_offset); + return new_offset; +} + +ZPL_IMPL_INLINE zpl_b32 zpl_file_read(zpl_file *f, void *buffer, zpl_isize size) { + zpl_i64 cur_offset = zpl_file_tell(f); + zpl_b32 result = zpl_file_read_at(f, buffer, size, zpl_file_tell(f)); + zpl_file_seek(f, cur_offset + size); + return result; +} + +ZPL_IMPL_INLINE zpl_b32 zpl_file_write(zpl_file *f, void const *buffer, zpl_isize size) { + zpl_i64 cur_offset = zpl_file_tell(f); + zpl_b32 result = zpl_file_write_at(f, buffer, size, zpl_file_tell(f)); + zpl_file_seek(f, cur_offset + size); + return result; +} + +ZPL_END_C_DECLS +// file: header/core/file_stream.h + +/** @file file_stream.c +@brief File stream +@defgroup fileio File stream + +File streaming operations on memory. + +@{ +*/ +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +typedef enum { + /* Allows us to write to the buffer directly. Beware: you can not append a new data! */ + ZPL_FILE_STREAM_WRITABLE = ZPL_BIT(0), + + /* Clones the input buffer so you can write (zpl_file_write*) data into it. */ + /* Since we work with a clone, the buffer size can dynamically grow as well. */ + ZPL_FILE_STREAM_CLONE_WRITABLE = ZPL_BIT(1), +} zpl_file_stream_flags; + +/** + * Opens a new memory stream + * @param file + * @param allocator + */ +ZPL_DEF void zpl_file_stream_new(zpl_file* file, zpl_allocator allocator); + +/** + * Opens a memory stream over an existing buffer + * @param file + * @param allocator + * @param buffer Memory to create stream from + * @param size Buffer's size + * @param flags + */ +ZPL_DEF void zpl_file_stream_open(zpl_file* file, zpl_allocator allocator, zpl_u8 *buffer, zpl_isize size, zpl_file_stream_flags flags); + +/** + * Retrieves the stream's underlying buffer and buffer size. + * @param file memory stream + * @param size (Optional) buffer size + */ +ZPL_DEF zpl_u8 *zpl_file_stream_buf(zpl_file* file, zpl_isize *size); + +extern zpl_file_operations const zpl_memory_file_operations; + +//! @} + +ZPL_END_C_DECLS +// file: header/core/file_misc.h + +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +#ifndef ZPL_PATH_SEPARATOR +#if defined(ZPL_SYSTEM_WINDOWS) +#define ZPL_PATH_SEPARATOR '\\' +#else +#define ZPL_PATH_SEPARATOR '/' +#endif +#endif + +/** + * Checks if file/directory exists + * @param filepath + */ +ZPL_DEF zpl_b32 zpl_fs_exists(char const *filepath); + +/** + * Retrieves node's type (file, folder, ...) + * @param path + */ +ZPL_DEF zpl_u8 zpl_fs_get_type(char const *path); + +/** + * Retrieves file's last write time + * @param filepath + */ +ZPL_DEF zpl_file_time zpl_fs_last_write_time(char const *filepath); + +/** + * Copies the file to a directory + * @param existing_filename + * @param new_filename + * @param fail_if_exists + */ +ZPL_DEF zpl_b32 zpl_fs_copy(char const *existing_filename, char const *new_filename, zpl_b32 fail_if_exists); + +/** + * Moves the file to a directory + * @param existing_filename + * @param new_filename + */ +ZPL_DEF zpl_b32 zpl_fs_move(char const *existing_filename, char const *new_filename); + +/** + * Removes a file from a directory + * @param filename + */ +ZPL_DEF zpl_b32 zpl_fs_remove(char const *filename); + +ZPL_DEF_INLINE zpl_b32 zpl_path_is_absolute(char const *path); +ZPL_DEF_INLINE zpl_b32 zpl_path_is_relative(char const *path); +ZPL_DEF_INLINE zpl_b32 zpl_path_is_root(char const *path); + +ZPL_DEF_INLINE char const *zpl_path_base_name(char const *path); +ZPL_DEF_INLINE char const *zpl_path_extension(char const *path); + +ZPL_DEF void zpl_path_fix_slashes(char *path); + +ZPL_DEF zpl_file_error zpl_path_mkdir(char const *path, zpl_i32 mode); +ZPL_DEF zpl_file_error zpl_path_rmdir(char const *path); + +ZPL_DEF char *zpl_path_get_full_name(zpl_allocator a, char const *path); + +/** + * Returns file paths terminated by newline (\n) + * @param alloc [description] + * @param dirname [description] + * @param recurse [description] + * @return [description] + */ +ZPL_DEF /*zpl_string*/char * zpl_path_dirlist(zpl_allocator alloc, char const *dirname, zpl_b32 recurse); + +/** + * Initialize dirinfo from specified path + * @param dir [description] + * @param path [description] + */ +ZPL_DEF void zpl_dirinfo_init(zpl_dir_info *dir, char const *path); +ZPL_DEF void zpl_dirinfo_free(zpl_dir_info *dir); + +/** + * Analyze the entry's dirinfo + * @param dir_entry [description] + */ +ZPL_DEF void zpl_dirinfo_step(zpl_dir_entry *dir_entry); + + +/* inlines */ + +ZPL_IMPL_INLINE zpl_b32 zpl_path_is_absolute(char const *path) { + zpl_b32 result = false; + ZPL_ASSERT_NOT_NULL(path); +#if defined(ZPL_SYSTEM_WINDOWS) + result = (zpl_strlen(path) > 2) && zpl_char_is_alpha(path[0]) && (path[1] == ':' && path[2] == ZPL_PATH_SEPARATOR); +#else + result = (zpl_strlen(path) > 0 && path[0] == ZPL_PATH_SEPARATOR); +#endif + return result; +} + +ZPL_IMPL_INLINE zpl_b32 zpl_path_is_relative(char const *path) { return !zpl_path_is_absolute(path); } + +ZPL_IMPL_INLINE zpl_b32 zpl_path_is_root(char const *path) { + zpl_b32 result = false; + ZPL_ASSERT_NOT_NULL(path); +#if defined(ZPL_SYSTEM_WINDOWS) + result = zpl_path_is_absolute(path) && (zpl_strlen(path) == 3); +#else + result = zpl_path_is_absolute(path) && (zpl_strlen(path) == 1); +#endif + return result; +} + +ZPL_IMPL_INLINE char const *zpl_path_base_name(char const *path) { + char const *ls; + ZPL_ASSERT_NOT_NULL(path); + zpl_path_fix_slashes((char *)path); + ls = zpl_char_last_occurence(path, ZPL_PATH_SEPARATOR); + return (ls == NULL) ? path : ls + 1; +} + +ZPL_IMPL_INLINE char const *zpl_path_extension(char const *path) { + char const *ld; + ZPL_ASSERT_NOT_NULL(path); + ld = zpl_char_last_occurence(path, '.'); + return (ld == NULL) ? NULL : ld + 1; +} + +ZPL_END_C_DECLS +// file: header/core/print.h + +/** @file print.c +@brief Printing methods +@defgroup print Printing methods + +Various printing methods. +@{ +*/ +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +ZPL_DEF zpl_isize zpl_printf(char const *fmt, ...); +ZPL_DEF zpl_isize zpl_printf_va(char const *fmt, va_list va); +ZPL_DEF zpl_isize zpl_printf_err(char const *fmt, ...); +ZPL_DEF zpl_isize zpl_printf_err_va(char const *fmt, va_list va); +ZPL_DEF zpl_isize zpl_fprintf(zpl_file *f, char const *fmt, ...); +ZPL_DEF zpl_isize zpl_fprintf_va(zpl_file *f, char const *fmt, va_list va); + +// NOTE: A locally persisting buffer is used internally +ZPL_DEF char *zpl_bprintf(char const *fmt, ...); + +// NOTE: A locally persisting buffer is used internally +ZPL_DEF char *zpl_bprintf_va(char const *fmt, va_list va); + +ZPL_DEF zpl_isize zpl_snprintf(char *str, zpl_isize n, char const *fmt, ...); +ZPL_DEF zpl_isize zpl_snprintf_va(char *str, zpl_isize n, char const *fmt, va_list va); + +ZPL_END_C_DECLS +// file: header/core/time.h + +/** @file time.c +@brief Time helper methods. +@defgroup time Time helpers + + Helper methods for retrieving the current time in many forms under different precisions. It also offers a simple to use timer library. + + @{ + */ + +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +//! Return CPU timestamp. +ZPL_DEF zpl_u64 zpl_rdtsc(void); + +//! Return relative time (in seconds) since the application start. +ZPL_DEF zpl_f64 zpl_time_rel(void); + +//! Return relative time since the application start. +ZPL_DEF zpl_u64 zpl_time_rel_ms(void); + +//! Return time (in seconds) since 1601-01-01 UTC. +ZPL_DEF zpl_f64 zpl_time_utc(void); + +//! Return time since 1601-01-01 UTC. +ZPL_DEF zpl_u64 zpl_time_utc_ms(void); + +//! Return local system time since 1601-01-01 +ZPL_DEF zpl_u64 zpl_time_tz_ms(void); + +//! Return local system time in seconds since 1601-01-01 +ZPL_DEF zpl_f64 zpl_time_tz(void); + +//! Convert Win32 epoch (1601-01-01 UTC) to UNIX (1970-01-01 UTC) +ZPL_DEF_INLINE zpl_u64 zpl_time_win32_to_unix(zpl_u64 ms); + +//! Convert UNIX (1970-01-01 UTC) to Win32 epoch (1601-01-01 UTC) +ZPL_DEF_INLINE zpl_u64 zpl_time_unix_to_win32(zpl_u64 ms); + +//! Sleep for specified number of milliseconds. +ZPL_DEF void zpl_sleep_ms(zpl_u32 ms); + +//! Sleep for specified number of seconds. +ZPL_DEF_INLINE void zpl_sleep(zpl_f32 s); + +// Deprecated methods +ZPL_DEPRECATED_FOR(10.9.0, zpl_time_rel) +ZPL_DEF_INLINE zpl_f64 zpl_time_now(void); + +ZPL_DEPRECATED_FOR(10.9.0, zpl_time_utc) +ZPL_DEF_INLINE zpl_f64 zpl_utc_time_now(void); + + +#ifndef ZPL__UNIX_TO_WIN32_EPOCH +#define ZPL__UNIX_TO_WIN32_EPOCH 11644473600000ull +#endif + +ZPL_IMPL_INLINE zpl_u64 zpl_time_win32_to_unix(zpl_u64 ms) { + return ms - ZPL__UNIX_TO_WIN32_EPOCH; +} + +ZPL_IMPL_INLINE zpl_u64 zpl_time_unix_to_win32(zpl_u64 ms) { + return ms + ZPL__UNIX_TO_WIN32_EPOCH; +} + +ZPL_IMPL_INLINE void zpl_sleep(zpl_f32 s) { + zpl_sleep_ms((zpl_u32)(s * 1000)); +} + +ZPL_IMPL_INLINE zpl_f64 zpl_time_now() { + return zpl_time_rel(); +} + +ZPL_IMPL_INLINE zpl_f64 zpl_utc_time_now() { + return zpl_time_utc(); +} + +ZPL_END_C_DECLS +// file: header/core/random.h + +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +typedef struct zpl_random { + zpl_u32 offsets[8]; + zpl_u32 value; +} zpl_random; + +// NOTE: Generates from numerous sources to produce a decent pseudo-random seed +ZPL_DEF void zpl_random_init(zpl_random *r); +ZPL_DEF zpl_u32 zpl_random_gen_u32(zpl_random *r); +ZPL_DEF zpl_u32 zpl_random_gen_u32_unique(zpl_random *r); +ZPL_DEF zpl_u64 zpl_random_gen_u64(zpl_random *r); // NOTE: (zpl_random_gen_u32() << 32) | zpl_random_gen_u32() +ZPL_DEF zpl_isize zpl_random_gen_isize(zpl_random *r); +ZPL_DEF zpl_i64 zpl_random_range_i64(zpl_random *r, zpl_i64 lower_inc, zpl_i64 higher_inc); +ZPL_DEF zpl_isize zpl_random_range_isize(zpl_random *r, zpl_isize lower_inc, zpl_isize higher_inc); +ZPL_DEF zpl_f64 zpl_random_range_f64(zpl_random *r, zpl_f64 lower_inc, zpl_f64 higher_inc); + +ZPL_END_C_DECLS +// file: header/core/misc.h + +/** @file misc.c +@brief Various other stuff +@defgroup misc Various other stuff + + Methods that don't belong anywhere but are still very useful in many occasions. + + @{ + */ +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +ZPL_DEF void zpl_exit(zpl_u32 code); +ZPL_DEF void zpl_yield(void); + +//! Returns allocated buffer +ZPL_DEF const char *zpl_get_env(const char *name); +ZPL_DEF const char *zpl_get_env_buf(const char *name); +ZPL_DEF zpl_string zpl_get_env_str(const char *name); +ZPL_DEF void zpl_set_env(const char *name, const char *value); +ZPL_DEF void zpl_unset_env(const char *name); + +ZPL_DEF zpl_u32 zpl_system_command(const char *command, zpl_usize buffer_len, char *buffer); +ZPL_DEF zpl_string zpl_system_command_str(const char *command, zpl_allocator backing); + +ZPL_DEF_INLINE zpl_u16 zpl_endian_swap16(zpl_u16 i); +ZPL_DEF_INLINE zpl_u32 zpl_endian_swap32(zpl_u32 i); +ZPL_DEF_INLINE zpl_u64 zpl_endian_swap64(zpl_u64 i); + +ZPL_DEF_INLINE zpl_isize zpl_count_set_bits(zpl_u64 mask); + +//! @} +//$$ + +ZPL_IMPL_INLINE zpl_u16 zpl_endian_swap16(zpl_u16 i) { + return (i>>8) | (i<<8); +} + +ZPL_IMPL_INLINE zpl_u32 zpl_endian_swap32(zpl_u32 i) { + return (i>>24) |(i<<24) | + ((i&0x00ff0000u)>>8) | ((i&0x0000ff00u)<<8); +} + +ZPL_IMPL_INLINE zpl_u64 zpl_endian_swap64(zpl_u64 i) { + return (i>>56) | (i<<56) | + ((i&0x00ff000000000000ull)>>40) | ((i&0x000000000000ff00ull)<<40) | + ((i&0x0000ff0000000000ull)>>24) | ((i&0x0000000000ff0000ull)<<24) | + ((i&0x000000ff00000000ull)>>8) | ((i&0x00000000ff000000ull)<<8); +} + +ZPL_IMPL_INLINE zpl_i32 zpl_next_pow2(zpl_i32 x) { + x--; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + return x + 1; +} + +ZPL_IMPL_INLINE void zpl_bit_set(zpl_u32* x, zpl_u32 bit) { *x = *x | (1 << bit); } +ZPL_IMPL_INLINE zpl_b8 zpl_bit_get(zpl_u32 x, zpl_u32 bit) { return (x & (1 << bit)); } +ZPL_IMPL_INLINE void zpl_bit_reset(zpl_u32* x, zpl_u32 bit) { *x = *x & ~(1 << bit); } + +ZPL_IMPL_INLINE zpl_isize zpl_count_set_bits(zpl_u64 mask) { + zpl_isize count = 0; + while (mask) { + count += (mask & 1); + mask >>= 1; + } + return count; +} + +ZPL_END_C_DECLS +// file: header/core/sort.h + +/** @file sort.c +@brief Sorting and searching methods. +@defgroup sort Sorting and searching + +Methods for sorting arrays using either Quick/Merge-sort combo or Radix sort. It also contains simple implementation of binary search, as well as an easy to use API to define your own comparators. + +@{ +*/ +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +#define ZPL_COMPARE_PROC(name) int name(void const *a, void const *b) +typedef ZPL_COMPARE_PROC(zpl_compare_proc); + +#define ZPL_COMPARE_PROC_PTR(def) ZPL_COMPARE_PROC((*def)) + +// Procedure pointers +// NOTE: The offset parameter specifies the offset in the structure +// e.g. zpl_i32_cmp(zpl_offset_of(Thing, value)) +// Use 0 if it's just the type instead. + +ZPL_DEF ZPL_COMPARE_PROC_PTR(i16_cmp(zpl_isize offset)); +ZPL_DEF ZPL_COMPARE_PROC_PTR(u8_cmp(zpl_isize offset)); +ZPL_DEF ZPL_COMPARE_PROC_PTR(i32_cmp(zpl_isize offset)); +ZPL_DEF ZPL_COMPARE_PROC_PTR(i64_cmp(zpl_isize offset)); +ZPL_DEF ZPL_COMPARE_PROC_PTR(isize_cmp(zpl_isize offset)); +ZPL_DEF ZPL_COMPARE_PROC_PTR(str_cmp(zpl_isize offset)); +ZPL_DEF ZPL_COMPARE_PROC_PTR(f32_cmp(zpl_isize offset)); +ZPL_DEF ZPL_COMPARE_PROC_PTR(f64_cmp(zpl_isize offset)); + +// TODO: Better sorting algorithms + +//! Sorts an array. + +//! Uses quick sort for large arrays but insertion sort for small ones. +#define zpl_sort_array(array, count, compare_proc) zpl_sort(array, count, zpl_size_of(*(array)), compare_proc) + +//! Perform sorting operation on a memory location with a specified item count and size. +ZPL_DEF void zpl_sort(void *base, zpl_isize count, zpl_isize size, zpl_compare_proc compare_proc); + +// NOTE: the count of temp == count of items +#define zpl_radix_sort(Type) zpl_radix_sort_##Type +#define ZPL_RADIX_SORT_PROC(Type) void zpl_radix_sort(Type)(zpl_##Type * items, zpl_##Type * temp, zpl_isize count) + +ZPL_DEF ZPL_RADIX_SORT_PROC(u8); +ZPL_DEF ZPL_RADIX_SORT_PROC(u16); +ZPL_DEF ZPL_RADIX_SORT_PROC(u32); +ZPL_DEF ZPL_RADIX_SORT_PROC(u64); + +//! Performs binary search on an array. + +//! Returns index or -1 if not found +#define zpl_binary_search_array(array, count, key, compare_proc) \ +zpl_binary_search(array, count, zpl_size_of(*(array)), key, compare_proc) + +//! Performs binary search on a memory location with specified item count and size. +ZPL_DEF_INLINE zpl_isize zpl_binary_search(void const *base, zpl_isize count, zpl_isize size, void const *key, + zpl_compare_proc compare_proc); + +#define zpl_shuffle_array(array, count) zpl_shuffle(array, count, zpl_size_of(*(array))) + +//! Shuffles a memory. +ZPL_DEF void zpl_shuffle(void *base, zpl_isize count, zpl_isize size); + +#define zpl_reverse_array(array, count) zpl_reverse(array, count, zpl_size_of(*(array))) + +//! Reverses memory's contents +ZPL_DEF void zpl_reverse(void *base, zpl_isize count, zpl_isize size); + +//! @} + + +ZPL_IMPL_INLINE zpl_isize zpl_binary_search(void const *base, zpl_isize count, zpl_isize size, void const *key, + zpl_compare_proc compare_proc) { + zpl_isize start = 0; + zpl_isize end = count; + + while (start < end) { + zpl_isize mid = start + (end - start) / 2; + zpl_isize result = compare_proc(key, cast(zpl_u8 *) base + mid * size); + if (result < 0) + end = mid; + else if (result > 0) + start = mid + 1; + else + return mid; + } + + return -1; +} + +ZPL_END_C_DECLS +#endif + +#if defined(ZPL_MODULE_TIMER) +// file: header/timer.h + +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +typedef void (*zpl_timer_cb)(void *data); + +//! Timer data structure +typedef struct zpl_timer { + zpl_timer_cb callback; + zpl_b32 enabled; + zpl_i32 remaining_calls; + zpl_i32 initial_calls; + zpl_f64 next_call_ts; + zpl_f64 duration; + void *user_data; +} zpl_timer; + +typedef zpl_timer *zpl_timer_pool; ///< zpl_array + +//! Initialize timer pool. +#define zpl_timer_init(pool, allocator) zpl_array_init(pool, allocator) + +//! Add new timer to pool and return it. +ZPL_DEF zpl_timer *zpl_timer_add(zpl_timer_pool pool); + +//! Perform timer pool update. + +//! Traverse over all timers and update them accordingly. Should be called by Main Thread in a tight loop. +ZPL_DEF void zpl_timer_update(zpl_timer_pool pool); + +//! Set up timer. + +//! Set up timer with specific options. +//! @param timer +//! @param duration How long/often to fire a timer. +//! @param count How many times we fire a timer. Use -1 for infinity. +//! @param callback A method to execute once a timer triggers. +ZPL_DEF void zpl_timer_set(zpl_timer *timer, zpl_f64 /* microseconds */ duration, zpl_i32 /* -1 for INFINITY */ count, + zpl_timer_cb callback); + +//! Start timer with specified delay. +ZPL_DEF void zpl_timer_start(zpl_timer *timer, zpl_f64 delay_start); + +//! Stop timer and prevent it from triggering. +ZPL_DEF void zpl_timer_stop(zpl_timer *timer); + +ZPL_END_C_DECLS +#endif + +#if defined(ZPL_MODULE_HASHING) +// file: header/hashing.h + +/** @file hashing.c +@brief Hashing and Checksum Functions +@defgroup hashing Hashing and Checksum Functions + +Several hashing methods used by ZPL internally but possibly useful outside of it. Contains: adler32, crc32/64, fnv32/64/a and murmur32/64 + +@{ +*/ + +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +ZPL_DEF zpl_u32 zpl_adler32(void const *data, zpl_isize len); + +ZPL_DEF zpl_u32 zpl_crc32(void const *data, zpl_isize len); +ZPL_DEF zpl_u64 zpl_crc64(void const *data, zpl_isize len); + +// These use FNV-1 algorithm +ZPL_DEF zpl_u32 zpl_fnv32(void const *data, zpl_isize len); +ZPL_DEF zpl_u64 zpl_fnv64(void const *data, zpl_isize len); +ZPL_DEF zpl_u32 zpl_fnv32a(void const *data, zpl_isize len); +ZPL_DEF zpl_u64 zpl_fnv64a(void const *data, zpl_isize len); + +ZPL_DEF zpl_u8 *zpl_base64_encode(zpl_allocator a, void const *data, zpl_isize len); +ZPL_DEF zpl_u8 *zpl_base64_decode(zpl_allocator a, void const *data, zpl_isize len); + +//! Based on MurmurHash3 +ZPL_DEF zpl_u32 zpl_murmur32_seed(void const *data, zpl_isize len, zpl_u32 seed); + +//! Based on MurmurHash2 +ZPL_DEF zpl_u64 zpl_murmur64_seed(void const *data, zpl_isize len, zpl_u64 seed); + +//! Default seed of 0x9747b28c +ZPL_DEF_INLINE zpl_u32 zpl_murmur32(void const *data, zpl_isize len); + +//! Default seed of 0x9747b28c +ZPL_DEF_INLINE zpl_u64 zpl_murmur64(void const *data, zpl_isize len); + +//! @} + +ZPL_IMPL_INLINE zpl_u32 zpl_murmur32(void const *data, zpl_isize len) { return zpl_murmur32_seed(data, len, 0x9747b28c); } +ZPL_IMPL_INLINE zpl_u64 zpl_murmur64(void const *data, zpl_isize len) { return zpl_murmur64_seed(data, len, 0x9747b28c); } + +ZPL_END_C_DECLS +#endif + +#if defined(ZPL_MODULE_REGEX) +// file: header/regex.h + +/** @file regex.c +@brief Regular expressions parser. +@defgroup regex Regex processor + +Port of gb_regex with several bugfixes applied. This is a simple regex library and is fast to perform. + +Supported Matching: + @n ^ - Beginning of string + @n $ - End of string + @n . - Match one (anything) + @n | - Branch (or) + @n () - Capturing group + @n [] - Any character included in set + @n [^] - Any character excluded from set + @n + - One or more (greedy) + @n +? - One or more (non-greedy) + @n * - Zero or more (greedy) + @n *? - Zero or more (non-greedy) + @n ? - Zero or once + @n [BACKSLASH]XX - Hex decimal digit (must be 2 digits) + @n [BACKSLASH]meta - Meta character + @n [BACKSLASH]s - Whitespace + @n [BACKSLASH]S - Not whitespace + @n [BACKSLASH]d - Digit + @n [BACKSLASH]D - Not digit + @n [BACKSLASH]a - Alphabetic character + @n [BACKSLASH]l - Lower case letter + @n [BACKSLASH]u - Upper case letter + @n [BACKSLASH]w - Word + @n [BACKSLASH]W - Not word + @n [BACKSLASH]x - Hex Digit + @n [BACKSLASH]p - Printable ASCII character + @n --Whitespace-- + @n [BACKSLASH]t - Tab + @n [BACKSLASH]n - New line + @n [BACKSLASH]r - Return carriage + @n [BACKSLASH]v - Vertical Tab + @n [BACKSLASH]f - Form feed + + @{ +*/ +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +typedef struct zpl_re { + zpl_allocator backing; + zpl_isize capture_count; + char *buf; + zpl_isize buf_len, buf_cap; + zpl_b32 can_realloc; +} zpl_re; + +typedef struct zpl_re_capture { + char const *str; + zpl_isize len; +} zpl_re_capture; + +#define zplRegexError zpl_regex_error +typedef enum zpl_regex_error { + ZPL_RE_ERROR_NONE, + ZPL_RE_ERROR_NO_MATCH, + ZPL_RE_ERROR_TOO_LONG, + ZPL_RE_ERROR_MISMATCHED_CAPTURES, + ZPL_RE_ERROR_MISMATCHED_BLOCKS, + ZPL_RE_ERROR_BRANCH_FAILURE, + ZPL_RE_ERROR_INVALID_QUANTIFIER, + ZPL_RE_ERROR_INTERNAL_FAILURE, +} zpl_regex_error; + +//! Compile regex pattern. +ZPL_DEF zpl_regex_error zpl_re_compile(zpl_re *re, zpl_allocator backing, char const *pattern, zpl_isize pattern_len); + +//! Compile regex pattern using a buffer. +ZPL_DEF zpl_regex_error zpl_re_compile_from_buffer(zpl_re *re, char const *pattern, zpl_isize pattern_len, void *buffer, zpl_isize buffer_len); + +//! Destroy regex object. +ZPL_DEF void zpl_re_destroy(zpl_re *re); + +//! Retrieve number of retrievable captures. +ZPL_DEF zpl_isize zpl_re_capture_count(zpl_re *re); + +//! Match input string and output captures of the occurence. +ZPL_DEF zpl_b32 zpl_re_match(zpl_re *re, char const *str, zpl_isize str_len, zpl_re_capture *captures, zpl_isize max_capture_count, zpl_isize *offset); + +//! Match all occurences in an input string and output them into captures. Array of captures is allocated on the heap and needs to be freed afterwards. +ZPL_DEF zpl_b32 zpl_re_match_all(zpl_re *re, char const *str, zpl_isize str_len, zpl_isize max_capture_count, zpl_re_capture **out_captures); + +ZPL_END_C_DECLS +#endif + +#if defined(ZPL_MODULE_DLL) +// file: header/dll.h + +/** @file dll.c +@brief DLL Handling +@defgroup dll DLL handling + +@{ +*/ +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +typedef void *zpl_dll_handle; +typedef void (*zpl_dll_proc)(void); + +ZPL_DEF zpl_dll_handle zpl_dll_load(char const *filepath); +ZPL_DEF void zpl_dll_unload(zpl_dll_handle dll); +ZPL_DEF zpl_dll_proc zpl_dll_proc_address(zpl_dll_handle dll, char const *proc_name); + +//! @} + +ZPL_END_C_DECLS +#endif + +#if defined(ZPL_MODULE_OPTS) +// file: header/opts.h + +/** @file opts.c +@brief CLI options processor +@defgroup cli CLI options processor + + Opts is a CLI options parser, it can parse flags, switches and arguments from command line + and offers an easy way to express input errors as well as the ability to display help screen. + +@{ + */ +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +typedef enum { + ZPL_OPTS_STRING, + ZPL_OPTS_FLOAT, + ZPL_OPTS_FLAG, + ZPL_OPTS_INT, +} zpl_opts_types; + +typedef struct { + char const *name, *lname, *desc; + zpl_u8 type; + zpl_b32 met, pos; + + //! values + union { + zpl_string text; + zpl_i64 integer; + zpl_f64 real; + }; +} zpl_opts_entry; + +typedef enum { + ZPL_OPTS_ERR_VALUE, + ZPL_OPTS_ERR_OPTION, + ZPL_OPTS_ERR_EXTRA_VALUE, + ZPL_OPTS_ERR_MISSING_VALUE, +} zpl_opts_err_type; + +typedef struct { + char *val; + zpl_u8 type; +} zpl_opts_err; + +typedef struct { + zpl_allocator alloc; + zpl_opts_entry *entries; ///< zpl_array + zpl_opts_err *errors; ///< zpl_array + zpl_opts_entry **positioned; ///< zpl_array + char const *appname; +} zpl_opts; + +//! Initializes options parser. + +//! Initializes CLI options parser using specified memory allocator and provided application name. +//! @param opts Options parser to initialize. +//! @param allocator Memory allocator to use. (ex. zpl_heap()) +//! @param app Application name displayed in help screen. +ZPL_DEF void zpl_opts_init(zpl_opts *opts, zpl_allocator allocator, char const *app); + +//! Releases the resources used by options parser. +ZPL_DEF void zpl_opts_free(zpl_opts *opts); + +//! Registers an option. + +//! Registers an option with its short and long name, specifies option's type and its description. +//! @param opts Options parser to add to. +//! @param lname Shorter name of option. (ex. "f") +//! @param name Full name of option. (ex. "foo") Note that rest of the module uses longer names to manipulate opts. +//! @param desc Description shown in the help screen. +//! @param type Option's type (see zpl_opts_types) +//! @see zpl_opts_types +ZPL_DEF void zpl_opts_add(zpl_opts *opts, char const *name, char const *lname, const char *desc, zpl_u8 type); + +//! Registers option as positional. + +//! Registers added option as positional, so that we can pass it anonymously. Arguments are expected on the command input in the same order they were registered as. +//! @param opts +//! @param name Name of already registered option. +ZPL_DEF void zpl_opts_positional_add(zpl_opts *opts, char const *name); + +//! Compiles CLI arguments. + +// This method takes CLI arguments as input and processes them based on rules that were set up. +//! @param opts +//! @param argc Argument count in an array. +//! @param argv Array of arguments. +ZPL_DEF zpl_b32 zpl_opts_compile(zpl_opts *opts, int argc, char **argv); + +//! Prints out help screen. + +//! Prints out help screen with example usage of application as well as with all the flags available. +ZPL_DEF void zpl_opts_print_help(zpl_opts *opts); + +//! Prints out parsing errors. + +//! Prints out possible errors caused by CLI input. +ZPL_DEF void zpl_opts_print_errors(zpl_opts *opts); + +//! Fetches a string from an option. + +//! @param opts +//! @param name Name of an option. +//! @param fallback Fallback string we return if option wasn't found. +ZPL_DEF zpl_string zpl_opts_string(zpl_opts *opts, char const *name, char const *fallback); + +//! Fetches a real number from an option. + +//! @param opts +//! @param name Name of an option. +//! @param fallback Fallback real number we return if option was not found. +ZPL_DEF zpl_f64 zpl_opts_real(zpl_opts *opts, char const *name, zpl_f64 fallback); + +//! Fetches an integer number from an option. + +//! @param opts +//! @param name Name of an option. +//! @param fallback Fallback integer number we return if option was not found. +ZPL_DEF zpl_i64 zpl_opts_integer(zpl_opts *opts, char const *name, zpl_i64 fallback); + +//! Checks whether an option was used. + +//! @param opts +//! @param name Name of an option. +ZPL_DEF zpl_b32 zpl_opts_has_arg(zpl_opts *opts, char const *name); + +//! Checks whether all positionals have been passed in. +ZPL_DEF zpl_b32 zpl_opts_positionals_filled(zpl_opts *opts); + +//! @} + +ZPL_END_C_DECLS +#endif + +#if defined(ZPL_MODULE_PROCESS) +// file: header/process.h + +/** @file process.c +@brief Process creation and manipulation methods +@defgroup process Process creation and manipulation methods + +Gives you the ability to create a new process, wait for it to end or terminate it. +It also exposes standard I/O with configurable options. + +@{ +*/ +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS +// TODO(zaklaus): Add Linux support + +typedef enum { + ZPL_PR_OPTS_COMBINE_STD_OUTPUT = ZPL_BIT(1), + ZPL_PR_OPTS_INHERIT_ENV = ZPL_BIT(2), + ZPL_PR_OPTS_CUSTOM_ENV = ZPL_BIT(3), +} zpl_pr_opts; + +typedef struct { + zpl_file in, out, err; + void *f_stdin, *f_stdout, *f_stderr; +#ifdef ZPL_SYSTEM_WINDOWS + void *win32_handle; +#else + // todo +#endif +} zpl_pr; + +typedef struct { + char *con_title; + char *workdir; + + zpl_isize env_count; + char **env; // format: "var=name" + + zpl_u32 posx, posy; + zpl_u32 resx, resy; + zpl_u32 bufx, bufy; + zpl_u32 fill_attr; + zpl_u32 flags; + zpl_b32 show_window; +} zpl_pr_si; + +ZPL_DEF zpl_i32 zpl_pr_create(zpl_pr *process, const char **args, zpl_isize argc, zpl_pr_si si, zpl_pr_opts options); +ZPL_DEF void zpl_pr_destroy(zpl_pr *process); +ZPL_DEF void zpl_pr_terminate(zpl_pr *process, zpl_i32 err_code); +ZPL_DEF zpl_i32 zpl_pr_join(zpl_pr *process); + +//! @} +ZPL_END_C_DECLS +#endif + +#if defined(ZPL_MODULE_MATH) +// file: header/math.h + +/** @file math.c +@brief Math operations +@defgroup math Math operations + +OpenGL gamedev friendly library for math. + +@{ +*/ +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +typedef union zpl_vec2 { + struct { + zpl_f32 x, y; + }; + struct { + zpl_f32 s, t; + }; + zpl_f32 e[2]; +} zpl_vec2; + +typedef union zpl_vec3 { + struct { + zpl_f32 x, y, z; + }; + struct { + zpl_f32 r, g, b; + }; + struct { + zpl_f32 s, t, p; + }; + + zpl_vec2 xy; + zpl_vec2 st; + zpl_f32 e[3]; +} zpl_vec3; + +typedef union zpl_vec4 { + struct { + zpl_f32 x, y, z, w; + }; + struct { + zpl_f32 r, g, b, a; + }; + struct { + zpl_f32 s, t, p, q; + }; + struct { + zpl_vec2 xy, zw; + }; + struct { + zpl_vec2 st, pq; + }; + zpl_vec3 xyz; + zpl_vec3 rgb; + zpl_f32 e[4]; +} zpl_vec4; + +typedef union zpl_mat2 { + struct { + zpl_vec2 x, y; + }; + zpl_vec2 col[2]; + zpl_f32 e[4]; +} zpl_mat2; + +typedef union zpl_mat3 { + struct { + zpl_vec3 x, y, z; + }; + zpl_vec3 col[3]; + zpl_f32 e[9]; +} zpl_mat3; + +typedef union zpl_mat4 { + struct { + zpl_vec4 x, y, z, w; + }; + zpl_vec4 col[4]; + zpl_f32 e[16]; +} zpl_mat4; + +typedef union zpl_quat { + struct { + zpl_f32 x, y, z, w; + }; + zpl_vec4 xyzw; + zpl_vec3 xyz; + zpl_f32 e[4]; +} zpl_quat; + +typedef union zpl_plane { + struct { + zpl_f32 a, b, c, d; + }; + zpl_vec4 xyzw; + zpl_vec3 n; + zpl_f32 e[4]; +} zpl_plane; + +typedef struct zpl_frustum { + zpl_plane x1; + zpl_plane x2; + zpl_plane y1; + zpl_plane y2; + zpl_plane z1; + zpl_plane z2; +} zpl_frustum; + +typedef zpl_f32 zpl_float2[2]; +typedef zpl_f32 zpl_float3[3]; +typedef zpl_f32 zpl_float4[4]; + +typedef struct zpl_rect2 { + zpl_vec2 pos, dim; +} zpl_rect2; +typedef struct zpl_rect3 { + zpl_vec3 pos, dim; +} zpl_rect3; + +typedef struct zpl_aabb2 { + zpl_vec2 centre, half_size; +} zpl_aabb2; +typedef struct zpl_aabb3 { + zpl_vec3 centre, half_size; +} zpl_aabb3; + +typedef short zpl_half; + +#ifndef ZPL_CONSTANTS +#define ZPL_CONSTANTS +#define ZPL_EPSILON 1.19209290e-7f +#define ZPL_ZERO 0.0f +#define ZPL_ONE 1.0f +#define ZPL_TWO_THIRDS 0.666666666666666666666666666666666666667f + +#define ZPL_TAU 6.28318530717958647692528676655900576f +#define ZPL_PI 3.14159265358979323846264338327950288f +#define ZPL_ONE_OVER_TAU 0.636619772367581343075535053490057448f +#define ZPL_ONE_OVER_PI 0.159154943091895335768883763372514362f + +#define ZPL_TAU_OVER_2 3.14159265358979323846264338327950288f +#define ZPL_TAU_OVER_4 1.570796326794896619231321691639751442f +#define ZPL_TAU_OVER_8 0.785398163397448309615660845819875721f + +#define ZPL_E 2.71828182845904523536f +#define ZPL_SQRT_TWO 1.41421356237309504880168872420969808f +#define ZPL_SQRT_THREE 1.73205080756887729352744634150587236f +#define ZPL_SQRT_FIVE 2.23606797749978969640917366873127623f + +#define ZPL_LOG_TWO 0.693147180559945309417232121458176568f +#define ZPL_LOG_TEN 2.30258509299404568401799145468436421f +#endif // ZPL_CONSTANTS + +#ifndef zpl_square +#define zpl_square(x) ((x) * (x)) +#endif + +#ifndef zpl_cube +#define zpl_cube(x) ((x) * (x) * (x)) +#endif + +#ifndef zpl_sign +#define zpl_sign(x) ((x) >= 0 ? 1 : -1) +#endif + +ZPL_DEF zpl_f32 zpl_to_radians(zpl_f32 degrees); +ZPL_DEF zpl_f32 zpl_to_degrees(zpl_f32 radians); + +/* NOTE: Because to interpolate angles */ +ZPL_DEF zpl_f32 zpl_angle_diff(zpl_f32 radians_a, zpl_f32 radians_b); + +ZPL_DEF zpl_f32 zpl_copy_sign(zpl_f32 x, zpl_f32 y); +ZPL_DEF zpl_f32 zpl_remainder(zpl_f32 x, zpl_f32 y); +ZPL_DEF zpl_f32 zpl_mod(zpl_f32 x, zpl_f32 y); +ZPL_DEF zpl_f64 zpl_copy_sign64(zpl_f64 x, zpl_f64 y); +ZPL_DEF zpl_f64 zpl_floor64(zpl_f64 x); +ZPL_DEF zpl_f64 zpl_ceil64(zpl_f64 x); +ZPL_DEF zpl_f64 zpl_round64(zpl_f64 x); +ZPL_DEF zpl_f64 zpl_remainder64(zpl_f64 x, zpl_f64 y); +ZPL_DEF zpl_f64 zpl_abs64(zpl_f64 x); +ZPL_DEF zpl_f64 zpl_sign64(zpl_f64 x); +ZPL_DEF zpl_f64 zpl_mod64(zpl_f64 x, zpl_f64 y); +ZPL_DEF zpl_f32 zpl_sqrt(zpl_f32 a); +ZPL_DEF zpl_f32 zpl_rsqrt(zpl_f32 a); +ZPL_DEF zpl_f32 zpl_quake_rsqrt(zpl_f32 a); /* NOTE: It's probably better to use 1.0f/zpl_sqrt(a) + * And for simd, there is usually isqrt functions too! + */ +ZPL_DEF zpl_f32 zpl_sin(zpl_f32 radians); +ZPL_DEF zpl_f32 zpl_cos(zpl_f32 radians); +ZPL_DEF zpl_f32 zpl_tan(zpl_f32 radians); +ZPL_DEF zpl_f32 zpl_arcsin(zpl_f32 a); +ZPL_DEF zpl_f32 zpl_arccos(zpl_f32 a); +ZPL_DEF zpl_f32 zpl_arctan(zpl_f32 a); +ZPL_DEF zpl_f32 zpl_arctan2(zpl_f32 y, zpl_f32 x); + +ZPL_DEF zpl_f32 zpl_exp(zpl_f32 x); +ZPL_DEF zpl_f32 zpl_exp2(zpl_f32 x); +ZPL_DEF zpl_f32 zpl_log(zpl_f32 x); +ZPL_DEF zpl_f32 zpl_log2(zpl_f32 x); +ZPL_DEF zpl_f32 zpl_fast_exp(zpl_f32 x); /* NOTE: Only valid from -1 <= x <= +1 */ +ZPL_DEF zpl_f32 zpl_fast_exp2(zpl_f32 x); /* NOTE: Only valid from -1 <= x <= +1 */ +ZPL_DEF zpl_f32 zpl_pow(zpl_f32 x, zpl_f32 y); /* x^y */ + +ZPL_DEF zpl_f32 zpl_round(zpl_f32 x); +ZPL_DEF zpl_f32 zpl_floor(zpl_f32 x); +ZPL_DEF zpl_f32 zpl_ceil(zpl_f32 x); + +ZPL_DEF zpl_f32 zpl_half_to_float(zpl_half value); +ZPL_DEF zpl_half zpl_float_to_half(zpl_f32 value); + +ZPL_DEF zpl_vec2 zpl_vec2f_zero(void); +ZPL_DEF zpl_vec2 zpl_vec2f(zpl_f32 x, zpl_f32 y); +ZPL_DEF zpl_vec2 zpl_vec2fv(zpl_f32 x[2]); + +ZPL_DEF zpl_vec3 zpl_vec3f_zero(void); +ZPL_DEF zpl_vec3 zpl_vec3f(zpl_f32 x, zpl_f32 y, zpl_f32 z); +ZPL_DEF zpl_vec3 zpl_vec3fv(zpl_f32 x[3]); + +ZPL_DEF zpl_vec4 zpl_vec4f_zero(void); +ZPL_DEF zpl_vec4 zpl_vec4f(zpl_f32 x, zpl_f32 y, zpl_f32 z, zpl_f32 w); +ZPL_DEF zpl_vec4 zpl_vec4fv(zpl_f32 x[4]); + +ZPL_DEF zpl_f32 zpl_vec2_max(zpl_vec2 v); +ZPL_DEF zpl_f32 zpl_vec2_side(zpl_vec2 p, zpl_vec2 q, zpl_vec2 r); +ZPL_DEF void zpl_vec2_add(zpl_vec2 *d, zpl_vec2 v0, zpl_vec2 v1); +ZPL_DEF void zpl_vec2_sub(zpl_vec2 *d, zpl_vec2 v0, zpl_vec2 v1); +ZPL_DEF void zpl_vec2_mul(zpl_vec2 *d, zpl_vec2 v, zpl_f32 s); +ZPL_DEF void zpl_vec2_div(zpl_vec2 *d, zpl_vec2 v, zpl_f32 s); + +ZPL_DEF zpl_f32 zpl_vec3_max(zpl_vec3 v); +ZPL_DEF void zpl_vec3_add(zpl_vec3 *d, zpl_vec3 v0, zpl_vec3 v1); +ZPL_DEF void zpl_vec3_sub(zpl_vec3 *d, zpl_vec3 v0, zpl_vec3 v1); +ZPL_DEF void zpl_vec3_mul(zpl_vec3 *d, zpl_vec3 v, zpl_f32 s); +ZPL_DEF void zpl_vec3_div(zpl_vec3 *d, zpl_vec3 v, zpl_f32 s); + +ZPL_DEF void zpl_vec4_add(zpl_vec4 *d, zpl_vec4 v0, zpl_vec4 v1); +ZPL_DEF void zpl_vec4_sub(zpl_vec4 *d, zpl_vec4 v0, zpl_vec4 v1); +ZPL_DEF void zpl_vec4_mul(zpl_vec4 *d, zpl_vec4 v, zpl_f32 s); +ZPL_DEF void zpl_vec4_div(zpl_vec4 *d, zpl_vec4 v, zpl_f32 s); + +ZPL_DEF void zpl_vec2_addeq(zpl_vec2 *d, zpl_vec2 v); +ZPL_DEF void zpl_vec2_subeq(zpl_vec2 *d, zpl_vec2 v); +ZPL_DEF void zpl_vec2_muleq(zpl_vec2 *d, zpl_f32 s); +ZPL_DEF void zpl_vec2_diveq(zpl_vec2 *d, zpl_f32 s); + +ZPL_DEF void zpl_vec3_addeq(zpl_vec3 *d, zpl_vec3 v); +ZPL_DEF void zpl_vec3_subeq(zpl_vec3 *d, zpl_vec3 v); +ZPL_DEF void zpl_vec3_muleq(zpl_vec3 *d, zpl_f32 s); +ZPL_DEF void zpl_vec3_diveq(zpl_vec3 *d, zpl_f32 s); + +ZPL_DEF void zpl_vec4_addeq(zpl_vec4 *d, zpl_vec4 v); +ZPL_DEF void zpl_vec4_subeq(zpl_vec4 *d, zpl_vec4 v); +ZPL_DEF void zpl_vec4_muleq(zpl_vec4 *d, zpl_f32 s); +ZPL_DEF void zpl_vec4_diveq(zpl_vec4 *d, zpl_f32 s); + +ZPL_DEF zpl_f32 zpl_vec2_dot(zpl_vec2 v0, zpl_vec2 v1); +ZPL_DEF zpl_f32 zpl_vec3_dot(zpl_vec3 v0, zpl_vec3 v1); +ZPL_DEF zpl_f32 zpl_vec4_dot(zpl_vec4 v0, zpl_vec4 v1); + +ZPL_DEF void zpl_vec2_cross(zpl_f32 *d, zpl_vec2 v0, zpl_vec2 v1); +ZPL_DEF void zpl_vec3_cross(zpl_vec3 *d, zpl_vec3 v0, zpl_vec3 v1); + +ZPL_DEF zpl_f32 zpl_vec2_mag2(zpl_vec2 v); +ZPL_DEF zpl_f32 zpl_vec3_mag2(zpl_vec3 v); +ZPL_DEF zpl_f32 zpl_vec4_mag2(zpl_vec4 v); + +ZPL_DEF zpl_f32 zpl_vec2_mag(zpl_vec2 v); +ZPL_DEF zpl_f32 zpl_vec3_mag(zpl_vec3 v); +ZPL_DEF zpl_f32 zpl_vec4_mag(zpl_vec4 v); + +ZPL_DEF void zpl_vec2_norm(zpl_vec2 *d, zpl_vec2 v); +ZPL_DEF void zpl_vec3_norm(zpl_vec3 *d, zpl_vec3 v); +ZPL_DEF void zpl_vec4_norm(zpl_vec4 *d, zpl_vec4 v); + +ZPL_DEF void zpl_vec2_norm0(zpl_vec2 *d, zpl_vec2 v); +ZPL_DEF void zpl_vec3_norm0(zpl_vec3 *d, zpl_vec3 v); +ZPL_DEF void zpl_vec4_norm0(zpl_vec4 *d, zpl_vec4 v); + +ZPL_DEF void zpl_vec2_reflect(zpl_vec2 *d, zpl_vec2 i, zpl_vec2 n); +ZPL_DEF void zpl_vec3_reflect(zpl_vec3 *d, zpl_vec3 i, zpl_vec3 n); +ZPL_DEF void zpl_vec2_refract(zpl_vec2 *d, zpl_vec2 i, zpl_vec2 n, zpl_f32 eta); +ZPL_DEF void zpl_vec3_refract(zpl_vec3 *d, zpl_vec3 i, zpl_vec3 n, zpl_f32 eta); + +ZPL_DEF zpl_f32 zpl_vec2_aspect_ratio(zpl_vec2 v); + +ZPL_DEF void zpl_mat2_identity(zpl_mat2 *m); +ZPL_DEF void zpl_float22_identity(zpl_f32 m[2][2]); + +ZPL_DEF void zpl_mat2_transpose(zpl_mat2 *m); +ZPL_DEF void zpl_mat2_mul(zpl_mat2 *out, zpl_mat2 *m1, zpl_mat2 *m2); +ZPL_DEF void zpl_mat2_mul_vec2(zpl_vec2 *out, zpl_mat2 *m, zpl_vec2 in); +ZPL_DEF void zpl_mat2_inverse(zpl_mat2 *out, zpl_mat2 *in); +ZPL_DEF zpl_f32 zpl_mat2_determinate(zpl_mat2 *m); + +ZPL_DEF zpl_mat2 *zpl_mat2_v(zpl_vec2 m[2]); +ZPL_DEF zpl_mat2 *zpl_mat2_f(zpl_f32 m[2][2]); +ZPL_DEF zpl_float2 *zpl_float22_m(zpl_mat2 *m); +ZPL_DEF zpl_float2 *zpl_float22_v(zpl_vec2 m[2]); +ZPL_DEF zpl_float2 *zpl_float22_4(zpl_f32 m[4]); + +ZPL_DEF void zpl_float22_transpose(zpl_f32 (*vec)[2]); +ZPL_DEF void zpl_float22_mul(zpl_f32 (*out)[2], zpl_f32 (*mat1)[2], zpl_f32 (*mat2)[2]); +ZPL_DEF void zpl_float22_mul_vec2(zpl_vec2 *out, zpl_f32 m[2][2], zpl_vec2 in); + +ZPL_DEF void zpl_mat3_identity(zpl_mat3 *m); +ZPL_DEF void zpl_float33_identity(zpl_f32 m[3][3]); + +ZPL_DEF void zpl_mat3_transpose(zpl_mat3 *m); +ZPL_DEF void zpl_mat3_mul(zpl_mat3 *out, zpl_mat3 *m1, zpl_mat3 *m2); +ZPL_DEF void zpl_mat3_mul_vec3(zpl_vec3 *out, zpl_mat3 *m, zpl_vec3 in); +ZPL_DEF void zpl_mat3_inverse(zpl_mat3 *out, zpl_mat3 *in); +ZPL_DEF zpl_f32 zpl_mat3_determinate(zpl_mat3 *m); + +ZPL_DEF zpl_mat3 *zpl_mat3_v(zpl_vec3 m[3]); +ZPL_DEF zpl_mat3 *zpl_mat3_f(zpl_f32 m[3][3]); + +ZPL_DEF zpl_float3 *zpl_float33_m(zpl_mat3 *m); +ZPL_DEF zpl_float3 *zpl_float33_v(zpl_vec3 m[3]); +ZPL_DEF zpl_float3 *zpl_float33_9(zpl_f32 m[9]); + +ZPL_DEF void zpl_float33_transpose(zpl_f32 (*vec)[3]); +ZPL_DEF void zpl_float33_mul(zpl_f32 (*out)[3], zpl_f32 (*mat1)[3], zpl_f32 (*mat2)[3]); +ZPL_DEF void zpl_float33_mul_vec3(zpl_vec3 *out, zpl_f32 m[3][3], zpl_vec3 in); + +ZPL_DEF void zpl_mat4_identity(zpl_mat4 *m); +ZPL_DEF void zpl_float44_identity(zpl_f32 m[4][4]); +ZPL_DEF void zpl_mat4_copy(zpl_mat4* out, zpl_mat4* m); + +ZPL_DEF void zpl_mat4_transpose(zpl_mat4 *m); +ZPL_DEF void zpl_mat4_mul(zpl_mat4 *out, zpl_mat4 *m1, zpl_mat4 *m2); +ZPL_DEF void zpl_mat4_mul_vec4(zpl_vec4 *out, zpl_mat4 *m, zpl_vec4 in); +ZPL_DEF void zpl_mat4_inverse(zpl_mat4 *out, zpl_mat4 *in); + +ZPL_DEF zpl_mat4 *zpl_mat4_v(zpl_vec4 m[4]); +ZPL_DEF zpl_mat4 *zpl_mat4_f(zpl_f32 m[4][4]); + +ZPL_DEF zpl_float4 *zpl_float44_m(zpl_mat4 *m); +ZPL_DEF zpl_float4 *zpl_float44_v(zpl_vec4 m[4]); +ZPL_DEF zpl_float4 *zpl_float44_16(zpl_f32 m[16]); + +ZPL_DEF void zpl_float44_transpose(zpl_f32 (*vec)[4]); +ZPL_DEF void zpl_float44_mul(zpl_f32 (*out)[4], zpl_f32 (*mat1)[4], zpl_f32 (*mat2)[4]); +ZPL_DEF void zpl_float44_mul_vec4(zpl_vec4 *out, zpl_f32 m[4][4], zpl_vec4 in); + +ZPL_DEF void zpl_mat4_translate(zpl_mat4 *out, zpl_vec3 v); +ZPL_DEF void zpl_mat4_rotate(zpl_mat4 *out, zpl_vec3 v, zpl_f32 angle_radians); +ZPL_DEF void zpl_mat4_scale(zpl_mat4 *out, zpl_vec3 v); +ZPL_DEF void zpl_mat4_scalef(zpl_mat4 *out, zpl_f32 s); +ZPL_DEF void zpl_mat4_ortho2d(zpl_mat4 *out, zpl_f32 left, zpl_f32 right, zpl_f32 bottom, zpl_f32 top); +ZPL_DEF void zpl_mat4_ortho3d(zpl_mat4 *out, zpl_f32 left, zpl_f32 right, zpl_f32 bottom, zpl_f32 top, zpl_f32 z_near, zpl_f32 z_far); +ZPL_DEF void zpl_mat4_perspective(zpl_mat4 *out, zpl_f32 fovy, zpl_f32 aspect, zpl_f32 z_near, zpl_f32 z_far); +ZPL_DEF void zpl_mat4_infinite_perspective(zpl_mat4 *out, zpl_f32 fovy, zpl_f32 aspect, zpl_f32 z_near); + +ZPL_DEF void zpl_mat4_ortho2d_dx(zpl_mat4 *out, zpl_f32 left, zpl_f32 right, zpl_f32 bottom, zpl_f32 top); +ZPL_DEF void zpl_mat4_ortho3d_dx(zpl_mat4 *out, zpl_f32 left, zpl_f32 right, zpl_f32 bottom, zpl_f32 top, zpl_f32 z_near, zpl_f32 z_far); +ZPL_DEF void zpl_mat4_perspective_dx(zpl_mat4 *out, zpl_f32 fovy, zpl_f32 aspect, zpl_f32 z_near, zpl_f32 z_far); +ZPL_DEF void zpl_mat4_infinite_perspective_dx(zpl_mat4 *out, zpl_f32 fovy, zpl_f32 aspect, zpl_f32 z_near); + +ZPL_DEF void zpl_mat4_look_at(zpl_mat4 *out, zpl_vec3 eye, zpl_vec3 centre, zpl_vec3 up); + +ZPL_DEF void zpl_mat4_look_at_lh(zpl_mat4 *out, zpl_vec3 eye, zpl_vec3 centre, zpl_vec3 up); + +ZPL_DEF zpl_quat zpl_quatf(zpl_f32 x, zpl_f32 y, zpl_f32 z, zpl_f32 w); +ZPL_DEF zpl_quat zpl_quatfv(zpl_f32 e[4]); +ZPL_DEF zpl_quat zpl_quat_axis_angle(zpl_vec3 axis, zpl_f32 angle_radians); +ZPL_DEF zpl_quat zpl_quat_euler_angles(zpl_f32 pitch, zpl_f32 yaw, zpl_f32 roll); +ZPL_DEF zpl_quat zpl_quat_identity(void); + +ZPL_DEF void zpl_quat_add(zpl_quat *d, zpl_quat q0, zpl_quat q1); +ZPL_DEF void zpl_quat_sub(zpl_quat *d, zpl_quat q0, zpl_quat q1); +ZPL_DEF void zpl_quat_mul(zpl_quat *d, zpl_quat q0, zpl_quat q1); +ZPL_DEF void zpl_quat_div(zpl_quat *d, zpl_quat q0, zpl_quat q1); + +ZPL_DEF void zpl_quat_mulf(zpl_quat *d, zpl_quat q, zpl_f32 s); +ZPL_DEF void zpl_quat_divf(zpl_quat *d, zpl_quat q, zpl_f32 s); + +ZPL_DEF void zpl_quat_addeq(zpl_quat *d, zpl_quat q); +ZPL_DEF void zpl_quat_subeq(zpl_quat *d, zpl_quat q); +ZPL_DEF void zpl_quat_muleq(zpl_quat *d, zpl_quat q); +ZPL_DEF void zpl_quat_diveq(zpl_quat *d, zpl_quat q); + +ZPL_DEF void zpl_quat_muleqf(zpl_quat *d, zpl_f32 s); +ZPL_DEF void zpl_quat_diveqf(zpl_quat *d, zpl_f32 s); + +ZPL_DEF zpl_f32 zpl_quat_dot(zpl_quat q0, zpl_quat q1); +ZPL_DEF zpl_f32 zpl_quat_mag(zpl_quat q); + +ZPL_DEF void zpl_quat_norm(zpl_quat *d, zpl_quat q); +ZPL_DEF void zpl_quat_conj(zpl_quat *d, zpl_quat q); +ZPL_DEF void zpl_quat_inverse(zpl_quat *d, zpl_quat q); + +ZPL_DEF void zpl_quat_axis(zpl_vec3 *axis, zpl_quat q); +ZPL_DEF zpl_f32 zpl_quat_angle(zpl_quat q); + +ZPL_DEF zpl_f32 zpl_quat_pitch(zpl_quat q); +ZPL_DEF zpl_f32 zpl_quat_yaw(zpl_quat q); +ZPL_DEF zpl_f32 zpl_quat_roll(zpl_quat q); + +/* NOTE: Rotate v by q */ +ZPL_DEF void zpl_quat_rotate_vec3(zpl_vec3 *d, zpl_quat q, zpl_vec3 v); +ZPL_DEF void zpl_mat4_from_quat(zpl_mat4 *out, zpl_quat q); +ZPL_DEF void zpl_quat_from_mat4(zpl_quat *out, zpl_mat4 *m); + +/* Plane math. */ +ZPL_DEF zpl_f32 zpl_plane_distance(zpl_plane* p, zpl_vec3 v); + +/* Frustum culling. */ +ZPL_DEF void zpl_frustum_create(zpl_frustum* out, zpl_mat4* camera, zpl_mat4* proj); +ZPL_DEF zpl_b8 zpl_frustum_sphere_inside(zpl_frustum* frustum, zpl_vec3 center, zpl_f32 radius); +ZPL_DEF zpl_b8 zpl_frustum_point_inside(zpl_frustum* frustum, zpl_vec3 point); +ZPL_DEF zpl_b8 zpl_frustum_box_inside(zpl_frustum* frustum, zpl_aabb3 box); + +/* Interpolations */ +ZPL_DEF zpl_f32 zpl_lerp(zpl_f32 a, zpl_f32 b, zpl_f32 t); +ZPL_DEF zpl_f32 zpl_unlerp(zpl_f32 t, zpl_f32 a, zpl_f32 b); +ZPL_DEF zpl_f32 zpl_smooth_step(zpl_f32 a, zpl_f32 b, zpl_f32 t); +ZPL_DEF zpl_f32 zpl_smoother_step(zpl_f32 a, zpl_f32 b, zpl_f32 t); + +ZPL_DEF void zpl_vec2_lerp(zpl_vec2 *d, zpl_vec2 a, zpl_vec2 b, zpl_f32 t); +ZPL_DEF void zpl_vec3_lerp(zpl_vec3 *d, zpl_vec3 a, zpl_vec3 b, zpl_f32 t); +ZPL_DEF void zpl_vec4_lerp(zpl_vec4 *d, zpl_vec4 a, zpl_vec4 b, zpl_f32 t); + +ZPL_DEF void zpl_vec2_cslerp(zpl_vec2 *d, zpl_vec2 a, zpl_vec2 v0, zpl_vec2 b, zpl_vec2 v1, zpl_f32 t); +ZPL_DEF void zpl_vec3_cslerp(zpl_vec3 *d, zpl_vec3 a, zpl_vec3 v0, zpl_vec3 b, zpl_vec3 v1, zpl_f32 t); +ZPL_DEF void zpl_vec2_dcslerp(zpl_vec2 *d, zpl_vec2 a, zpl_vec2 v0, zpl_vec2 b, zpl_vec2 v1, zpl_f32 t); +ZPL_DEF void zpl_vec3_dcslerp(zpl_vec3 *d, zpl_vec3 a, zpl_vec3 v0, zpl_vec3 b, zpl_vec3 v1, zpl_f32 t); + +ZPL_DEF void zpl_quat_lerp(zpl_quat *d, zpl_quat a, zpl_quat b, zpl_f32 t); +ZPL_DEF void zpl_quat_nlerp(zpl_quat *d, zpl_quat a, zpl_quat b, zpl_f32 t); +ZPL_DEF void zpl_quat_slerp(zpl_quat *d, zpl_quat a, zpl_quat b, zpl_f32 t); +ZPL_DEF void zpl_quat_nquad(zpl_quat *d, zpl_quat p, zpl_quat a, zpl_quat b, zpl_quat q, zpl_f32 t); +ZPL_DEF void zpl_quat_squad(zpl_quat *d, zpl_quat p, zpl_quat a, zpl_quat b, zpl_quat q, zpl_f32 t); +ZPL_DEF void zpl_quat_slerp_approx(zpl_quat *d, zpl_quat a, zpl_quat b, zpl_f32 t); +ZPL_DEF void zpl_quat_squad_approx(zpl_quat *d, zpl_quat p, zpl_quat a, zpl_quat b, zpl_quat q, zpl_f32 t); + +/* Rects */ +ZPL_DEF zpl_rect2 zpl_rect2f(zpl_vec2 pos, zpl_vec2 dim); +ZPL_DEF zpl_rect3 zpl_rect3f(zpl_vec3 pos, zpl_vec3 dim); + +ZPL_DEF int zpl_rect2_contains(zpl_rect2 a, zpl_f32 x, zpl_f32 y); +ZPL_DEF int zpl_rect2_contains_vec2(zpl_rect2 a, zpl_vec2 p); +ZPL_DEF int zpl_rect2_intersects(zpl_rect2 a, zpl_rect2 b); +ZPL_DEF int zpl_rect2_intersection_result(zpl_rect2 a, zpl_rect2 b, zpl_rect2 *intersection); + +//! @} +ZPL_END_C_DECLS +#if defined(__cplusplus) +ZPL_INLINE bool operator==(zpl_vec2 a, zpl_vec2 b) { return (a.x == b.x) && (a.y == b.y); } +ZPL_INLINE bool operator!=(zpl_vec2 a, zpl_vec2 b) { return !operator==(a, b); } + +ZPL_INLINE zpl_vec2 operator+(zpl_vec2 a) { return a; } +ZPL_INLINE zpl_vec2 operator-(zpl_vec2 a) { zpl_vec2 r = {-a.x, -a.y}; return r; } + +ZPL_INLINE zpl_vec2 operator+(zpl_vec2 a, zpl_vec2 b) { zpl_vec2 r; zpl_vec2_add(&r, a, b); return r; } +ZPL_INLINE zpl_vec2 operator-(zpl_vec2 a, zpl_vec2 b) { zpl_vec2 r; zpl_vec2_sub(&r, a, b); return r; } + +ZPL_INLINE zpl_vec2 operator*(zpl_vec2 a, float scalar) { zpl_vec2 r; zpl_vec2_mul(&r, a, scalar); return r; } +ZPL_INLINE zpl_vec2 operator*(float scalar, zpl_vec2 a) { return operator*(a, scalar); } + +ZPL_INLINE zpl_vec2 operator/(zpl_vec2 a, float scalar) { return operator*(a, 1.0f/scalar); } + +/* Hadamard Product */ +ZPL_INLINE zpl_vec2 operator*(zpl_vec2 a, zpl_vec2 b) { zpl_vec2 r = {a.x*b.x, a.y*b.y}; return r; } +ZPL_INLINE zpl_vec2 operator/(zpl_vec2 a, zpl_vec2 b) { zpl_vec2 r = {a.x/b.x, a.y/b.y}; return r; } + +ZPL_INLINE zpl_vec2 &operator+=(zpl_vec2 &a, zpl_vec2 b) { return (a = a + b); } +ZPL_INLINE zpl_vec2 &operator-=(zpl_vec2 &a, zpl_vec2 b) { return (a = a - b); } +ZPL_INLINE zpl_vec2 &operator*=(zpl_vec2 &a, float scalar) { return (a = a * scalar); } +ZPL_INLINE zpl_vec2 &operator/=(zpl_vec2 &a, float scalar) { return (a = a / scalar); } + + +ZPL_INLINE bool operator==(zpl_vec3 a, zpl_vec3 b) { return (a.x == b.x) && (a.y == b.y) && (a.z == b.z); } +ZPL_INLINE bool operator!=(zpl_vec3 a, zpl_vec3 b) { return !operator==(a, b); } + +ZPL_INLINE zpl_vec3 operator+(zpl_vec3 a) { return a; } +ZPL_INLINE zpl_vec3 operator-(zpl_vec3 a) { zpl_vec3 r = {-a.x, -a.y, -a.z}; return r; } + +ZPL_INLINE zpl_vec3 operator+(zpl_vec3 a, zpl_vec3 b) { zpl_vec3 r; zpl_vec3_add(&r, a, b); return r; } +ZPL_INLINE zpl_vec3 operator-(zpl_vec3 a, zpl_vec3 b) { zpl_vec3 r; zpl_vec3_sub(&r, a, b); return r; } + +ZPL_INLINE zpl_vec3 operator*(zpl_vec3 a, float scalar) { zpl_vec3 r; zpl_vec3_mul(&r, a, scalar); return r; } +ZPL_INLINE zpl_vec3 operator*(float scalar, zpl_vec3 a) { return operator*(a, scalar); } + +ZPL_INLINE zpl_vec3 operator/(zpl_vec3 a, float scalar) { return operator*(a, 1.0f/scalar); } + +/* Hadamard Product */ +ZPL_INLINE zpl_vec3 operator*(zpl_vec3 a, zpl_vec3 b) { zpl_vec3 r = {a.x*b.x, a.y*b.y, a.z*b.z}; return r; } +ZPL_INLINE zpl_vec3 operator/(zpl_vec3 a, zpl_vec3 b) { zpl_vec3 r = {a.x/b.x, a.y/b.y, a.z/b.z}; return r; } + +ZPL_INLINE zpl_vec3 &operator+=(zpl_vec3 &a, zpl_vec3 b) { return (a = a + b); } +ZPL_INLINE zpl_vec3 &operator-=(zpl_vec3 &a, zpl_vec3 b) { return (a = a - b); } +ZPL_INLINE zpl_vec3 &operator*=(zpl_vec3 &a, float scalar) { return (a = a * scalar); } +ZPL_INLINE zpl_vec3 &operator/=(zpl_vec3 &a, float scalar) { return (a = a / scalar); } + + +ZPL_INLINE bool operator==(zpl_vec4 a, zpl_vec4 b) { return (a.x == b.x) && (a.y == b.y) && (a.z == b.z) && (a.w == b.w); } +ZPL_INLINE bool operator!=(zpl_vec4 a, zpl_vec4 b) { return !operator==(a, b); } + +ZPL_INLINE zpl_vec4 operator+(zpl_vec4 a) { return a; } +ZPL_INLINE zpl_vec4 operator-(zpl_vec4 a) { zpl_vec4 r = {-a.x, -a.y, -a.z, -a.w}; return r; } + +ZPL_INLINE zpl_vec4 operator+(zpl_vec4 a, zpl_vec4 b) { zpl_vec4 r; zpl_vec4_add(&r, a, b); return r; } +ZPL_INLINE zpl_vec4 operator-(zpl_vec4 a, zpl_vec4 b) { zpl_vec4 r; zpl_vec4_sub(&r, a, b); return r; } + +ZPL_INLINE zpl_vec4 operator*(zpl_vec4 a, float scalar) { zpl_vec4 r; zpl_vec4_mul(&r, a, scalar); return r; } +ZPL_INLINE zpl_vec4 operator*(float scalar, zpl_vec4 a) { return operator*(a, scalar); } + +ZPL_INLINE zpl_vec4 operator/(zpl_vec4 a, float scalar) { return operator*(a, 1.0f/scalar); } + +/* Hadamard Product */ +ZPL_INLINE zpl_vec4 operator*(zpl_vec4 a, zpl_vec4 b) { zpl_vec4 r = {a.x*b.x, a.y*b.y, a.z*b.z, a.w*b.w}; return r; } +ZPL_INLINE zpl_vec4 operator/(zpl_vec4 a, zpl_vec4 b) { zpl_vec4 r = {a.x/b.x, a.y/b.y, a.z/b.z, a.w/b.w}; return r; } + +ZPL_INLINE zpl_vec4 &operator+=(zpl_vec4 &a, zpl_vec4 b) { return (a = a + b); } +ZPL_INLINE zpl_vec4 &operator-=(zpl_vec4 &a, zpl_vec4 b) { return (a = a - b); } +ZPL_INLINE zpl_vec4 &operator*=(zpl_vec4 &a, float scalar) { return (a = a * scalar); } +ZPL_INLINE zpl_vec4 &operator/=(zpl_vec4 &a, float scalar) { return (a = a / scalar); } + + +ZPL_INLINE zpl_mat2 operator+(zpl_mat2 const &a, zpl_mat2 const &b) { + int i, j; + zpl_mat2 r = {0}; + for (j = 0; j < 2; j++) { + for (i = 0; i < 2; i++) + r.e[2*j+i] = a.e[2*j+i] + b.e[2*j+i]; + } + return r; +} + +ZPL_INLINE zpl_mat2 operator-(zpl_mat2 const &a, zpl_mat2 const &b) { + int i, j; + zpl_mat2 r = {0}; + for (j = 0; j < 2; j++) { + for (i = 0; i < 2; i++) + r.e[2*j+i] = a.e[2*j+i] - b.e[2*j+i]; + } + return r; +} + +ZPL_INLINE zpl_mat2 operator*(zpl_mat2 const &a, zpl_mat2 const &b) { zpl_mat2 r; zpl_mat2_mul(&r, (zpl_mat2 *)&a, (zpl_mat2 *)&b); return r; } +ZPL_INLINE zpl_vec2 operator*(zpl_mat2 const &a, zpl_vec2 v) { zpl_vec2 r; zpl_mat2_mul_vec2(&r, (zpl_mat2 *)&a, v); return r; } +ZPL_INLINE zpl_mat2 operator*(zpl_mat2 const &a, float scalar) { + zpl_mat2 r = {0}; + int i; + for (i = 0; i < 2*2; i++) r.e[i] = a.e[i] * scalar; + return r; +} +ZPL_INLINE zpl_mat2 operator*(float scalar, zpl_mat2 const &a) { return operator*(a, scalar); } +ZPL_INLINE zpl_mat2 operator/(zpl_mat2 const &a, float scalar) { return operator*(a, 1.0f/scalar); } + +ZPL_INLINE zpl_mat2& operator+=(zpl_mat2& a, zpl_mat2 const &b) { return (a = a + b); } +ZPL_INLINE zpl_mat2& operator-=(zpl_mat2& a, zpl_mat2 const &b) { return (a = a - b); } +ZPL_INLINE zpl_mat2& operator*=(zpl_mat2& a, zpl_mat2 const &b) { return (a = a * b); } + + + +ZPL_INLINE zpl_mat3 operator+(zpl_mat3 const &a, zpl_mat3 const &b) { + int i, j; + zpl_mat3 r = {0}; + for (j = 0; j < 3; j++) { + for (i = 0; i < 3; i++) + r.e[3*j+i] = a.e[3*j+i] + b.e[3*j+i]; + } + return r; +} + +ZPL_INLINE zpl_mat3 operator-(zpl_mat3 const &a, zpl_mat3 const &b) { + int i, j; + zpl_mat3 r = {0}; + for (j = 0; j < 3; j++) { + for (i = 0; i < 3; i++) + r.e[3*j+i] = a.e[3*j+i] - b.e[3*j+i]; + } + return r; +} + +ZPL_INLINE zpl_mat3 operator*(zpl_mat3 const &a, zpl_mat3 const &b) { zpl_mat3 r; zpl_mat3_mul(&r, (zpl_mat3 *)&a, (zpl_mat3 *)&b); return r; } +ZPL_INLINE zpl_vec3 operator*(zpl_mat3 const &a, zpl_vec3 v) { zpl_vec3 r; zpl_mat3_mul_vec3(&r, (zpl_mat3 *)&a, v); return r; } +ZPL_INLINE zpl_mat3 operator*(zpl_mat3 const &a, float scalar) { + zpl_mat3 r = {0}; + int i; + for (i = 0; i < 3*3; i++) r.e[i] = a.e[i] * scalar; + return r; +} +ZPL_INLINE zpl_mat3 operator*(float scalar, zpl_mat3 const &a) { return operator*(a, scalar); } +ZPL_INLINE zpl_mat3 operator/(zpl_mat3 const &a, float scalar) { return operator*(a, 1.0f/scalar); } + +ZPL_INLINE zpl_mat3& operator+=(zpl_mat3& a, zpl_mat3 const &b) { return (a = a + b); } +ZPL_INLINE zpl_mat3& operator-=(zpl_mat3& a, zpl_mat3 const &b) { return (a = a - b); } +ZPL_INLINE zpl_mat3& operator*=(zpl_mat3& a, zpl_mat3 const &b) { return (a = a * b); } + + + +ZPL_INLINE zpl_mat4 operator+(zpl_mat4 const &a, zpl_mat4 const &b) { + int i, j; + zpl_mat4 r = {0}; + for (j = 0; j < 4; j++) { + for (i = 0; i < 4; i++) + r.e[4*j+i] = a.e[4*j+i] + b.e[4*j+i]; + } + return r; +} + +ZPL_INLINE zpl_mat4 operator-(zpl_mat4 const &a, zpl_mat4 const &b) { + int i, j; + zpl_mat4 r = {0}; + for (j = 0; j < 4; j++) { + for (i = 0; i < 4; i++) + r.e[4*j+i] = a.e[4*j+i] - b.e[4*j+i]; + } + return r; +} + +ZPL_INLINE zpl_mat4 operator*(zpl_mat4 const &a, zpl_mat4 const &b) { zpl_mat4 r; zpl_mat4_mul(&r, (zpl_mat4 *)&a, (zpl_mat4 *)&b); return r; } +ZPL_INLINE zpl_vec4 operator*(zpl_mat4 const &a, zpl_vec4 v) { zpl_vec4 r; zpl_mat4_mul_vec4(&r, (zpl_mat4 *)&a, v); return r; } +ZPL_INLINE zpl_mat4 operator*(zpl_mat4 const &a, float scalar) { + zpl_mat4 r = {0}; + int i; + for (i = 0; i < 4*4; i++) r.e[i] = a.e[i] * scalar; + return r; +} +ZPL_INLINE zpl_mat4 operator*(float scalar, zpl_mat4 const &a) { return operator*(a, scalar); } +ZPL_INLINE zpl_mat4 operator/(zpl_mat4 const &a, float scalar) { return operator*(a, 1.0f/scalar); } + +ZPL_INLINE zpl_mat4& operator+=(zpl_mat4 &a, zpl_mat4 const &b) { return (a = a + b); } +ZPL_INLINE zpl_mat4& operator-=(zpl_mat4 &a, zpl_mat4 const &b) { return (a = a - b); } +ZPL_INLINE zpl_mat4& operator*=(zpl_mat4 &a, zpl_mat4 const &b) { return (a = a * b); } + + + +ZPL_INLINE bool operator==(zpl_quat a, zpl_quat b) { return a.xyzw == b.xyzw; } +ZPL_INLINE bool operator!=(zpl_quat a, zpl_quat b) { return !operator==(a, b); } + +ZPL_INLINE zpl_quat operator+(zpl_quat q) { return q; } +ZPL_INLINE zpl_quat operator-(zpl_quat q) { return zpl_quatf(-q.x, -q.y, -q.z, -q.w); } + +ZPL_INLINE zpl_quat operator+(zpl_quat a, zpl_quat b) { zpl_quat r; zpl_quat_add(&r, a, b); return r; } +ZPL_INLINE zpl_quat operator-(zpl_quat a, zpl_quat b) { zpl_quat r; zpl_quat_sub(&r, a, b); return r; } + +ZPL_INLINE zpl_quat operator*(zpl_quat a, zpl_quat b) { zpl_quat r; zpl_quat_mul(&r, a, b); return r; } +ZPL_INLINE zpl_quat operator*(zpl_quat q, float s) { zpl_quat r; zpl_quat_mulf(&r, q, s); return r; } +ZPL_INLINE zpl_quat operator*(float s, zpl_quat q) { return operator*(q, s); } +ZPL_INLINE zpl_quat operator/(zpl_quat q, float s) { zpl_quat r; zpl_quat_divf(&r, q, s); return r; } + +ZPL_INLINE zpl_quat &operator+=(zpl_quat &a, zpl_quat b) { zpl_quat_addeq(&a, b); return a; } +ZPL_INLINE zpl_quat &operator-=(zpl_quat &a, zpl_quat b) { zpl_quat_subeq(&a, b); return a; } +ZPL_INLINE zpl_quat &operator*=(zpl_quat &a, zpl_quat b) { zpl_quat_muleq(&a, b); return a; } +ZPL_INLINE zpl_quat &operator/=(zpl_quat &a, zpl_quat b) { zpl_quat_diveq(&a, b); return a; } + +ZPL_INLINE zpl_quat &operator*=(zpl_quat &a, float b) { zpl_quat_muleqf(&a, b); return a; } +ZPL_INLINE zpl_quat &operator/=(zpl_quat &a, float b) { zpl_quat_diveqf(&a, b); return a; } + +/* Rotate v by a */ +ZPL_INLINE zpl_vec3 operator*(zpl_quat q, zpl_vec3 v) { zpl_vec3 r; zpl_quat_rotate_vec3(&r, q, v); return r; } +#endif +#endif + +#if defined(ZPL_MODULE_JSON) +// file: header/json.h + +/** @file json.c +@brief JSON5 Parser/Writer +@defgroup json JSON5 parser/writer + +Easy to use and very fast JSON5 parser that can easily load 50 megabytes of JSON content under half a second. It also contains simple JSON5 writer and acts as a good library for handling config files. The parser also supports the **Simplified JSON (SJSON)** format. + +We can parse JSON5 files in two different modes: + @n 1) Fast way (useful for raw data), which can not handle comments and might cause parsing failure if comment is present. + @n 2) Slower way (useful for config files), which handles comments perfectly but **might** have performance impact + on bigger JSON files. (+50MiB) +@{ +*/ +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +//! Debug mode + +#ifdef ZPL_JSON_DEBUG +#define ZPL_JSON_ASSERT ZPL_ASSERT(0) +#else +#define ZPL_JSON_ASSERT +#endif + +//! JSON object types +typedef enum zpl_json_type { + ZPL_JSON_TYPE_OBJECT, + ZPL_JSON_TYPE_STRING, + ZPL_JSON_TYPE_MULTISTRING, + ZPL_JSON_TYPE_ARRAY, + ZPL_JSON_TYPE_INTEGER, + ZPL_JSON_TYPE_REAL, + ZPL_JSON_TYPE_CONSTANT +} zpl_json_type; + +//! Field value properties +typedef enum zpl_json_props { + ZPL_JSON_PROPS_NONE = 0, + ZPL_JSON_PROPS_NAN = 1, + ZPL_JSON_PROPS_NAN_NEG = 2, + ZPL_JSON_PROPS_INFINITY = 3, + ZPL_JSON_PROPS_INFINITY_NEG = 4, + ZPL_JSON_PROPS_IS_EXP = 5, + ZPL_JSON_PROPS_IS_HEX = 6, + + // Used internally so that people can fill in real numbers for JSON files they plan to write. + ZPL_JSON_PROPS_IS_PARSED_REAL = 7, +} zpl_json_props; + +//! Value constants +typedef enum zpl_json_const { + ZPL_JSON_CONST_FALSE, + ZPL_JSON_CONST_TRUE, + ZPL_JSON_CONST_NULL, +} zpl_json_const; + +// TODO(ZaKlaus): Error handling +//! Parser error types +typedef enum zpl_json_error { + ZPL_JSON_ERROR_NONE, + ZPL_JSON_ERROR_INVALID_NAME, + ZPL_JSON_ERROR_INVALID_VALUE, + ZPL_JSON_ERROR_OBJECT_OR_SOURCE_WAS_NULL, +} zpl_json_error; + +//! Field name decoration style +typedef enum zpl_json_naming_style { + ZPL_JSON_NAME_STYLE_DOUBLE_QUOTE, + ZPL_JSON_NAME_STYLE_SINGLE_QUOTE, + ZPL_JSON_NAME_STYLE_NO_QUOTES, +} zpl_json_naming_style; + +//! Field value assign style +typedef enum zpl_json_assign_style { + ZPL_JSON_ASSIGN_STYLE_COLON, + ZPL_JSON_ASSIGN_STYLE_EQUALS, + ZPL_JSON_ASSIGN_STYLE_LINE, +} zpl_json_assign_style; + +//! Field delimiter style +typedef enum zpl_json_delim_style { + ZPL_JSON_DELIM_STYLE_COMMA, + ZPL_JSON_DELIM_STYLE_LINE, + ZPL_JSON_DELIM_STYLE_NEWLINE, +} zpl_json_delim_style; + +#define zpl_json_object zpl_json_object + +//! JSON object definition. +typedef struct zpl_json_object { + zpl_allocator backing; + char *name; + zpl_u8 type :6; + zpl_u8 name_style :2; + zpl_u8 props :7; + zpl_u8 cfg_mode :1; + zpl_u8 assign_style:4; + zpl_u8 delim_style :4; + zpl_u8 delim_line_width; + + union { + struct zpl_json_object *nodes; ///< zpl_array + zpl_i64 integer; + char *string; + + struct { + zpl_f64 real; + zpl_i32 base; + zpl_i32 base2; + zpl_i32 base2_offset; + zpl_i32 exp; + zpl_u8 exp_neg :1; + zpl_u8 lead_digit:1; + }; + zpl_u8 constant; + }; +} zpl_json_object; + +//! Parses JSON5/SJSON text. + +//! This method takes text form of JSON document as a source and parses its contents into JSON object structure we can work with. It also optionally handles comments that usually appear in documents used for configuration. +//! @param root JSON object we store data to. +//! @param len Text length. (reserved) +//! @param source Text to be processed. This string will be modified during the process! +//! @param allocator Memory allocator to use. (ex. zpl_heap()) +//! @param handle_comments Whether to handle possible comments or not. Note that if we won't handle comments in a document containing them, the parser will error out. See remark in source code. +//! @param err_code Variable we will store error code in. +ZPL_DEF void zpl_json_parse(zpl_json_object *root, zpl_usize len, char *source, zpl_allocator allocator, zpl_b32 handle_comments, + zpl_u8 *err_code); + +//! Exports JSON5 document into text form and outputs it into a file. + +//! This method takes JSON object tree and exports it into valid JSON5 form with the support of various styles that were preserved during import or set up programatically. +//! @param file File we write text to. +//! @param obj JSON object we export data from. +//! @param indent Text indentation used during export. Use 0 for root objects. +ZPL_DEF void zpl_json_write(zpl_file *file, zpl_json_object *obj, zpl_isize indent); + +//! Exports JSON5 document into text form and returns a zpl_string + +//! This method takes JSON object tree and exports it into valid JSON5 form with the support of various styles that were preserved during import or set up programatically. +//! @param obj JSON object we export data from. +//! @param indent Text indentation used during export. Use 0 for root objects. +//! @return zpl_string +ZPL_DEF zpl_string zpl_json_write_string(zpl_allocator a, zpl_json_object *obj, zpl_isize indent); + +//! Releases used resources by a JSON object. + +//! @param obj JSON object to free. +ZPL_DEF void zpl_json_free(zpl_json_object *obj); + +//! Searches for a JSON node within a document by its name. + +//! @param obj JSON object to search in. +//! @param name JSON node's name to search for. +//! @param deep_search Perform the search recursively. +ZPL_DEF zpl_json_object *zpl_json_find(zpl_json_object *obj, char const *name, zpl_b32 deep_search); + +//! Initializes a JSON node. + +//! @param obj JSON node to initialize. +//! @param backing Memory allocator to use (ex. zpl_heap()) +//! @param name JSON node's name. +//! @param type JSON node's type. (See zpl_json_type) +//! @see zpl_json_type +ZPL_DEF void zpl_json_init_node(zpl_json_object *obj, zpl_allocator backing, char const *name, zpl_u8 type); + +//! Adds object into JSON document at a specific index. + +//! Initializes and adds a JSON object into a JSON document at a specific index. +//! @param obj Root node to add to. +//! @param index Index to store at. +//! @param name JSON node's name. +//! @param type JSON node's type. (See zpl_json_type) +//! @see zpl_json_type +ZPL_DEF zpl_json_object *zpl_json_add_at(zpl_json_object *obj, zpl_isize index, char const *name, zpl_u8 type); + +//! Appends object into JSON document. + +//! Initializes and appends a JSON object into a JSON document. +//! @param obj Root node to add to. +//! @param name JSON node's name. +//! @param type JSON node's type. (See zpl_json_type) +//! @see zpl_json_type +ZPL_DEF zpl_json_object *zpl_json_add(zpl_json_object *obj, char const *name, zpl_u8 type); + +//! @} + +ZPL_END_C_DECLS +#endif + +#if defined(ZPL_MODULE_THREADING) +#if defined(ZPL_SYSTEM_UNIX) || defined(ZPL_SYSTEM_MACOS) +#include +#endif + +#if defined(ZPL_SYSTEM_WINDOWS) +#if !defined(ZPL_NO_WINDOWS_H) +#ifndef WIN32_LEAN_AND_MEAN +#define NOMINMAX +#define WIN32_LEAN_AND_MEAN +#define WIN32_MEAN_AND_LEAN +#define VC_EXTRALEAN +#endif +#include +#undef NOMINMAX +#undef WIN32_LEAN_AND_MEAN +#undef WIN32_MEAN_AND_LEAN +#undef VC_EXTRALEAN + +/* prevent it from including later */ +#define ZPL_NO_WINDOWS_H +#endif + +// include errno.h for MinGW +#if defined(ZPL_COMPILER_GCC) +#include +#endif +#endif + +#if !defined(zpl_thread_local) +#if defined(_MSC_VER) && _MSC_VER >= 1300 +#define zpl_thread_local __declspec(thread) +#elif defined(__GNUC__) +#define zpl_thread_local __thread +#else +#define zpl_thread_local thread_local +#endif +#endif + +// file: header/threading/atomic.h + +// Atomics +#ifdef ZPL_EDITOR +#include +#endif + +// TODO: Be specific with memory order? +// e.g. relaxed, acquire, release, acquire_release + +#if !defined(__STDC_NO_ATOMICS__) && !defined(__cplusplus) && !defined(ZPL_COMPILER_MSVC) +# include +# define zpl_atomic(X) volatile _Atomic(X) +#else +// TODO: Fix once C++ guys bother to add C atomics to std. +//# include +# define zpl_atomic(X) volatile X /*std::atomic*/ +#endif + +#define zpl_atomicarg(X) volatile X + +ZPL_BEGIN_C_DECLS + +#if defined(ZPL_COMPILER_MSVC) +typedef struct zpl_atomic32 { zpl_atomic(zpl_i32) value; } zpl_atomic32; +typedef struct zpl_atomic64 { zpl_atomic(zpl_i64) value; } zpl_atomic64; +typedef struct zpl_atomic_ptr { zpl_atomic(void*) value; } zpl_atomic_ptr; +#else +#if defined(ZPL_ARCH_32_BIT) +#define ZPL_ATOMIC_PTR_ALIGNMENT 4 +#elif defined(ZPL_ARCH_64_BIT) +#define ZPL_ATOMIC_PTR_ALIGNMENT 8 +#else +#error Unknown architecture +#endif + +typedef struct zpl_atomic32 { zpl_atomic(zpl_i32) value; } __attribute__ ((aligned(4))) zpl_atomic32; +typedef struct zpl_atomic64 { zpl_atomic(zpl_i64) value; } __attribute__ ((aligned(8))) zpl_atomic64; +typedef struct zpl_atomic_ptr { zpl_atomic(void*) value; } __attribute__ ((aligned(ZPL_ATOMIC_PTR_ALIGNMENT))) zpl_atomic_ptr; +#endif + +ZPL_DEF zpl_i32 zpl_atomic32_load (zpl_atomic32 const *a); +ZPL_DEF void zpl_atomic32_store (zpl_atomic32 *a, zpl_atomicarg(zpl_i32) value); +ZPL_DEF zpl_i32 zpl_atomic32_compare_exchange(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) expected, zpl_atomicarg(zpl_i32) desired); +ZPL_DEF zpl_i32 zpl_atomic32_exchange (zpl_atomic32 *a, zpl_atomicarg(zpl_i32) desired); +ZPL_DEF zpl_i32 zpl_atomic32_fetch_add (zpl_atomic32 *a, zpl_atomicarg(zpl_i32) operand); +ZPL_DEF zpl_i32 zpl_atomic32_fetch_and (zpl_atomic32 *a, zpl_atomicarg(zpl_i32) operand); +ZPL_DEF zpl_i32 zpl_atomic32_fetch_or (zpl_atomic32 *a, zpl_atomicarg(zpl_i32) operand); +ZPL_DEF zpl_b32 zpl_atomic32_spin_lock (zpl_atomic32 *a, zpl_isize time_out); // NOTE: time_out = -1 as default +ZPL_DEF void zpl_atomic32_spin_unlock (zpl_atomic32 *a); +ZPL_DEF zpl_b32 zpl_atomic32_try_acquire_lock(zpl_atomic32 *a); + + +ZPL_DEF zpl_i64 zpl_atomic64_load (zpl_atomic64 const *a); +ZPL_DEF void zpl_atomic64_store (zpl_atomic64 *a, zpl_atomicarg(zpl_i64) value); +ZPL_DEF zpl_i64 zpl_atomic64_compare_exchange(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) expected, zpl_atomicarg(zpl_i64) desired); +ZPL_DEF zpl_i64 zpl_atomic64_exchange (zpl_atomic64 *a, zpl_atomicarg(zpl_i64) desired); +ZPL_DEF zpl_i64 zpl_atomic64_fetch_add (zpl_atomic64 *a, zpl_atomicarg(zpl_i64) operand); +ZPL_DEF zpl_i64 zpl_atomic64_fetch_and (zpl_atomic64 *a, zpl_atomicarg(zpl_i64) operand); +ZPL_DEF zpl_i64 zpl_atomic64_fetch_or (zpl_atomic64 *a, zpl_atomicarg(zpl_i64) operand); +ZPL_DEF zpl_b32 zpl_atomic64_spin_lock (zpl_atomic64 *a, zpl_isize time_out); // NOTE: time_out = -1 as default +ZPL_DEF void zpl_atomic64_spin_unlock (zpl_atomic64 *a); +ZPL_DEF zpl_b32 zpl_atomic64_try_acquire_lock(zpl_atomic64 *a); + + +ZPL_DEF void *zpl_atomic_ptr_load (zpl_atomic_ptr const *a); +ZPL_DEF void zpl_atomic_ptr_store (zpl_atomic_ptr *a, zpl_atomicarg(void *)value); +ZPL_DEF void *zpl_atomic_ptr_compare_exchange(zpl_atomic_ptr *a, zpl_atomicarg(void *)expected, zpl_atomicarg(void *)desired); +ZPL_DEF void *zpl_atomic_ptr_exchange (zpl_atomic_ptr *a, zpl_atomicarg(void *)desired); +ZPL_DEF void *zpl_atomic_ptr_fetch_add (zpl_atomic_ptr *a, zpl_atomicarg(void *)operand); +ZPL_DEF void *zpl_atomic_ptr_fetch_and (zpl_atomic_ptr *a, zpl_atomicarg(void *)operand); +ZPL_DEF void *zpl_atomic_ptr_fetch_or (zpl_atomic_ptr *a, zpl_atomicarg(void *)operand); +ZPL_DEF zpl_b32 zpl_atomic_ptr_spin_lock (zpl_atomic_ptr *a, zpl_isize time_out); // NOTE: time_out = -1 as default +ZPL_DEF void zpl_atomic_ptr_spin_unlock (zpl_atomic_ptr *a); +ZPL_DEF zpl_b32 zpl_atomic_ptr_try_acquire_lock(zpl_atomic_ptr *a); + +ZPL_END_C_DECLS +// file: header/threading/fence.h + +// Fences +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +ZPL_DEF void zpl_yield_thread(void); +ZPL_DEF void zpl_mfence (void); +ZPL_DEF void zpl_sfence (void); +ZPL_DEF void zpl_lfence (void); + +ZPL_END_C_DECLS +// file: header/threading/sem.h + +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +#if defined(ZPL_SYSTEM_MACOS) +#include +#elif defined(ZPL_SYSTEM_UNIX) +#include +#endif + +#if defined(ZPL_SYSTEM_WINDOWS) +typedef struct zpl_semaphore { void *win32_handle; } zpl_semaphore; +#elif defined(ZPL_SYSTEM_MACOS) +typedef struct zpl_semaphore { semaphore_t osx_handle; } zpl_semaphore; +#elif defined(ZPL_SYSTEM_UNIX) +typedef struct zpl_semaphore { sem_t unix_handle; } zpl_semaphore; +#else +#error +#endif + +ZPL_DEF void zpl_semaphore_init (zpl_semaphore *s); +ZPL_DEF void zpl_semaphore_destroy(zpl_semaphore *s); +ZPL_DEF void zpl_semaphore_post (zpl_semaphore *s, zpl_i32 count); +ZPL_DEF void zpl_semaphore_release(zpl_semaphore *s); // NOTE: zpl_semaphore_post(s, 1) +ZPL_DEF void zpl_semaphore_wait (zpl_semaphore *s); + +ZPL_END_C_DECLS +// file: header/threading/mutex.h + +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +typedef struct zpl_mutex { +#if defined(ZPL_SYSTEM_WINDOWS) + CRITICAL_SECTION win32_critical_section; +#else + pthread_mutex_t pthread_mutex; +#endif +} zpl_mutex; + +ZPL_DEF void zpl_mutex_init (zpl_mutex *m); +ZPL_DEF void zpl_mutex_destroy (zpl_mutex *m); +ZPL_DEF void zpl_mutex_lock (zpl_mutex *m); +ZPL_DEF zpl_b32 zpl_mutex_try_lock(zpl_mutex *m); +ZPL_DEF void zpl_mutex_unlock (zpl_mutex *m); + +ZPL_END_C_DECLS +// file: header/threading/thread.h + +#ifdef ZPL_EDITOR +#include +#else +struct zpl_thread; +#endif + +ZPL_BEGIN_C_DECLS + +typedef zpl_isize (*zpl_thread_proc)(struct zpl_thread *thread); + +typedef struct zpl_thread { +#if defined(ZPL_SYSTEM_WINDOWS) + void * win32_handle; +#else + pthread_t posix_handle; +#endif + + zpl_thread_proc proc; + void * user_data; + zpl_isize user_index; + zpl_isize return_value; + + zpl_semaphore semaphore; + zpl_isize stack_size; + zpl_b32 is_running; +} zpl_thread; + +ZPL_DEF void zpl_thread_init (zpl_thread *t); +ZPL_DEF void zpl_thread_destroy (zpl_thread *t); +ZPL_DEF void zpl_thread_start (zpl_thread *t, zpl_thread_proc proc, void *data); +ZPL_DEF void zpl_thread_start_with_stack(zpl_thread *t, zpl_thread_proc proc, void *data, zpl_isize stack_size); +ZPL_DEF void zpl_thread_join (zpl_thread *t); +ZPL_DEF zpl_b32 zpl_thread_is_running (zpl_thread const *t); +ZPL_DEF zpl_u32 zpl_thread_current_id (void); +ZPL_DEF void zpl_thread_set_name (zpl_thread *t, char const *name); + +ZPL_END_C_DECLS +// file: header/threading/sync.h + +// NOTE: Thread Merge Operation +// Based on Sean Barrett's stb_sync +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +typedef struct zpl_sync { + zpl_i32 target; // Target Number of threads + zpl_i32 current; // Threads to hit + zpl_i32 waiting; // Threads waiting + + zpl_mutex start; + zpl_mutex mutex; + zpl_semaphore release; +} zpl_sync; + +ZPL_DEF void zpl_sync_init (zpl_sync *s); +ZPL_DEF void zpl_sync_destroy (zpl_sync *s); +ZPL_DEF void zpl_sync_set_target (zpl_sync *s, zpl_i32 count); +ZPL_DEF void zpl_sync_release (zpl_sync *s); +ZPL_DEF zpl_i32 zpl_sync_reach (zpl_sync *s); +ZPL_DEF void zpl_sync_reach_and_wait(zpl_sync *s); + +ZPL_END_C_DECLS +// file: header/threading/affinity.h + +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +#if defined(ZPL_SYSTEM_WINDOWS) || defined (ZPL_SYSTEM_CYGWIN) + +typedef struct zpl_affinity { + zpl_b32 is_accurate; + zpl_isize core_count; + zpl_isize thread_count; + +#define ZPL_WIN32_MAX_THREADS (8 * zpl_size_of(zpl_usize)) + zpl_usize core_masks[ZPL_WIN32_MAX_THREADS]; +} zpl_affinity; + +#elif defined(ZPL_SYSTEM_OSX) + +typedef struct zpl_affinity { + zpl_b32 is_accurate; + zpl_isize core_count; + zpl_isize thread_count; + zpl_isize threads_per_core; +} zpl_affinity; + +#elif defined(ZPL_SYSTEM_LINUX) || defined(ZPL_SYSTEM_FREEBSD) || defined(ZPL_SYSTEM_EMSCRIPTEN) || defined(ZPL_SYSTEM_OPENBSD) + +typedef struct zpl_affinity { + zpl_b32 is_accurate; + zpl_isize core_count; + zpl_isize thread_count; + zpl_isize threads_per_core; +} zpl_affinity; + +#else +#error TODO: Unknown system +#endif + +ZPL_DEF void zpl_affinity_init (zpl_affinity *a); +ZPL_DEF void zpl_affinity_destroy(zpl_affinity *a); +ZPL_DEF zpl_b32 zpl_affinity_set (zpl_affinity *a, zpl_isize core, zpl_isize thread); +ZPL_DEF zpl_isize zpl_affinity_thread_count_for_core(zpl_affinity *a, zpl_isize core); + +ZPL_END_C_DECLS + +#if defined(ZPL_MODULE_JOBS) +// file: header/jobs.h + +/** @file threadpool.c +@brief Job system +@defgroup jobs Job system + + This job system follows thread pool pattern to minimize the costs of thread initialization. + It reuses fixed number of threads to process variable number of jobs. + + @{ + */ +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +typedef void (*zpl_jobs_proc)(void *data); + +#define ZPL_INVALID_JOB ZPL_U32_MAX + +typedef enum { + ZPL_JOBS_STATUS_READY, + ZPL_JOBS_STATUS_BUSY, + ZPL_JOBS_STATUS_WAITING, + ZPL_JOBS_STATUS_TERM, +} zpl_jobs_status; + +typedef struct { + zpl_jobs_proc proc; + void *data; + + zpl_f32 priority; +} zpl_thread_job; + +typedef struct { + zpl_thread thread; + zpl_atomic32 status; + zpl_u32 jobid; + void *pool; +} zpl_thread_worker; + +typedef struct { + zpl_allocator alloc; + zpl_u32 max_threads; + zpl_f32 job_spawn_treshold; + zpl_mutex access; + zpl_thread_worker *workers; ///< zpl_buffer + zpl_thread_job *jobs; ///< zpl_array + zpl_u32 *queue; ///< zpl_array + zpl_u32 *available; ///< zpl_array +} zpl_thread_pool; + +//! Initialize thread pool with specified amount of fixed threads. +ZPL_DEF void zpl_jobs_init(zpl_thread_pool *pool, zpl_allocator a, zpl_u32 max_threads); + +//! Release the resources use by thread pool. +ZPL_DEF void zpl_jobs_free(zpl_thread_pool *pool); + +//! Enqueue a job with specified data. +ZPL_DEF void zpl_jobs_enqueue(zpl_thread_pool *pool, zpl_jobs_proc proc, void *data); + +//! Enqueue a job with specific priority with specified data. +ZPL_DEF void zpl_jobs_enqueue_with_priority(zpl_thread_pool *pool, zpl_jobs_proc proc, void *data, zpl_f32 priority); + +//! Process all jobs and check all threads. Should be called by Main Thread in a tight loop. +ZPL_DEF zpl_b32 zpl_jobs_process(zpl_thread_pool *pool); + +ZPL_END_C_DECLS +#endif + +#if defined(ZPL_MODULE_COROUTINES) +// file: header/coroutines.h + +/** @file coroutines.c +@brief Coroutines module +@defgroup misc Coroutines module + + This module implements co-routines feature for C99. + + @{ + */ +/* + See test/coroutines.c for an example usage + */ +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +#ifndef ZPL_CO_ARG_STACK_CAPACITY +#define ZPL_CO_ARG_STACK_CAPACITY 128 +#endif + +typedef enum { + ZPL_CO_READY, + ZPL_CO_ENQUEUED, + ZPL_CO_RUNNING, + ZPL_CO_WAITING, + ZPL_CO_DEAD, +} zpl_co_status; + +struct zpl_co; + +typedef void (*zpl_co_proc)(struct zpl_co *co); + +typedef struct zpl_co { + zpl_atomic32 status; + zpl_co_proc f; + void *data; // overwritten internally, use inside of co-routines + void *data_stack[ZPL_CO_ARG_STACK_CAPACITY]; + zpl_i32 data_read_idx, data_write_idx; + zpl_atomic32 resume, push_arg; +} zpl_co; + +// These methods are used to initialize the co-routine subsystem + +/** + * Initializes the coroutines subsystem + * @param a Memory allocator to be used + * @param max_threads Maximum amount of threads to use for coroutines execution + */ +ZPL_DEF void zpl_co_init(zpl_allocator a, zpl_u32 max_threads); + +/** + * Destroys the coroutines subsystem + * + * IMPORTANT: This is a blocking method that waits until all the coroutines are finished. + * Please, make sure your coroutines are correctly designed, so that you + * won't end up in an infinite loop. + */ +ZPL_DEF void zpl_co_destroy(void); + +// These methods are used by the host to create and run/resume co-routines +// Make sure the co-routine subsystem is initialized first! + +/** + * Create a paused coroutine + * @param co Coroutine reference + * @param f Coroutine method + */ +ZPL_DEF void zpl_co_make(zpl_co *co, zpl_co_proc f); + +/** + * Starts/Resumes a coroutine execution. + * + * IMPORTANT: Data you pass is stored in a stack of up to ZPL_CO_ARG_STACK_CAPACITY. + * This means that you can cause stack corruption if you + * call 'zpl_co_resume' with data passed (ZPL_CO_ARG_STACK_CAPACITY+1) times. + * Raise the number by defining ZPL_CO_ARG_STACK_CAPACITY if required. + * + * @param co Coroutine + * @param data Data we want to pass (or NULL) + */ +ZPL_DEF void zpl_co_resume(zpl_co *co, void *data); + +/** + * Is a coroutine running at the moment? + * @param co Coroutine + * @return + */ +ZPL_DEF_INLINE zpl_b32 zpl_co_running(zpl_co *co); + +/** + * Is a coroutine already finished? + * @param co Coroutine + * @return + */ +ZPL_DEF_INLINE zpl_b32 zpl_co_finished(zpl_co *co); + +/** + * Is coroutine waiting? (in yield state) + * @param co Coroutine + * @return + */ +ZPL_DEF_INLINE zpl_b32 zpl_co_waiting(zpl_co *co); + +// This method is used by the co-routine to await execution +// + +/** + * Yield the coroutine. + * + * IMPORTANT: Only to be used by the coroutine!! + * @param co Coroutine + */ +ZPL_DEF void zpl_co_yield(zpl_co *co); + +//! @} + +ZPL_IMPL_INLINE zpl_b32 zpl_co_running(zpl_co *co) { + return zpl_atomic32_load(&co->status) == ZPL_CO_RUNNING; +} + +ZPL_IMPL_INLINE zpl_b32 zpl_co_finished(zpl_co *co) { + return zpl_atomic32_load(&co->status) == ZPL_CO_DEAD; +} + +ZPL_IMPL_INLINE zpl_b32 zpl_co_waiting(zpl_co *co) { + return zpl_atomic32_load(&co->resume) == 0; +} + +ZPL_END_C_DECLS +#endif +#endif + +#if defined(ZPL_COMPILER_MSVC) +#pragma warning(pop) +#endif + +#if defined(__GCC__) || defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic pop +#endif + +#if defined(ZPL_IMPLEMENTATION) && !defined(ZPL_IMPLEMENTATION_DONE) +#define ZPL_IMPLEMENTATION_DONE + +#if defined(__GCC__) || defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wattributes" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-function" +#pragma GCC diagnostic ignored "-Wwrite-strings" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#pragma GCC diagnostic ignored "-Wmissing-braces" +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" +#pragma GCC diagnostic ignored "-Wimplicit-fallthrough" +#pragma GCC diagnostic ignored "-Wignored-qualifiers" +#endif + +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4201) +#pragma warning(disable : 4996) // Disable deprecated POSIX functions warning +#pragma warning(disable : 4127) // Conditional expression is constant +#endif + +/* general purpose includes */ + +#include + +#if defined(ZPL_SYSTEM_UNIX) || defined(ZPL_SYSTEM_MACOS) +#include +#include +#elif defined(ZPL_SYSTEM_WINDOWS) +#if !defined(ZPL_NO_WINDOWS_H) +#ifndef WIN32_LEAN_AND_MEAN +#ifndef NOMINMAX +#define NOMINMAX +#endif + +#define WIN32_LEAN_AND_MEAN +#define WIN32_MEAN_AND_LEAN +#define VC_EXTRALEAN +#endif +#include +#undef NOMINMAX +#undef WIN32_LEAN_AND_MEAN +#undef WIN32_MEAN_AND_LEAN +#undef VC_EXTRALEAN +#endif +#endif + +#if defined(ZPL_MODULE_CORE) +// file: source/core/debug.c + +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +void zpl_assert_handler(char const *condition, char const *file, zpl_i32 line, char const *msg, ...) { + zpl_printf_err("%s:(%d): Assert Failure: ", file, line); + + if (condition) zpl_printf_err("`%s` ", condition); + + if (msg) { + va_list va; + va_start(va, msg); + zpl_printf_err_va(msg, va); + va_end(va); + } + + zpl_printf_err("\n"); +} + +zpl_i32 zpl_assert_crash(char const *condition) { + ZPL_PANIC(condition); + return 0; +} + +ZPL_END_C_DECLS +// file: source/core/memory.c + +#ifdef ZPL_EDITOR +#include +#endif + +#include + +ZPL_BEGIN_C_DECLS + + +void zpl_memswap(void *i, void *j, zpl_isize size) { + if (i == j) return; + + if (size == 4) { + zpl_swap(zpl_u32, *cast(zpl_u32 *) i, *cast(zpl_u32 *) j); + } else if (size == 8) { + zpl_swap(zpl_u64, *cast(zpl_u64 *) i, *cast(zpl_u64 *) j); + } else if (size < 8) { + zpl_u8 *a = cast(zpl_u8 *) i; + zpl_u8 *b = cast(zpl_u8 *) j; + if (a != b) { + while (size--) { zpl_swap(zpl_u8, *a++, *b++); } } - - ZPL_END_C_DECLS - // file: header/core/memory_virtual.h - - - //////////////////////////////////////////////////////////////// - // - // Virtual Memory - // - // - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - typedef struct zpl_virtual_memory { - void *data; - zpl_isize size; - } zpl_virtual_memory; - - //! Initialize virtual memory from existing data. - ZPL_DEF zpl_virtual_memory zpl_vm(void *data, zpl_isize size); - - //! Allocate virtual memory at address with size. - - //! @param addr The starting address of the region to reserve. If NULL, it lets operating system to decide where to allocate it. - //! @param size The size to server. - ZPL_DEF zpl_virtual_memory zpl_vm_alloc(void *addr, zpl_isize size); - - //! Release the virtual memory. - ZPL_DEF zpl_b32 zpl_vm_free(zpl_virtual_memory vm); - - //! Trim virtual memory. - ZPL_DEF zpl_virtual_memory zpl_vm_trim(zpl_virtual_memory vm, zpl_isize lead_size, zpl_isize size); - - //! Purge virtual memory. - ZPL_DEF zpl_b32 zpl_vm_purge(zpl_virtual_memory vm); - - //! Retrieve VM's page size and alignment. - ZPL_DEF zpl_isize zpl_virtual_memory_page_size(zpl_isize *alignment_out); - - ZPL_END_C_DECLS - // file: header/core/memory_custom.h - - //////////////////////////////////////////////////////////////// - // - // Custom Allocation - // - // - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - typedef enum zplAllocationType { - ZPL_ALLOCATION_ALLOC, - ZPL_ALLOCATION_FREE, - ZPL_ALLOCATION_FREE_ALL, - ZPL_ALLOCATION_RESIZE, - } zplAllocationType; - - // NOTE: This is useful so you can define an allocator of the same type and parameters - #define ZPL_ALLOCATOR_PROC(name) \ - void *name(void *allocator_data, zplAllocationType type, zpl_isize size, zpl_isize alignment, void *old_memory, \ - zpl_isize old_size, zpl_u64 flags) - typedef ZPL_ALLOCATOR_PROC(zpl_allocator_proc); - - - typedef struct zpl_allocator { - zpl_allocator_proc *proc; - void *data; - } zpl_allocator; - - typedef enum zplAllocatorFlag { - ZPL_ALLOCATOR_FLAG_CLEAR_TO_ZERO = ZPL_BIT(0), - } zplAllocatorFlag; - - #ifndef ZPL_DEFAULT_MEMORY_ALIGNMENT - #define ZPL_DEFAULT_MEMORY_ALIGNMENT (2 * zpl_size_of(void *)) - #endif - - #ifndef ZPL_DEFAULT_ALLOCATOR_FLAGS - #define ZPL_DEFAULT_ALLOCATOR_FLAGS (ZPL_ALLOCATOR_FLAG_CLEAR_TO_ZERO) - #endif - - //! Allocate memory with specified alignment. - ZPL_DEF_INLINE void *zpl_alloc_align(zpl_allocator a, zpl_isize size, zpl_isize alignment); - - //! Allocate memory with default alignment. - ZPL_DEF_INLINE void *zpl_alloc(zpl_allocator a, zpl_isize size); - - //! Free allocated memory. - ZPL_DEF_INLINE void zpl_free(zpl_allocator a, void *ptr); - - //! Free all memory allocated by an allocator. - ZPL_DEF_INLINE void zpl_free_all(zpl_allocator a); - - //! Resize an allocated memory. - ZPL_DEF_INLINE void *zpl_resize(zpl_allocator a, void *ptr, zpl_isize old_size, zpl_isize new_size); - - //! Resize an allocated memory with specified alignment. - ZPL_DEF_INLINE void *zpl_resize_align(zpl_allocator a, void *ptr, zpl_isize old_size, zpl_isize new_size, zpl_isize alignment); - - //! Allocate memory and copy data into it. - ZPL_DEF_INLINE void *zpl_alloc_copy(zpl_allocator a, void const *src, zpl_isize size); - - //! Allocate memory with specified alignment and copy data into it. - ZPL_DEF_INLINE void *zpl_alloc_copy_align(zpl_allocator a, void const *src, zpl_isize size, zpl_isize alignment); - - //! Allocate memory for null-terminated C-String. - ZPL_DEF char *zpl_alloc_str(zpl_allocator a, char const *str); - - //! Allocate memory for C-String with specified size. - ZPL_DEF_INLINE char *zpl_alloc_str_len(zpl_allocator a, char const *str, zpl_isize len); - - #ifndef zpl_alloc_item - - //! Allocate memory for an item. - #define zpl_alloc_item(allocator_, Type) (Type *)zpl_alloc(allocator_, zpl_size_of(Type)) - - //! Allocate memory for an array of items. - #define zpl_alloc_array(allocator_, Type, count) (Type *)zpl_alloc(allocator_, zpl_size_of(Type) * (count)) - #endif - - //! Allocate/Resize memory using default options. - - //! Use this if you don't need a "fancy" resize allocation - ZPL_DEF_INLINE void *zpl_default_resize_align(zpl_allocator a, void *ptr, zpl_isize old_size, zpl_isize new_size, zpl_isize alignment); - - //! The heap allocator backed by operating system's memory manager. - ZPL_DEF_INLINE zpl_allocator zpl_heap_allocator(void); - ZPL_DEF ZPL_ALLOCATOR_PROC(zpl_heap_allocator_proc); - - #ifndef zpl_malloc - - //! Helper to allocate memory using heap allocator. - #define zpl_malloc(sz) zpl_alloc(zpl_heap_allocator( ), sz) - - //! Helper to free memory allocated by heap allocator. - #define zpl_mfree(ptr) zpl_free(zpl_heap_allocator( ), ptr) - - //! Alias to heap allocator. - #define zpl_heap zpl_heap_allocator - #endif - - // - // Arena Allocator - // - - typedef struct zpl_arena { - zpl_allocator backing; - void *physical_start; - zpl_isize total_size; - zpl_isize total_allocated; - zpl_isize temp_count; - } zpl_arena; - - //! Initialize memory arena from existing memory region. - ZPL_DEF_INLINE void zpl_arena_init_from_memory(zpl_arena *arena, void *start, zpl_isize size); - - //! Initialize memory arena using existing memory allocator. - ZPL_DEF_INLINE void zpl_arena_init_from_allocator(zpl_arena *arena, zpl_allocator backing, zpl_isize size); - - //! Initialize memory arena within an existing parent memory arena. - ZPL_DEF_INLINE void zpl_arena_init_sub(zpl_arena *arena, zpl_arena *parent_arena, zpl_isize size); - - //! Release the memory used by memory arena. - ZPL_DEF_INLINE void zpl_arena_free(zpl_arena *arena); - - - //! Retrieve memory arena's aligned allocation address. - ZPL_DEF_INLINE zpl_isize zpl_arena_alignment_of(zpl_arena *arena, zpl_isize alignment); - - //! Retrieve memory arena's remaining size. - ZPL_DEF_INLINE zpl_isize zpl_arena_size_remaining(zpl_arena *arena, zpl_isize alignment); - - //! Check whether memory arena has any temporary snapshots. - ZPL_DEF_INLINE void zpl_arena_check(zpl_arena *arena); - - //! Allocation Types: alloc, free_all, resize - ZPL_DEF_INLINE zpl_allocator zpl_arena_allocator(zpl_arena *arena); - ZPL_DEF ZPL_ALLOCATOR_PROC(zpl_arena_allocator_proc); - - - typedef struct zpl_temp_arena_memory { - zpl_arena *arena; - zpl_isize original_count; - } zpl_temp_arena_memory; - - //! Capture a snapshot of used memory in a memory arena. - ZPL_DEF_INLINE zpl_temp_arena_memory zpl_temp_arena_memory_begin(zpl_arena *arena); - - //! Reset memory arena's usage by a captured snapshot. - ZPL_DEF_INLINE void zpl_temp_arena_memory_end(zpl_temp_arena_memory tmp_mem); - - // - // Pool Allocator - // - - - typedef struct zpl_pool { - zpl_allocator backing; - void *physical_start; - void *free_list; - zpl_isize block_size; - zpl_isize block_align; - zpl_isize total_size; - zpl_isize num_blocks; - } zpl_pool; - - - //! Initialize pool allocator. - ZPL_DEF_INLINE void zpl_pool_init(zpl_pool *pool, zpl_allocator backing, zpl_isize num_blocks, zpl_isize block_size); - - //! Initialize pool allocator with specific block alignment. - ZPL_DEF void zpl_pool_init_align(zpl_pool *pool, zpl_allocator backing, zpl_isize num_blocks, zpl_isize block_size, - zpl_isize block_align); - - //! Release the resources used by pool allocator. - ZPL_DEF_INLINE void zpl_pool_free(zpl_pool *pool); - - //! Allocation Types: alloc, free - ZPL_DEF_INLINE zpl_allocator zpl_pool_allocator(zpl_pool *pool); - ZPL_DEF ZPL_ALLOCATOR_PROC(zpl_pool_allocator_proc); - - - typedef struct zpl_allocation_header_ev { - zpl_isize size; - } zpl_allocation_header_ev; - - ZPL_DEF_INLINE zpl_allocation_header_ev *zpl_allocation_header(void *data); - ZPL_DEF_INLINE void zpl_allocation_header_fill(zpl_allocation_header_ev *header, void *data, zpl_isize size); - - #if defined(ZPL_ARCH_32_BIT) - #define ZPL_ISIZE_HIGH_BIT 0x80000000 - #elif defined(ZPL_ARCH_64_BIT) - #define ZPL_ISIZE_HIGH_BIT 0x8000000000000000ll - #else - #error - #endif - - // - // Scratch Memory Allocator - Ring Buffer Based Arena - // - - - typedef struct zpl_scratch_memory { - void *physical_start; - zpl_isize total_size; - void *alloc_point; - void *free_point; - } zpl_scratch_memory; - - //! Initialize ring buffer arena. - ZPL_DEF void zpl_scratch_memory_init(zpl_scratch_memory *s, void *start, zpl_isize size); - - //! Check whether ring buffer arena is in use. - ZPL_DEF zpl_b32 zpl_scratch_memory_is_in_use(zpl_scratch_memory *s, void *ptr); - - //! Allocation Types: alloc, free, free_all, resize - ZPL_DEF zpl_allocator zpl_scratch_allocator(zpl_scratch_memory *s); - ZPL_DEF ZPL_ALLOCATOR_PROC(zpl_scratch_allocator_proc); - - // - // Stack Memory Allocator - // - - - typedef struct zpl_stack_memory { - zpl_allocator backing; - - void *physical_start; - zpl_usize total_size; - zpl_usize allocated; - } zpl_stack_memory; - - //! Initialize stack allocator from existing memory. - ZPL_DEF_INLINE void zpl_stack_memory_init_from_memory(zpl_stack_memory *s, void *start, zpl_isize size); - - //! Initialize stack allocator using existing memory allocator. - ZPL_DEF_INLINE void zpl_stack_memory_init(zpl_stack_memory *s, zpl_allocator backing, zpl_isize size); - - //! Check whether stack allocator is in use. - ZPL_DEF_INLINE zpl_b32 zpl_stack_memory_is_in_use(zpl_stack_memory *s, void *ptr); - - //! Release the resources used by stack allocator. - ZPL_DEF_INLINE void zpl_stack_memory_free(zpl_stack_memory *s); - - //! Allocation Types: alloc, free, free_all - ZPL_DEF_INLINE zpl_allocator zpl_stack_allocator(zpl_stack_memory *s); - ZPL_DEF ZPL_ALLOCATOR_PROC(zpl_stack_allocator_proc); - - // TODO: Fixed heap allocator - // TODO: General heap allocator. Maybe a TCMalloc like clone? - - - /* inlines */ - - ZPL_IMPL_INLINE void *zpl_alloc_align(zpl_allocator a, zpl_isize size, zpl_isize alignment) { - return a.proc(a.data, ZPL_ALLOCATION_ALLOC, size, alignment, NULL, 0, ZPL_DEFAULT_ALLOCATOR_FLAGS); - } - ZPL_IMPL_INLINE void *zpl_alloc(zpl_allocator a, zpl_isize size) { - return zpl_alloc_align(a, size, ZPL_DEFAULT_MEMORY_ALIGNMENT); - } - ZPL_IMPL_INLINE void zpl_free(zpl_allocator a, void *ptr) { - if (ptr != NULL) a.proc(a.data, ZPL_ALLOCATION_FREE, 0, 0, ptr, 0, ZPL_DEFAULT_ALLOCATOR_FLAGS); - } - ZPL_IMPL_INLINE void zpl_free_all(zpl_allocator a) { - a.proc(a.data, ZPL_ALLOCATION_FREE_ALL, 0, 0, NULL, 0, ZPL_DEFAULT_ALLOCATOR_FLAGS); - } - ZPL_IMPL_INLINE void *zpl_resize(zpl_allocator a, void *ptr, zpl_isize old_size, zpl_isize new_size) { - return zpl_resize_align(a, ptr, old_size, new_size, ZPL_DEFAULT_MEMORY_ALIGNMENT); - } - ZPL_IMPL_INLINE void *zpl_resize_align(zpl_allocator a, void *ptr, zpl_isize old_size, zpl_isize new_size, zpl_isize alignment) { - return a.proc(a.data, ZPL_ALLOCATION_RESIZE, new_size, alignment, ptr, old_size, ZPL_DEFAULT_ALLOCATOR_FLAGS); + } else { + char buffer[256]; + + while (size > zpl_size_of(buffer)) { + zpl_memswap(i, j, zpl_size_of(buffer)); + i = zpl_pointer_add(i, zpl_size_of(buffer)); + j = zpl_pointer_add(j, zpl_size_of(buffer)); + size -= zpl_size_of(buffer); } + + zpl_memcopy(buffer, i, size); + zpl_memcopy(i, j, size); + zpl_memcopy(j, buffer, size); + } +} - ZPL_IMPL_INLINE void *zpl_alloc_copy(zpl_allocator a, void const *src, zpl_isize size) { - return zpl_memcopy(zpl_alloc(a, size), src, size); +void const *zpl_memchr(void const *data, zpl_u8 c, zpl_isize n) { + zpl_u8 const *s = cast(zpl_u8 const *) data; + while ((cast(zpl_uintptr) s & (sizeof(zpl_usize) - 1)) && n && *s != c) { + s++; + n--; + } + if (n && *s != c) { + zpl_isize const *w; + zpl_isize k = ZPL__ONES * c; + w = cast(zpl_isize const *) s; + while (n >= zpl_size_of(zpl_isize) && !ZPL__HAS_ZERO(*w ^ k)) { + w++; + n -= zpl_size_of(zpl_isize); } - ZPL_IMPL_INLINE void *zpl_alloc_copy_align(zpl_allocator a, void const *src, zpl_isize size, zpl_isize alignment) { - return zpl_memcopy(zpl_alloc_align(a, size, alignment), src, size); + s = cast(zpl_u8 const *) w; + while (n && *s != c) { + s++; + n--; } + } + + return n ? cast(void const *) s : NULL; +} - ZPL_IMPL_INLINE char *zpl_alloc_str_len(zpl_allocator a, char const *str, zpl_isize len) { - char *result; - result = cast(char *) zpl_alloc_copy(a, str, len + 1); - result[len] = '\0'; - return result; +void const *zpl_memrchr(void const *data, zpl_u8 c, zpl_isize n) { + zpl_u8 const *s = cast(zpl_u8 const *) data; + while (n--) { + if (s[n] == c) return cast(void const *)(s + n); + } + return NULL; +} + +void *zpl_memcopy(void *dest, void const *source, zpl_isize n) { + if (dest == NULL) { return NULL; } + + return memcpy(dest, source, n); + + // TODO: Re-work the whole method +#if 0 +#if defined(_MSC_VER) + __movsb(cast(zpl_u8 *) dest, cast(zpl_u8 *) source, n); +#elif defined(ZPL_CPU_X86) && !defined(ZPL_SYSTEM_EMSCRIPTEN) + zpl_u8 *__dest8 = cast(zpl_u8 *) dest; + zpl_u8 *__source8 = cast(zpl_u8 *) source; + __asm__ __volatile__("rep movsb" : "+D"(__dest8), "+S"(__source8), "+c"(n) : : "memory"); +#elif defined(ZPL_CPU_ARM) + return memcpy(dest, source, n); +#else + zpl_u8 *d = cast(zpl_u8 *) dest; + zpl_u8 const *s = cast(zpl_u8 const *) source; + zpl_u32 w, x; + + for (; cast(zpl_uintptr) s % 4 && n; n--) *d++ = *s++; + + if (cast(zpl_uintptr) d % 4 == 0) { + for (; n >= 16; s += 16, d += 16, n -= 16) { + *cast(zpl_u32 *)(d + 0) = *cast(zpl_u32 *)(s + 0); + *cast(zpl_u32 *)(d + 4) = *cast(zpl_u32 *)(s + 4); + *cast(zpl_u32 *)(d + 8) = *cast(zpl_u32 *)(s + 8); + *cast(zpl_u32 *)(d + 12) = *cast(zpl_u32 *)(s + 12); } + if (n & 8) { + *cast(zpl_u32 *)(d + 0) = *cast(zpl_u32 *)(s + 0); + *cast(zpl_u32 *)(d + 4) = *cast(zpl_u32 *)(s + 4); + d += 8; + s += 8; + } + if (n & 4) { + *cast(zpl_u32 *)(d + 0) = *cast(zpl_u32 *)(s + 0); + d += 4; + s += 4; + } + if (n & 2) { + *d++ = *s++; + *d++ = *s++; + } + if (n & 1) { *d = *s; } + return dest; + } + + if (n >= 32) { +#if __BYTE_ORDER == __BIG_ENDIAN +#define LS << +#define RS >> +#else +#define LS >> +#define RS << +#endif + switch (cast(zpl_uintptr) d % 4) { + case 1: { + w = *cast(zpl_u32 *) s; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + n -= 3; + while (n > 16) { + x = *cast(zpl_u32 *)(s + 1); + *cast(zpl_u32 *)(d + 0) = (w LS 24) | (x RS 8); + w = *cast(zpl_u32 *)(s + 5); + *cast(zpl_u32 *)(d + 4) = (x LS 24) | (w RS 8); + x = *cast(zpl_u32 *)(s + 9); + *cast(zpl_u32 *)(d + 8) = (w LS 24) | (x RS 8); + w = *cast(zpl_u32 *)(s + 13); + *cast(zpl_u32 *)(d + 12) = (x LS 24) | (w RS 8); + + s += 16; + d += 16; + n -= 16; + } + } break; + case 2: { + w = *cast(zpl_u32 *) s; + *d++ = *s++; + *d++ = *s++; + n -= 2; + while (n > 17) { + x = *cast(zpl_u32 *)(s + 2); + *cast(zpl_u32 *)(d + 0) = (w LS 16) | (x RS 16); + w = *cast(zpl_u32 *)(s + 6); + *cast(zpl_u32 *)(d + 4) = (x LS 16) | (w RS 16); + x = *cast(zpl_u32 *)(s + 10); + *cast(zpl_u32 *)(d + 8) = (w LS 16) | (x RS 16); + w = *cast(zpl_u32 *)(s + 14); + *cast(zpl_u32 *)(d + 12) = (x LS 16) | (w RS 16); + + s += 16; + d += 16; + n -= 16; + } + } break; + case 3: { + w = *cast(zpl_u32 *) s; + *d++ = *s++; + n -= 1; + while (n > 18) { + x = *cast(zpl_u32 *)(s + 3); + *cast(zpl_u32 *)(d + 0) = (w LS 8) | (x RS 24); + w = *cast(zpl_u32 *)(s + 7); + *cast(zpl_u32 *)(d + 4) = (x LS 8) | (w RS 24); + x = *cast(zpl_u32 *)(s + 11); + *cast(zpl_u32 *)(d + 8) = (w LS 8) | (x RS 24); + w = *cast(zpl_u32 *)(s + 15); + *cast(zpl_u32 *)(d + 12) = (x LS 8) | (w RS 24); + + s += 16; + d += 16; + n -= 16; + } + } break; + default: break; // NOTE: Do nowt! + } +#undef LS +#undef RS + if (n & 16) { + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + } + if (n & 8) { + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + } + if (n & 4) { + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + } + if (n & 2) { + *d++ = *s++; + *d++ = *s++; + } + if (n & 1) { *d = *s; } + } + +#endif +#endif + + return dest; +} - ZPL_IMPL_INLINE void *zpl_default_resize_align(zpl_allocator a, void *old_memory, zpl_isize old_size, zpl_isize new_size, - zpl_isize alignment) { - if (!old_memory) return zpl_alloc_align(a, new_size, alignment); +ZPL_END_C_DECLS +// file: source/core/memory_virtual.c - if (new_size == 0) { - zpl_free(a, old_memory); +//////////////////////////////////////////////////////////////// +// +// Virtual Memory +// +// +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +zpl_virtual_memory zpl_vm(void *data, zpl_isize size) { + zpl_virtual_memory vm; + vm.data = data; + vm.size = size; + return vm; +} + +#if defined(ZPL_SYSTEM_WINDOWS) +zpl_virtual_memory zpl_vm_alloc(void *addr, zpl_isize size) { + zpl_virtual_memory vm; + ZPL_ASSERT(size > 0); + vm.data = VirtualAlloc(addr, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + vm.size = size; + return vm; +} + +zpl_b32 zpl_vm_free(zpl_virtual_memory vm) { + MEMORY_BASIC_INFORMATION info; + while (vm.size > 0) { + if (VirtualQuery(vm.data, &info, zpl_size_of(info)) == 0) return false; + if (info.BaseAddress != vm.data || info.AllocationBase != vm.data || info.State != MEM_COMMIT || + info.RegionSize > cast(zpl_usize) vm.size) { + return false; + } + if (VirtualFree(vm.data, 0, MEM_RELEASE) == 0) return false; + vm.data = zpl_pointer_add(vm.data, info.RegionSize); + vm.size -= info.RegionSize; + } + return true; +} + +zpl_virtual_memory zpl_vm_trim(zpl_virtual_memory vm, zpl_isize lead_size, zpl_isize size) { + zpl_virtual_memory new_vm = { 0 }; + void *ptr; + ZPL_ASSERT(vm.size >= lead_size + size); + + ptr = zpl_pointer_add(vm.data, lead_size); + + zpl_vm_free(vm); + new_vm = zpl_vm_alloc(ptr, size); + if (new_vm.data == ptr) return new_vm; + if (new_vm.data) zpl_vm_free(new_vm); + return new_vm; +} + +zpl_b32 zpl_vm_purge(zpl_virtual_memory vm) { + VirtualAlloc(vm.data, vm.size, MEM_RESET, PAGE_READWRITE); + // NOTE: Can this really fail? + return true; +} + +zpl_isize zpl_virtual_memory_page_size(zpl_isize *alignment_out) { + SYSTEM_INFO info; + GetSystemInfo(&info); + if (alignment_out) *alignment_out = info.dwAllocationGranularity; + return info.dwPageSize; +} + +#else +#include + +#ifndef MAP_ANONYMOUS +#define MAP_ANONYMOUS MAP_ANON +#endif + +zpl_virtual_memory zpl_vm_alloc(void *addr, zpl_isize size) { + zpl_virtual_memory vm; + ZPL_ASSERT(size > 0); + vm.data = mmap(addr, size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + vm.size = size; + return vm; +} + +zpl_b32 zpl_vm_free(zpl_virtual_memory vm) { + munmap(vm.data, vm.size); + return true; +} + +zpl_virtual_memory zpl_vm_trim(zpl_virtual_memory vm, zpl_isize lead_size, zpl_isize size) { + void *ptr; + zpl_isize trail_size; + ZPL_ASSERT(vm.size >= lead_size + size); + + ptr = zpl_pointer_add(vm.data, lead_size); + trail_size = vm.size - lead_size - size; + + if (lead_size != 0) zpl_vm_free(zpl_vm(vm.data, lead_size)); + if (trail_size != 0) zpl_vm_free(zpl_vm(ptr, trail_size)); + return zpl_vm(ptr, size); +} + +zpl_b32 zpl_vm_purge(zpl_virtual_memory vm) { + int err = madvise(vm.data, vm.size, MADV_DONTNEED); + return err != 0; +} + +zpl_isize zpl_virtual_memory_page_size(zpl_isize *alignment_out) { + // TODO: Is this always true? + zpl_isize result = cast(zpl_isize) sysconf(_SC_PAGE_SIZE); + if (alignment_out) *alignment_out = result; + return result; +} + +#endif + +ZPL_END_C_DECLS +// file: source/core/memory_custom.c + +#ifdef ZPL_EDITOR +#include +#endif + +#ifndef _IOSC11_SOURCE +#define _IOSC11_SOURCE +#endif + +#include + +#if defined(ZPL_SYSTEM_WINDOWS) +#include +#endif + +#if defined(ZPL_COMPILER_MINGW) +#ifdef __MINGW32__ +#define _aligned_malloc __mingw_aligned_malloc +#define _aligned_free __mingw_aligned_free +#endif //MINGW +#endif + +ZPL_BEGIN_C_DECLS + +char *zpl_alloc_str(zpl_allocator a, char const *str) { + return zpl_alloc_str_len(a, str, zpl_strlen(str)); +} + +//////////////////////////////////////////////////////////////// +// +// Custom Allocation +// +// + +// +// Heap Allocator +// + +ZPL_ALLOCATOR_PROC(zpl_heap_allocator_proc) { + void *ptr = NULL; + zpl_unused(allocator_data); + zpl_unused(old_size); + // TODO: Throughly test! + switch (type) { +#if defined(ZPL_COMPILER_MSVC) || (defined(ZPL_COMPILER_GCC) && defined(ZPL_SYSTEM_WINDOWS)) + case ZPL_ALLOCATION_ALLOC: + ptr = _aligned_malloc(size, alignment); + if (flags & ZPL_ALLOCATOR_FLAG_CLEAR_TO_ZERO) zpl_zero_size(ptr, size); + break; + case ZPL_ALLOCATION_FREE: _aligned_free(old_memory); break; + case ZPL_ALLOCATION_RESIZE: ptr = _aligned_realloc(old_memory, size, alignment); break; + +#elif defined(ZPL_SYSTEM_LINUX) && !defined(ZPL_CPU_ARM) + case ZPL_ALLOCATION_ALLOC: { + ptr = aligned_alloc(alignment, size); + + if (flags & ZPL_ALLOCATOR_FLAG_CLEAR_TO_ZERO) { zpl_zero_size(ptr, size); } + } break; + + case ZPL_ALLOCATION_FREE: { + free(old_memory); + } break; + + case ZPL_ALLOCATION_RESIZE: { + zpl_allocator a = zpl_heap_allocator( ); + ptr = zpl_default_resize_align(a, old_memory, old_size, size, alignment); + } break; +#else + case ZPL_ALLOCATION_ALLOC: { + posix_memalign(&ptr, alignment, size); + + if (flags & ZPL_ALLOCATOR_FLAG_CLEAR_TO_ZERO) { zpl_zero_size(ptr, size); } + } break; + + case ZPL_ALLOCATION_FREE: { + free(old_memory); + } break; + + case ZPL_ALLOCATION_RESIZE: { + zpl_allocator a = zpl_heap_allocator( ); + ptr = zpl_default_resize_align(a, old_memory, old_size, size, alignment); + } break; +#endif + + case ZPL_ALLOCATION_FREE_ALL: break; + } + + return ptr; +} + +// +// Arena Allocator +// + +ZPL_ALLOCATOR_PROC(zpl_arena_allocator_proc) { + zpl_arena *arena = cast(zpl_arena *) allocator_data; + void *ptr = NULL; + + zpl_unused(old_size); + + switch (type) { + case ZPL_ALLOCATION_ALLOC: { + void *end = zpl_pointer_add(arena->physical_start, arena->total_allocated); + zpl_isize total_size = size + alignment; + + // NOTE: Out of memory + if (arena->total_allocated + total_size > cast(zpl_isize) arena->total_size) { + zpl_printf_err("Arena out of memory\n"); return NULL; } - - if (new_size < old_size) new_size = old_size; - - if (old_size == new_size) { - return old_memory; - } else { - void *new_memory = zpl_alloc_align(a, new_size, alignment); - if (!new_memory) return NULL; - zpl_memmove(new_memory, old_memory, zpl_min(new_size, old_size)); - zpl_free(a, old_memory); - return new_memory; - } - } - - - // - // Heap Allocator - // - - ZPL_IMPL_INLINE zpl_allocator zpl_heap_allocator(void) { - zpl_allocator a; - a.proc = zpl_heap_allocator_proc; - a.data = NULL; - return a; - } - - // - // Arena Allocator - // - - ZPL_IMPL_INLINE void zpl_arena_init_from_memory(zpl_arena *arena, void *start, zpl_isize size) { - arena->backing.proc = NULL; - arena->backing.data = NULL; - arena->physical_start = start; - arena->total_size = size; - arena->total_allocated = 0; - arena->temp_count = 0; - } - - ZPL_IMPL_INLINE void zpl_arena_init_from_allocator(zpl_arena *arena, zpl_allocator backing, zpl_isize size) { - arena->backing = backing; - arena->physical_start = zpl_alloc(backing, size); // NOTE: Uses default alignment - arena->total_size = size; - arena->total_allocated = 0; - arena->temp_count = 0; - } - - ZPL_IMPL_INLINE void zpl_arena_init_sub(zpl_arena *arena, zpl_arena *parent_arena, zpl_isize size) { - zpl_arena_init_from_allocator(arena, zpl_arena_allocator(parent_arena), size); - } - - ZPL_IMPL_INLINE void zpl_arena_free(zpl_arena *arena) { - if (arena->backing.proc) { - zpl_free(arena->backing, arena->physical_start); - arena->physical_start = NULL; - } - } - - ZPL_IMPL_INLINE zpl_isize zpl_arena_alignment_of(zpl_arena *arena, zpl_isize alignment) { - zpl_isize alignment_offset, result_pointer, mask; - ZPL_ASSERT(zpl_is_power_of_two(alignment)); - - alignment_offset = 0; - result_pointer = cast(zpl_isize) arena->physical_start + arena->total_allocated; - mask = alignment - 1; - if (result_pointer & mask) alignment_offset = alignment - (result_pointer & mask); - - return alignment_offset; - } - - ZPL_IMPL_INLINE zpl_isize zpl_arena_size_remaining(zpl_arena *arena, zpl_isize alignment) { - zpl_isize result = arena->total_size - (arena->total_allocated + zpl_arena_alignment_of(arena, alignment)); - return result; - } - - ZPL_IMPL_INLINE void zpl_arena_check(zpl_arena *arena) { ZPL_ASSERT(arena->temp_count == 0); } - - ZPL_IMPL_INLINE zpl_allocator zpl_arena_allocator(zpl_arena *arena) { - zpl_allocator allocator; - allocator.proc = zpl_arena_allocator_proc; - allocator.data = arena; - return allocator; - } - - ZPL_IMPL_INLINE zpl_temp_arena_memory zpl_temp_arena_memory_begin(zpl_arena *arena) { - zpl_temp_arena_memory tmp; - tmp.arena = arena; - tmp.original_count = arena->total_allocated; - arena->temp_count++; - return tmp; - } - - ZPL_IMPL_INLINE void zpl_temp_arena_memory_end(zpl_temp_arena_memory tmp) { - ZPL_ASSERT(tmp.arena->total_allocated >= tmp.original_count); - ZPL_ASSERT(tmp.arena->temp_count > 0); - tmp.arena->total_allocated = tmp.original_count; - tmp.arena->temp_count--; - } - - // - // Pool Allocator - // - - ZPL_IMPL_INLINE void zpl_pool_init(zpl_pool *pool, zpl_allocator backing, zpl_isize num_blocks, zpl_isize block_size) { - zpl_pool_init_align(pool, backing, num_blocks, block_size, ZPL_DEFAULT_MEMORY_ALIGNMENT); - } - - ZPL_IMPL_INLINE void zpl_pool_free(zpl_pool *pool) { - if (pool->backing.proc) { zpl_free(pool->backing, pool->physical_start); } - } - - ZPL_IMPL_INLINE zpl_allocator zpl_pool_allocator(zpl_pool *pool) { - zpl_allocator allocator; - allocator.proc = zpl_pool_allocator_proc; - allocator.data = pool; - return allocator; - } - - ZPL_IMPL_INLINE zpl_allocation_header_ev *zpl_allocation_header(void *data) { - zpl_isize *p = cast(zpl_isize *) data; - while (p[-1] == cast(zpl_isize)(-1)) p--; - return cast(zpl_allocation_header_ev *) p - 1; - } - - ZPL_IMPL_INLINE void zpl_allocation_header_fill(zpl_allocation_header_ev *header, void *data, zpl_isize size) { - zpl_isize *ptr; - header->size = size; - ptr = cast(zpl_isize *)(header + 1); - while (cast(void *) ptr < data) *ptr++ = cast(zpl_isize)(-1); - } - - // - // Stack Memory Allocator - // - - #define ZPL_STACK_ALLOC_OFFSET sizeof(zpl_u64) - ZPL_STATIC_ASSERT(ZPL_STACK_ALLOC_OFFSET == 8, "ZPL_STACK_ALLOC_OFFSET != 8"); - - ZPL_IMPL_INLINE void zpl_stack_memory_init_from_memory(zpl_stack_memory *s, void *start, zpl_isize size) { - s->physical_start = start; - s->total_size = size; - s->allocated = 0; - } - - ZPL_IMPL_INLINE void zpl_stack_memory_init(zpl_stack_memory *s, zpl_allocator backing, zpl_isize size) { - s->backing = backing; - s->physical_start = zpl_alloc(backing, size); - s->total_size = size; - s->allocated = 0; - } - - ZPL_IMPL_INLINE zpl_b32 zpl_stack_memory_is_in_use(zpl_stack_memory *s, void *ptr) { - if (s->allocated == 0) return false; - - if (ptr > s->physical_start && ptr < zpl_pointer_add(s->physical_start, s->total_size)) { return true; } - - return false; - } - - ZPL_IMPL_INLINE void zpl_stack_memory_free(zpl_stack_memory *s) { - if (s->backing.proc) { - zpl_free(s->backing, s->physical_start); - s->physical_start = NULL; - } - } - - ZPL_IMPL_INLINE zpl_allocator zpl_stack_allocator(zpl_stack_memory *s) { - zpl_allocator a; - a.proc = zpl_stack_allocator_proc; - a.data = s; - return a; - } - - ZPL_END_C_DECLS - // file: header/core/collections/array.h - - //////////////////////////////////////////////////////////////// - // - // Dynamic Array (POD Types) - // - // zpl_array(Type) works like zpl_string or zpl_buffer where the actual type is just a pointer to the first - // element. - // - // Available Procedures for zpl_array(Type) - // zpl_array_init - // zpl_array_free - // zpl_array_set_capacity - // zpl_array_grow - // zpl_array_append - // zpl_array_appendv - // zpl_array_pop - // zpl_array_clear - // zpl_array_back - // zpl_array_front - // zpl_array_resize - // zpl_array_reserve - // - - #if 0 // Example - void foo(void) { - zpl_isize i; - int test_values[] = {4, 2, 1, 7}; - zpl_allocator a = zpl_heap_allocator(); - zpl_array(int) items; - - zpl_array_init(items, a); - - zpl_array_append(items, 1); - zpl_array_append(items, 4); - zpl_array_append(items, 9); - zpl_array_append(items, 16); - - items[1] = 3; // Manually set value - // NOTE: No array bounds checking - - for (i = 0; i < items.count; i++) - zpl_printf("%d\n", items[i]); - // 1 - // 3 - // 9 - // 16 - - zpl_array_clear(items); - - zpl_array_appendv(items, test_values, zpl_count_of(test_values)); - for (i = 0; i < items.count; i++) - zpl_printf("%d\n", items[i]); - // 4 - // 2 - // 1 - // 7 - - zpl_array_free(items); - } - #endif - - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - typedef struct zpl_array_header { - char *data; - zpl_isize count; - zpl_isize capacity; - zpl_allocator allocator; - } zpl_array_header; - - #define zpl_array(Type) Type * - - #define zpl_array_make(Type, Name, allocator) Type *Name; zpl_array_init(Name, allocator) - - #ifndef ZPL_ARRAY_GROW_FORMULA - #define ZPL_ARRAY_GROW_FORMULA(x) (2 * (x) + 8) - #endif - - ZPL_STATIC_ASSERT(ZPL_ARRAY_GROW_FORMULA(0) > 0, "ZPL_ARRAY_GROW_FORMULA(0) <= 0"); - - #define ZPL_ARRAY_HEADER(x) (cast(zpl_array_header *)(x) - 1) - #define zpl_array_allocator(x) (ZPL_ARRAY_HEADER(x)->allocator) - #define zpl_array_count(x) (ZPL_ARRAY_HEADER(x)->count) - #define zpl_array_capacity(x) (ZPL_ARRAY_HEADER(x)->capacity) - #define zpl_array_end(x) (x + (zpl_array_count(x) - 1)) - - #define zpl_array_init_reserve(x, allocator_, cap) \ - do { \ - void **zpl__array_ = cast(void **) & (x); \ - zpl_array_header *zpl__ah = \ - cast(zpl_array_header *) zpl_alloc(allocator_, zpl_size_of(zpl_array_header) + zpl_size_of(*(x)) * (cap)); \ - zpl__ah->allocator = allocator_; \ - zpl__ah->count = 0; \ - zpl__ah->data = (char *)x; \ - zpl__ah->capacity = cap; \ - *zpl__array_ = cast(void *)(zpl__ah + 1); \ - } while (0) - - // NOTE: Give it an initial default capacity - #define zpl_array_init(x, allocator) zpl_array_init_reserve(x, allocator, ZPL_ARRAY_GROW_FORMULA(0)) - - #define zpl_array_free(x) \ - do { \ - zpl_array_header *zpl__ah = ZPL_ARRAY_HEADER(x); \ - zpl_free(zpl__ah->allocator, zpl__ah); \ - } while (0) - - #define zpl_array_set_capacity(x, capacity) \ - do { \ - if (x) { \ - void **zpl__array_ = cast(void **) & (x); \ - *zpl__array_ = zpl__array_set_capacity((x), (capacity), zpl_size_of(*(x))); \ - } \ - } while (0) - - // NOTE: Do not use the thing below directly, use the macro - ZPL_DEF void *zpl__array_set_capacity(void *array, zpl_isize capacity, zpl_isize element_size); - - #define zpl_array_grow(x, min_capacity) \ - do { \ - zpl_isize new_capacity = ZPL_ARRAY_GROW_FORMULA(zpl_array_capacity(x)); \ - if (new_capacity < (min_capacity)) new_capacity = (min_capacity); \ - zpl_array_set_capacity(x, new_capacity); \ - } while (0) - - #define zpl_array_append(x, item) \ - do { \ - if (zpl_array_capacity(x) < zpl_array_count(x) + 1) zpl_array_grow(x, 0); \ - (x)[zpl_array_count(x)++] = (item); \ - } while (0) - - #define zpl_array_append_at(x, item, ind) \ - do { \ - zpl_array_header *zpl__ah = ZPL_ARRAY_HEADER(x); \ - if (ind == zpl__ah->count) { zpl_array_append(x, item); break; } \ - if (zpl_array_capacity(x) < zpl_array_count(x) + 1) zpl_array_grow(x, 0); \ - zpl_memmove(&(x)[ind + 1], (x + ind), zpl_size_of(x[0]) * (zpl__ah->count - ind)); \ - x[ind] = item; \ - zpl__ah->count++; \ - } while (0) - - #define zpl_array_appendv(x, items, item_count) \ - do { \ - zpl_array_header *zpl__ah = ZPL_ARRAY_HEADER(x); \ - ZPL_ASSERT(zpl_size_of((items)[0]) == zpl_size_of((x)[0])); \ - if (zpl__ah->capacity < zpl__ah->count + (item_count)) zpl_array_grow(x, zpl__ah->count + (item_count)); \ - zpl_memcopy(&(x)[zpl__ah->count], (items), zpl_size_of((x)[0]) * (item_count)); \ - zpl__ah->count += (item_count); \ - } while (0) - - #define zpl_array_remove_at(x, index) \ - do { \ - zpl_array_header *zpl__ah = ZPL_ARRAY_HEADER(x); \ - ZPL_ASSERT(index < zpl__ah->count); \ - zpl_memmove(x + index, x + index + 1, zpl_size_of(x[0]) * (zpl__ah->count - index)); \ - --zpl__ah->count; \ - } while (0) - - #define zpl_array_copy_init(y, x) \ - do { \ - zpl_array_init_reserve(y, zpl_array_allocator(x), zpl_array_capacity(x)); \ - zpl_memcopy(y, x, zpl_array_capacity(x) * zpl_size_of(*x)); \ - zpl_array_count(y) = zpl_array_count(x); \ - } while (0) - - #define zpl_array_pop(x) \ - do { \ - ZPL_ASSERT(ZPL_ARRAY_HEADER(x)->count > 0); \ - ZPL_ARRAY_HEADER(x)->count--; \ - } while (0) - #define zpl_array_back(x) x[ZPL_ARRAY_HEADER(x)->count - 1] - #define zpl_array_front(x) x[0] - #define zpl_array_clear(x) \ - do { ZPL_ARRAY_HEADER(x)->count = 0; } while (0) - - #define zpl_array_resize(x, new_count) \ - do { \ - if (ZPL_ARRAY_HEADER(x)->capacity < (new_count)) zpl_array_grow(x, (new_count)); \ - ZPL_ARRAY_HEADER(x)->count = (new_count); \ - } while (0) - - #define zpl_array_reserve(x, new_capacity) \ - do { \ - if (ZPL_ARRAY_HEADER(x)->capacity < (new_capacity)) zpl_array_set_capacity(x, new_capacity); \ - } while (0) - - ZPL_END_C_DECLS - // file: header/core/collections/buffer.h - - //////////////////////////////////////////////////////////////// - // - // Fixed Capacity Buffer (POD Types) - // - // - // zpl_buffer(Type) works like zpl_string or zpl_array where the actual type is just a pointer to the first - // element. - // - // Available Procedures for zpl_buffer(Type) - // zpl_buffer_init - // zpl_buffer_free - // zpl_buffer_append - // zpl_buffer_appendv - // zpl_buffer_pop - // zpl_buffer_clear - - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - typedef struct zpl_buffer_header { - zpl_allocator backing; - zpl_isize count; - zpl_isize capacity; - } zpl_buffer_header; - - #define zpl_buffer(Type) Type * - - #define zpl_buffer_make(Type, Name, allocator, cap) Type *Name; zpl_buffer_init(Name, allocator, cap) - - #define ZPL_BUFFER_HEADER(x) (cast(zpl_buffer_header *)(x) - 1) - #define zpl_buffer_count(x) (ZPL_BUFFER_HEADER(x)->count) - #define zpl_buffer_capacity(x) (ZPL_BUFFER_HEADER(x)->capacity) - #define zpl_buffer_end(x) (x + (zpl_buffer_count(x) - 1)) - - #define zpl_buffer_init(x, allocator, cap) \ - do { \ - void **nx = cast(void **) & (x); \ - zpl_buffer_header *zpl__bh = \ - cast(zpl_buffer_header *) zpl_alloc((allocator), sizeof(zpl_buffer_header) + (cap)*zpl_size_of(*(x))); \ - zpl__bh->backing = allocator; \ - zpl__bh->count = 0; \ - zpl__bh->capacity = cap; \ - *nx = cast(void *)(zpl__bh + 1); \ - } while (0) - - #define zpl_buffer_free(x) (zpl_free(ZPL_BUFFER_HEADER(x)->backing, ZPL_BUFFER_HEADER(x))) - - #define zpl_buffer_append(x, item) \ - do { (x)[zpl_buffer_count(x)++] = (item); } while (0) - - #define zpl_buffer_appendv(x, items, item_count) \ - do { \ - ZPL_ASSERT(zpl_size_of(*(items)) == zpl_size_of(*(x))); \ - ZPL_ASSERT(zpl_buffer_count(x) + item_count <= zpl_buffer_capacity(x)); \ - zpl_memcopy(&(x)[zpl_buffer_count(x)], (items), zpl_size_of(*(x)) * (item_count)); \ - zpl_buffer_count(x) += (item_count); \ - } while (0) - - #define zpl_buffer_copy_init(y, x) \ - do { \ - zpl_buffer_init_reserve(y, zpl_buffer_allocator(x), zpl_buffer_capacity(x)); \ - zpl_memcopy(y, x, zpl_buffer_capacity(x) * zpl_size_of(*x)); \ - zpl_buffer_count(y) = zpl_buffer_count(x); \ - } while (0) - - #define zpl_buffer_pop(x) \ - do { \ - ZPL_ASSERT(zpl_buffer_count(x) > 0); \ - zpl_buffer_count(x)--; \ - } while (0) - #define zpl_buffer_clear(x) \ - do { zpl_buffer_count(x) = 0; } while (0) - - ZPL_END_C_DECLS - // file: header/core/collections/list.h - - //////////////////////////////////////////////////////////////// - // - // Linked List - // - // zpl_list encapsulates pointer to data and points to the next and the previous element in the list. - // - // Available Procedures for zpl_list - // zpl_list_init - // zpl_list_add - // zpl_list_remove - - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - #if 0 - #define ZPL_IMPLEMENTATION - #include "zpl.h" - int main(void) - { - zpl_list s, *head, *cursor; - zpl_list_init(&s, "it is optional to call init: "); - head = cursor = &s; - - // since we can construct an element implicitly this way - // the second field gets overwritten once we add it to a list. - zpl_list a = {"hello"}; - cursor = zpl_list_add(cursor, &a); - - zpl_list b = {"world"}; - cursor = zpl_list_add(cursor, &b); - - zpl_list c = {"!!! OK"}; - cursor = zpl_list_add(cursor, &c); - - for (zpl_list *l=head; l; l=l->next) { - zpl_printf("%s ", cast(char *)l->ptr); - } - zpl_printf("\n"); - - return 0; - } - #endif - - - typedef struct zpl__list { - void const *ptr; - struct zpl__list *next, *prev; - } zpl_list; - - ZPL_DEF_INLINE void zpl_list_init(zpl_list *list, void const *ptr); - ZPL_DEF_INLINE zpl_list *zpl_list_add(zpl_list *list, zpl_list *item); - - // NOTE(zaklaus): Returns a pointer to the next node (or NULL if the removed node has no trailing node.) - ZPL_DEF_INLINE zpl_list *zpl_list_remove(zpl_list *list); - - - ZPL_IMPL_INLINE void zpl_list_init(zpl_list *list, void const *ptr) { - zpl_list list_ = { 0 }; - *list = list_; - list->ptr = ptr; - } - - ZPL_IMPL_INLINE zpl_list *zpl_list_add(zpl_list *list, zpl_list *item) { - item->next = NULL; - - if (list->next) { item->next = list->next; } - - list->next = item; - item->prev = list; - return item; - } - - ZPL_IMPL_INLINE zpl_list *zpl_list_remove(zpl_list *list) { - if (list->prev) { list->prev->next = list->next; } - - return list->next; - } - - ZPL_END_C_DECLS - // file: header/core/collections/ring.h - - //////////////////////////////////////////////////////////////// - // - // Instantiated Circular buffer - // - /* - int main() - { - zpl_ring_zpl_u32 pad={0}; - zpl_ring_zpl_u32_init(&pad, zpl_heap(), 3); - zpl_ring_zpl_u32_append(&pad, 1); - zpl_ring_zpl_u32_append(&pad, 2); - zpl_ring_zpl_u32_append(&pad, 3); - - while (!zpl_ring_zpl_u32_empty(&pad)) { - zpl_printf("Result is %d\n", *zpl_ring_zpl_u32_get(&pad)); - } - - zpl_ring_zpl_u32_free(&pad); - - return 0; - } - */ - - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - #define ZPL_RING_DECLARE(type) \ - typedef struct { \ - zpl_allocator backing; \ - zpl_buffer(type) buf; \ - zpl_usize head, tail; \ - zpl_usize capacity; \ - } ZPL_JOIN2(zpl_ring_, type); \ - \ - ZPL_DEF void ZPL_JOIN3(zpl_ring_, type, _init)(ZPL_JOIN2(zpl_ring_, type) * pad, zpl_allocator a, zpl_isize max_size); \ - ZPL_DEF void ZPL_JOIN3(zpl_ring_, type, _free)(ZPL_JOIN2(zpl_ring_, type) * pad); \ - ZPL_DEF zpl_b32 ZPL_JOIN3(zpl_ring_, type, _full)(ZPL_JOIN2(zpl_ring_, type) * pad); \ - ZPL_DEF zpl_b32 ZPL_JOIN3(zpl_ring_, type, _empty)(ZPL_JOIN2(zpl_ring_, type) * pad); \ - ZPL_DEF void ZPL_JOIN3(zpl_ring_, type, _append)(ZPL_JOIN2(zpl_ring_, type) * pad, type data); \ - ZPL_DEF void ZPL_JOIN3(zpl_ring_, type, _append_array)(ZPL_JOIN2(zpl_ring_, type) * pad, zpl_array(type) data); \ - ZPL_DEF type *ZPL_JOIN3(zpl_ring_, type, _get)(ZPL_JOIN2(zpl_ring_, type) * pad); \ - ZPL_DEF zpl_array(type) \ - ZPL_JOIN3(zpl_ring_, type, _get_array)(ZPL_JOIN2(zpl_ring_, type) * pad, zpl_usize max_size, zpl_allocator a); - - #define ZPL_RING_DEFINE(type) \ - void ZPL_JOIN3(zpl_ring_, type, _init)(ZPL_JOIN2(zpl_ring_, type) * pad, zpl_allocator a, zpl_isize max_size) { \ - ZPL_JOIN2(zpl_ring_, type) pad_ = { 0 }; \ - *pad = pad_; \ - \ - pad->backing = a; \ - zpl_buffer_init(pad->buf, a, max_size + 1); \ - pad->capacity = max_size + 1; \ - pad->head = pad->tail = 0; \ - } \ - void ZPL_JOIN3(zpl_ring_, type, _free)(ZPL_JOIN2(zpl_ring_, type) * pad) { \ - zpl_buffer_free(pad->buf); \ - } \ - \ - zpl_b32 ZPL_JOIN3(zpl_ring_, type, _full)(ZPL_JOIN2(zpl_ring_, type) * pad) { \ - return ((pad->head + 1) % pad->capacity) == pad->tail; \ - } \ - \ - zpl_b32 ZPL_JOIN3(zpl_ring_, type, _empty)(ZPL_JOIN2(zpl_ring_, type) * pad) { return pad->head == pad->tail; } \ - \ - void ZPL_JOIN3(zpl_ring_, type, _append)(ZPL_JOIN2(zpl_ring_, type) * pad, type data) { \ - pad->buf[pad->head] = data; \ - pad->head = (pad->head + 1) % pad->capacity; \ - \ - if (pad->head == pad->tail) { pad->tail = (pad->tail + 1) % pad->capacity; } \ - } \ - \ - void ZPL_JOIN3(zpl_ring_, type, _append_array)(ZPL_JOIN2(zpl_ring_, type) * pad, zpl_array(type) data) { \ - zpl_usize c = zpl_array_count(data); \ - for (zpl_usize i = 0; i < c; ++i) { ZPL_JOIN3(zpl_ring_, type, _append)(pad, data[i]); } \ - } \ - \ - type *ZPL_JOIN3(zpl_ring_, type, _get)(ZPL_JOIN2(zpl_ring_, type) * pad) { \ - if (ZPL_JOIN3(zpl_ring_, type, _empty)(pad)) { return NULL; } \ - \ - type *data = &pad->buf[pad->tail]; \ - pad->tail = (pad->tail + 1) % pad->capacity; \ - \ - return data; \ - } \ - \ - zpl_array(type) \ - ZPL_JOIN3(zpl_ring_, type, _get_array)(ZPL_JOIN2(zpl_ring_, type) * pad, zpl_usize max_size, zpl_allocator a) { \ - zpl_array(type) vals = 0; \ - zpl_array_init(vals, a); \ - while (--max_size && !ZPL_JOIN3(zpl_ring_, type, _empty)(pad)) { \ - zpl_array_append(vals, *ZPL_JOIN3(zpl_ring_, type, _get)(pad)); \ - } \ - return vals; \ - } - - ZPL_END_C_DECLS - // file: header/core/collections/hashtable.h - - /** @file hashtable.c - @brief Instantiated hash table - @defgroup hashtable Instantiated hash table - - @n - @n This is an attempt to implement a templated hash table - @n NOTE: The key is always a zpl_u64 for simplicity and you will _probably_ _never_ need anything bigger. - @n - @n Hash table type and function declaration, call: ZPL_TABLE_DECLARE(PREFIX, NAME, N, VALUE) - @n Hash table function definitions, call: ZPL_TABLE_DEFINE(NAME, N, VALUE) - @n - @n PREFIX - a prefix for function prototypes e.g. extern, static, etc. - @n NAME - Name of the Hash Table - @n FUNC - the name will prefix function names - @n VALUE - the type of the value to be stored - @n - @n tablename_init(NAME * h, zpl_allocator a); - @n tablename_destroy(NAME * h); - @n tablename_get(NAME * h, zpl_u64 key); - @n tablename_set(NAME * h, zpl_u64 key, VALUE value); - @n tablename_grow(NAME * h); - @n tablename_rehash(NAME * h, zpl_isize new_count); - @n tablename_remove(NAME * h, zpl_u64 key); - - @{ - */ - - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - typedef struct zpl_hash_table_find_result { - zpl_isize hash_index; - zpl_isize entry_prev; - zpl_isize entry_index; - } zpl_hash_table_find_result; - - #define ZPL_TABLE(PREFIX, NAME, FUNC, VALUE) \ - ZPL_TABLE_DECLARE(PREFIX, NAME, FUNC, VALUE); \ - ZPL_TABLE_DEFINE(NAME, FUNC, VALUE); - - #define ZPL_TABLE_DECLARE(PREFIX, NAME, FUNC, VALUE) \ - typedef struct ZPL_JOIN2(NAME, Entry) { \ - zpl_u64 key; \ - zpl_isize next; \ - VALUE value; \ - } ZPL_JOIN2(NAME, Entry); \ - \ - typedef struct NAME { \ - zpl_array(zpl_isize) hashes; \ - zpl_array(ZPL_JOIN2(NAME, Entry)) entries; \ - } NAME; \ - \ - PREFIX void ZPL_JOIN2(FUNC, init)(NAME * h, zpl_allocator a); \ - PREFIX void ZPL_JOIN2(FUNC, destroy)(NAME * h); \ - PREFIX VALUE *ZPL_JOIN2(FUNC, get)(NAME * h, zpl_u64 key); \ - PREFIX void ZPL_JOIN2(FUNC, set)(NAME * h, zpl_u64 key, VALUE value); \ - PREFIX void ZPL_JOIN2(FUNC, grow)(NAME * h); \ - PREFIX void ZPL_JOIN2(FUNC, rehash)(NAME * h, zpl_isize new_count); \ - PREFIX void ZPL_JOIN2(FUNC, remove)(NAME * h, zpl_u64 key); - - #define ZPL_TABLE_DEFINE(NAME, FUNC, VALUE) \ - void ZPL_JOIN2(FUNC, init)(NAME * h, zpl_allocator a) { \ - zpl_array_init(h->hashes, a); \ - zpl_array_init(h->entries, a); \ - } \ - \ - void ZPL_JOIN2(FUNC, destroy)(NAME * h) { \ - if (h->entries) zpl_array_free(h->entries); \ - if (h->hashes) zpl_array_free(h->hashes); \ - } \ - \ - zpl_internal zpl_isize ZPL_JOIN2(FUNC, _add_entry)(NAME * h, zpl_u64 key) { \ - zpl_isize index; \ - ZPL_JOIN2(NAME, Entry) e = { 0 }; \ - e.key = key; \ - e.next = -1; \ - index = zpl_array_count(h->entries); \ - zpl_array_append(h->entries, e); \ - return index; \ - } \ - \ - zpl_internal zpl_hash_table_find_result ZPL_JOIN2(FUNC, _find)(NAME * h, zpl_u64 key) { \ - zpl_hash_table_find_result r = { -1, -1, -1 }; \ - if (zpl_array_count(h->hashes) > 0) { \ - r.hash_index = key % zpl_array_count(h->hashes); \ - r.entry_index = h->hashes[r.hash_index]; \ - while (r.entry_index >= 0) { \ - if (h->entries[r.entry_index].key == key) return r; \ - r.entry_prev = r.entry_index; \ - r.entry_index = h->entries[r.entry_index].next; \ - } \ - } \ - return r; \ - } \ - \ - zpl_internal zpl_b32 ZPL_JOIN2(FUNC, _full)(NAME * h) { \ - return 0.75f * zpl_array_count(h->hashes) < zpl_array_count(h->entries); \ - } \ - \ - void ZPL_JOIN2(FUNC, grow)(NAME * h) { \ - zpl_isize new_count = ZPL_ARRAY_GROW_FORMULA(zpl_array_count(h->entries)); \ - ZPL_JOIN2(FUNC, rehash)(h, new_count); \ - } \ - \ - void ZPL_JOIN2(FUNC, rehash)(NAME * h, zpl_isize new_count) { \ - zpl_isize i, j; \ - NAME nh = { 0 }; \ - ZPL_JOIN2(FUNC, init)(&nh, zpl_array_allocator(h->hashes)); \ - zpl_array_resize(nh.hashes, new_count); \ - zpl_array_reserve(nh.entries, zpl_array_count(h->entries)); \ - for (i = 0; i < new_count; i++) nh.hashes[i] = -1; \ - for (i = 0; i < zpl_array_count(h->entries); i++) { \ - ZPL_JOIN2(NAME, Entry) * e; \ - zpl_hash_table_find_result fr; \ - if (zpl_array_count(nh.hashes) == 0) ZPL_JOIN2(FUNC, grow)(&nh); \ - e = &h->entries[i]; \ - fr = ZPL_JOIN2(FUNC, _find)(&nh, e->key); \ - j = ZPL_JOIN2(FUNC, _add_entry)(&nh, e->key); \ - if (fr.entry_prev < 0) \ - nh.hashes[fr.hash_index] = j; \ - else \ - nh.entries[fr.entry_prev].next = j; \ - nh.entries[j].next = fr.entry_index; \ - nh.entries[j].value = e->value; \ - } \ - ZPL_JOIN2(FUNC, destroy)(h); \ - h->hashes = nh.hashes; \ - h->entries = nh.entries; \ - } \ - \ - VALUE *ZPL_JOIN2(FUNC, get)(NAME * h, zpl_u64 key) { \ - zpl_isize index = ZPL_JOIN2(FUNC, _find)(h, key).entry_index; \ - if (index >= 0) return &h->entries[index].value; \ - return NULL; \ - } \ - \ - void ZPL_JOIN2(FUNC, remove)(NAME * h, zpl_u64 key) { \ - zpl_hash_table_find_result fr = ZPL_JOIN2(FUNC, _find)(h, key); \ - if (fr.entry_index >= 0) { \ - if (fr.entry_prev >= 0) { \ - h->entries[fr.entry_prev].next = h->entries[fr.entry_index].next; \ - } else { \ - h->hashes[fr.hash_index] = fr.entry_index; \ - } \ - zpl_array_remove_at(h->entries, fr.entry_index); \ - } \ - ZPL_JOIN2(FUNC, rehash)(h, zpl_array_count(h->entries)); \ - } \ - \ - void ZPL_JOIN2(FUNC, set)(NAME * h, zpl_u64 key, VALUE value) { \ - zpl_isize index; \ - zpl_hash_table_find_result fr; \ - if (zpl_array_count(h->hashes) == 0) ZPL_JOIN2(FUNC, grow)(h); \ - fr = ZPL_JOIN2(FUNC, _find)(h, key); \ - if (fr.entry_index >= 0) { \ - index = fr.entry_index; \ - } else { \ - index = ZPL_JOIN2(FUNC, _add_entry)(h, key); \ - if (fr.entry_prev >= 0) { \ - h->entries[fr.entry_prev].next = index; \ - } else { \ - h->hashes[fr.hash_index] = index; \ - } \ - } \ - h->entries[index].value = value; \ - if (ZPL_JOIN2(FUNC, _full)(h)) ZPL_JOIN2(FUNC, grow)(h); \ - }\ - - //! @} - - ZPL_END_C_DECLS - // file: header/core/string.h - - /** @file string.c - @brief String operations and library - @defgroup string String library - - Offers methods for c-string manipulation, but also a string library based on gb_string, which is c-string friendly. - - @{ - */ - - //////////////////////////////////////////////////////////////// - // - // Char Functions - // - // - - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - ZPL_DEF_INLINE char zpl_char_to_lower(char c); - ZPL_DEF_INLINE char zpl_char_to_upper(char c); - ZPL_DEF_INLINE zpl_b32 zpl_char_is_space(char c); - ZPL_DEF_INLINE zpl_b32 zpl_char_is_digit(char c); - ZPL_DEF_INLINE zpl_b32 zpl_char_is_hex_digit(char c); - ZPL_DEF_INLINE zpl_b32 zpl_char_is_alpha(char c); - ZPL_DEF_INLINE zpl_b32 zpl_char_is_alphanumeric(char c); - ZPL_DEF_INLINE zpl_i32 zpl_digit_to_int(char c); - ZPL_DEF_INLINE zpl_i32 zpl_hex_digit_to_int(char c); - ZPL_DEF_INLINE zpl_u8 zpl_char_to_hex_digit(char c); - ZPL_DEF_INLINE zpl_b32 zpl_char_is_control(char c); - - // NOTE: ASCII only - ZPL_DEF_INLINE void zpl_str_to_lower(char *str); - ZPL_DEF_INLINE void zpl_str_to_upper(char *str); - - ZPL_DEF_INLINE char *zpl_str_trim(char *str, zpl_b32 skip_newline); - ZPL_DEF_INLINE char *zpl_str_skip(char *str, char c); - ZPL_DEF_INLINE char *zpl_str_control_skip(char *str, char c); - - ZPL_DEF_INLINE zpl_isize zpl_strlen(const char *str); - ZPL_DEF_INLINE zpl_isize zpl_strnlen(const char *str, zpl_isize max_len); - ZPL_DEF_INLINE zpl_i32 zpl_strcmp(const char *s1, const char *s2); - ZPL_DEF_INLINE zpl_i32 zpl_strncmp(const char *s1, const char *s2, zpl_isize len); - ZPL_DEF_INLINE char *zpl_strcpy(char *dest, const char *source); - ZPL_DEF_INLINE char *zpl_strncpy(char *dest, const char *source, zpl_isize len); - ZPL_DEF_INLINE zpl_isize zpl_strlcpy(char *dest, const char *source, zpl_isize len); - ZPL_DEF_INLINE char *zpl_strrev(char *str); // NOTE: ASCII only - ZPL_DEF_INLINE const char *zpl_strtok(char *output, const char *src, const char *delimit); - - ZPL_DEF_INLINE char *zpl_strdup(zpl_allocator a, char *src, zpl_isize max_len); - ZPL_DEF_INLINE char **zpl_str_split_lines(zpl_allocator alloc, char *source, zpl_b32 strip_whitespace); - - #define zpl_str_expand(str) str, zpl_strlen(str) - - ZPL_DEF_INLINE zpl_b32 zpl_str_has_prefix(const char *str, const char *prefix); - ZPL_DEF_INLINE zpl_b32 zpl_str_has_suffix(const char *str, const char *suffix); - - ZPL_DEF_INLINE const char *zpl_char_first_occurence(const char *str, char c); - ZPL_DEF_INLINE const char *zpl_char_last_occurence(const char *str, char c); - #define zpl_strchr zpl_char_first_occurence - - ZPL_DEF_INLINE void zpl_str_concat(char *dest, zpl_isize dest_len, const char *src_a, zpl_isize src_a_len, const char *src_b, zpl_isize src_b_len); - - ZPL_DEF zpl_u64 zpl_str_to_u64(const char *str, char **end_ptr, zpl_i32 base); // TODO: Support more than just decimal and hexadecimal - ZPL_DEF zpl_i64 zpl_str_to_i64(const char *str, char **end_ptr, zpl_i32 base); // TODO: Support more than just decimal and hexadecimal - ZPL_DEF zpl_f64 zpl_str_to_f64(const char *str, char **end_ptr); - ZPL_DEF void zpl_i64_to_str(zpl_i64 value, char *string, zpl_i32 base); - ZPL_DEF void zpl_u64_to_str(zpl_u64 value, char *string, zpl_i32 base); - - ZPL_DEF_INLINE zpl_f32 zpl_str_to_f32(const char *str, char **end_ptr); - - //////////////////////////////////////////////////////////////// - // - // UTF-8 Handling - // - // - - // NOTE: Does not check if utf-8 string is valid - ZPL_IMPL_INLINE zpl_isize zpl_utf8_strlen(zpl_u8 const *str); - ZPL_IMPL_INLINE zpl_isize zpl_utf8_strnlen(zpl_u8 const *str, zpl_isize max_len); - - // NOTE: Windows doesn't handle 8 bit filenames well - ZPL_DEF zpl_u16 *zpl_utf8_to_ucs2(zpl_u16 *buffer, zpl_isize len, zpl_u8 const *str); - ZPL_DEF zpl_u8 *zpl_ucs2_to_utf8(zpl_u8 *buffer, zpl_isize len, zpl_u16 const *str); - ZPL_DEF zpl_u16 *zpl_utf8_to_ucs2_buf(zpl_u8 const *str); // NOTE: Uses locally persisting buffer - ZPL_DEF zpl_u8 *zpl_ucs2_to_utf8_buf(zpl_u16 const *str); // NOTE: Uses locally persisting buffer - - // NOTE: Returns size of codepoint in bytes - ZPL_DEF zpl_isize zpl_utf8_decode(zpl_u8 const *str, zpl_isize str_len, zpl_rune *codepoint); - ZPL_DEF zpl_isize zpl_utf8_codepoint_size(zpl_u8 const *str, zpl_isize str_len); - ZPL_DEF zpl_isize zpl_utf8_encode_rune(zpl_u8 buf[4], zpl_rune r); - - /* inlines */ - - ZPL_IMPL_INLINE char zpl_char_to_lower(char c) { - if (c >= 'A' && c <= 'Z') return 'a' + (c - 'A'); - return c; - } - - ZPL_IMPL_INLINE char zpl_char_to_upper(char c) { - if (c >= 'a' && c <= 'z') return 'A' + (c - 'a'); - return c; - } - - ZPL_IMPL_INLINE zpl_b32 zpl_char_is_space(char c) { - if (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v') return true; - return false; - } - - ZPL_IMPL_INLINE zpl_b32 zpl_char_is_digit(char c) { - if (c >= '0' && c <= '9') return true; - return false; - } - - ZPL_IMPL_INLINE zpl_b32 zpl_char_is_hex_digit(char c) { - if (zpl_char_is_digit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) return true; - return false; - } - - ZPL_IMPL_INLINE zpl_b32 zpl_char_is_alpha(char c) { - if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) return true; - return false; - } - - ZPL_IMPL_INLINE zpl_b32 zpl_char_is_alphanumeric(char c) { return zpl_char_is_alpha(c) || zpl_char_is_digit(c); } - - ZPL_IMPL_INLINE zpl_i32 zpl_digit_to_int(char c) { return zpl_char_is_digit(c) ? c - '0' : c - 'W'; } - - ZPL_IMPL_INLINE zpl_i32 zpl_hex_digit_to_int(char c) { - if (zpl_char_is_digit(c)) - return zpl_digit_to_int(c); - else if (zpl_is_between(c, 'a', 'f')) - return c - 'a' + 10; - else if (zpl_is_between(c, 'A', 'F')) - return c - 'A' + 10; - return -1; - } - - ZPL_IMPL_INLINE zpl_u8 zpl_char_to_hex_digit(char c) { - if (c >= '0' && c <= '9') - return (zpl_u8)(c - '0'); - if (c >= 'a' && c <= 'f') - return (zpl_u8)(c - 'a'); - if (c >= 'A' && c <= 'F') - return (zpl_u8)(c - 'A'); - return 0; - } - - - ZPL_IMPL_INLINE void zpl_str_to_lower(char *str) { - if (!str) return; - while (*str) { - *str = zpl_char_to_lower(*str); - str++; - } - } - - ZPL_IMPL_INLINE void zpl_str_to_upper(char *str) { - if (!str) return; - while (*str) { - *str = zpl_char_to_upper(*str); - str++; - } - } - - ZPL_IMPL_INLINE zpl_isize zpl_strlen(const char *str) { - if (str == NULL) { return 0; } - - const char *begin = str; - zpl_isize const *w; - while (cast(zpl_uintptr) str % sizeof(zpl_usize)) { - if (!*str) return str - begin; - str++; - } - w = cast(zpl_isize const *) str; - while (!ZPL__HAS_ZERO(*w)) w++; - str = cast(const char *) w; - while (*str) str++; - return str - begin; - } - - ZPL_IMPL_INLINE zpl_isize zpl_strnlen(const char *str, zpl_isize max_len) { - const char *end = cast(const char *) zpl_memchr(str, 0, max_len); - if (end) return end - str; - return max_len; - } - - ZPL_IMPL_INLINE zpl_isize zpl_utf8_strlen(zpl_u8 const *str) { - zpl_isize count = 0; - for (; *str; count++) { - zpl_u8 c = *str; - zpl_isize inc = 0; - if (c < 0x80) - inc = 1; - else if ((c & 0xe0) == 0xc0) - inc = 2; - else if ((c & 0xf0) == 0xe0) - inc = 3; - else if ((c & 0xf8) == 0xf0) - inc = 4; - else - return -1; - - str += inc; - } - return count; - } - - ZPL_IMPL_INLINE zpl_isize zpl_utf8_strnlen(zpl_u8 const *str, zpl_isize max_len) { - zpl_isize count = 0; - for (; *str && max_len > 0; count++) { - zpl_u8 c = *str; - zpl_isize inc = 0; - if (c < 0x80) - inc = 1; - else if ((c & 0xe0) == 0xc0) - inc = 2; - else if ((c & 0xf0) == 0xe0) - inc = 3; - else if ((c & 0xf8) == 0xf0) - inc = 4; - else - return -1; - - str += inc; - max_len -= inc; - } - return count; - } - - ZPL_IMPL_INLINE zpl_i32 zpl_strcmp(const char *s1, const char *s2) { - while (*s1 && (*s1 == *s2)) { s1++, s2++; } - return *(zpl_u8 *)s1 - *(zpl_u8 *)s2; - } - - ZPL_IMPL_INLINE char *zpl_strcpy(char *dest, const char *source) { - ZPL_ASSERT_NOT_NULL(dest); - if (source) { - char *str = dest; - while (*source) *str++ = *source++; - } - return dest; - } - - ZPL_IMPL_INLINE char *zpl_strncpy(char *dest, const char *source, zpl_isize len) { - ZPL_ASSERT_NOT_NULL(dest); - if (source) { - char *str = dest; - while (len > 0 && *source) { - *str++ = *source++; - len--; - } - while (len > 0) { - *str++ = '\0'; - len--; - } - } - return dest; - } - - ZPL_IMPL_INLINE zpl_isize zpl_strlcpy(char *dest, const char *source, zpl_isize len) { - zpl_isize result = 0; - ZPL_ASSERT_NOT_NULL(dest); - if (source) { - const char *source_start = source; - char *str = dest; - while (len > 0 && *source) { - *str++ = *source++; - len--; - } - while (len > 0) { - *str++ = '\0'; - len--; - } - - result = source - source_start; - } - return result; - } - - ZPL_IMPL_INLINE char *zpl_strrev(char *str) { - zpl_isize len = zpl_strlen(str); - char *a = str + 0; - char *b = str + len - 1; - len /= 2; - while (len--) { - zpl_swap(char, *a, *b); - a++, b--; - } - return str; - } - - ZPL_IMPL_INLINE zpl_i32 zpl_strncmp(const char *s1, const char *s2, zpl_isize len) { - for (; len > 0; s1++, s2++, len--) { - if (*s1 != *s2) - return ((s1 < s2) ? -1 : +1); - else if (*s1 == '\0') - return 0; - } - return 0; - } - - ZPL_IMPL_INLINE const char *zpl_strtok(char *output, const char *src, const char *delimit) { - while (*src && zpl_char_first_occurence(delimit, *src) == NULL) *output++ = *src++; - - *output = 0; - return *src ? src + 1 : src; - } - - ZPL_IMPL_INLINE zpl_b32 zpl_char_is_control(char c) { - return !!zpl_strchr("\"\\/bfnrt", c); - } - - ZPL_IMPL_INLINE zpl_b32 zpl__is_special_char(char c) { return !!zpl_strchr("<>:/", c); } - ZPL_IMPL_INLINE zpl_b32 zpl__is_assign_char(char c) { return !!zpl_strchr(":=|", c); } - ZPL_IMPL_INLINE zpl_b32 zpl__is_delim_char(char c) { return !!zpl_strchr(",|\n", c); } - - - ZPL_IMPL_INLINE char *zpl_str_control_skip(char *str, char c) { - while ((*str && *str != c) || (*(str - 1) == '\\' && *str == c && zpl_char_is_control(c))) { ++str; } - - return str; - } - - - ZPL_IMPL_INLINE zpl_b32 zpl_str_has_prefix(const char *str, const char *prefix) { - while (*prefix) { - if (*str++ != *prefix++) return false; - } - return true; - } - - ZPL_IMPL_INLINE zpl_b32 zpl_str_has_suffix(const char *str, const char *suffix) { - zpl_isize i = zpl_strlen(str); - zpl_isize j = zpl_strlen(suffix); - if (j <= i) return zpl_strcmp(str + i - j, suffix) == 0; - return false; - } - - ZPL_IMPL_INLINE const char *zpl_char_first_occurence(const char *s, char c) { - char ch = c; - for (; *s != ch; s++) { - if (*s == '\0') return NULL; - } - return s; - } - - ZPL_IMPL_INLINE const char *zpl_char_last_occurence(const char *s, char c) { - char *result = (char*)NULL; - do { - if (*s == c) result = (char *)s; - } while (*s++); - - return result; - } - - ZPL_IMPL_INLINE char *zpl_str_trim(char *str, zpl_b32 skip_newline) - { - while (*str && zpl_char_is_space(*str) && (!skip_newline || (skip_newline && *str != '\n'))) { ++str; } - return str; - } - - ZPL_IMPL_INLINE char *zpl_str_skip(char *str, char c) { - while (*str && *str != c) { ++str; } - return str; - } - - ZPL_IMPL_INLINE void zpl_str_concat(char *dest, zpl_isize dest_len, const char *src_a, zpl_isize src_a_len, const char *src_b, - zpl_isize src_b_len) { - ZPL_ASSERT(dest_len >= src_a_len + src_b_len + 1); - if (dest) { - zpl_memcopy(dest, src_a, src_a_len); - zpl_memcopy(dest + src_a_len, src_b, src_b_len); - dest[src_a_len + src_b_len] = '\0'; - } - } - - ZPL_IMPL_INLINE zpl_f32 zpl_str_to_f32(const char *str, char **end_ptr) { - zpl_f64 f = zpl_str_to_f64(str, end_ptr); - zpl_f32 r = cast(zpl_f32) f; - return r; - } - - ZPL_IMPL_INLINE char *zpl_strdup(zpl_allocator a, char *src, zpl_isize max_len) { - ZPL_ASSERT_NOT_NULL(src); - zpl_isize len = zpl_strlen(src); - char *dest = cast(char *) zpl_alloc(a, max_len); - zpl_memset(dest + len, 0, max_len - len); - zpl_strncpy(dest, src, max_len); - - return dest; - } - - ZPL_IMPL_INLINE char **zpl_str_split_lines(zpl_allocator alloc, char *source, zpl_b32 strip_whitespace) { - char **lines = NULL, *p = source, *pd = p; - zpl_array_init(lines, alloc); - - while (*p) { - if (*pd == '\n') { - *pd = 0; - if (*(pd - 1) == '\r') *(pd - 1) = 0; - if (strip_whitespace && (pd - p) == 0) { - p = pd + 1; - continue; - } - zpl_array_append(lines, p); - p = pd + 1; - } - ++pd; - } - return lines; - } - - ZPL_END_C_DECLS - // file: header/core/stringlib.h - - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - typedef char *zpl_string; - - typedef struct zpl_string_header { - zpl_allocator allocator; - zpl_isize length; - zpl_isize capacity; - } zpl_string_header; - - #define ZPL_STRING_HEADER(str) (cast(zpl_string_header *)(str) - 1) - - ZPL_DEF zpl_string zpl_string_make_reserve(zpl_allocator a, zpl_isize capacity); - ZPL_DEF zpl_string zpl_string_make_length(zpl_allocator a, void const *str, zpl_isize num_bytes); - ZPL_DEF zpl_string zpl_string_sprintf(zpl_allocator a, char *buf, zpl_isize num_bytes, const char *fmt, ...); - ZPL_DEF zpl_string zpl_string_sprintf_buf(zpl_allocator a, const char *fmt, ...); // NOTE: Uses locally persistent buffer - ZPL_DEF zpl_string zpl_string_append_length(zpl_string str, void const *other, zpl_isize num_bytes); - ZPL_DEF zpl_string zpl_string_appendc(zpl_string str, const char *other); - ZPL_DEF zpl_string zpl_string_join(zpl_allocator a, const char **parts, zpl_isize count, const char *glue); - ZPL_DEF zpl_string zpl_string_set(zpl_string str, const char *cstr); - ZPL_DEF zpl_string zpl_string_make_space_for(zpl_string str, zpl_isize add_len); - ZPL_DEF zpl_isize zpl_string_allocation_size(zpl_string const str); - ZPL_DEF zpl_b32 zpl_string_are_equal(zpl_string const lhs, zpl_string const rhs); - ZPL_DEF zpl_string zpl_string_trim(zpl_string str, const char *cut_set); - ZPL_DEF zpl_string zpl_string_append_rune(zpl_string str, zpl_rune r); - ZPL_DEF zpl_string zpl_string_append_fmt(zpl_string str, const char *fmt, ...); - - ZPL_DEF_INLINE zpl_string zpl_string_make(zpl_allocator a, const char *str); - ZPL_DEF_INLINE void zpl_string_free(zpl_string str); - ZPL_DEF_INLINE void zpl_string_clear(zpl_string str); - ZPL_DEF_INLINE zpl_string zpl_string_duplicate(zpl_allocator a, zpl_string const str); - ZPL_DEF_INLINE zpl_isize zpl_string_length(zpl_string const str); - ZPL_DEF_INLINE zpl_isize zpl_string_capacity(zpl_string const str); - ZPL_DEF_INLINE zpl_isize zpl_string_available_space(zpl_string const str); - ZPL_DEF_INLINE zpl_string zpl_string_append(zpl_string str, zpl_string const other); - ZPL_DEF_INLINE zpl_string zpl_string_trim_space(zpl_string str); // Whitespace ` \t\r\n\v\f` - ZPL_DEF_INLINE void zpl__set_string_length(zpl_string str, zpl_isize len); - ZPL_DEF_INLINE void zpl__set_string_capacity(zpl_string str, zpl_isize cap); - - ZPL_IMPL_INLINE void zpl__set_string_length(zpl_string str, zpl_isize len) { ZPL_STRING_HEADER(str)->length = len; } - ZPL_IMPL_INLINE void zpl__set_string_capacity(zpl_string str, zpl_isize cap) { ZPL_STRING_HEADER(str)->capacity = cap; } - ZPL_IMPL_INLINE zpl_string zpl_string_make(zpl_allocator a, const char *str) { - zpl_isize len = str ? zpl_strlen(str) : 0; - return zpl_string_make_length(a, str, len); - } - - ZPL_IMPL_INLINE void zpl_string_free(zpl_string str) { - if (str) { - zpl_string_header *header = ZPL_STRING_HEADER(str); - zpl_free(header->allocator, header); - } - } - - ZPL_IMPL_INLINE zpl_string zpl_string_duplicate(zpl_allocator a, zpl_string const str) { - return zpl_string_make_length(a, str, zpl_string_length(str)); - } - - ZPL_IMPL_INLINE zpl_isize zpl_string_length(zpl_string const str) { return ZPL_STRING_HEADER(str)->length; } - ZPL_IMPL_INLINE zpl_isize zpl_string_capacity(zpl_string const str) { return ZPL_STRING_HEADER(str)->capacity; } - - ZPL_IMPL_INLINE zpl_isize zpl_string_available_space(zpl_string const str) { - zpl_string_header *h = ZPL_STRING_HEADER(str); - if (h->capacity > h->length) return h->capacity - h->length; - return 0; - } - - ZPL_IMPL_INLINE void zpl_string_clear(zpl_string str) { - zpl__set_string_length(str, 0); - str[0] = '\0'; - } - - ZPL_IMPL_INLINE zpl_string zpl_string_append(zpl_string str, zpl_string const other) { - return zpl_string_append_length(str, other, zpl_string_length(other)); - } - - ZPL_IMPL_INLINE zpl_string zpl_string_trim_space(zpl_string str) { return zpl_string_trim(str, " \t\r\n\v\f"); } - - - ZPL_END_C_DECLS - // file: header/core/file.h - - /** @file file.c - @brief File handling - @defgroup fileio File handling - - File I/O operations as well as path and folder structure manipulation methods. With threading enabled, it also offers async read/write methods. - - @{ - */ - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - typedef zpl_u32 zpl_file_mode; - - typedef enum zpl_file_mode_flag { - ZPL_FILE_MODE_READ = ZPL_BIT(0), - ZPL_FILE_MODE_WRITE = ZPL_BIT(1), - ZPL_FILE_MODE_APPEND = ZPL_BIT(2), - ZPL_FILE_MODE_RW = ZPL_BIT(3), - ZPL_FILE_MODES = ZPL_FILE_MODE_READ | ZPL_FILE_MODE_WRITE | ZPL_FILE_MODE_APPEND | ZPL_FILE_MODE_RW, - } zpl_file_mode_flag; - - // NOTE: Only used internally and for the file operations - typedef enum zpl_seek_whence_type { - ZPL_SEEK_WHENCE_BEGIN = 0, - ZPL_SEEK_WHENCE_CURRENT = 1, - ZPL_SEEK_WHENCE_END = 2, - } zpl_seek_whence_type; - - typedef enum zpl_file_error { - ZPL_FILE_ERROR_NONE, - ZPL_FILE_ERROR_INVALID, - ZPL_FILE_ERROR_INVALID_FILENAME, - ZPL_FILE_ERROR_EXISTS, - ZPL_FILE_ERROR_NOT_EXISTS, - ZPL_FILE_ERROR_PERMISSION, - ZPL_FILE_ERROR_TRUNCATION_FAILURE, - ZPL_FILE_ERROR_NOT_EMPTY, - ZPL_FILE_ERROR_NAME_TOO_LONG, - ZPL_FILE_ERROR_UNKNOWN, - } zpl_file_error; - - typedef union zpl_file_descriptor { - void *p; - zpl_intptr i; - zpl_uintptr u; - } zpl_file_descriptor; - - typedef struct zpl_file_operations zpl_file_operations; - - #define ZPL_FILE_OPEN_PROC(name) zpl_file_error name(zpl_file_descriptor *fd, zpl_file_operations *ops, zpl_file_mode mode, char const *filename) - #define ZPL_FILE_READ_AT_PROC(name) zpl_b32 name(zpl_file_descriptor fd, void *buffer, zpl_isize size, zpl_i64 offset, zpl_isize *bytes_read, zpl_b32 stop_at_newline) - #define ZPL_FILE_WRITE_AT_PROC(name) zpl_b32 name(zpl_file_descriptor fd, void const *buffer, zpl_isize size, zpl_i64 offset, zpl_isize *bytes_written) - #define ZPL_FILE_SEEK_PROC(name) zpl_b32 name(zpl_file_descriptor fd, zpl_i64 offset, zpl_seek_whence_type whence, zpl_i64 *new_offset) - #define ZPL_FILE_CLOSE_PROC(name) void name(zpl_file_descriptor fd) - - typedef ZPL_FILE_OPEN_PROC(zpl_file_open_proc); - typedef ZPL_FILE_READ_AT_PROC(zpl_file_read_proc); - typedef ZPL_FILE_WRITE_AT_PROC(zpl_file_write_proc); - typedef ZPL_FILE_SEEK_PROC(zpl_file_seek_proc); - typedef ZPL_FILE_CLOSE_PROC(zpl_file_close_proc); - - struct zpl_file_operations { - zpl_file_read_proc *read_at; - zpl_file_write_proc *write_at; - zpl_file_seek_proc *seek; - zpl_file_close_proc *close; - }; - - extern zpl_file_operations const zpl_default_file_operations; - - typedef zpl_u64 zpl_file_time; - typedef enum zpl_dir_type { - ZPL_DIR_TYPE_FILE, - ZPL_DIR_TYPE_FOLDER, - ZPL_DIR_TYPE_UNKNOWN, - } zpl_dir_type; - - struct zpl_dir_info; - - typedef struct zpl_dir_entry { - char const *filename; - struct zpl_dir_info *dir_info; - zpl_u8 type; - } zpl_dir_entry; - - typedef struct zpl_dir_info { - char const *fullpath; - zpl_dir_entry *entries; // zpl_array - - // Internals - char **filenames; // zpl_array - zpl_string buf; - } zpl_dir_info; - - typedef struct zpl_file { - zpl_file_operations ops; - zpl_file_descriptor fd; - zpl_b32 is_temp; - - char const *filename; - zpl_file_time last_write_time; - zpl_dir_entry *dir; - } zpl_file; - - typedef enum zpl_file_standard_type { - ZPL_FILE_STANDARD_INPUT, - ZPL_FILE_STANDARD_OUTPUT, - ZPL_FILE_STANDARD_ERROR, - - ZPL_FILE_STANDARD_COUNT, - } zpl_file_standard_type; - - /** - * Get standard file I/O. - * @param std Check zpl_file_standard_type - * @return File handle to standard I/O - */ - ZPL_DEF zpl_file *zpl_file_get_standard(zpl_file_standard_type std); - - /** - * Connects a system handle to a ZPL file. - * @param file Pointer to ZPL file - * @param handle Low-level OS handle to connect - */ - ZPL_DEF void zpl_file_connect_handle(zpl_file *file, void *handle); - - /** - * Creates a new file - * @param file - * @param filename - */ - ZPL_DEF zpl_file_error zpl_file_create(zpl_file *file, char const *filename); - - /** - * Opens a file - * @param file - * @param filename - */ - ZPL_DEF zpl_file_error zpl_file_open(zpl_file *file, char const *filename); - - /** - * Opens a file using a specified mode - * @param file - * @param mode Access mode to use - * @param filename - */ - ZPL_DEF zpl_file_error zpl_file_open_mode(zpl_file *file, zpl_file_mode mode, char const *filename); - - /** - * Constructs a new file from data - * @param file - * @param fd Low-level file descriptor to use - * @param ops File operations to rely upon - * @param filename - */ - ZPL_DEF zpl_file_error zpl_file_new(zpl_file *file, zpl_file_descriptor fd, zpl_file_operations ops, char const *filename); - - /** - * Returns a size of the file - * @param file - * @return File size - */ - ZPL_DEF zpl_i64 zpl_file_size(zpl_file *file); - - /** - * Returns the currently opened file's name - * @param file - */ - ZPL_DEF char const *zpl_file_name(zpl_file *file); - - /** - * Truncates the file by a specified size - * @param file - * @param size Size to truncate - */ - ZPL_DEF zpl_file_error zpl_file_truncate(zpl_file *file, zpl_i64 size); - - /** - * Checks whether a file's been changed since the last check - * @param file - */ - ZPL_DEF zpl_b32 zpl_file_has_changed(zpl_file *file); - - /** - * Retrieves a directory listing relative to the file - * @param file - */ - ZPL_DEF void zpl_file_dirinfo_refresh(zpl_file *file); - - /** - * Creates a temporary file - * @param file - */ - zpl_file_error zpl_file_temp(zpl_file *file); - - /** - * Closes the file - * @param file - */ - ZPL_DEF zpl_file_error zpl_file_close(zpl_file *file); - - /** - * Reads file safely - * @param file - * @param buffer Buffer to read to - * @param size Size to read - * @param offset Offset to read from - * @param bytes_read How much data we've actually read - */ - ZPL_DEF_INLINE zpl_b32 zpl_file_read_at_check(zpl_file *file, void *buffer, zpl_isize size, zpl_i64 offset, zpl_isize *bytes_read); - - /** - * Writes to file safely - * @param file - * @param buffer Buffer to read from - * @param size Size to write - * @param offset Offset to write to - * @param bytes_written How much data we've actually written - */ - ZPL_DEF_INLINE zpl_b32 zpl_file_write_at_check(zpl_file *file, void const *buffer, zpl_isize size, zpl_i64 offset, zpl_isize *bytes_written); - - - /** - * Reads file at a specific offset - * @param file - * @param buffer Buffer to read to - * @param size Size to read - * @param offset Offset to read from - * @param bytes_read How much data we've actually read - */ - ZPL_DEF_INLINE zpl_b32 zpl_file_read_at(zpl_file *file, void *buffer, zpl_isize size, zpl_i64 offset); - - /** - * Writes to file at a specific offset - * @param file - * @param buffer Buffer to read from - * @param size Size to write - * @param offset Offset to write to - * @param bytes_written How much data we've actually written - */ - ZPL_DEF_INLINE zpl_b32 zpl_file_write_at(zpl_file *file, void const *buffer, zpl_isize size, zpl_i64 offset); - - /** - * Seeks the file cursor from the beginning of file to a specific position - * @param file - * @param offset Offset to seek to - */ - ZPL_DEF_INLINE zpl_i64 zpl_file_seek(zpl_file *file, zpl_i64 offset); - - /** - * Seeks the file cursor to the end of the file - * @param file - */ - ZPL_DEF_INLINE zpl_i64 zpl_file_seek_to_end(zpl_file *file); - - /** - * Skips N bytes at the current position - * @param file - * @param bytes Bytes to skip - */ - ZPL_DEF_INLINE zpl_i64 zpl_file_skip(zpl_file *file, zpl_i64 bytes); // NOTE: Skips a certain amount of bytes - - /** - * Returns the length from the beginning of the file we've read so far - * @param file - * @return Our current position in file - */ - ZPL_DEF_INLINE zpl_i64 zpl_file_tell(zpl_file *file); - - /** - * Reads from a file - * @param file - * @param buffer Buffer to read to - * @param size Size to read - */ - ZPL_DEF_INLINE zpl_b32 zpl_file_read(zpl_file *file, void *buffer, zpl_isize size); - - /** - * Writes to a file - * @param file - * @param buffer Buffer to read from - * @param size Size to read - */ - ZPL_DEF_INLINE zpl_b32 zpl_file_write(zpl_file *file, void const *buffer, zpl_isize size); - - - typedef struct zpl_file_contents { - zpl_allocator allocator; - void *data; - zpl_isize size; - } zpl_file_contents; - - /** - * Reads the whole file contents - * @param a Allocator to use - * @param zero_terminate End the read data with null terminator - * @param filepath Path to the file - * @return File contents data - */ - ZPL_DEF zpl_file_contents zpl_file_read_contents(zpl_allocator a, zpl_b32 zero_terminate, char const *filepath); - - /** - * Frees the file content data previously read - * @param fc - */ - ZPL_DEF void zpl_file_free_contents(zpl_file_contents *fc); - - /** - * Writes content to a file - */ - ZPL_DEF zpl_b32 zpl_file_write_contents(char const* filepath, void const* buffer, zpl_isize size, zpl_file_error* err); - - /** - * Reads the file as array of lines - * - * Make sure you free both the returned buffer and the lines (zpl_array) - * @param alloc Allocator to use - * @param lines Reference to zpl_array container we store lines to - * @param filename Path to the file - * @param strip_whitespace Strip whitespace when we split to lines? - * @return File content we've read itself - */ - ZPL_DEF char *zpl_file_read_lines(zpl_allocator alloc, zpl_array(char *)*lines, char const *filename, zpl_b32 strip_whitespace); - - //! @} - - /* inlines */ - - - ZPL_IMPL_INLINE zpl_b32 zpl_file_read_at_check(zpl_file *f, void *buffer, zpl_isize size, zpl_i64 offset, zpl_isize *bytes_read) { - if (!f->ops.read_at) f->ops = zpl_default_file_operations; - return f->ops.read_at(f->fd, buffer, size, offset, bytes_read, false); - } - - ZPL_IMPL_INLINE zpl_b32 zpl_file_write_at_check(zpl_file *f, void const *buffer, zpl_isize size, zpl_i64 offset, zpl_isize *bytes_written) { - if (!f->ops.read_at) f->ops = zpl_default_file_operations; - return f->ops.write_at(f->fd, buffer, size, offset, bytes_written); - } - - ZPL_IMPL_INLINE zpl_b32 zpl_file_read_at(zpl_file *f, void *buffer, zpl_isize size, zpl_i64 offset) { - return zpl_file_read_at_check(f, buffer, size, offset, NULL); - } - - ZPL_IMPL_INLINE zpl_b32 zpl_file_write_at(zpl_file *f, void const *buffer, zpl_isize size, zpl_i64 offset) { - return zpl_file_write_at_check(f, buffer, size, offset, NULL); - } - - ZPL_IMPL_INLINE zpl_i64 zpl_file_seek(zpl_file *f, zpl_i64 offset) { - zpl_i64 new_offset = 0; - if (!f->ops.read_at) f->ops = zpl_default_file_operations; - f->ops.seek(f->fd, offset, ZPL_SEEK_WHENCE_BEGIN, &new_offset); - return new_offset; - } - - ZPL_IMPL_INLINE zpl_i64 zpl_file_seek_to_end(zpl_file *f) { - zpl_i64 new_offset = 0; - if (!f->ops.read_at) f->ops = zpl_default_file_operations; - f->ops.seek(f->fd, 0, ZPL_SEEK_WHENCE_END, &new_offset); - return new_offset; - } - - // NOTE: Skips a certain amount of bytes - ZPL_IMPL_INLINE zpl_i64 zpl_file_skip(zpl_file *f, zpl_i64 bytes) { - zpl_i64 new_offset = 0; - if (!f->ops.read_at) f->ops = zpl_default_file_operations; - f->ops.seek(f->fd, bytes, ZPL_SEEK_WHENCE_CURRENT, &new_offset); - return new_offset; - } - - ZPL_IMPL_INLINE zpl_i64 zpl_file_tell(zpl_file *f) { - zpl_i64 new_offset = 0; - if (!f->ops.read_at) f->ops = zpl_default_file_operations; - f->ops.seek(f->fd, 0, ZPL_SEEK_WHENCE_CURRENT, &new_offset); - return new_offset; - } - - ZPL_IMPL_INLINE zpl_b32 zpl_file_read(zpl_file *f, void *buffer, zpl_isize size) { - zpl_i64 cur_offset = zpl_file_tell(f); - zpl_b32 result = zpl_file_read_at(f, buffer, size, zpl_file_tell(f)); - zpl_file_seek(f, cur_offset + size); - return result; - } - - ZPL_IMPL_INLINE zpl_b32 zpl_file_write(zpl_file *f, void const *buffer, zpl_isize size) { - zpl_i64 cur_offset = zpl_file_tell(f); - zpl_b32 result = zpl_file_write_at(f, buffer, size, zpl_file_tell(f)); - zpl_file_seek(f, cur_offset + size); - return result; - } - - ZPL_END_C_DECLS - // file: header/core/file_stream.h - - /** @file file_stream.c - @brief File stream - @defgroup fileio File stream - - File streaming operations on memory. - - @{ - */ - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - typedef enum { - /* Allows us to write to the buffer directly. Beware: you can not append a new data! */ - ZPL_FILE_STREAM_WRITABLE = ZPL_BIT(0), - - /* Clones the input buffer so you can write (zpl_file_write*) data into it. */ - /* Since we work with a clone, the buffer size can dynamically grow as well. */ - ZPL_FILE_STREAM_CLONE_WRITABLE = ZPL_BIT(1), - } zpl_file_stream_flags; - - /** - * Opens a new memory stream - * @param file - * @param allocator - */ - ZPL_DEF void zpl_file_stream_new(zpl_file* file, zpl_allocator allocator); - - /** - * Opens a memory stream over an existing buffer - * @param file - * @param allocator - * @param buffer Memory to create stream from - * @param size Buffer's size - * @param flags - */ - ZPL_DEF void zpl_file_stream_open(zpl_file* file, zpl_allocator allocator, zpl_u8 *buffer, zpl_isize size, zpl_file_stream_flags flags); - - /** - * Retrieves the stream's underlying buffer and buffer size. - * @param file memory stream - * @param size (Optional) buffer size - */ - ZPL_DEF zpl_u8 *zpl_file_stream_buf(zpl_file* file, zpl_isize *size); - - extern zpl_file_operations const zpl_memory_file_operations; - - //! @} - - ZPL_END_C_DECLS - // file: header/core/file_misc.h - - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - #ifndef ZPL_PATH_SEPARATOR - #if defined(ZPL_SYSTEM_WINDOWS) - #define ZPL_PATH_SEPARATOR '\\' - #else - #define ZPL_PATH_SEPARATOR '/' - #endif - #endif - - /** - * Checks if file/directory exists - * @param filepath - */ - ZPL_DEF zpl_b32 zpl_fs_exists(char const *filepath); - - /** - * Retrieves node's type (file, folder, ...) - * @param path - */ - ZPL_DEF zpl_u8 zpl_fs_get_type(char const *path); - - /** - * Retrieves file's last write time - * @param filepath - */ - ZPL_DEF zpl_file_time zpl_fs_last_write_time(char const *filepath); - - /** - * Copies the file to a directory - * @param existing_filename - * @param new_filename - * @param fail_if_exists - */ - ZPL_DEF zpl_b32 zpl_fs_copy(char const *existing_filename, char const *new_filename, zpl_b32 fail_if_exists); - - /** - * Moves the file to a directory - * @param existing_filename - * @param new_filename - */ - ZPL_DEF zpl_b32 zpl_fs_move(char const *existing_filename, char const *new_filename); - - /** - * Removes a file from a directory - * @param filename - */ - ZPL_DEF zpl_b32 zpl_fs_remove(char const *filename); - - ZPL_DEF_INLINE zpl_b32 zpl_path_is_absolute(char const *path); - ZPL_DEF_INLINE zpl_b32 zpl_path_is_relative(char const *path); - ZPL_DEF_INLINE zpl_b32 zpl_path_is_root(char const *path); - - ZPL_DEF_INLINE char const *zpl_path_base_name(char const *path); - ZPL_DEF_INLINE char const *zpl_path_extension(char const *path); - - ZPL_DEF void zpl_path_fix_slashes(char *path); - - ZPL_DEF zpl_file_error zpl_path_mkdir(char const *path, zpl_i32 mode); - ZPL_DEF zpl_file_error zpl_path_rmdir(char const *path); - - ZPL_DEF char *zpl_path_get_full_name(zpl_allocator a, char const *path); - - /** - * Returns file paths terminated by newline (\n) - * @param alloc [description] - * @param dirname [description] - * @param recurse [description] - * @return [description] - */ - ZPL_DEF /*zpl_string*/char * zpl_path_dirlist(zpl_allocator alloc, char const *dirname, zpl_b32 recurse); - - /** - * Initialize dirinfo from specified path - * @param dir [description] - * @param path [description] - */ - ZPL_DEF void zpl_dirinfo_init(zpl_dir_info *dir, char const *path); - ZPL_DEF void zpl_dirinfo_free(zpl_dir_info *dir); - - /** - * Analyze the entry's dirinfo - * @param dir_entry [description] - */ - ZPL_DEF void zpl_dirinfo_step(zpl_dir_entry *dir_entry); - - - /* inlines */ - - ZPL_IMPL_INLINE zpl_b32 zpl_path_is_absolute(char const *path) { - zpl_b32 result = false; - ZPL_ASSERT_NOT_NULL(path); - #if defined(ZPL_SYSTEM_WINDOWS) - result = (zpl_strlen(path) > 2) && zpl_char_is_alpha(path[0]) && (path[1] == ':' && path[2] == ZPL_PATH_SEPARATOR); - #else - result = (zpl_strlen(path) > 0 && path[0] == ZPL_PATH_SEPARATOR); - #endif - return result; - } - - ZPL_IMPL_INLINE zpl_b32 zpl_path_is_relative(char const *path) { return !zpl_path_is_absolute(path); } - - ZPL_IMPL_INLINE zpl_b32 zpl_path_is_root(char const *path) { - zpl_b32 result = false; - ZPL_ASSERT_NOT_NULL(path); - #if defined(ZPL_SYSTEM_WINDOWS) - result = zpl_path_is_absolute(path) && (zpl_strlen(path) == 3); - #else - result = zpl_path_is_absolute(path) && (zpl_strlen(path) == 1); - #endif - return result; - } - - ZPL_IMPL_INLINE char const *zpl_path_base_name(char const *path) { - char const *ls; - ZPL_ASSERT_NOT_NULL(path); - zpl_path_fix_slashes((char *)path); - ls = zpl_char_last_occurence(path, ZPL_PATH_SEPARATOR); - return (ls == NULL) ? path : ls + 1; - } - - ZPL_IMPL_INLINE char const *zpl_path_extension(char const *path) { - char const *ld; - ZPL_ASSERT_NOT_NULL(path); - ld = zpl_char_last_occurence(path, '.'); - return (ld == NULL) ? NULL : ld + 1; - } - - ZPL_END_C_DECLS - // file: header/core/print.h - - /** @file print.c - @brief Printing methods - @defgroup print Printing methods - - Various printing methods. - @{ - */ - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - ZPL_DEF zpl_isize zpl_printf(char const *fmt, ...); - ZPL_DEF zpl_isize zpl_printf_va(char const *fmt, va_list va); - ZPL_DEF zpl_isize zpl_printf_err(char const *fmt, ...); - ZPL_DEF zpl_isize zpl_printf_err_va(char const *fmt, va_list va); - ZPL_DEF zpl_isize zpl_fprintf(zpl_file *f, char const *fmt, ...); - ZPL_DEF zpl_isize zpl_fprintf_va(zpl_file *f, char const *fmt, va_list va); - - // NOTE: A locally persisting buffer is used internally - ZPL_DEF char *zpl_bprintf(char const *fmt, ...); - - // NOTE: A locally persisting buffer is used internally - ZPL_DEF char *zpl_bprintf_va(char const *fmt, va_list va); - - ZPL_DEF zpl_isize zpl_snprintf(char *str, zpl_isize n, char const *fmt, ...); - ZPL_DEF zpl_isize zpl_snprintf_va(char *str, zpl_isize n, char const *fmt, va_list va); - - ZPL_END_C_DECLS - // file: header/core/time.h - - /** @file time.c - @brief Time helper methods. - @defgroup time Time helpers - - Helper methods for retrieving the current time in many forms under different precisions. It also offers a simple to use timer library. - - @{ - */ - - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - //! Return CPU timestamp. - ZPL_DEF zpl_u64 zpl_rdtsc(void); - - //! Return relative time (in seconds) since the application start. - ZPL_DEF zpl_f64 zpl_time_rel(void); - - //! Return relative time since the application start. - ZPL_DEF zpl_u64 zpl_time_rel_ms(void); - - //! Return time (in seconds) since 1601-01-01 UTC. - ZPL_DEF zpl_f64 zpl_time_utc(void); - - //! Return time since 1601-01-01 UTC. - ZPL_DEF zpl_u64 zpl_time_utc_ms(void); - - //! Return local system time since 1601-01-01 - ZPL_DEF zpl_u64 zpl_time_tz_ms(void); - - //! Return local system time in seconds since 1601-01-01 - ZPL_DEF zpl_f64 zpl_time_tz(void); - - //! Convert Win32 epoch (1601-01-01 UTC) to UNIX (1970-01-01 UTC) - ZPL_DEF_INLINE zpl_u64 zpl_time_win32_to_unix(zpl_u64 ms); - - //! Convert UNIX (1970-01-01 UTC) to Win32 epoch (1601-01-01 UTC) - ZPL_DEF_INLINE zpl_u64 zpl_time_unix_to_win32(zpl_u64 ms); - - //! Sleep for specified number of milliseconds. - ZPL_DEF void zpl_sleep_ms(zpl_u32 ms); - - //! Sleep for specified number of seconds. - ZPL_DEF_INLINE void zpl_sleep(zpl_f32 s); - - // Deprecated methods - ZPL_DEPRECATED_FOR(10.9.0, zpl_time_rel) - ZPL_DEF_INLINE zpl_f64 zpl_time_now(void); - - ZPL_DEPRECATED_FOR(10.9.0, zpl_time_utc) - ZPL_DEF_INLINE zpl_f64 zpl_utc_time_now(void); - - - #ifndef ZPL__UNIX_TO_WIN32_EPOCH - #define ZPL__UNIX_TO_WIN32_EPOCH 11644473600000ull - #endif - - ZPL_IMPL_INLINE zpl_u64 zpl_time_win32_to_unix(zpl_u64 ms) { - return ms - ZPL__UNIX_TO_WIN32_EPOCH; - } - - ZPL_IMPL_INLINE zpl_u64 zpl_time_unix_to_win32(zpl_u64 ms) { - return ms + ZPL__UNIX_TO_WIN32_EPOCH; - } - - ZPL_IMPL_INLINE void zpl_sleep(zpl_f32 s) { - zpl_sleep_ms((zpl_u32)(s * 1000)); - } - - ZPL_IMPL_INLINE zpl_f64 zpl_time_now() { - return zpl_time_rel(); - } - - ZPL_IMPL_INLINE zpl_f64 zpl_utc_time_now() { - return zpl_time_utc(); - } - - ZPL_END_C_DECLS - // file: header/core/random.h - - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - typedef struct zpl_random { - zpl_u32 offsets[8]; - zpl_u32 value; - } zpl_random; - - // NOTE: Generates from numerous sources to produce a decent pseudo-random seed - ZPL_DEF void zpl_random_init(zpl_random *r); - ZPL_DEF zpl_u32 zpl_random_gen_u32(zpl_random *r); - ZPL_DEF zpl_u32 zpl_random_gen_u32_unique(zpl_random *r); - ZPL_DEF zpl_u64 zpl_random_gen_u64(zpl_random *r); // NOTE: (zpl_random_gen_u32() << 32) | zpl_random_gen_u32() - ZPL_DEF zpl_isize zpl_random_gen_isize(zpl_random *r); - ZPL_DEF zpl_i64 zpl_random_range_i64(zpl_random *r, zpl_i64 lower_inc, zpl_i64 higher_inc); - ZPL_DEF zpl_isize zpl_random_range_isize(zpl_random *r, zpl_isize lower_inc, zpl_isize higher_inc); - ZPL_DEF zpl_f64 zpl_random_range_f64(zpl_random *r, zpl_f64 lower_inc, zpl_f64 higher_inc); - - ZPL_END_C_DECLS - // file: header/core/misc.h - - /** @file misc.c - @brief Various other stuff - @defgroup misc Various other stuff - - Methods that don't belong anywhere but are still very useful in many occasions. - - @{ - */ - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - ZPL_DEF void zpl_exit(zpl_u32 code); - ZPL_DEF void zpl_yield(void); - - //! Returns allocated buffer - ZPL_DEF const char *zpl_get_env(const char *name); - ZPL_DEF const char *zpl_get_env_buf(const char *name); - ZPL_DEF zpl_string zpl_get_env_str(const char *name); - ZPL_DEF void zpl_set_env(const char *name, const char *value); - ZPL_DEF void zpl_unset_env(const char *name); - - ZPL_DEF zpl_u32 zpl_system_command(const char *command, zpl_usize buffer_len, char *buffer); - ZPL_DEF zpl_string zpl_system_command_str(const char *command, zpl_allocator backing); - - ZPL_DEF_INLINE zpl_u16 zpl_endian_swap16(zpl_u16 i); - ZPL_DEF_INLINE zpl_u32 zpl_endian_swap32(zpl_u32 i); - ZPL_DEF_INLINE zpl_u64 zpl_endian_swap64(zpl_u64 i); - - ZPL_DEF_INLINE zpl_isize zpl_count_set_bits(zpl_u64 mask); - - //! @} - //$$ - - ZPL_IMPL_INLINE zpl_u16 zpl_endian_swap16(zpl_u16 i) { - return (i>>8) | (i<<8); - } - - ZPL_IMPL_INLINE zpl_u32 zpl_endian_swap32(zpl_u32 i) { - return (i>>24) |(i<<24) | - ((i&0x00ff0000u)>>8) | ((i&0x0000ff00u)<<8); - } - - ZPL_IMPL_INLINE zpl_u64 zpl_endian_swap64(zpl_u64 i) { - return (i>>56) | (i<<56) | - ((i&0x00ff000000000000ull)>>40) | ((i&0x000000000000ff00ull)<<40) | - ((i&0x0000ff0000000000ull)>>24) | ((i&0x0000000000ff0000ull)<<24) | - ((i&0x000000ff00000000ull)>>8) | ((i&0x00000000ff000000ull)<<8); - } - - ZPL_IMPL_INLINE zpl_i32 zpl_next_pow2(zpl_i32 x) { - x--; - x |= x >> 1; - x |= x >> 2; - x |= x >> 4; - x |= x >> 8; - x |= x >> 16; - return x + 1; - } - - ZPL_IMPL_INLINE void zpl_bit_set(zpl_u32* x, zpl_u32 bit) { *x = *x | (1 << bit); } - ZPL_IMPL_INLINE zpl_b8 zpl_bit_get(zpl_u32 x, zpl_u32 bit) { return (x & (1 << bit)); } - ZPL_IMPL_INLINE void zpl_bit_reset(zpl_u32* x, zpl_u32 bit) { *x = *x & ~(1 << bit); } - - ZPL_IMPL_INLINE zpl_isize zpl_count_set_bits(zpl_u64 mask) { - zpl_isize count = 0; - while (mask) { - count += (mask & 1); - mask >>= 1; - } - return count; - } - - ZPL_END_C_DECLS - // file: header/core/sort.h - - /** @file sort.c - @brief Sorting and searching methods. - @defgroup sort Sorting and searching - - Methods for sorting arrays using either Quick/Merge-sort combo or Radix sort. It also contains simple implementation of binary search, as well as an easy to use API to define your own comparators. - - @{ - */ - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - #define ZPL_COMPARE_PROC(name) int name(void const *a, void const *b) - typedef ZPL_COMPARE_PROC(zpl_compare_proc); - - #define ZPL_COMPARE_PROC_PTR(def) ZPL_COMPARE_PROC((*def)) - - // Procedure pointers - // NOTE: The offset parameter specifies the offset in the structure - // e.g. zpl_i32_cmp(zpl_offset_of(Thing, value)) - // Use 0 if it's just the type instead. - - ZPL_DEF ZPL_COMPARE_PROC_PTR(i16_cmp(zpl_isize offset)); - ZPL_DEF ZPL_COMPARE_PROC_PTR(u8_cmp(zpl_isize offset)); - ZPL_DEF ZPL_COMPARE_PROC_PTR(i32_cmp(zpl_isize offset)); - ZPL_DEF ZPL_COMPARE_PROC_PTR(i64_cmp(zpl_isize offset)); - ZPL_DEF ZPL_COMPARE_PROC_PTR(isize_cmp(zpl_isize offset)); - ZPL_DEF ZPL_COMPARE_PROC_PTR(str_cmp(zpl_isize offset)); - ZPL_DEF ZPL_COMPARE_PROC_PTR(f32_cmp(zpl_isize offset)); - ZPL_DEF ZPL_COMPARE_PROC_PTR(f64_cmp(zpl_isize offset)); - - // TODO: Better sorting algorithms - - //! Sorts an array. - - //! Uses quick sort for large arrays but insertion sort for small ones. - #define zpl_sort_array(array, count, compare_proc) zpl_sort(array, count, zpl_size_of(*(array)), compare_proc) - - //! Perform sorting operation on a memory location with a specified item count and size. - ZPL_DEF void zpl_sort(void *base, zpl_isize count, zpl_isize size, zpl_compare_proc compare_proc); - - // NOTE: the count of temp == count of items - #define zpl_radix_sort(Type) zpl_radix_sort_##Type - #define ZPL_RADIX_SORT_PROC(Type) void zpl_radix_sort(Type)(zpl_##Type * items, zpl_##Type * temp, zpl_isize count) - - ZPL_DEF ZPL_RADIX_SORT_PROC(u8); - ZPL_DEF ZPL_RADIX_SORT_PROC(u16); - ZPL_DEF ZPL_RADIX_SORT_PROC(u32); - ZPL_DEF ZPL_RADIX_SORT_PROC(u64); - - //! Performs binary search on an array. - - //! Returns index or -1 if not found - #define zpl_binary_search_array(array, count, key, compare_proc) \ - zpl_binary_search(array, count, zpl_size_of(*(array)), key, compare_proc) - - //! Performs binary search on a memory location with specified item count and size. - ZPL_DEF_INLINE zpl_isize zpl_binary_search(void const *base, zpl_isize count, zpl_isize size, void const *key, - zpl_compare_proc compare_proc); - - #define zpl_shuffle_array(array, count) zpl_shuffle(array, count, zpl_size_of(*(array))) - - //! Shuffles a memory. - ZPL_DEF void zpl_shuffle(void *base, zpl_isize count, zpl_isize size); - - #define zpl_reverse_array(array, count) zpl_reverse(array, count, zpl_size_of(*(array))) - - //! Reverses memory's contents - ZPL_DEF void zpl_reverse(void *base, zpl_isize count, zpl_isize size); - - //! @} - - - ZPL_IMPL_INLINE zpl_isize zpl_binary_search(void const *base, zpl_isize count, zpl_isize size, void const *key, - zpl_compare_proc compare_proc) { - zpl_isize start = 0; - zpl_isize end = count; - - while (start < end) { - zpl_isize mid = start + (end - start) / 2; - zpl_isize result = compare_proc(key, cast(zpl_u8 *) base + mid * size); - if (result < 0) - end = mid; - else if (result > 0) - start = mid + 1; - else - return mid; - } - - return -1; - } - - ZPL_END_C_DECLS - #endif - - #if defined(ZPL_MODULE_TIMER) - // file: header/timer.h - - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - typedef void (*zpl_timer_cb)(void *data); - - //! Timer data structure - typedef struct zpl_timer { - zpl_timer_cb callback; - zpl_b32 enabled; - zpl_i32 remaining_calls; - zpl_i32 initial_calls; - zpl_f64 next_call_ts; - zpl_f64 duration; - void *user_data; - } zpl_timer; - - typedef zpl_timer *zpl_timer_pool; ///< zpl_array - - //! Initialize timer pool. - #define zpl_timer_init(pool, allocator) zpl_array_init(pool, allocator) - - //! Add new timer to pool and return it. - ZPL_DEF zpl_timer *zpl_timer_add(zpl_timer_pool pool); - - //! Perform timer pool update. - - //! Traverse over all timers and update them accordingly. Should be called by Main Thread in a tight loop. - ZPL_DEF void zpl_timer_update(zpl_timer_pool pool); - - //! Set up timer. - - //! Set up timer with specific options. - //! @param timer - //! @param duration How long/often to fire a timer. - //! @param count How many times we fire a timer. Use -1 for infinity. - //! @param callback A method to execute once a timer triggers. - ZPL_DEF void zpl_timer_set(zpl_timer *timer, zpl_f64 /* microseconds */ duration, zpl_i32 /* -1 for INFINITY */ count, - zpl_timer_cb callback); - - //! Start timer with specified delay. - ZPL_DEF void zpl_timer_start(zpl_timer *timer, zpl_f64 delay_start); - - //! Stop timer and prevent it from triggering. - ZPL_DEF void zpl_timer_stop(zpl_timer *timer); - - ZPL_END_C_DECLS - #endif - - #if defined(ZPL_MODULE_HASHING) - // file: header/hashing.h - - /** @file hashing.c - @brief Hashing and Checksum Functions - @defgroup hashing Hashing and Checksum Functions - - Several hashing methods used by ZPL internally but possibly useful outside of it. Contains: adler32, crc32/64, fnv32/64/a and murmur32/64 - - @{ - */ - - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - ZPL_DEF zpl_u32 zpl_adler32(void const *data, zpl_isize len); - - ZPL_DEF zpl_u32 zpl_crc32(void const *data, zpl_isize len); - ZPL_DEF zpl_u64 zpl_crc64(void const *data, zpl_isize len); - - // These use FNV-1 algorithm - ZPL_DEF zpl_u32 zpl_fnv32(void const *data, zpl_isize len); - ZPL_DEF zpl_u64 zpl_fnv64(void const *data, zpl_isize len); - ZPL_DEF zpl_u32 zpl_fnv32a(void const *data, zpl_isize len); - ZPL_DEF zpl_u64 zpl_fnv64a(void const *data, zpl_isize len); - - ZPL_DEF zpl_u8 *zpl_base64_encode(zpl_allocator a, void const *data, zpl_isize len); - ZPL_DEF zpl_u8 *zpl_base64_decode(zpl_allocator a, void const *data, zpl_isize len); - - //! Based on MurmurHash3 - ZPL_DEF zpl_u32 zpl_murmur32_seed(void const *data, zpl_isize len, zpl_u32 seed); - - //! Based on MurmurHash2 - ZPL_DEF zpl_u64 zpl_murmur64_seed(void const *data, zpl_isize len, zpl_u64 seed); - - //! Default seed of 0x9747b28c - ZPL_DEF_INLINE zpl_u32 zpl_murmur32(void const *data, zpl_isize len); - - //! Default seed of 0x9747b28c - ZPL_DEF_INLINE zpl_u64 zpl_murmur64(void const *data, zpl_isize len); - - //! @} - - ZPL_IMPL_INLINE zpl_u32 zpl_murmur32(void const *data, zpl_isize len) { return zpl_murmur32_seed(data, len, 0x9747b28c); } - ZPL_IMPL_INLINE zpl_u64 zpl_murmur64(void const *data, zpl_isize len) { return zpl_murmur64_seed(data, len, 0x9747b28c); } - - ZPL_END_C_DECLS - #endif - - #if defined(ZPL_MODULE_REGEX) - // file: header/regex.h - - /** @file regex.c - @brief Regular expressions parser. - @defgroup regex Regex processor - - Port of gb_regex with several bugfixes applied. This is a simple regex library and is fast to perform. - - Supported Matching: - @n ^ - Beginning of string - @n $ - End of string - @n . - Match one (anything) - @n | - Branch (or) - @n () - Capturing group - @n [] - Any character included in set - @n [^] - Any character excluded from set - @n + - One or more (greedy) - @n +? - One or more (non-greedy) - @n * - Zero or more (greedy) - @n *? - Zero or more (non-greedy) - @n ? - Zero or once - @n [BACKSLASH]XX - Hex decimal digit (must be 2 digits) - @n [BACKSLASH]meta - Meta character - @n [BACKSLASH]s - Whitespace - @n [BACKSLASH]S - Not whitespace - @n [BACKSLASH]d - Digit - @n [BACKSLASH]D - Not digit - @n [BACKSLASH]a - Alphabetic character - @n [BACKSLASH]l - Lower case letter - @n [BACKSLASH]u - Upper case letter - @n [BACKSLASH]w - Word - @n [BACKSLASH]W - Not word - @n [BACKSLASH]x - Hex Digit - @n [BACKSLASH]p - Printable ASCII character - @n --Whitespace-- - @n [BACKSLASH]t - Tab - @n [BACKSLASH]n - New line - @n [BACKSLASH]r - Return carriage - @n [BACKSLASH]v - Vertical Tab - @n [BACKSLASH]f - Form feed - - @{ - */ - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - typedef struct zpl_re { - zpl_allocator backing; - zpl_isize capture_count; - char *buf; - zpl_isize buf_len, buf_cap; - zpl_b32 can_realloc; - } zpl_re; - - typedef struct zpl_re_capture { - char const *str; - zpl_isize len; - } zpl_re_capture; - - #define zplRegexError zpl_regex_error - typedef enum zpl_regex_error { - ZPL_RE_ERROR_NONE, - ZPL_RE_ERROR_NO_MATCH, - ZPL_RE_ERROR_TOO_LONG, - ZPL_RE_ERROR_MISMATCHED_CAPTURES, - ZPL_RE_ERROR_MISMATCHED_BLOCKS, - ZPL_RE_ERROR_BRANCH_FAILURE, - ZPL_RE_ERROR_INVALID_QUANTIFIER, - ZPL_RE_ERROR_INTERNAL_FAILURE, - } zpl_regex_error; - - //! Compile regex pattern. - ZPL_DEF zpl_regex_error zpl_re_compile(zpl_re *re, zpl_allocator backing, char const *pattern, zpl_isize pattern_len); - - //! Compile regex pattern using a buffer. - ZPL_DEF zpl_regex_error zpl_re_compile_from_buffer(zpl_re *re, char const *pattern, zpl_isize pattern_len, void *buffer, zpl_isize buffer_len); - - //! Destroy regex object. - ZPL_DEF void zpl_re_destroy(zpl_re *re); - - //! Retrieve number of retrievable captures. - ZPL_DEF zpl_isize zpl_re_capture_count(zpl_re *re); - - //! Match input string and output captures of the occurence. - ZPL_DEF zpl_b32 zpl_re_match(zpl_re *re, char const *str, zpl_isize str_len, zpl_re_capture *captures, zpl_isize max_capture_count, zpl_isize *offset); - - //! Match all occurences in an input string and output them into captures. Array of captures is allocated on the heap and needs to be freed afterwards. - ZPL_DEF zpl_b32 zpl_re_match_all(zpl_re *re, char const *str, zpl_isize str_len, zpl_isize max_capture_count, zpl_re_capture **out_captures); - - ZPL_END_C_DECLS - #endif - - #if defined(ZPL_MODULE_DLL) - // file: header/dll.h - - /** @file dll.c - @brief DLL Handling - @defgroup dll DLL handling - - @{ - */ - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - typedef void *zpl_dll_handle; - typedef void (*zpl_dll_proc)(void); - - ZPL_DEF zpl_dll_handle zpl_dll_load(char const *filepath); - ZPL_DEF void zpl_dll_unload(zpl_dll_handle dll); - ZPL_DEF zpl_dll_proc zpl_dll_proc_address(zpl_dll_handle dll, char const *proc_name); - - //! @} - - ZPL_END_C_DECLS - #endif - - #if defined(ZPL_MODULE_OPTS) - // file: header/opts.h - - /** @file opts.c - @brief CLI options processor - @defgroup cli CLI options processor - - Opts is a CLI options parser, it can parse flags, switches and arguments from command line - and offers an easy way to express input errors as well as the ability to display help screen. - - @{ - */ - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - typedef enum { - ZPL_OPTS_STRING, - ZPL_OPTS_FLOAT, - ZPL_OPTS_FLAG, - ZPL_OPTS_INT, - } zpl_opts_types; - - typedef struct { - char const *name, *lname, *desc; - zpl_u8 type; - zpl_b32 met, pos; - - //! values - union { - zpl_string text; - zpl_i64 integer; - zpl_f64 real; - }; - } zpl_opts_entry; - - typedef enum { - ZPL_OPTS_ERR_VALUE, - ZPL_OPTS_ERR_OPTION, - ZPL_OPTS_ERR_EXTRA_VALUE, - ZPL_OPTS_ERR_MISSING_VALUE, - } zpl_opts_err_type; - - typedef struct { - char *val; - zpl_u8 type; - } zpl_opts_err; - - typedef struct { - zpl_allocator alloc; - zpl_opts_entry *entries; ///< zpl_array - zpl_opts_err *errors; ///< zpl_array - zpl_opts_entry **positioned; ///< zpl_array - char const *appname; - } zpl_opts; - - //! Initializes options parser. - - //! Initializes CLI options parser using specified memory allocator and provided application name. - //! @param opts Options parser to initialize. - //! @param allocator Memory allocator to use. (ex. zpl_heap()) - //! @param app Application name displayed in help screen. - ZPL_DEF void zpl_opts_init(zpl_opts *opts, zpl_allocator allocator, char const *app); - - //! Releases the resources used by options parser. - ZPL_DEF void zpl_opts_free(zpl_opts *opts); - - //! Registers an option. - - //! Registers an option with its short and long name, specifies option's type and its description. - //! @param opts Options parser to add to. - //! @param lname Shorter name of option. (ex. "f") - //! @param name Full name of option. (ex. "foo") Note that rest of the module uses longer names to manipulate opts. - //! @param desc Description shown in the help screen. - //! @param type Option's type (see zpl_opts_types) - //! @see zpl_opts_types - ZPL_DEF void zpl_opts_add(zpl_opts *opts, char const *name, char const *lname, const char *desc, zpl_u8 type); - - //! Registers option as positional. - - //! Registers added option as positional, so that we can pass it anonymously. Arguments are expected on the command input in the same order they were registered as. - //! @param opts - //! @param name Name of already registered option. - ZPL_DEF void zpl_opts_positional_add(zpl_opts *opts, char const *name); - - //! Compiles CLI arguments. - - // This method takes CLI arguments as input and processes them based on rules that were set up. - //! @param opts - //! @param argc Argument count in an array. - //! @param argv Array of arguments. - ZPL_DEF zpl_b32 zpl_opts_compile(zpl_opts *opts, int argc, char **argv); - - //! Prints out help screen. - - //! Prints out help screen with example usage of application as well as with all the flags available. - ZPL_DEF void zpl_opts_print_help(zpl_opts *opts); - - //! Prints out parsing errors. - - //! Prints out possible errors caused by CLI input. - ZPL_DEF void zpl_opts_print_errors(zpl_opts *opts); - - //! Fetches a string from an option. - - //! @param opts - //! @param name Name of an option. - //! @param fallback Fallback string we return if option wasn't found. - ZPL_DEF zpl_string zpl_opts_string(zpl_opts *opts, char const *name, char const *fallback); - - //! Fetches a real number from an option. - - //! @param opts - //! @param name Name of an option. - //! @param fallback Fallback real number we return if option was not found. - ZPL_DEF zpl_f64 zpl_opts_real(zpl_opts *opts, char const *name, zpl_f64 fallback); - - //! Fetches an integer number from an option. - - //! @param opts - //! @param name Name of an option. - //! @param fallback Fallback integer number we return if option was not found. - ZPL_DEF zpl_i64 zpl_opts_integer(zpl_opts *opts, char const *name, zpl_i64 fallback); - - //! Checks whether an option was used. - - //! @param opts - //! @param name Name of an option. - ZPL_DEF zpl_b32 zpl_opts_has_arg(zpl_opts *opts, char const *name); - - //! Checks whether all positionals have been passed in. - ZPL_DEF zpl_b32 zpl_opts_positionals_filled(zpl_opts *opts); - - //! @} - - ZPL_END_C_DECLS - #endif - - #if defined(ZPL_MODULE_PROCESS) - // file: header/process.h - - /** @file process.c - @brief Process creation and manipulation methods - @defgroup process Process creation and manipulation methods - - Gives you the ability to create a new process, wait for it to end or terminate it. - It also exposes standard I/O with configurable options. - - @{ - */ - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - // TODO(zaklaus): Add Linux support - - typedef enum { - ZPL_PR_OPTS_COMBINE_STD_OUTPUT = ZPL_BIT(1), - ZPL_PR_OPTS_INHERIT_ENV = ZPL_BIT(2), - ZPL_PR_OPTS_CUSTOM_ENV = ZPL_BIT(3), - } zpl_pr_opts; - - typedef struct { - zpl_file in, out, err; - void *f_stdin, *f_stdout, *f_stderr; - #ifdef ZPL_SYSTEM_WINDOWS - void *win32_handle; - #else - // todo - #endif - } zpl_pr; - - typedef struct { - char *con_title; - char *workdir; - - zpl_isize env_count; - char **env; // format: "var=name" - - zpl_u32 posx, posy; - zpl_u32 resx, resy; - zpl_u32 bufx, bufy; - zpl_u32 fill_attr; - zpl_u32 flags; - zpl_b32 show_window; - } zpl_pr_si; - - ZPL_DEF zpl_i32 zpl_pr_create(zpl_pr *process, const char **args, zpl_isize argc, zpl_pr_si si, zpl_pr_opts options); - ZPL_DEF void zpl_pr_destroy(zpl_pr *process); - ZPL_DEF void zpl_pr_terminate(zpl_pr *process, zpl_i32 err_code); - ZPL_DEF zpl_i32 zpl_pr_join(zpl_pr *process); - - //! @} - ZPL_END_C_DECLS - #endif - - #if defined(ZPL_MODULE_MATH) - // file: header/math.h - - /** @file math.c - @brief Math operations - @defgroup math Math operations - - OpenGL gamedev friendly library for math. - - @{ - */ - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - typedef union zpl_vec2 { - struct { - zpl_f32 x, y; - }; - struct { - zpl_f32 s, t; - }; - zpl_f32 e[2]; - } zpl_vec2; - - typedef union zpl_vec3 { - struct { - zpl_f32 x, y, z; - }; - struct { - zpl_f32 r, g, b; - }; - struct { - zpl_f32 s, t, p; - }; - - zpl_vec2 xy; - zpl_vec2 st; - zpl_f32 e[3]; - } zpl_vec3; - - typedef union zpl_vec4 { - struct { - zpl_f32 x, y, z, w; - }; - struct { - zpl_f32 r, g, b, a; - }; - struct { - zpl_f32 s, t, p, q; - }; - struct { - zpl_vec2 xy, zw; - }; - struct { - zpl_vec2 st, pq; - }; - zpl_vec3 xyz; - zpl_vec3 rgb; - zpl_f32 e[4]; - } zpl_vec4; - - typedef union zpl_mat2 { - struct { - zpl_vec2 x, y; - }; - zpl_vec2 col[2]; - zpl_f32 e[4]; - } zpl_mat2; - - typedef union zpl_mat3 { - struct { - zpl_vec3 x, y, z; - }; - zpl_vec3 col[3]; - zpl_f32 e[9]; - } zpl_mat3; - - typedef union zpl_mat4 { - struct { - zpl_vec4 x, y, z, w; - }; - zpl_vec4 col[4]; - zpl_f32 e[16]; - } zpl_mat4; - - typedef union zpl_quat { - struct { - zpl_f32 x, y, z, w; - }; - zpl_vec4 xyzw; - zpl_vec3 xyz; - zpl_f32 e[4]; - } zpl_quat; - - typedef union zpl_plane { - struct { - zpl_f32 a, b, c, d; - }; - zpl_vec4 xyzw; - zpl_vec3 n; - zpl_f32 e[4]; - } zpl_plane; - - typedef struct zpl_frustum { - zpl_plane x1; - zpl_plane x2; - zpl_plane y1; - zpl_plane y2; - zpl_plane z1; - zpl_plane z2; - } zpl_frustum; - - typedef zpl_f32 zpl_float2[2]; - typedef zpl_f32 zpl_float3[3]; - typedef zpl_f32 zpl_float4[4]; - - typedef struct zpl_rect2 { - zpl_vec2 pos, dim; - } zpl_rect2; - typedef struct zpl_rect3 { - zpl_vec3 pos, dim; - } zpl_rect3; - - typedef struct zpl_aabb2 { - zpl_vec2 centre, half_size; - } zpl_aabb2; - typedef struct zpl_aabb3 { - zpl_vec3 centre, half_size; - } zpl_aabb3; - - typedef short zpl_half; - - #ifndef ZPL_CONSTANTS - #define ZPL_CONSTANTS - #define ZPL_EPSILON 1.19209290e-7f - #define ZPL_ZERO 0.0f - #define ZPL_ONE 1.0f - #define ZPL_TWO_THIRDS 0.666666666666666666666666666666666666667f - - #define ZPL_TAU 6.28318530717958647692528676655900576f - #define ZPL_PI 3.14159265358979323846264338327950288f - #define ZPL_ONE_OVER_TAU 0.636619772367581343075535053490057448f - #define ZPL_ONE_OVER_PI 0.159154943091895335768883763372514362f - - #define ZPL_TAU_OVER_2 3.14159265358979323846264338327950288f - #define ZPL_TAU_OVER_4 1.570796326794896619231321691639751442f - #define ZPL_TAU_OVER_8 0.785398163397448309615660845819875721f - - #define ZPL_E 2.71828182845904523536f - #define ZPL_SQRT_TWO 1.41421356237309504880168872420969808f - #define ZPL_SQRT_THREE 1.73205080756887729352744634150587236f - #define ZPL_SQRT_FIVE 2.23606797749978969640917366873127623f - - #define ZPL_LOG_TWO 0.693147180559945309417232121458176568f - #define ZPL_LOG_TEN 2.30258509299404568401799145468436421f - #endif // ZPL_CONSTANTS - - #ifndef zpl_square - #define zpl_square(x) ((x) * (x)) - #endif - - #ifndef zpl_cube - #define zpl_cube(x) ((x) * (x) * (x)) - #endif - - #ifndef zpl_sign - #define zpl_sign(x) ((x) >= 0 ? 1 : -1) - #endif - - ZPL_DEF zpl_f32 zpl_to_radians(zpl_f32 degrees); - ZPL_DEF zpl_f32 zpl_to_degrees(zpl_f32 radians); - - /* NOTE: Because to interpolate angles */ - ZPL_DEF zpl_f32 zpl_angle_diff(zpl_f32 radians_a, zpl_f32 radians_b); - - ZPL_DEF zpl_f32 zpl_copy_sign(zpl_f32 x, zpl_f32 y); - ZPL_DEF zpl_f32 zpl_remainder(zpl_f32 x, zpl_f32 y); - ZPL_DEF zpl_f32 zpl_mod(zpl_f32 x, zpl_f32 y); - ZPL_DEF zpl_f64 zpl_copy_sign64(zpl_f64 x, zpl_f64 y); - ZPL_DEF zpl_f64 zpl_floor64(zpl_f64 x); - ZPL_DEF zpl_f64 zpl_ceil64(zpl_f64 x); - ZPL_DEF zpl_f64 zpl_round64(zpl_f64 x); - ZPL_DEF zpl_f64 zpl_remainder64(zpl_f64 x, zpl_f64 y); - ZPL_DEF zpl_f64 zpl_abs64(zpl_f64 x); - ZPL_DEF zpl_f64 zpl_sign64(zpl_f64 x); - ZPL_DEF zpl_f64 zpl_mod64(zpl_f64 x, zpl_f64 y); - ZPL_DEF zpl_f32 zpl_sqrt(zpl_f32 a); - ZPL_DEF zpl_f32 zpl_rsqrt(zpl_f32 a); - ZPL_DEF zpl_f32 zpl_quake_rsqrt(zpl_f32 a); /* NOTE: It's probably better to use 1.0f/zpl_sqrt(a) - * And for simd, there is usually isqrt functions too! - */ - ZPL_DEF zpl_f32 zpl_sin(zpl_f32 radians); - ZPL_DEF zpl_f32 zpl_cos(zpl_f32 radians); - ZPL_DEF zpl_f32 zpl_tan(zpl_f32 radians); - ZPL_DEF zpl_f32 zpl_arcsin(zpl_f32 a); - ZPL_DEF zpl_f32 zpl_arccos(zpl_f32 a); - ZPL_DEF zpl_f32 zpl_arctan(zpl_f32 a); - ZPL_DEF zpl_f32 zpl_arctan2(zpl_f32 y, zpl_f32 x); - - ZPL_DEF zpl_f32 zpl_exp(zpl_f32 x); - ZPL_DEF zpl_f32 zpl_exp2(zpl_f32 x); - ZPL_DEF zpl_f32 zpl_log(zpl_f32 x); - ZPL_DEF zpl_f32 zpl_log2(zpl_f32 x); - ZPL_DEF zpl_f32 zpl_fast_exp(zpl_f32 x); /* NOTE: Only valid from -1 <= x <= +1 */ - ZPL_DEF zpl_f32 zpl_fast_exp2(zpl_f32 x); /* NOTE: Only valid from -1 <= x <= +1 */ - ZPL_DEF zpl_f32 zpl_pow(zpl_f32 x, zpl_f32 y); /* x^y */ - - ZPL_DEF zpl_f32 zpl_round(zpl_f32 x); - ZPL_DEF zpl_f32 zpl_floor(zpl_f32 x); - ZPL_DEF zpl_f32 zpl_ceil(zpl_f32 x); - - ZPL_DEF zpl_f32 zpl_half_to_float(zpl_half value); - ZPL_DEF zpl_half zpl_float_to_half(zpl_f32 value); - - ZPL_DEF zpl_vec2 zpl_vec2f_zero(void); - ZPL_DEF zpl_vec2 zpl_vec2f(zpl_f32 x, zpl_f32 y); - ZPL_DEF zpl_vec2 zpl_vec2fv(zpl_f32 x[2]); - - ZPL_DEF zpl_vec3 zpl_vec3f_zero(void); - ZPL_DEF zpl_vec3 zpl_vec3f(zpl_f32 x, zpl_f32 y, zpl_f32 z); - ZPL_DEF zpl_vec3 zpl_vec3fv(zpl_f32 x[3]); - - ZPL_DEF zpl_vec4 zpl_vec4f_zero(void); - ZPL_DEF zpl_vec4 zpl_vec4f(zpl_f32 x, zpl_f32 y, zpl_f32 z, zpl_f32 w); - ZPL_DEF zpl_vec4 zpl_vec4fv(zpl_f32 x[4]); - - ZPL_DEF zpl_f32 zpl_vec2_max(zpl_vec2 v); - ZPL_DEF zpl_f32 zpl_vec2_side(zpl_vec2 p, zpl_vec2 q, zpl_vec2 r); - ZPL_DEF void zpl_vec2_add(zpl_vec2 *d, zpl_vec2 v0, zpl_vec2 v1); - ZPL_DEF void zpl_vec2_sub(zpl_vec2 *d, zpl_vec2 v0, zpl_vec2 v1); - ZPL_DEF void zpl_vec2_mul(zpl_vec2 *d, zpl_vec2 v, zpl_f32 s); - ZPL_DEF void zpl_vec2_div(zpl_vec2 *d, zpl_vec2 v, zpl_f32 s); - - ZPL_DEF zpl_f32 zpl_vec3_max(zpl_vec3 v); - ZPL_DEF void zpl_vec3_add(zpl_vec3 *d, zpl_vec3 v0, zpl_vec3 v1); - ZPL_DEF void zpl_vec3_sub(zpl_vec3 *d, zpl_vec3 v0, zpl_vec3 v1); - ZPL_DEF void zpl_vec3_mul(zpl_vec3 *d, zpl_vec3 v, zpl_f32 s); - ZPL_DEF void zpl_vec3_div(zpl_vec3 *d, zpl_vec3 v, zpl_f32 s); - - ZPL_DEF void zpl_vec4_add(zpl_vec4 *d, zpl_vec4 v0, zpl_vec4 v1); - ZPL_DEF void zpl_vec4_sub(zpl_vec4 *d, zpl_vec4 v0, zpl_vec4 v1); - ZPL_DEF void zpl_vec4_mul(zpl_vec4 *d, zpl_vec4 v, zpl_f32 s); - ZPL_DEF void zpl_vec4_div(zpl_vec4 *d, zpl_vec4 v, zpl_f32 s); - - ZPL_DEF void zpl_vec2_addeq(zpl_vec2 *d, zpl_vec2 v); - ZPL_DEF void zpl_vec2_subeq(zpl_vec2 *d, zpl_vec2 v); - ZPL_DEF void zpl_vec2_muleq(zpl_vec2 *d, zpl_f32 s); - ZPL_DEF void zpl_vec2_diveq(zpl_vec2 *d, zpl_f32 s); - - ZPL_DEF void zpl_vec3_addeq(zpl_vec3 *d, zpl_vec3 v); - ZPL_DEF void zpl_vec3_subeq(zpl_vec3 *d, zpl_vec3 v); - ZPL_DEF void zpl_vec3_muleq(zpl_vec3 *d, zpl_f32 s); - ZPL_DEF void zpl_vec3_diveq(zpl_vec3 *d, zpl_f32 s); - - ZPL_DEF void zpl_vec4_addeq(zpl_vec4 *d, zpl_vec4 v); - ZPL_DEF void zpl_vec4_subeq(zpl_vec4 *d, zpl_vec4 v); - ZPL_DEF void zpl_vec4_muleq(zpl_vec4 *d, zpl_f32 s); - ZPL_DEF void zpl_vec4_diveq(zpl_vec4 *d, zpl_f32 s); - - ZPL_DEF zpl_f32 zpl_vec2_dot(zpl_vec2 v0, zpl_vec2 v1); - ZPL_DEF zpl_f32 zpl_vec3_dot(zpl_vec3 v0, zpl_vec3 v1); - ZPL_DEF zpl_f32 zpl_vec4_dot(zpl_vec4 v0, zpl_vec4 v1); - - ZPL_DEF void zpl_vec2_cross(zpl_f32 *d, zpl_vec2 v0, zpl_vec2 v1); - ZPL_DEF void zpl_vec3_cross(zpl_vec3 *d, zpl_vec3 v0, zpl_vec3 v1); - - ZPL_DEF zpl_f32 zpl_vec2_mag2(zpl_vec2 v); - ZPL_DEF zpl_f32 zpl_vec3_mag2(zpl_vec3 v); - ZPL_DEF zpl_f32 zpl_vec4_mag2(zpl_vec4 v); - - ZPL_DEF zpl_f32 zpl_vec2_mag(zpl_vec2 v); - ZPL_DEF zpl_f32 zpl_vec3_mag(zpl_vec3 v); - ZPL_DEF zpl_f32 zpl_vec4_mag(zpl_vec4 v); - - ZPL_DEF void zpl_vec2_norm(zpl_vec2 *d, zpl_vec2 v); - ZPL_DEF void zpl_vec3_norm(zpl_vec3 *d, zpl_vec3 v); - ZPL_DEF void zpl_vec4_norm(zpl_vec4 *d, zpl_vec4 v); - - ZPL_DEF void zpl_vec2_norm0(zpl_vec2 *d, zpl_vec2 v); - ZPL_DEF void zpl_vec3_norm0(zpl_vec3 *d, zpl_vec3 v); - ZPL_DEF void zpl_vec4_norm0(zpl_vec4 *d, zpl_vec4 v); - - ZPL_DEF void zpl_vec2_reflect(zpl_vec2 *d, zpl_vec2 i, zpl_vec2 n); - ZPL_DEF void zpl_vec3_reflect(zpl_vec3 *d, zpl_vec3 i, zpl_vec3 n); - ZPL_DEF void zpl_vec2_refract(zpl_vec2 *d, zpl_vec2 i, zpl_vec2 n, zpl_f32 eta); - ZPL_DEF void zpl_vec3_refract(zpl_vec3 *d, zpl_vec3 i, zpl_vec3 n, zpl_f32 eta); - - ZPL_DEF zpl_f32 zpl_vec2_aspect_ratio(zpl_vec2 v); - - ZPL_DEF void zpl_mat2_identity(zpl_mat2 *m); - ZPL_DEF void zpl_float22_identity(zpl_f32 m[2][2]); - - ZPL_DEF void zpl_mat2_transpose(zpl_mat2 *m); - ZPL_DEF void zpl_mat2_mul(zpl_mat2 *out, zpl_mat2 *m1, zpl_mat2 *m2); - ZPL_DEF void zpl_mat2_mul_vec2(zpl_vec2 *out, zpl_mat2 *m, zpl_vec2 in); - ZPL_DEF void zpl_mat2_inverse(zpl_mat2 *out, zpl_mat2 *in); - ZPL_DEF zpl_f32 zpl_mat2_determinate(zpl_mat2 *m); - - ZPL_DEF zpl_mat2 *zpl_mat2_v(zpl_vec2 m[2]); - ZPL_DEF zpl_mat2 *zpl_mat2_f(zpl_f32 m[2][2]); - ZPL_DEF zpl_float2 *zpl_float22_m(zpl_mat2 *m); - ZPL_DEF zpl_float2 *zpl_float22_v(zpl_vec2 m[2]); - ZPL_DEF zpl_float2 *zpl_float22_4(zpl_f32 m[4]); - - ZPL_DEF void zpl_float22_transpose(zpl_f32 (*vec)[2]); - ZPL_DEF void zpl_float22_mul(zpl_f32 (*out)[2], zpl_f32 (*mat1)[2], zpl_f32 (*mat2)[2]); - ZPL_DEF void zpl_float22_mul_vec2(zpl_vec2 *out, zpl_f32 m[2][2], zpl_vec2 in); - - ZPL_DEF void zpl_mat3_identity(zpl_mat3 *m); - ZPL_DEF void zpl_float33_identity(zpl_f32 m[3][3]); - - ZPL_DEF void zpl_mat3_transpose(zpl_mat3 *m); - ZPL_DEF void zpl_mat3_mul(zpl_mat3 *out, zpl_mat3 *m1, zpl_mat3 *m2); - ZPL_DEF void zpl_mat3_mul_vec3(zpl_vec3 *out, zpl_mat3 *m, zpl_vec3 in); - ZPL_DEF void zpl_mat3_inverse(zpl_mat3 *out, zpl_mat3 *in); - ZPL_DEF zpl_f32 zpl_mat3_determinate(zpl_mat3 *m); - - ZPL_DEF zpl_mat3 *zpl_mat3_v(zpl_vec3 m[3]); - ZPL_DEF zpl_mat3 *zpl_mat3_f(zpl_f32 m[3][3]); - - ZPL_DEF zpl_float3 *zpl_float33_m(zpl_mat3 *m); - ZPL_DEF zpl_float3 *zpl_float33_v(zpl_vec3 m[3]); - ZPL_DEF zpl_float3 *zpl_float33_9(zpl_f32 m[9]); - - ZPL_DEF void zpl_float33_transpose(zpl_f32 (*vec)[3]); - ZPL_DEF void zpl_float33_mul(zpl_f32 (*out)[3], zpl_f32 (*mat1)[3], zpl_f32 (*mat2)[3]); - ZPL_DEF void zpl_float33_mul_vec3(zpl_vec3 *out, zpl_f32 m[3][3], zpl_vec3 in); - - ZPL_DEF void zpl_mat4_identity(zpl_mat4 *m); - ZPL_DEF void zpl_float44_identity(zpl_f32 m[4][4]); - ZPL_DEF void zpl_mat4_copy(zpl_mat4* out, zpl_mat4* m); - - ZPL_DEF void zpl_mat4_transpose(zpl_mat4 *m); - ZPL_DEF void zpl_mat4_mul(zpl_mat4 *out, zpl_mat4 *m1, zpl_mat4 *m2); - ZPL_DEF void zpl_mat4_mul_vec4(zpl_vec4 *out, zpl_mat4 *m, zpl_vec4 in); - ZPL_DEF void zpl_mat4_inverse(zpl_mat4 *out, zpl_mat4 *in); - - ZPL_DEF zpl_mat4 *zpl_mat4_v(zpl_vec4 m[4]); - ZPL_DEF zpl_mat4 *zpl_mat4_f(zpl_f32 m[4][4]); - - ZPL_DEF zpl_float4 *zpl_float44_m(zpl_mat4 *m); - ZPL_DEF zpl_float4 *zpl_float44_v(zpl_vec4 m[4]); - ZPL_DEF zpl_float4 *zpl_float44_16(zpl_f32 m[16]); - - ZPL_DEF void zpl_float44_transpose(zpl_f32 (*vec)[4]); - ZPL_DEF void zpl_float44_mul(zpl_f32 (*out)[4], zpl_f32 (*mat1)[4], zpl_f32 (*mat2)[4]); - ZPL_DEF void zpl_float44_mul_vec4(zpl_vec4 *out, zpl_f32 m[4][4], zpl_vec4 in); - - ZPL_DEF void zpl_mat4_translate(zpl_mat4 *out, zpl_vec3 v); - ZPL_DEF void zpl_mat4_rotate(zpl_mat4 *out, zpl_vec3 v, zpl_f32 angle_radians); - ZPL_DEF void zpl_mat4_scale(zpl_mat4 *out, zpl_vec3 v); - ZPL_DEF void zpl_mat4_scalef(zpl_mat4 *out, zpl_f32 s); - ZPL_DEF void zpl_mat4_ortho2d(zpl_mat4 *out, zpl_f32 left, zpl_f32 right, zpl_f32 bottom, zpl_f32 top); - ZPL_DEF void zpl_mat4_ortho3d(zpl_mat4 *out, zpl_f32 left, zpl_f32 right, zpl_f32 bottom, zpl_f32 top, zpl_f32 z_near, zpl_f32 z_far); - ZPL_DEF void zpl_mat4_perspective(zpl_mat4 *out, zpl_f32 fovy, zpl_f32 aspect, zpl_f32 z_near, zpl_f32 z_far); - ZPL_DEF void zpl_mat4_infinite_perspective(zpl_mat4 *out, zpl_f32 fovy, zpl_f32 aspect, zpl_f32 z_near); - - ZPL_DEF void zpl_mat4_ortho2d_dx(zpl_mat4 *out, zpl_f32 left, zpl_f32 right, zpl_f32 bottom, zpl_f32 top); - ZPL_DEF void zpl_mat4_ortho3d_dx(zpl_mat4 *out, zpl_f32 left, zpl_f32 right, zpl_f32 bottom, zpl_f32 top, zpl_f32 z_near, zpl_f32 z_far); - ZPL_DEF void zpl_mat4_perspective_dx(zpl_mat4 *out, zpl_f32 fovy, zpl_f32 aspect, zpl_f32 z_near, zpl_f32 z_far); - ZPL_DEF void zpl_mat4_infinite_perspective_dx(zpl_mat4 *out, zpl_f32 fovy, zpl_f32 aspect, zpl_f32 z_near); - - ZPL_DEF void zpl_mat4_look_at(zpl_mat4 *out, zpl_vec3 eye, zpl_vec3 centre, zpl_vec3 up); - - ZPL_DEF void zpl_mat4_look_at_lh(zpl_mat4 *out, zpl_vec3 eye, zpl_vec3 centre, zpl_vec3 up); - - ZPL_DEF zpl_quat zpl_quatf(zpl_f32 x, zpl_f32 y, zpl_f32 z, zpl_f32 w); - ZPL_DEF zpl_quat zpl_quatfv(zpl_f32 e[4]); - ZPL_DEF zpl_quat zpl_quat_axis_angle(zpl_vec3 axis, zpl_f32 angle_radians); - ZPL_DEF zpl_quat zpl_quat_euler_angles(zpl_f32 pitch, zpl_f32 yaw, zpl_f32 roll); - ZPL_DEF zpl_quat zpl_quat_identity(void); - - ZPL_DEF void zpl_quat_add(zpl_quat *d, zpl_quat q0, zpl_quat q1); - ZPL_DEF void zpl_quat_sub(zpl_quat *d, zpl_quat q0, zpl_quat q1); - ZPL_DEF void zpl_quat_mul(zpl_quat *d, zpl_quat q0, zpl_quat q1); - ZPL_DEF void zpl_quat_div(zpl_quat *d, zpl_quat q0, zpl_quat q1); - - ZPL_DEF void zpl_quat_mulf(zpl_quat *d, zpl_quat q, zpl_f32 s); - ZPL_DEF void zpl_quat_divf(zpl_quat *d, zpl_quat q, zpl_f32 s); - - ZPL_DEF void zpl_quat_addeq(zpl_quat *d, zpl_quat q); - ZPL_DEF void zpl_quat_subeq(zpl_quat *d, zpl_quat q); - ZPL_DEF void zpl_quat_muleq(zpl_quat *d, zpl_quat q); - ZPL_DEF void zpl_quat_diveq(zpl_quat *d, zpl_quat q); - - ZPL_DEF void zpl_quat_muleqf(zpl_quat *d, zpl_f32 s); - ZPL_DEF void zpl_quat_diveqf(zpl_quat *d, zpl_f32 s); - - ZPL_DEF zpl_f32 zpl_quat_dot(zpl_quat q0, zpl_quat q1); - ZPL_DEF zpl_f32 zpl_quat_mag(zpl_quat q); - - ZPL_DEF void zpl_quat_norm(zpl_quat *d, zpl_quat q); - ZPL_DEF void zpl_quat_conj(zpl_quat *d, zpl_quat q); - ZPL_DEF void zpl_quat_inverse(zpl_quat *d, zpl_quat q); - - ZPL_DEF void zpl_quat_axis(zpl_vec3 *axis, zpl_quat q); - ZPL_DEF zpl_f32 zpl_quat_angle(zpl_quat q); - - ZPL_DEF zpl_f32 zpl_quat_pitch(zpl_quat q); - ZPL_DEF zpl_f32 zpl_quat_yaw(zpl_quat q); - ZPL_DEF zpl_f32 zpl_quat_roll(zpl_quat q); - - /* NOTE: Rotate v by q */ - ZPL_DEF void zpl_quat_rotate_vec3(zpl_vec3 *d, zpl_quat q, zpl_vec3 v); - ZPL_DEF void zpl_mat4_from_quat(zpl_mat4 *out, zpl_quat q); - ZPL_DEF void zpl_quat_from_mat4(zpl_quat *out, zpl_mat4 *m); - - /* Plane math. */ - ZPL_DEF zpl_f32 zpl_plane_distance(zpl_plane* p, zpl_vec3 v); - - /* Frustum culling. */ - ZPL_DEF void zpl_frustum_create(zpl_frustum* out, zpl_mat4* camera, zpl_mat4* proj); - ZPL_DEF zpl_b8 zpl_frustum_sphere_inside(zpl_frustum* frustum, zpl_vec3 center, zpl_f32 radius); - ZPL_DEF zpl_b8 zpl_frustum_point_inside(zpl_frustum* frustum, zpl_vec3 point); - ZPL_DEF zpl_b8 zpl_frustum_box_inside(zpl_frustum* frustum, zpl_aabb3 box); - - /* Interpolations */ - ZPL_DEF zpl_f32 zpl_lerp(zpl_f32 a, zpl_f32 b, zpl_f32 t); - ZPL_DEF zpl_f32 zpl_unlerp(zpl_f32 t, zpl_f32 a, zpl_f32 b); - ZPL_DEF zpl_f32 zpl_smooth_step(zpl_f32 a, zpl_f32 b, zpl_f32 t); - ZPL_DEF zpl_f32 zpl_smoother_step(zpl_f32 a, zpl_f32 b, zpl_f32 t); - - ZPL_DEF void zpl_vec2_lerp(zpl_vec2 *d, zpl_vec2 a, zpl_vec2 b, zpl_f32 t); - ZPL_DEF void zpl_vec3_lerp(zpl_vec3 *d, zpl_vec3 a, zpl_vec3 b, zpl_f32 t); - ZPL_DEF void zpl_vec4_lerp(zpl_vec4 *d, zpl_vec4 a, zpl_vec4 b, zpl_f32 t); - - ZPL_DEF void zpl_vec2_cslerp(zpl_vec2 *d, zpl_vec2 a, zpl_vec2 v0, zpl_vec2 b, zpl_vec2 v1, zpl_f32 t); - ZPL_DEF void zpl_vec3_cslerp(zpl_vec3 *d, zpl_vec3 a, zpl_vec3 v0, zpl_vec3 b, zpl_vec3 v1, zpl_f32 t); - ZPL_DEF void zpl_vec2_dcslerp(zpl_vec2 *d, zpl_vec2 a, zpl_vec2 v0, zpl_vec2 b, zpl_vec2 v1, zpl_f32 t); - ZPL_DEF void zpl_vec3_dcslerp(zpl_vec3 *d, zpl_vec3 a, zpl_vec3 v0, zpl_vec3 b, zpl_vec3 v1, zpl_f32 t); - - ZPL_DEF void zpl_quat_lerp(zpl_quat *d, zpl_quat a, zpl_quat b, zpl_f32 t); - ZPL_DEF void zpl_quat_nlerp(zpl_quat *d, zpl_quat a, zpl_quat b, zpl_f32 t); - ZPL_DEF void zpl_quat_slerp(zpl_quat *d, zpl_quat a, zpl_quat b, zpl_f32 t); - ZPL_DEF void zpl_quat_nquad(zpl_quat *d, zpl_quat p, zpl_quat a, zpl_quat b, zpl_quat q, zpl_f32 t); - ZPL_DEF void zpl_quat_squad(zpl_quat *d, zpl_quat p, zpl_quat a, zpl_quat b, zpl_quat q, zpl_f32 t); - ZPL_DEF void zpl_quat_slerp_approx(zpl_quat *d, zpl_quat a, zpl_quat b, zpl_f32 t); - ZPL_DEF void zpl_quat_squad_approx(zpl_quat *d, zpl_quat p, zpl_quat a, zpl_quat b, zpl_quat q, zpl_f32 t); - - /* Rects */ - ZPL_DEF zpl_rect2 zpl_rect2f(zpl_vec2 pos, zpl_vec2 dim); - ZPL_DEF zpl_rect3 zpl_rect3f(zpl_vec3 pos, zpl_vec3 dim); - - ZPL_DEF int zpl_rect2_contains(zpl_rect2 a, zpl_f32 x, zpl_f32 y); - ZPL_DEF int zpl_rect2_contains_vec2(zpl_rect2 a, zpl_vec2 p); - ZPL_DEF int zpl_rect2_intersects(zpl_rect2 a, zpl_rect2 b); - ZPL_DEF int zpl_rect2_intersection_result(zpl_rect2 a, zpl_rect2 b, zpl_rect2 *intersection); - - //! @} - ZPL_END_C_DECLS - #if defined(__cplusplus) - ZPL_INLINE bool operator==(zpl_vec2 a, zpl_vec2 b) { return (a.x == b.x) && (a.y == b.y); } - ZPL_INLINE bool operator!=(zpl_vec2 a, zpl_vec2 b) { return !operator==(a, b); } - - ZPL_INLINE zpl_vec2 operator+(zpl_vec2 a) { return a; } - ZPL_INLINE zpl_vec2 operator-(zpl_vec2 a) { zpl_vec2 r = {-a.x, -a.y}; return r; } - - ZPL_INLINE zpl_vec2 operator+(zpl_vec2 a, zpl_vec2 b) { zpl_vec2 r; zpl_vec2_add(&r, a, b); return r; } - ZPL_INLINE zpl_vec2 operator-(zpl_vec2 a, zpl_vec2 b) { zpl_vec2 r; zpl_vec2_sub(&r, a, b); return r; } - - ZPL_INLINE zpl_vec2 operator*(zpl_vec2 a, float scalar) { zpl_vec2 r; zpl_vec2_mul(&r, a, scalar); return r; } - ZPL_INLINE zpl_vec2 operator*(float scalar, zpl_vec2 a) { return operator*(a, scalar); } - - ZPL_INLINE zpl_vec2 operator/(zpl_vec2 a, float scalar) { return operator*(a, 1.0f/scalar); } - - /* Hadamard Product */ - ZPL_INLINE zpl_vec2 operator*(zpl_vec2 a, zpl_vec2 b) { zpl_vec2 r = {a.x*b.x, a.y*b.y}; return r; } - ZPL_INLINE zpl_vec2 operator/(zpl_vec2 a, zpl_vec2 b) { zpl_vec2 r = {a.x/b.x, a.y/b.y}; return r; } - - ZPL_INLINE zpl_vec2 &operator+=(zpl_vec2 &a, zpl_vec2 b) { return (a = a + b); } - ZPL_INLINE zpl_vec2 &operator-=(zpl_vec2 &a, zpl_vec2 b) { return (a = a - b); } - ZPL_INLINE zpl_vec2 &operator*=(zpl_vec2 &a, float scalar) { return (a = a * scalar); } - ZPL_INLINE zpl_vec2 &operator/=(zpl_vec2 &a, float scalar) { return (a = a / scalar); } - - - ZPL_INLINE bool operator==(zpl_vec3 a, zpl_vec3 b) { return (a.x == b.x) && (a.y == b.y) && (a.z == b.z); } - ZPL_INLINE bool operator!=(zpl_vec3 a, zpl_vec3 b) { return !operator==(a, b); } - - ZPL_INLINE zpl_vec3 operator+(zpl_vec3 a) { return a; } - ZPL_INLINE zpl_vec3 operator-(zpl_vec3 a) { zpl_vec3 r = {-a.x, -a.y, -a.z}; return r; } - - ZPL_INLINE zpl_vec3 operator+(zpl_vec3 a, zpl_vec3 b) { zpl_vec3 r; zpl_vec3_add(&r, a, b); return r; } - ZPL_INLINE zpl_vec3 operator-(zpl_vec3 a, zpl_vec3 b) { zpl_vec3 r; zpl_vec3_sub(&r, a, b); return r; } - - ZPL_INLINE zpl_vec3 operator*(zpl_vec3 a, float scalar) { zpl_vec3 r; zpl_vec3_mul(&r, a, scalar); return r; } - ZPL_INLINE zpl_vec3 operator*(float scalar, zpl_vec3 a) { return operator*(a, scalar); } - - ZPL_INLINE zpl_vec3 operator/(zpl_vec3 a, float scalar) { return operator*(a, 1.0f/scalar); } - - /* Hadamard Product */ - ZPL_INLINE zpl_vec3 operator*(zpl_vec3 a, zpl_vec3 b) { zpl_vec3 r = {a.x*b.x, a.y*b.y, a.z*b.z}; return r; } - ZPL_INLINE zpl_vec3 operator/(zpl_vec3 a, zpl_vec3 b) { zpl_vec3 r = {a.x/b.x, a.y/b.y, a.z/b.z}; return r; } - - ZPL_INLINE zpl_vec3 &operator+=(zpl_vec3 &a, zpl_vec3 b) { return (a = a + b); } - ZPL_INLINE zpl_vec3 &operator-=(zpl_vec3 &a, zpl_vec3 b) { return (a = a - b); } - ZPL_INLINE zpl_vec3 &operator*=(zpl_vec3 &a, float scalar) { return (a = a * scalar); } - ZPL_INLINE zpl_vec3 &operator/=(zpl_vec3 &a, float scalar) { return (a = a / scalar); } - - - ZPL_INLINE bool operator==(zpl_vec4 a, zpl_vec4 b) { return (a.x == b.x) && (a.y == b.y) && (a.z == b.z) && (a.w == b.w); } - ZPL_INLINE bool operator!=(zpl_vec4 a, zpl_vec4 b) { return !operator==(a, b); } - - ZPL_INLINE zpl_vec4 operator+(zpl_vec4 a) { return a; } - ZPL_INLINE zpl_vec4 operator-(zpl_vec4 a) { zpl_vec4 r = {-a.x, -a.y, -a.z, -a.w}; return r; } - - ZPL_INLINE zpl_vec4 operator+(zpl_vec4 a, zpl_vec4 b) { zpl_vec4 r; zpl_vec4_add(&r, a, b); return r; } - ZPL_INLINE zpl_vec4 operator-(zpl_vec4 a, zpl_vec4 b) { zpl_vec4 r; zpl_vec4_sub(&r, a, b); return r; } - - ZPL_INLINE zpl_vec4 operator*(zpl_vec4 a, float scalar) { zpl_vec4 r; zpl_vec4_mul(&r, a, scalar); return r; } - ZPL_INLINE zpl_vec4 operator*(float scalar, zpl_vec4 a) { return operator*(a, scalar); } - - ZPL_INLINE zpl_vec4 operator/(zpl_vec4 a, float scalar) { return operator*(a, 1.0f/scalar); } - - /* Hadamard Product */ - ZPL_INLINE zpl_vec4 operator*(zpl_vec4 a, zpl_vec4 b) { zpl_vec4 r = {a.x*b.x, a.y*b.y, a.z*b.z, a.w*b.w}; return r; } - ZPL_INLINE zpl_vec4 operator/(zpl_vec4 a, zpl_vec4 b) { zpl_vec4 r = {a.x/b.x, a.y/b.y, a.z/b.z, a.w/b.w}; return r; } - - ZPL_INLINE zpl_vec4 &operator+=(zpl_vec4 &a, zpl_vec4 b) { return (a = a + b); } - ZPL_INLINE zpl_vec4 &operator-=(zpl_vec4 &a, zpl_vec4 b) { return (a = a - b); } - ZPL_INLINE zpl_vec4 &operator*=(zpl_vec4 &a, float scalar) { return (a = a * scalar); } - ZPL_INLINE zpl_vec4 &operator/=(zpl_vec4 &a, float scalar) { return (a = a / scalar); } - - - ZPL_INLINE zpl_mat2 operator+(zpl_mat2 const &a, zpl_mat2 const &b) { - int i, j; - zpl_mat2 r = {0}; - for (j = 0; j < 2; j++) { - for (i = 0; i < 2; i++) - r.e[2*j+i] = a.e[2*j+i] + b.e[2*j+i]; - } - return r; - } - - ZPL_INLINE zpl_mat2 operator-(zpl_mat2 const &a, zpl_mat2 const &b) { - int i, j; - zpl_mat2 r = {0}; - for (j = 0; j < 2; j++) { - for (i = 0; i < 2; i++) - r.e[2*j+i] = a.e[2*j+i] - b.e[2*j+i]; - } - return r; - } - - ZPL_INLINE zpl_mat2 operator*(zpl_mat2 const &a, zpl_mat2 const &b) { zpl_mat2 r; zpl_mat2_mul(&r, (zpl_mat2 *)&a, (zpl_mat2 *)&b); return r; } - ZPL_INLINE zpl_vec2 operator*(zpl_mat2 const &a, zpl_vec2 v) { zpl_vec2 r; zpl_mat2_mul_vec2(&r, (zpl_mat2 *)&a, v); return r; } - ZPL_INLINE zpl_mat2 operator*(zpl_mat2 const &a, float scalar) { - zpl_mat2 r = {0}; - int i; - for (i = 0; i < 2*2; i++) r.e[i] = a.e[i] * scalar; - return r; - } - ZPL_INLINE zpl_mat2 operator*(float scalar, zpl_mat2 const &a) { return operator*(a, scalar); } - ZPL_INLINE zpl_mat2 operator/(zpl_mat2 const &a, float scalar) { return operator*(a, 1.0f/scalar); } - - ZPL_INLINE zpl_mat2& operator+=(zpl_mat2& a, zpl_mat2 const &b) { return (a = a + b); } - ZPL_INLINE zpl_mat2& operator-=(zpl_mat2& a, zpl_mat2 const &b) { return (a = a - b); } - ZPL_INLINE zpl_mat2& operator*=(zpl_mat2& a, zpl_mat2 const &b) { return (a = a * b); } - - - - ZPL_INLINE zpl_mat3 operator+(zpl_mat3 const &a, zpl_mat3 const &b) { - int i, j; - zpl_mat3 r = {0}; - for (j = 0; j < 3; j++) { - for (i = 0; i < 3; i++) - r.e[3*j+i] = a.e[3*j+i] + b.e[3*j+i]; - } - return r; - } - - ZPL_INLINE zpl_mat3 operator-(zpl_mat3 const &a, zpl_mat3 const &b) { - int i, j; - zpl_mat3 r = {0}; - for (j = 0; j < 3; j++) { - for (i = 0; i < 3; i++) - r.e[3*j+i] = a.e[3*j+i] - b.e[3*j+i]; - } - return r; - } - - ZPL_INLINE zpl_mat3 operator*(zpl_mat3 const &a, zpl_mat3 const &b) { zpl_mat3 r; zpl_mat3_mul(&r, (zpl_mat3 *)&a, (zpl_mat3 *)&b); return r; } - ZPL_INLINE zpl_vec3 operator*(zpl_mat3 const &a, zpl_vec3 v) { zpl_vec3 r; zpl_mat3_mul_vec3(&r, (zpl_mat3 *)&a, v); return r; } - ZPL_INLINE zpl_mat3 operator*(zpl_mat3 const &a, float scalar) { - zpl_mat3 r = {0}; - int i; - for (i = 0; i < 3*3; i++) r.e[i] = a.e[i] * scalar; - return r; - } - ZPL_INLINE zpl_mat3 operator*(float scalar, zpl_mat3 const &a) { return operator*(a, scalar); } - ZPL_INLINE zpl_mat3 operator/(zpl_mat3 const &a, float scalar) { return operator*(a, 1.0f/scalar); } - - ZPL_INLINE zpl_mat3& operator+=(zpl_mat3& a, zpl_mat3 const &b) { return (a = a + b); } - ZPL_INLINE zpl_mat3& operator-=(zpl_mat3& a, zpl_mat3 const &b) { return (a = a - b); } - ZPL_INLINE zpl_mat3& operator*=(zpl_mat3& a, zpl_mat3 const &b) { return (a = a * b); } - - - - ZPL_INLINE zpl_mat4 operator+(zpl_mat4 const &a, zpl_mat4 const &b) { - int i, j; - zpl_mat4 r = {0}; - for (j = 0; j < 4; j++) { - for (i = 0; i < 4; i++) - r.e[4*j+i] = a.e[4*j+i] + b.e[4*j+i]; - } - return r; - } - - ZPL_INLINE zpl_mat4 operator-(zpl_mat4 const &a, zpl_mat4 const &b) { - int i, j; - zpl_mat4 r = {0}; - for (j = 0; j < 4; j++) { - for (i = 0; i < 4; i++) - r.e[4*j+i] = a.e[4*j+i] - b.e[4*j+i]; - } - return r; - } - - ZPL_INLINE zpl_mat4 operator*(zpl_mat4 const &a, zpl_mat4 const &b) { zpl_mat4 r; zpl_mat4_mul(&r, (zpl_mat4 *)&a, (zpl_mat4 *)&b); return r; } - ZPL_INLINE zpl_vec4 operator*(zpl_mat4 const &a, zpl_vec4 v) { zpl_vec4 r; zpl_mat4_mul_vec4(&r, (zpl_mat4 *)&a, v); return r; } - ZPL_INLINE zpl_mat4 operator*(zpl_mat4 const &a, float scalar) { - zpl_mat4 r = {0}; - int i; - for (i = 0; i < 4*4; i++) r.e[i] = a.e[i] * scalar; - return r; - } - ZPL_INLINE zpl_mat4 operator*(float scalar, zpl_mat4 const &a) { return operator*(a, scalar); } - ZPL_INLINE zpl_mat4 operator/(zpl_mat4 const &a, float scalar) { return operator*(a, 1.0f/scalar); } - - ZPL_INLINE zpl_mat4& operator+=(zpl_mat4 &a, zpl_mat4 const &b) { return (a = a + b); } - ZPL_INLINE zpl_mat4& operator-=(zpl_mat4 &a, zpl_mat4 const &b) { return (a = a - b); } - ZPL_INLINE zpl_mat4& operator*=(zpl_mat4 &a, zpl_mat4 const &b) { return (a = a * b); } - - - - ZPL_INLINE bool operator==(zpl_quat a, zpl_quat b) { return a.xyzw == b.xyzw; } - ZPL_INLINE bool operator!=(zpl_quat a, zpl_quat b) { return !operator==(a, b); } - - ZPL_INLINE zpl_quat operator+(zpl_quat q) { return q; } - ZPL_INLINE zpl_quat operator-(zpl_quat q) { return zpl_quatf(-q.x, -q.y, -q.z, -q.w); } - - ZPL_INLINE zpl_quat operator+(zpl_quat a, zpl_quat b) { zpl_quat r; zpl_quat_add(&r, a, b); return r; } - ZPL_INLINE zpl_quat operator-(zpl_quat a, zpl_quat b) { zpl_quat r; zpl_quat_sub(&r, a, b); return r; } - - ZPL_INLINE zpl_quat operator*(zpl_quat a, zpl_quat b) { zpl_quat r; zpl_quat_mul(&r, a, b); return r; } - ZPL_INLINE zpl_quat operator*(zpl_quat q, float s) { zpl_quat r; zpl_quat_mulf(&r, q, s); return r; } - ZPL_INLINE zpl_quat operator*(float s, zpl_quat q) { return operator*(q, s); } - ZPL_INLINE zpl_quat operator/(zpl_quat q, float s) { zpl_quat r; zpl_quat_divf(&r, q, s); return r; } - - ZPL_INLINE zpl_quat &operator+=(zpl_quat &a, zpl_quat b) { zpl_quat_addeq(&a, b); return a; } - ZPL_INLINE zpl_quat &operator-=(zpl_quat &a, zpl_quat b) { zpl_quat_subeq(&a, b); return a; } - ZPL_INLINE zpl_quat &operator*=(zpl_quat &a, zpl_quat b) { zpl_quat_muleq(&a, b); return a; } - ZPL_INLINE zpl_quat &operator/=(zpl_quat &a, zpl_quat b) { zpl_quat_diveq(&a, b); return a; } - - ZPL_INLINE zpl_quat &operator*=(zpl_quat &a, float b) { zpl_quat_muleqf(&a, b); return a; } - ZPL_INLINE zpl_quat &operator/=(zpl_quat &a, float b) { zpl_quat_diveqf(&a, b); return a; } - - /* Rotate v by a */ - ZPL_INLINE zpl_vec3 operator*(zpl_quat q, zpl_vec3 v) { zpl_vec3 r; zpl_quat_rotate_vec3(&r, q, v); return r; } - #endif - #endif - - #if defined(ZPL_MODULE_JSON) - // file: header/json.h - - /** @file json.c - @brief JSON5 Parser/Writer - @defgroup json JSON5 parser/writer - - Easy to use and very fast JSON5 parser that can easily load 50 megabytes of JSON content under half a second. It also contains simple JSON5 writer and acts as a good library for handling config files. The parser also supports the **Simplified JSON (SJSON)** format. - - We can parse JSON5 files in two different modes: - @n 1) Fast way (useful for raw data), which can not handle comments and might cause parsing failure if comment is present. - @n 2) Slower way (useful for config files), which handles comments perfectly but **might** have performance impact - on bigger JSON files. (+50MiB) - @{ - */ - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - //! Debug mode - - #ifdef ZPL_JSON_DEBUG - #define ZPL_JSON_ASSERT ZPL_ASSERT(0) - #else - #define ZPL_JSON_ASSERT - #endif - - //! JSON object types - typedef enum zpl_json_type { - ZPL_JSON_TYPE_OBJECT, - ZPL_JSON_TYPE_STRING, - ZPL_JSON_TYPE_MULTISTRING, - ZPL_JSON_TYPE_ARRAY, - ZPL_JSON_TYPE_INTEGER, - ZPL_JSON_TYPE_REAL, - ZPL_JSON_TYPE_CONSTANT - } zpl_json_type; - - //! Field value properties - typedef enum zpl_json_props { - ZPL_JSON_PROPS_NONE = 0, - ZPL_JSON_PROPS_NAN = 1, - ZPL_JSON_PROPS_NAN_NEG = 2, - ZPL_JSON_PROPS_INFINITY = 3, - ZPL_JSON_PROPS_INFINITY_NEG = 4, - ZPL_JSON_PROPS_IS_EXP = 5, - ZPL_JSON_PROPS_IS_HEX = 6, - - // Used internally so that people can fill in real numbers for JSON files they plan to write. - ZPL_JSON_PROPS_IS_PARSED_REAL = 7, - } zpl_json_props; - - //! Value constants - typedef enum zpl_json_const { - ZPL_JSON_CONST_FALSE, - ZPL_JSON_CONST_TRUE, - ZPL_JSON_CONST_NULL, - } zpl_json_const; - - // TODO(ZaKlaus): Error handling - //! Parser error types - typedef enum zpl_json_error { - ZPL_JSON_ERROR_NONE, - ZPL_JSON_ERROR_INVALID_NAME, - ZPL_JSON_ERROR_INVALID_VALUE, - ZPL_JSON_ERROR_OBJECT_OR_SOURCE_WAS_NULL, - } zpl_json_error; - - //! Field name decoration style - typedef enum zpl_json_naming_style { - ZPL_JSON_NAME_STYLE_DOUBLE_QUOTE, - ZPL_JSON_NAME_STYLE_SINGLE_QUOTE, - ZPL_JSON_NAME_STYLE_NO_QUOTES, - } zpl_json_naming_style; - - //! Field value assign style - typedef enum zpl_json_assign_style { - ZPL_JSON_ASSIGN_STYLE_COLON, - ZPL_JSON_ASSIGN_STYLE_EQUALS, - ZPL_JSON_ASSIGN_STYLE_LINE, - } zpl_json_assign_style; - - //! Field delimiter style - typedef enum zpl_json_delim_style { - ZPL_JSON_DELIM_STYLE_COMMA, - ZPL_JSON_DELIM_STYLE_LINE, - ZPL_JSON_DELIM_STYLE_NEWLINE, - } zpl_json_delim_style; - - #define zpl_json_object zpl_json_object - - //! JSON object definition. - typedef struct zpl_json_object { - zpl_allocator backing; - char *name; - zpl_u8 type :6; - zpl_u8 name_style :2; - zpl_u8 props :7; - zpl_u8 cfg_mode :1; - zpl_u8 assign_style:4; - zpl_u8 delim_style :4; - zpl_u8 delim_line_width; - - union { - struct zpl_json_object *nodes; ///< zpl_array - zpl_i64 integer; - char *string; - - struct { - zpl_f64 real; - zpl_i32 base; - zpl_i32 base2; - zpl_i32 base2_offset; - zpl_i32 exp; - zpl_u8 exp_neg :1; - zpl_u8 lead_digit:1; - }; - zpl_u8 constant; - }; - } zpl_json_object; - - //! Parses JSON5/SJSON text. - - //! This method takes text form of JSON document as a source and parses its contents into JSON object structure we can work with. It also optionally handles comments that usually appear in documents used for configuration. - //! @param root JSON object we store data to. - //! @param len Text length. (reserved) - //! @param source Text to be processed. This string will be modified during the process! - //! @param allocator Memory allocator to use. (ex. zpl_heap()) - //! @param handle_comments Whether to handle possible comments or not. Note that if we won't handle comments in a document containing them, the parser will error out. See remark in source code. - //! @param err_code Variable we will store error code in. - ZPL_DEF void zpl_json_parse(zpl_json_object *root, zpl_usize len, char *source, zpl_allocator allocator, zpl_b32 handle_comments, - zpl_u8 *err_code); - - //! Exports JSON5 document into text form and outputs it into a file. - - //! This method takes JSON object tree and exports it into valid JSON5 form with the support of various styles that were preserved during import or set up programatically. - //! @param file File we write text to. - //! @param obj JSON object we export data from. - //! @param indent Text indentation used during export. Use 0 for root objects. - ZPL_DEF void zpl_json_write(zpl_file *file, zpl_json_object *obj, zpl_isize indent); - - //! Exports JSON5 document into text form and returns a zpl_string - - //! This method takes JSON object tree and exports it into valid JSON5 form with the support of various styles that were preserved during import or set up programatically. - //! @param obj JSON object we export data from. - //! @param indent Text indentation used during export. Use 0 for root objects. - //! @return zpl_string - ZPL_DEF zpl_string zpl_json_write_string(zpl_allocator a, zpl_json_object *obj, zpl_isize indent); - - //! Releases used resources by a JSON object. - - //! @param obj JSON object to free. - ZPL_DEF void zpl_json_free(zpl_json_object *obj); - - //! Searches for a JSON node within a document by its name. - - //! @param obj JSON object to search in. - //! @param name JSON node's name to search for. - //! @param deep_search Perform the search recursively. - ZPL_DEF zpl_json_object *zpl_json_find(zpl_json_object *obj, char const *name, zpl_b32 deep_search); - - //! Initializes a JSON node. - - //! @param obj JSON node to initialize. - //! @param backing Memory allocator to use (ex. zpl_heap()) - //! @param name JSON node's name. - //! @param type JSON node's type. (See zpl_json_type) - //! @see zpl_json_type - ZPL_DEF void zpl_json_init_node(zpl_json_object *obj, zpl_allocator backing, char const *name, zpl_u8 type); - - //! Adds object into JSON document at a specific index. - - //! Initializes and adds a JSON object into a JSON document at a specific index. - //! @param obj Root node to add to. - //! @param index Index to store at. - //! @param name JSON node's name. - //! @param type JSON node's type. (See zpl_json_type) - //! @see zpl_json_type - ZPL_DEF zpl_json_object *zpl_json_add_at(zpl_json_object *obj, zpl_isize index, char const *name, zpl_u8 type); - - //! Appends object into JSON document. - - //! Initializes and appends a JSON object into a JSON document. - //! @param obj Root node to add to. - //! @param name JSON node's name. - //! @param type JSON node's type. (See zpl_json_type) - //! @see zpl_json_type - ZPL_DEF zpl_json_object *zpl_json_add(zpl_json_object *obj, char const *name, zpl_u8 type); - - //! @} - - ZPL_END_C_DECLS - #endif - - #if defined(ZPL_MODULE_THREADING) - #if defined(ZPL_SYSTEM_UNIX) || defined(ZPL_SYSTEM_MACOS) - #include - #endif - - #if defined(ZPL_SYSTEM_WINDOWS) - #if !defined(ZPL_NO_WINDOWS_H) - #ifndef WIN32_LEAN_AND_MEAN - #define NOMINMAX - #define WIN32_LEAN_AND_MEAN - #define WIN32_MEAN_AND_LEAN - #define VC_EXTRALEAN - #endif - #include - #undef NOMINMAX - #undef WIN32_LEAN_AND_MEAN - #undef WIN32_MEAN_AND_LEAN - #undef VC_EXTRALEAN - - /* prevent it from including later */ - #define ZPL_NO_WINDOWS_H - #endif - - // include errno.h for MinGW - #if defined(ZPL_COMPILER_GCC) - #include - #endif - #endif - - #if !defined(zpl_thread_local) - #if defined(_MSC_VER) && _MSC_VER >= 1300 - #define zpl_thread_local __declspec(thread) - #elif defined(__GNUC__) - #define zpl_thread_local __thread - #else - #define zpl_thread_local thread_local - #endif - #endif - - // file: header/threading/atomic.h - - // Atomics - #ifdef ZPL_EDITOR - #include - #endif - - // TODO: Be specific with memory order? - // e.g. relaxed, acquire, release, acquire_release - - #if !defined(__STDC_NO_ATOMICS__) && !defined(__cplusplus) && !defined(ZPL_COMPILER_MSVC) - # include - # define zpl_atomic(X) volatile _Atomic(X) - #else - // TODO: Fix once C++ guys bother to add C atomics to std. - //# include - # define zpl_atomic(X) volatile X /*std::atomic*/ - #endif - - #define zpl_atomicarg(X) volatile X - - ZPL_BEGIN_C_DECLS - - #if defined(ZPL_COMPILER_MSVC) - typedef struct zpl_atomic32 { zpl_atomic(zpl_i32) value; } zpl_atomic32; - typedef struct zpl_atomic64 { zpl_atomic(zpl_i64) value; } zpl_atomic64; - typedef struct zpl_atomic_ptr { zpl_atomic(void*) value; } zpl_atomic_ptr; - #else - #if defined(ZPL_ARCH_32_BIT) - #define ZPL_ATOMIC_PTR_ALIGNMENT 4 - #elif defined(ZPL_ARCH_64_BIT) - #define ZPL_ATOMIC_PTR_ALIGNMENT 8 - #else - #error Unknown architecture - #endif - - typedef struct zpl_atomic32 { zpl_atomic(zpl_i32) value; } __attribute__ ((aligned(4))) zpl_atomic32; - typedef struct zpl_atomic64 { zpl_atomic(zpl_i64) value; } __attribute__ ((aligned(8))) zpl_atomic64; - typedef struct zpl_atomic_ptr { zpl_atomic(void*) value; } __attribute__ ((aligned(ZPL_ATOMIC_PTR_ALIGNMENT))) zpl_atomic_ptr; - #endif - - ZPL_DEF zpl_i32 zpl_atomic32_load (zpl_atomic32 const *a); - ZPL_DEF void zpl_atomic32_store (zpl_atomic32 *a, zpl_atomicarg(zpl_i32) value); - ZPL_DEF zpl_i32 zpl_atomic32_compare_exchange(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) expected, zpl_atomicarg(zpl_i32) desired); - ZPL_DEF zpl_i32 zpl_atomic32_exchange (zpl_atomic32 *a, zpl_atomicarg(zpl_i32) desired); - ZPL_DEF zpl_i32 zpl_atomic32_fetch_add (zpl_atomic32 *a, zpl_atomicarg(zpl_i32) operand); - ZPL_DEF zpl_i32 zpl_atomic32_fetch_and (zpl_atomic32 *a, zpl_atomicarg(zpl_i32) operand); - ZPL_DEF zpl_i32 zpl_atomic32_fetch_or (zpl_atomic32 *a, zpl_atomicarg(zpl_i32) operand); - ZPL_DEF zpl_b32 zpl_atomic32_spin_lock (zpl_atomic32 *a, zpl_isize time_out); // NOTE: time_out = -1 as default - ZPL_DEF void zpl_atomic32_spin_unlock (zpl_atomic32 *a); - ZPL_DEF zpl_b32 zpl_atomic32_try_acquire_lock(zpl_atomic32 *a); - - - ZPL_DEF zpl_i64 zpl_atomic64_load (zpl_atomic64 const *a); - ZPL_DEF void zpl_atomic64_store (zpl_atomic64 *a, zpl_atomicarg(zpl_i64) value); - ZPL_DEF zpl_i64 zpl_atomic64_compare_exchange(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) expected, zpl_atomicarg(zpl_i64) desired); - ZPL_DEF zpl_i64 zpl_atomic64_exchange (zpl_atomic64 *a, zpl_atomicarg(zpl_i64) desired); - ZPL_DEF zpl_i64 zpl_atomic64_fetch_add (zpl_atomic64 *a, zpl_atomicarg(zpl_i64) operand); - ZPL_DEF zpl_i64 zpl_atomic64_fetch_and (zpl_atomic64 *a, zpl_atomicarg(zpl_i64) operand); - ZPL_DEF zpl_i64 zpl_atomic64_fetch_or (zpl_atomic64 *a, zpl_atomicarg(zpl_i64) operand); - ZPL_DEF zpl_b32 zpl_atomic64_spin_lock (zpl_atomic64 *a, zpl_isize time_out); // NOTE: time_out = -1 as default - ZPL_DEF void zpl_atomic64_spin_unlock (zpl_atomic64 *a); - ZPL_DEF zpl_b32 zpl_atomic64_try_acquire_lock(zpl_atomic64 *a); - - - ZPL_DEF void *zpl_atomic_ptr_load (zpl_atomic_ptr const *a); - ZPL_DEF void zpl_atomic_ptr_store (zpl_atomic_ptr *a, zpl_atomicarg(void *)value); - ZPL_DEF void *zpl_atomic_ptr_compare_exchange(zpl_atomic_ptr *a, zpl_atomicarg(void *)expected, zpl_atomicarg(void *)desired); - ZPL_DEF void *zpl_atomic_ptr_exchange (zpl_atomic_ptr *a, zpl_atomicarg(void *)desired); - ZPL_DEF void *zpl_atomic_ptr_fetch_add (zpl_atomic_ptr *a, zpl_atomicarg(void *)operand); - ZPL_DEF void *zpl_atomic_ptr_fetch_and (zpl_atomic_ptr *a, zpl_atomicarg(void *)operand); - ZPL_DEF void *zpl_atomic_ptr_fetch_or (zpl_atomic_ptr *a, zpl_atomicarg(void *)operand); - ZPL_DEF zpl_b32 zpl_atomic_ptr_spin_lock (zpl_atomic_ptr *a, zpl_isize time_out); // NOTE: time_out = -1 as default - ZPL_DEF void zpl_atomic_ptr_spin_unlock (zpl_atomic_ptr *a); - ZPL_DEF zpl_b32 zpl_atomic_ptr_try_acquire_lock(zpl_atomic_ptr *a); - - ZPL_END_C_DECLS - // file: header/threading/fence.h - - // Fences - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - ZPL_DEF void zpl_yield_thread(void); - ZPL_DEF void zpl_mfence (void); - ZPL_DEF void zpl_sfence (void); - ZPL_DEF void zpl_lfence (void); - - ZPL_END_C_DECLS - // file: header/threading/sem.h - - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - #if defined(ZPL_SYSTEM_MACOS) - #include - #elif defined(ZPL_SYSTEM_UNIX) - #include - #endif - - #if defined(ZPL_SYSTEM_WINDOWS) - typedef struct zpl_semaphore { void *win32_handle; } zpl_semaphore; - #elif defined(ZPL_SYSTEM_MACOS) - typedef struct zpl_semaphore { semaphore_t osx_handle; } zpl_semaphore; - #elif defined(ZPL_SYSTEM_UNIX) - typedef struct zpl_semaphore { sem_t unix_handle; } zpl_semaphore; - #else - #error - #endif - - ZPL_DEF void zpl_semaphore_init (zpl_semaphore *s); - ZPL_DEF void zpl_semaphore_destroy(zpl_semaphore *s); - ZPL_DEF void zpl_semaphore_post (zpl_semaphore *s, zpl_i32 count); - ZPL_DEF void zpl_semaphore_release(zpl_semaphore *s); // NOTE: zpl_semaphore_post(s, 1) - ZPL_DEF void zpl_semaphore_wait (zpl_semaphore *s); - - ZPL_END_C_DECLS - // file: header/threading/mutex.h - - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - typedef struct zpl_mutex { - #if defined(ZPL_SYSTEM_WINDOWS) - CRITICAL_SECTION win32_critical_section; - #else - pthread_mutex_t pthread_mutex; - #endif - } zpl_mutex; - - ZPL_DEF void zpl_mutex_init (zpl_mutex *m); - ZPL_DEF void zpl_mutex_destroy (zpl_mutex *m); - ZPL_DEF void zpl_mutex_lock (zpl_mutex *m); - ZPL_DEF zpl_b32 zpl_mutex_try_lock(zpl_mutex *m); - ZPL_DEF void zpl_mutex_unlock (zpl_mutex *m); - - ZPL_END_C_DECLS - // file: header/threading/thread.h - - #ifdef ZPL_EDITOR - #include - #else - struct zpl_thread; - #endif - - ZPL_BEGIN_C_DECLS - - typedef zpl_isize (*zpl_thread_proc)(struct zpl_thread *thread); - - typedef struct zpl_thread { - #if defined(ZPL_SYSTEM_WINDOWS) - void * win32_handle; - #else - pthread_t posix_handle; - #endif - - zpl_thread_proc proc; - void * user_data; - zpl_isize user_index; - zpl_isize return_value; - - zpl_semaphore semaphore; - zpl_isize stack_size; - zpl_b32 is_running; - } zpl_thread; - - ZPL_DEF void zpl_thread_init (zpl_thread *t); - ZPL_DEF void zpl_thread_destroy (zpl_thread *t); - ZPL_DEF void zpl_thread_start (zpl_thread *t, zpl_thread_proc proc, void *data); - ZPL_DEF void zpl_thread_start_with_stack(zpl_thread *t, zpl_thread_proc proc, void *data, zpl_isize stack_size); - ZPL_DEF void zpl_thread_join (zpl_thread *t); - ZPL_DEF zpl_b32 zpl_thread_is_running (zpl_thread const *t); - ZPL_DEF zpl_u32 zpl_thread_current_id (void); - ZPL_DEF void zpl_thread_set_name (zpl_thread *t, char const *name); - - ZPL_END_C_DECLS - // file: header/threading/sync.h - - // NOTE: Thread Merge Operation - // Based on Sean Barrett's stb_sync - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - typedef struct zpl_sync { - zpl_i32 target; // Target Number of threads - zpl_i32 current; // Threads to hit - zpl_i32 waiting; // Threads waiting - - zpl_mutex start; - zpl_mutex mutex; - zpl_semaphore release; - } zpl_sync; - - ZPL_DEF void zpl_sync_init (zpl_sync *s); - ZPL_DEF void zpl_sync_destroy (zpl_sync *s); - ZPL_DEF void zpl_sync_set_target (zpl_sync *s, zpl_i32 count); - ZPL_DEF void zpl_sync_release (zpl_sync *s); - ZPL_DEF zpl_i32 zpl_sync_reach (zpl_sync *s); - ZPL_DEF void zpl_sync_reach_and_wait(zpl_sync *s); - - ZPL_END_C_DECLS - // file: header/threading/affinity.h - - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - #if defined(ZPL_SYSTEM_WINDOWS) || defined (ZPL_SYSTEM_CYGWIN) - - typedef struct zpl_affinity { - zpl_b32 is_accurate; - zpl_isize core_count; - zpl_isize thread_count; - - #define ZPL_WIN32_MAX_THREADS (8 * zpl_size_of(zpl_usize)) - zpl_usize core_masks[ZPL_WIN32_MAX_THREADS]; - } zpl_affinity; - - #elif defined(ZPL_SYSTEM_OSX) - - typedef struct zpl_affinity { - zpl_b32 is_accurate; - zpl_isize core_count; - zpl_isize thread_count; - zpl_isize threads_per_core; - } zpl_affinity; - - #elif defined(ZPL_SYSTEM_LINUX) || defined(ZPL_SYSTEM_FREEBSD) || defined(ZPL_SYSTEM_EMSCRIPTEN) || defined(ZPL_SYSTEM_OPENBSD) - - typedef struct zpl_affinity { - zpl_b32 is_accurate; - zpl_isize core_count; - zpl_isize thread_count; - zpl_isize threads_per_core; - } zpl_affinity; - - #else - #error TODO: Unknown system - #endif - - ZPL_DEF void zpl_affinity_init (zpl_affinity *a); - ZPL_DEF void zpl_affinity_destroy(zpl_affinity *a); - ZPL_DEF zpl_b32 zpl_affinity_set (zpl_affinity *a, zpl_isize core, zpl_isize thread); - ZPL_DEF zpl_isize zpl_affinity_thread_count_for_core(zpl_affinity *a, zpl_isize core); - - ZPL_END_C_DECLS - - #if defined(ZPL_MODULE_JOBS) - // file: header/jobs.h - - /** @file threadpool.c - @brief Job system - @defgroup jobs Job system - - This job system follows thread pool pattern to minimize the costs of thread initialization. - It reuses fixed number of threads to process variable number of jobs. - - @{ - */ - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - typedef void (*zpl_jobs_proc)(void *data); - - #define ZPL_INVALID_JOB ZPL_U32_MAX - - typedef enum { - ZPL_JOBS_STATUS_READY, - ZPL_JOBS_STATUS_BUSY, - ZPL_JOBS_STATUS_WAITING, - ZPL_JOBS_STATUS_TERM, - } zpl_jobs_status; - - typedef struct { - zpl_jobs_proc proc; - void *data; - - zpl_f32 priority; - } zpl_thread_job; - - typedef struct { - zpl_thread thread; - zpl_atomic32 status; - zpl_u32 jobid; - void *pool; - } zpl_thread_worker; - - typedef struct { - zpl_allocator alloc; - zpl_u32 max_threads; - zpl_f32 job_spawn_treshold; - zpl_mutex access; - zpl_thread_worker *workers; ///< zpl_buffer - zpl_thread_job *jobs; ///< zpl_array - zpl_u32 *queue; ///< zpl_array - zpl_u32 *available; ///< zpl_array - } zpl_thread_pool; - - //! Initialize thread pool with specified amount of fixed threads. - ZPL_DEF void zpl_jobs_init(zpl_thread_pool *pool, zpl_allocator a, zpl_u32 max_threads); - - //! Release the resources use by thread pool. - ZPL_DEF void zpl_jobs_free(zpl_thread_pool *pool); - - //! Enqueue a job with specified data. - ZPL_DEF void zpl_jobs_enqueue(zpl_thread_pool *pool, zpl_jobs_proc proc, void *data); - - //! Enqueue a job with specific priority with specified data. - ZPL_DEF void zpl_jobs_enqueue_with_priority(zpl_thread_pool *pool, zpl_jobs_proc proc, void *data, zpl_f32 priority); - - //! Process all jobs and check all threads. Should be called by Main Thread in a tight loop. - ZPL_DEF zpl_b32 zpl_jobs_process(zpl_thread_pool *pool); - - ZPL_END_C_DECLS - #endif - - #if defined(ZPL_MODULE_COROUTINES) - // file: header/coroutines.h - - /** @file coroutines.c - @brief Coroutines module - @defgroup misc Coroutines module - - This module implements co-routines feature for C99. - - @{ - */ - /* - See test/coroutines.c for an example usage - */ - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - #ifndef ZPL_CO_ARG_STACK_CAPACITY - #define ZPL_CO_ARG_STACK_CAPACITY 128 - #endif - - typedef enum { - ZPL_CO_READY, - ZPL_CO_ENQUEUED, - ZPL_CO_RUNNING, - ZPL_CO_WAITING, - ZPL_CO_DEAD, - } zpl_co_status; - - struct zpl_co; - - typedef void (*zpl_co_proc)(struct zpl_co *co); - - typedef struct zpl_co { - zpl_atomic32 status; - zpl_co_proc f; - void *data; // overwritten internally, use inside of co-routines - void *data_stack[ZPL_CO_ARG_STACK_CAPACITY]; - zpl_i32 data_read_idx, data_write_idx; - zpl_atomic32 resume, push_arg; - } zpl_co; - - // These methods are used to initialize the co-routine subsystem - - /** - * Initializes the coroutines subsystem - * @param a Memory allocator to be used - * @param max_threads Maximum amount of threads to use for coroutines execution - */ - ZPL_DEF void zpl_co_init(zpl_allocator a, zpl_u32 max_threads); - - /** - * Destroys the coroutines subsystem - * - * IMPORTANT: This is a blocking method that waits until all the coroutines are finished. - * Please, make sure your coroutines are correctly designed, so that you - * won't end up in an infinite loop. - */ - ZPL_DEF void zpl_co_destroy(void); - - // These methods are used by the host to create and run/resume co-routines - // Make sure the co-routine subsystem is initialized first! - - /** - * Create a paused coroutine - * @param co Coroutine reference - * @param f Coroutine method - */ - ZPL_DEF void zpl_co_make(zpl_co *co, zpl_co_proc f); - - /** - * Starts/Resumes a coroutine execution. - * - * IMPORTANT: Data you pass is stored in a stack of up to ZPL_CO_ARG_STACK_CAPACITY. - * This means that you can cause stack corruption if you - * call 'zpl_co_resume' with data passed (ZPL_CO_ARG_STACK_CAPACITY+1) times. - * Raise the number by defining ZPL_CO_ARG_STACK_CAPACITY if required. - * - * @param co Coroutine - * @param data Data we want to pass (or NULL) - */ - ZPL_DEF void zpl_co_resume(zpl_co *co, void *data); - - /** - * Is a coroutine running at the moment? - * @param co Coroutine - * @return - */ - ZPL_DEF_INLINE zpl_b32 zpl_co_running(zpl_co *co); - - /** - * Is a coroutine already finished? - * @param co Coroutine - * @return - */ - ZPL_DEF_INLINE zpl_b32 zpl_co_finished(zpl_co *co); - - /** - * Is coroutine waiting? (in yield state) - * @param co Coroutine - * @return - */ - ZPL_DEF_INLINE zpl_b32 zpl_co_waiting(zpl_co *co); - - // This method is used by the co-routine to await execution - // - - /** - * Yield the coroutine. - * - * IMPORTANT: Only to be used by the coroutine!! - * @param co Coroutine - */ - ZPL_DEF void zpl_co_yield(zpl_co *co); - - //! @} - - ZPL_IMPL_INLINE zpl_b32 zpl_co_running(zpl_co *co) { - return zpl_atomic32_load(&co->status) == ZPL_CO_RUNNING; - } - - ZPL_IMPL_INLINE zpl_b32 zpl_co_finished(zpl_co *co) { - return zpl_atomic32_load(&co->status) == ZPL_CO_DEAD; - } - - ZPL_IMPL_INLINE zpl_b32 zpl_co_waiting(zpl_co *co) { - return zpl_atomic32_load(&co->resume) == 0; - } - - ZPL_END_C_DECLS - #endif - #endif - - #if defined(ZPL_COMPILER_MSVC) - #pragma warning(pop) - #endif - - #if defined(__GCC__) || defined(__GNUC__) || defined(__clang__) - #pragma GCC diagnostic pop - #endif - - #if defined(ZPL_IMPLEMENTATION) && !defined(ZPL_IMPLEMENTATION_DONE) - #define ZPL_IMPLEMENTATION_DONE - - #if defined(__GCC__) || defined(__GNUC__) || defined(__clang__) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wattributes" - #pragma GCC diagnostic ignored "-Wunused-value" - #pragma GCC diagnostic ignored "-Wunused-function" - #pragma GCC diagnostic ignored "-Wwrite-strings" - #pragma GCC diagnostic ignored "-Wunused-parameter" - #pragma GCC diagnostic ignored "-Wdeprecated-declarations" - #pragma GCC diagnostic ignored "-Wmissing-braces" - #pragma GCC diagnostic ignored "-Wmissing-field-initializers" - #pragma GCC diagnostic ignored "-Wimplicit-fallthrough" - #pragma GCC diagnostic ignored "-Wignored-qualifiers" - #endif - - #if defined(_MSC_VER) - #pragma warning(push) - #pragma warning(disable : 4201) - #pragma warning(disable : 4996) // Disable deprecated POSIX functions warning - #pragma warning(disable : 4127) // Conditional expression is constant - #endif - - /* general purpose includes */ - - #include - - #if defined(ZPL_SYSTEM_UNIX) || defined(ZPL_SYSTEM_MACOS) - #include - #include - #elif defined(ZPL_SYSTEM_WINDOWS) - #if !defined(ZPL_NO_WINDOWS_H) - #ifndef WIN32_LEAN_AND_MEAN - #ifndef NOMINMAX - #define NOMINMAX - #endif - - #define WIN32_LEAN_AND_MEAN - #define WIN32_MEAN_AND_LEAN - #define VC_EXTRALEAN - #endif - #include - #undef NOMINMAX - #undef WIN32_LEAN_AND_MEAN - #undef WIN32_MEAN_AND_LEAN - #undef VC_EXTRALEAN - #endif - #endif - - #if defined(ZPL_MODULE_CORE) - // file: source/core/debug.c - - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - void zpl_assert_handler(char const *condition, char const *file, zpl_i32 line, char const *msg, ...) { - zpl_printf_err("%s:(%d): Assert Failure: ", file, line); - - if (condition) zpl_printf_err("`%s` ", condition); - - if (msg) { - va_list va; - va_start(va, msg); - zpl_printf_err_va(msg, va); - va_end(va); - } - - zpl_printf_err("\n"); - } - - zpl_i32 zpl_assert_crash(char const *condition) { - ZPL_PANIC(condition); - return 0; - } - - ZPL_END_C_DECLS - // file: source/core/memory.c - - #ifdef ZPL_EDITOR - #include - #endif - - #include - - ZPL_BEGIN_C_DECLS - - - void zpl_memswap(void *i, void *j, zpl_isize size) { - if (i == j) return; - - if (size == 4) { - zpl_swap(zpl_u32, *cast(zpl_u32 *) i, *cast(zpl_u32 *) j); - } else if (size == 8) { - zpl_swap(zpl_u64, *cast(zpl_u64 *) i, *cast(zpl_u64 *) j); - } else if (size < 8) { - zpl_u8 *a = cast(zpl_u8 *) i; - zpl_u8 *b = cast(zpl_u8 *) j; - if (a != b) { - while (size--) { zpl_swap(zpl_u8, *a++, *b++); } - } - } else { - char buffer[256]; - - while (size > zpl_size_of(buffer)) { - zpl_memswap(i, j, zpl_size_of(buffer)); - i = zpl_pointer_add(i, zpl_size_of(buffer)); - j = zpl_pointer_add(j, zpl_size_of(buffer)); - size -= zpl_size_of(buffer); - } - - zpl_memcopy(buffer, i, size); - zpl_memcopy(i, j, size); - zpl_memcopy(j, buffer, size); - } - } - - void const *zpl_memchr(void const *data, zpl_u8 c, zpl_isize n) { - zpl_u8 const *s = cast(zpl_u8 const *) data; - while ((cast(zpl_uintptr) s & (sizeof(zpl_usize) - 1)) && n && *s != c) { - s++; - n--; - } - if (n && *s != c) { - zpl_isize const *w; - zpl_isize k = ZPL__ONES * c; - w = cast(zpl_isize const *) s; - while (n >= zpl_size_of(zpl_isize) && !ZPL__HAS_ZERO(*w ^ k)) { - w++; - n -= zpl_size_of(zpl_isize); - } - s = cast(zpl_u8 const *) w; - while (n && *s != c) { - s++; - n--; - } - } - - return n ? cast(void const *) s : NULL; - } - - void const *zpl_memrchr(void const *data, zpl_u8 c, zpl_isize n) { - zpl_u8 const *s = cast(zpl_u8 const *) data; - while (n--) { - if (s[n] == c) return cast(void const *)(s + n); - } - return NULL; - } - - void *zpl_memcopy(void *dest, void const *source, zpl_isize n) { - if (dest == NULL) { return NULL; } - - return memcpy(dest, source, n); - - // TODO: Re-work the whole method - #if 0 - #if defined(_MSC_VER) - __movsb(cast(zpl_u8 *) dest, cast(zpl_u8 *) source, n); - #elif defined(ZPL_CPU_X86) && !defined(ZPL_SYSTEM_EMSCRIPTEN) - zpl_u8 *__dest8 = cast(zpl_u8 *) dest; - zpl_u8 *__source8 = cast(zpl_u8 *) source; - __asm__ __volatile__("rep movsb" : "+D"(__dest8), "+S"(__source8), "+c"(n) : : "memory"); - #elif defined(ZPL_CPU_ARM) - return memcpy(dest, source, n); - #else - zpl_u8 *d = cast(zpl_u8 *) dest; - zpl_u8 const *s = cast(zpl_u8 const *) source; - zpl_u32 w, x; - - for (; cast(zpl_uintptr) s % 4 && n; n--) *d++ = *s++; - - if (cast(zpl_uintptr) d % 4 == 0) { - for (; n >= 16; s += 16, d += 16, n -= 16) { - *cast(zpl_u32 *)(d + 0) = *cast(zpl_u32 *)(s + 0); - *cast(zpl_u32 *)(d + 4) = *cast(zpl_u32 *)(s + 4); - *cast(zpl_u32 *)(d + 8) = *cast(zpl_u32 *)(s + 8); - *cast(zpl_u32 *)(d + 12) = *cast(zpl_u32 *)(s + 12); - } - if (n & 8) { - *cast(zpl_u32 *)(d + 0) = *cast(zpl_u32 *)(s + 0); - *cast(zpl_u32 *)(d + 4) = *cast(zpl_u32 *)(s + 4); - d += 8; - s += 8; - } - if (n & 4) { - *cast(zpl_u32 *)(d + 0) = *cast(zpl_u32 *)(s + 0); - d += 4; - s += 4; - } - if (n & 2) { - *d++ = *s++; - *d++ = *s++; - } - if (n & 1) { *d = *s; } - return dest; - } - - if (n >= 32) { - #if __BYTE_ORDER == __BIG_ENDIAN - #define LS << - #define RS >> - #else - #define LS >> - #define RS << - #endif - switch (cast(zpl_uintptr) d % 4) { - case 1: { - w = *cast(zpl_u32 *) s; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - n -= 3; - while (n > 16) { - x = *cast(zpl_u32 *)(s + 1); - *cast(zpl_u32 *)(d + 0) = (w LS 24) | (x RS 8); - w = *cast(zpl_u32 *)(s + 5); - *cast(zpl_u32 *)(d + 4) = (x LS 24) | (w RS 8); - x = *cast(zpl_u32 *)(s + 9); - *cast(zpl_u32 *)(d + 8) = (w LS 24) | (x RS 8); - w = *cast(zpl_u32 *)(s + 13); - *cast(zpl_u32 *)(d + 12) = (x LS 24) | (w RS 8); - - s += 16; - d += 16; - n -= 16; - } - } break; - case 2: { - w = *cast(zpl_u32 *) s; - *d++ = *s++; - *d++ = *s++; - n -= 2; - while (n > 17) { - x = *cast(zpl_u32 *)(s + 2); - *cast(zpl_u32 *)(d + 0) = (w LS 16) | (x RS 16); - w = *cast(zpl_u32 *)(s + 6); - *cast(zpl_u32 *)(d + 4) = (x LS 16) | (w RS 16); - x = *cast(zpl_u32 *)(s + 10); - *cast(zpl_u32 *)(d + 8) = (w LS 16) | (x RS 16); - w = *cast(zpl_u32 *)(s + 14); - *cast(zpl_u32 *)(d + 12) = (x LS 16) | (w RS 16); - - s += 16; - d += 16; - n -= 16; - } - } break; - case 3: { - w = *cast(zpl_u32 *) s; - *d++ = *s++; - n -= 1; - while (n > 18) { - x = *cast(zpl_u32 *)(s + 3); - *cast(zpl_u32 *)(d + 0) = (w LS 8) | (x RS 24); - w = *cast(zpl_u32 *)(s + 7); - *cast(zpl_u32 *)(d + 4) = (x LS 8) | (w RS 24); - x = *cast(zpl_u32 *)(s + 11); - *cast(zpl_u32 *)(d + 8) = (w LS 8) | (x RS 24); - w = *cast(zpl_u32 *)(s + 15); - *cast(zpl_u32 *)(d + 12) = (x LS 8) | (w RS 24); - - s += 16; - d += 16; - n -= 16; - } - } break; - default: break; // NOTE: Do nowt! - } - #undef LS - #undef RS - if (n & 16) { - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - } - if (n & 8) { - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - } - if (n & 4) { - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - } - if (n & 2) { - *d++ = *s++; - *d++ = *s++; - } - if (n & 1) { *d = *s; } - } - - #endif - #endif - - return dest; - } - - ZPL_END_C_DECLS - // file: source/core/memory_virtual.c - - //////////////////////////////////////////////////////////////// - // - // Virtual Memory - // - // - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - zpl_virtual_memory zpl_vm(void *data, zpl_isize size) { - zpl_virtual_memory vm; - vm.data = data; - vm.size = size; - return vm; - } - - #if defined(ZPL_SYSTEM_WINDOWS) - zpl_virtual_memory zpl_vm_alloc(void *addr, zpl_isize size) { - zpl_virtual_memory vm; - ZPL_ASSERT(size > 0); - vm.data = VirtualAlloc(addr, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); - vm.size = size; - return vm; - } - - zpl_b32 zpl_vm_free(zpl_virtual_memory vm) { - MEMORY_BASIC_INFORMATION info; - while (vm.size > 0) { - if (VirtualQuery(vm.data, &info, zpl_size_of(info)) == 0) return false; - if (info.BaseAddress != vm.data || info.AllocationBase != vm.data || info.State != MEM_COMMIT || - info.RegionSize > cast(zpl_usize) vm.size) { - return false; - } - if (VirtualFree(vm.data, 0, MEM_RELEASE) == 0) return false; - vm.data = zpl_pointer_add(vm.data, info.RegionSize); - vm.size -= info.RegionSize; - } - return true; - } - - zpl_virtual_memory zpl_vm_trim(zpl_virtual_memory vm, zpl_isize lead_size, zpl_isize size) { - zpl_virtual_memory new_vm = { 0 }; - void *ptr; - ZPL_ASSERT(vm.size >= lead_size + size); - - ptr = zpl_pointer_add(vm.data, lead_size); - - zpl_vm_free(vm); - new_vm = zpl_vm_alloc(ptr, size); - if (new_vm.data == ptr) return new_vm; - if (new_vm.data) zpl_vm_free(new_vm); - return new_vm; - } - - zpl_b32 zpl_vm_purge(zpl_virtual_memory vm) { - VirtualAlloc(vm.data, vm.size, MEM_RESET, PAGE_READWRITE); - // NOTE: Can this really fail? - return true; - } - - zpl_isize zpl_virtual_memory_page_size(zpl_isize *alignment_out) { - SYSTEM_INFO info; - GetSystemInfo(&info); - if (alignment_out) *alignment_out = info.dwAllocationGranularity; - return info.dwPageSize; - } - - #else - #include - - #ifndef MAP_ANONYMOUS - #define MAP_ANONYMOUS MAP_ANON - #endif - - zpl_virtual_memory zpl_vm_alloc(void *addr, zpl_isize size) { - zpl_virtual_memory vm; - ZPL_ASSERT(size > 0); - vm.data = mmap(addr, size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); - vm.size = size; - return vm; - } - - zpl_b32 zpl_vm_free(zpl_virtual_memory vm) { - munmap(vm.data, vm.size); - return true; - } - - zpl_virtual_memory zpl_vm_trim(zpl_virtual_memory vm, zpl_isize lead_size, zpl_isize size) { - void *ptr; - zpl_isize trail_size; - ZPL_ASSERT(vm.size >= lead_size + size); - - ptr = zpl_pointer_add(vm.data, lead_size); - trail_size = vm.size - lead_size - size; - - if (lead_size != 0) zpl_vm_free(zpl_vm(vm.data, lead_size)); - if (trail_size != 0) zpl_vm_free(zpl_vm(ptr, trail_size)); - return zpl_vm(ptr, size); - } - - zpl_b32 zpl_vm_purge(zpl_virtual_memory vm) { - int err = madvise(vm.data, vm.size, MADV_DONTNEED); - return err != 0; - } - - zpl_isize zpl_virtual_memory_page_size(zpl_isize *alignment_out) { - // TODO: Is this always true? - zpl_isize result = cast(zpl_isize) sysconf(_SC_PAGE_SIZE); - if (alignment_out) *alignment_out = result; - return result; - } - - #endif - - ZPL_END_C_DECLS - // file: source/core/memory_custom.c - - #ifdef ZPL_EDITOR - #include - #endif - - #ifndef _IOSC11_SOURCE - #define _IOSC11_SOURCE - #endif - - #include - - #if defined(ZPL_SYSTEM_WINDOWS) - #include - #endif - - #if defined(ZPL_COMPILER_MINGW) - #ifdef __MINGW32__ - #define _aligned_malloc __mingw_aligned_malloc - #define _aligned_free __mingw_aligned_free - #endif //MINGW - #endif - - ZPL_BEGIN_C_DECLS - - char *zpl_alloc_str(zpl_allocator a, char const *str) { - return zpl_alloc_str_len(a, str, zpl_strlen(str)); - } - - //////////////////////////////////////////////////////////////// - // - // Custom Allocation - // - // - - // - // Heap Allocator - // - - ZPL_ALLOCATOR_PROC(zpl_heap_allocator_proc) { - void *ptr = NULL; - zpl_unused(allocator_data); - zpl_unused(old_size); - // TODO: Throughly test! - switch (type) { - #if defined(ZPL_COMPILER_MSVC) || (defined(ZPL_COMPILER_GCC) && defined(ZPL_SYSTEM_WINDOWS)) - case ZPL_ALLOCATION_ALLOC: - ptr = _aligned_malloc(size, alignment); - if (flags & ZPL_ALLOCATOR_FLAG_CLEAR_TO_ZERO) zpl_zero_size(ptr, size); - break; - case ZPL_ALLOCATION_FREE: _aligned_free(old_memory); break; - case ZPL_ALLOCATION_RESIZE: ptr = _aligned_realloc(old_memory, size, alignment); break; - - #elif defined(ZPL_SYSTEM_LINUX) && !defined(ZPL_CPU_ARM) - case ZPL_ALLOCATION_ALLOC: { - ptr = aligned_alloc(alignment, size); - - if (flags & ZPL_ALLOCATOR_FLAG_CLEAR_TO_ZERO) { zpl_zero_size(ptr, size); } - } break; - - case ZPL_ALLOCATION_FREE: { - free(old_memory); - } break; - - case ZPL_ALLOCATION_RESIZE: { - zpl_allocator a = zpl_heap_allocator( ); - ptr = zpl_default_resize_align(a, old_memory, old_size, size, alignment); - } break; - #else - case ZPL_ALLOCATION_ALLOC: { - posix_memalign(&ptr, alignment, size); - - if (flags & ZPL_ALLOCATOR_FLAG_CLEAR_TO_ZERO) { zpl_zero_size(ptr, size); } - } break; - - case ZPL_ALLOCATION_FREE: { - free(old_memory); - } break; - - case ZPL_ALLOCATION_RESIZE: { - zpl_allocator a = zpl_heap_allocator( ); - ptr = zpl_default_resize_align(a, old_memory, old_size, size, alignment); - } break; - #endif - - case ZPL_ALLOCATION_FREE_ALL: break; - } - - return ptr; - } - - // - // Arena Allocator - // - - ZPL_ALLOCATOR_PROC(zpl_arena_allocator_proc) { - zpl_arena *arena = cast(zpl_arena *) allocator_data; - void *ptr = NULL; - - zpl_unused(old_size); - - switch (type) { - case ZPL_ALLOCATION_ALLOC: { - void *end = zpl_pointer_add(arena->physical_start, arena->total_allocated); - zpl_isize total_size = size + alignment; - - // NOTE: Out of memory - if (arena->total_allocated + total_size > cast(zpl_isize) arena->total_size) { - zpl_printf_err("Arena out of memory\n"); - return NULL; - } - - ptr = zpl_align_forward(end, alignment); - arena->total_allocated += total_size; - if (flags & ZPL_ALLOCATOR_FLAG_CLEAR_TO_ZERO) zpl_zero_size(ptr, size); - } break; - - case ZPL_ALLOCATION_FREE: - // NOTE: Free all at once - // Use Temp_Arena_Memory if you want to free a block - break; - - case ZPL_ALLOCATION_FREE_ALL: arena->total_allocated = 0; break; - - case ZPL_ALLOCATION_RESIZE: { - // TODO: Check if ptr is on top of stack and just extend - zpl_allocator a = zpl_arena_allocator(arena); - ptr = zpl_default_resize_align(a, old_memory, old_size, size, alignment); - } break; - } - return ptr; - } - - // - // Pool Allocator - // - - void zpl_pool_init_align(zpl_pool *pool, zpl_allocator backing, zpl_isize num_blocks, zpl_isize block_size, zpl_isize block_align) { - zpl_isize actual_block_size, pool_size, block_index; - void *data, *curr; + + ptr = zpl_align_forward(end, alignment); + arena->total_allocated += total_size; + if (flags & ZPL_ALLOCATOR_FLAG_CLEAR_TO_ZERO) zpl_zero_size(ptr, size); + } break; + + case ZPL_ALLOCATION_FREE: + // NOTE: Free all at once + // Use Temp_Arena_Memory if you want to free a block + break; + + case ZPL_ALLOCATION_FREE_ALL: arena->total_allocated = 0; break; + + case ZPL_ALLOCATION_RESIZE: { + // TODO: Check if ptr is on top of stack and just extend + zpl_allocator a = zpl_arena_allocator(arena); + ptr = zpl_default_resize_align(a, old_memory, old_size, size, alignment); + } break; + } + return ptr; +} + +// +// Pool Allocator +// + +void zpl_pool_init_align(zpl_pool *pool, zpl_allocator backing, zpl_isize num_blocks, zpl_isize block_size, zpl_isize block_align) { + zpl_isize actual_block_size, pool_size, block_index; + void *data, *curr; + zpl_uintptr *end; + + zpl_zero_item(pool); + + pool->backing = backing; + pool->block_size = block_size; + pool->block_align = block_align; + pool->num_blocks = num_blocks; + + actual_block_size = block_size + block_align; + pool_size = num_blocks * actual_block_size; + + data = zpl_alloc_align(backing, pool_size, block_align); + + // NOTE: Init intrusive freelist + curr = data; + for (block_index = 0; block_index < num_blocks - 1; block_index++) { + zpl_uintptr *next = cast(zpl_uintptr *) curr; + *next = cast(zpl_uintptr) curr + actual_block_size; + curr = zpl_pointer_add(curr, actual_block_size); + } + + end = cast(zpl_uintptr *) curr; + *end = cast(zpl_uintptr) NULL; + + pool->physical_start = data; + pool->free_list = data; +} + +ZPL_ALLOCATOR_PROC(zpl_pool_allocator_proc) { + zpl_pool *pool = cast(zpl_pool *) allocator_data; + void *ptr = NULL; + + zpl_unused(old_size); + + switch (type) { + case ZPL_ALLOCATION_ALLOC: { + zpl_uintptr next_free; + ZPL_ASSERT(size == pool->block_size); + ZPL_ASSERT(alignment == pool->block_align); + ZPL_ASSERT(pool->free_list != NULL); + + next_free = *cast(zpl_uintptr *) pool->free_list; + ptr = pool->free_list; + pool->free_list = cast(void *) next_free; + pool->total_size += pool->block_size; + if (flags & ZPL_ALLOCATOR_FLAG_CLEAR_TO_ZERO) zpl_zero_size(ptr, size); + } break; + + case ZPL_ALLOCATION_FREE: { + zpl_uintptr *next; + if (old_memory == NULL) return NULL; + + next = cast(zpl_uintptr *) old_memory; + *next = cast(zpl_uintptr) pool->free_list; + pool->free_list = old_memory; + pool->total_size -= pool->block_size; + } break; + + case ZPL_ALLOCATION_FREE_ALL: { + zpl_isize actual_block_size, block_index; + void *curr; zpl_uintptr *end; - - zpl_zero_item(pool); - - pool->backing = backing; - pool->block_size = block_size; - pool->block_align = block_align; - pool->num_blocks = num_blocks; - - actual_block_size = block_size + block_align; - pool_size = num_blocks * actual_block_size; - - data = zpl_alloc_align(backing, pool_size, block_align); - + + actual_block_size = pool->block_size + pool->block_align; + pool->total_size = 0; + // NOTE: Init intrusive freelist - curr = data; - for (block_index = 0; block_index < num_blocks - 1; block_index++) { + curr = pool->physical_start; + for (block_index = 0; block_index < pool->num_blocks - 1; block_index++) { zpl_uintptr *next = cast(zpl_uintptr *) curr; *next = cast(zpl_uintptr) curr + actual_block_size; curr = zpl_pointer_add(curr, actual_block_size); } - + end = cast(zpl_uintptr *) curr; *end = cast(zpl_uintptr) NULL; - - pool->physical_start = data; - pool->free_list = data; - } - - ZPL_ALLOCATOR_PROC(zpl_pool_allocator_proc) { - zpl_pool *pool = cast(zpl_pool *) allocator_data; - void *ptr = NULL; - - zpl_unused(old_size); - - switch (type) { - case ZPL_ALLOCATION_ALLOC: { - zpl_uintptr next_free; - ZPL_ASSERT(size == pool->block_size); - ZPL_ASSERT(alignment == pool->block_align); - ZPL_ASSERT(pool->free_list != NULL); - - next_free = *cast(zpl_uintptr *) pool->free_list; - ptr = pool->free_list; - pool->free_list = cast(void *) next_free; - pool->total_size += pool->block_size; - if (flags & ZPL_ALLOCATOR_FLAG_CLEAR_TO_ZERO) zpl_zero_size(ptr, size); - } break; - - case ZPL_ALLOCATION_FREE: { - zpl_uintptr *next; - if (old_memory == NULL) return NULL; - - next = cast(zpl_uintptr *) old_memory; - *next = cast(zpl_uintptr) pool->free_list; - pool->free_list = old_memory; - pool->total_size -= pool->block_size; - } break; - - case ZPL_ALLOCATION_FREE_ALL: { - zpl_isize actual_block_size, block_index; - void *curr; - zpl_uintptr *end; - - actual_block_size = pool->block_size + pool->block_align; - pool->total_size = 0; - - // NOTE: Init intrusive freelist - curr = pool->physical_start; - for (block_index = 0; block_index < pool->num_blocks - 1; block_index++) { - zpl_uintptr *next = cast(zpl_uintptr *) curr; - *next = cast(zpl_uintptr) curr + actual_block_size; - curr = zpl_pointer_add(curr, actual_block_size); - } - - end = cast(zpl_uintptr *) curr; - *end = cast(zpl_uintptr) NULL; - pool->free_list = pool->physical_start; - } break; - - case ZPL_ALLOCATION_RESIZE: - // NOTE: Cannot resize - ZPL_PANIC("You cannot resize something allocated by with a pool."); - break; - } - - return ptr; - } - - - // - // Scratch Memory Allocator - // - - void zpl_scratch_memory_init(zpl_scratch_memory *s, void *start, zpl_isize size) { - s->physical_start = start; - s->total_size = size; - s->alloc_point = start; - s->free_point = start; - } - - zpl_b32 zpl_scratch_memory_is_in_use(zpl_scratch_memory *s, void *ptr) { - if (s->free_point == s->alloc_point) return false; - if (s->alloc_point > s->free_point) return ptr >= s->free_point && ptr < s->alloc_point; - return ptr >= s->free_point || ptr < s->alloc_point; - } - - zpl_allocator zpl_scratch_allocator(zpl_scratch_memory *s) { - zpl_allocator a; - a.proc = zpl_scratch_allocator_proc; - a.data = s; - return a; - } - - ZPL_ALLOCATOR_PROC(zpl_scratch_allocator_proc) { - zpl_scratch_memory *s = cast(zpl_scratch_memory *) allocator_data; - void *ptr = NULL; - ZPL_ASSERT_NOT_NULL(s); - - switch (type) { - case ZPL_ALLOCATION_ALLOC: { - void *pt = s->alloc_point; - zpl_allocation_header_ev *header = cast(zpl_allocation_header_ev *) pt; - void *data = zpl_align_forward(header + 1, alignment); - void *end = zpl_pointer_add(s->physical_start, s->total_size); - - ZPL_ASSERT(alignment % 4 == 0); - size = ((size + 3) / 4) * 4; - pt = zpl_pointer_add(pt, size); - - // NOTE: Wrap around - if (pt > end) { - header->size = zpl_pointer_diff(header, end) | ZPL_ISIZE_HIGH_BIT; - pt = s->physical_start; - header = cast(zpl_allocation_header_ev *) pt; - data = zpl_align_forward(header + 1, alignment); - pt = zpl_pointer_add(pt, size); - } - - if (!zpl_scratch_memory_is_in_use(s, pt)) { - zpl_allocation_header_fill(header, pt, zpl_pointer_diff(header, pt)); - s->alloc_point = cast(zpl_u8 *) pt; - ptr = data; - } - - if (flags & ZPL_ALLOCATOR_FLAG_CLEAR_TO_ZERO) zpl_zero_size(ptr, size); - } break; - - case ZPL_ALLOCATION_FREE: { - if (old_memory) { - void *end = zpl_pointer_add(s->physical_start, s->total_size); - if (old_memory < s->physical_start || old_memory >= end) { - ZPL_ASSERT(false); - } else { - // NOTE: Mark as free - zpl_allocation_header_ev *h = zpl_allocation_header(old_memory); - ZPL_ASSERT((h->size & ZPL_ISIZE_HIGH_BIT) == 0); - h->size = h->size | ZPL_ISIZE_HIGH_BIT; - - while (s->free_point != s->alloc_point) { - zpl_allocation_header_ev *header = cast(zpl_allocation_header_ev *) s->free_point; - if ((header->size & ZPL_ISIZE_HIGH_BIT) == 0) break; - - s->free_point = zpl_pointer_add(s->free_point, h->size & (~ZPL_ISIZE_HIGH_BIT)); - if (s->free_point == end) s->free_point = s->physical_start; - } - } - } - } break; - - case ZPL_ALLOCATION_FREE_ALL: - s->alloc_point = s->physical_start; - s->free_point = s->physical_start; - break; - - case ZPL_ALLOCATION_RESIZE: - ptr = zpl_default_resize_align(zpl_scratch_allocator(s), old_memory, old_size, size, alignment); - break; - } - - return ptr; - } - - // - // Stack Memory Allocator - // - ZPL_ALLOCATOR_PROC(zpl_stack_allocator_proc) { - zpl_stack_memory *s = cast(zpl_stack_memory *) allocator_data; - void *ptr = NULL; - ZPL_ASSERT_NOT_NULL(s); - zpl_unused(old_size); - zpl_unused(flags); - - switch (type) { - case ZPL_ALLOCATION_ALLOC: { - size += ZPL_STACK_ALLOC_OFFSET; - zpl_u64 alloc_offset = s->allocated; - - void *curr = - cast(zpl_u64 *) zpl_align_forward(cast(zpl_u64 *) zpl_pointer_add(s->physical_start, s->allocated), alignment); - - if (cast(zpl_u64 *) zpl_pointer_add(curr, size) > cast(zpl_u64 *) zpl_pointer_add(s->physical_start, s->total_size)) { - if (s->backing.proc) { - void *old_start = s->physical_start; - s->physical_start = - zpl_resize_align(s->backing, s->physical_start, s->total_size, s->total_size + size, alignment); - curr = cast(zpl_u64 *) - zpl_align_forward(cast(zpl_u64 *) zpl_pointer_add(s->physical_start, s->allocated), alignment); - s->total_size = zpl_pointer_diff(old_start, s->physical_start); - } else { - ZPL_PANIC("Can not resize stack's memory! Allocator not defined!"); - } - } - - s->allocated = zpl_pointer_diff(s->physical_start, curr) + size; - - *(zpl_u64 *)curr = alloc_offset; - curr = zpl_pointer_add(curr, ZPL_STACK_ALLOC_OFFSET); - - ptr = curr; - } break; - - case ZPL_ALLOCATION_FREE: { - if (old_memory) { - void *curr = old_memory; - curr = zpl_pointer_sub(curr, ZPL_STACK_ALLOC_OFFSET); - - zpl_u64 alloc_offset = *(zpl_u64 *)curr; - s->allocated = (zpl_usize)alloc_offset; - } - } break; - - case ZPL_ALLOCATION_FREE_ALL: { - s->allocated = 0; - } break; - - case ZPL_ALLOCATION_RESIZE: { - ZPL_PANIC("You cannot resize something allocated by a stack."); - } break; - } - return ptr; - } - - ZPL_END_C_DECLS - // file: source/core/array.c - - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - ZPL_NEVER_INLINE void *zpl__array_set_capacity(void *array, zpl_isize capacity, zpl_isize element_size) { - zpl_array_header *h = ZPL_ARRAY_HEADER(array); - - ZPL_ASSERT(element_size > 0); - - if (capacity == h->capacity) return array; - - if (capacity < h->count) { - if (h->capacity < capacity) { - zpl_isize new_capacity = ZPL_ARRAY_GROW_FORMULA(h->capacity); - if (new_capacity < capacity) new_capacity = capacity; - zpl__array_set_capacity(array, new_capacity, element_size); - } - h->count = capacity; - } - - { - zpl_isize size = zpl_size_of(zpl_array_header) + element_size * capacity; - zpl_array_header *nh = cast(zpl_array_header *) zpl_alloc(h->allocator, size); - zpl_memmove(nh, h, zpl_size_of(zpl_array_header) + element_size * h->count); - nh->allocator = h->allocator; - nh->count = h->count; - nh->data = (char *)nh + 1; - nh->capacity = capacity; - zpl_free(h->allocator, h); - return nh + 1; - } - } - - ZPL_END_C_DECLS - // file: source/core/string.c - - //////////////////////////////////////////////////////////////// - // - // Char things - // - // - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - zpl_internal zpl_isize zpl__scan_zpl_i64(const char *text, zpl_i32 base, zpl_i64 *value) { - const char *text_begin = text; - zpl_i64 result = 0; - zpl_b32 negative = false; - - if (*text == '-') { - negative = true; - text++; - } - - if (base == 16 && zpl_strncmp(text, "0x", 2) == 0) text += 2; - - for (;;) { - zpl_i64 v; - if (zpl_char_is_digit(*text)) - v = *text - '0'; - else if (base == 16 && zpl_char_is_hex_digit(*text)) - v = zpl_hex_digit_to_int(*text); - else - break; - - result *= base; - result += v; - text++; - } - - if (value) { - if (negative) result = -result; - *value = result; - } - - return (text - text_begin); - } - - zpl_internal zpl_isize zpl__scan_zpl_u64(const char *text, zpl_i32 base, zpl_u64 *value) { - const char *text_begin = text; - zpl_u64 result = 0; - - if (base == 16 && zpl_strncmp(text, "0x", 2) == 0) text += 2; - - for (;;) { - zpl_u64 v; - if (zpl_char_is_digit(*text)) - v = *text - '0'; - else if (base == 16 && zpl_char_is_hex_digit(*text)) - v = zpl_hex_digit_to_int(*text); - else { - break; - } - - result *= base; - result += v; - text++; - } - - if (value) *value = result; - - return (text - text_begin); - } - - // TODO: Make better - zpl_u64 zpl_str_to_u64(const char *str, char **end_ptr, zpl_i32 base) { - zpl_isize len; - zpl_u64 value = 0; - - if (!base) { - if ((zpl_strlen(str) > 2) && (zpl_strncmp(str, "0x", 2) == 0)) - base = 16; - else - base = 10; - } - - len = zpl__scan_zpl_u64(str, base, &value); - if (end_ptr) *end_ptr = (char *)str + len; - return value; - } - - zpl_i64 zpl_str_to_i64(const char *str, char **end_ptr, zpl_i32 base) { - zpl_isize len; - zpl_i64 value; - - if (!base) { - if ((zpl_strlen(str) > 2) && (zpl_strncmp(str, "0x", 2) == 0)) - base = 16; - else - base = 10; - } - - len = zpl__scan_zpl_i64(str, base, &value); - if (end_ptr) *end_ptr = (char *)str + len; - return value; - } - - // TODO: Are these good enough for characters? - zpl_global const char zpl__num_to_char_table[] = "0123456789" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "@$"; - - void zpl_i64_to_str(zpl_i64 value, char *string, zpl_i32 base) { - char *buf = string; - zpl_b32 negative = false; - zpl_u64 v; - - if (value < 0) { - negative = true; - value = -value; - } - - v = cast(zpl_u64) value; - if (v != 0) { - while (v > 0) { - *buf++ = zpl__num_to_char_table[v % base]; - v /= base; - } - } else { - *buf++ = '0'; - } - if (negative) *buf++ = '-'; - *buf = '\0'; - zpl_strrev(string); - } - - void zpl_u64_to_str(zpl_u64 value, char *string, zpl_i32 base) { - char *buf = string; - - if (value) { - while (value > 0) { - *buf++ = zpl__num_to_char_table[value % base]; - value /= base; - } - } else { - *buf++ = '0'; - } - *buf = '\0'; - - zpl_strrev(string); - } - - zpl_f64 zpl_str_to_f64(const char *str, char **end_ptr) { - zpl_f64 result, value, sign, scale; - zpl_i32 frac; - - while (zpl_char_is_space(*str)) { str++; } - - sign = 1.0; - if (*str == '-') { - sign = -1.0; - str++; - } else if (*str == '+') { - str++; - } - - for (value = 0.0; zpl_char_is_digit(*str); str++) { value = value * 10.0 + (*str - '0'); } - - if (*str == '.') { - zpl_f64 pow10 = 10.0; - str++; - while (zpl_char_is_digit(*str)) { - value += (*str - '0') / pow10; - pow10 *= 10.0; - str++; - } - } - - frac = 0; - scale = 1.0; - if ((*str == 'e') || (*str == 'E')) { - zpl_u32 exp; - - str++; - if (*str == '-') { - frac = 1; - str++; - } else if (*str == '+') { - str++; - } - - for (exp = 0; zpl_char_is_digit(*str); str++) { exp = exp * 10 + (*str - '0'); } - if (exp > 308) exp = 308; - - while (exp >= 50) { - scale *= 1e50; - exp -= 50; - } - while (exp >= 8) { - scale *= 1e8; - exp -= 8; - } - while (exp > 0) { - scale *= 10.0; - exp -= 1; - } - } - - result = sign * (frac ? (value / scale) : (value * scale)); - - if (end_ptr) *end_ptr = cast(char *) str; - - return result; - } - - - - //////////////////////////////////////////////////////////////// - // - // Windows UTF-8 Handling - // - // - - zpl_u16 *zpl_utf8_to_ucs2(zpl_u16 *buffer, zpl_isize len, zpl_u8 const *str) { - zpl_rune c; - zpl_isize i = 0; - len--; - while (*str) { - if (i >= len) return NULL; - if (!(*str & 0x80)) { - buffer[i++] = *str++; - } else if ((*str & 0xe0) == 0xc0) { - if (*str < 0xc2) return NULL; - c = (*str++ & 0x1f) << 6; - if ((*str & 0xc0) != 0x80) return NULL; - buffer[i++] = cast(zpl_u16)(c + (*str++ & 0x3f)); - } else if ((*str & 0xf0) == 0xe0) { - if (*str == 0xe0 && (str[1] < 0xa0 || str[1] > 0xbf)) return NULL; - if (*str == 0xed && str[1] > 0x9f) // str[1] < 0x80 is checked below - return NULL; - c = (*str++ & 0x0f) << 12; - if ((*str & 0xc0) != 0x80) return NULL; - c += (*str++ & 0x3f) << 6; - if ((*str & 0xc0) != 0x80) return NULL; - buffer[i++] = cast(zpl_u16)(c + (*str++ & 0x3f)); - } else if ((*str & 0xf8) == 0xf0) { - if (*str > 0xf4) return NULL; - if (*str == 0xf0 && (str[1] < 0x90 || str[1] > 0xbf)) return NULL; - if (*str == 0xf4 && str[1] > 0x8f) // str[1] < 0x80 is checked below - return NULL; - c = (*str++ & 0x07) << 18; - if ((*str & 0xc0) != 0x80) return NULL; - c += (*str++ & 0x3f) << 12; - if ((*str & 0xc0) != 0x80) return NULL; - c += (*str++ & 0x3f) << 6; - if ((*str & 0xc0) != 0x80) return NULL; - c += (*str++ & 0x3f); - // UTF-8 encodings of values used in surrogate pairs are invalid - if ((c & 0xfffff800) == 0xd800) return NULL; - if (c >= 0x10000) { - c -= 0x10000; - if (i + 2 > len) return NULL; - buffer[i++] = 0xd800 | (0x3ff & (c >> 10)); - buffer[i++] = 0xdc00 | (0x3ff & (c)); - } - } else { - return NULL; - } - } - buffer[i] = 0; - return buffer; - } - - zpl_u8 *zpl_ucs2_to_utf8(zpl_u8 *buffer, zpl_isize len, zpl_u16 const *str) { - zpl_isize i = 0; - len--; - while (*str) { - if (*str < 0x80) { - if (i + 1 > len) return NULL; - buffer[i++] = (char)*str++; - } else if (*str < 0x800) { - if (i + 2 > len) return NULL; - buffer[i++] = cast(char)(0xc0 + (*str >> 6)); - buffer[i++] = cast(char)(0x80 + (*str & 0x3f)); - str += 1; - } else if (*str >= 0xd800 && *str < 0xdc00) { - zpl_rune c; - if (i + 4 > len) return NULL; - c = ((str[0] - 0xd800) << 10) + ((str[1]) - 0xdc00) + 0x10000; - buffer[i++] = cast(char)(0xf0 + (c >> 18)); - buffer[i++] = cast(char)(0x80 + ((c >> 12) & 0x3f)); - buffer[i++] = cast(char)(0x80 + ((c >> 6) & 0x3f)); - buffer[i++] = cast(char)(0x80 + ((c)&0x3f)); - str += 2; - } else if (*str >= 0xdc00 && *str < 0xe000) { - return NULL; - } else { - if (i + 3 > len) return NULL; - buffer[i++] = 0xe0 + (*str >> 12); - buffer[i++] = 0x80 + ((*str >> 6) & 0x3f); - buffer[i++] = 0x80 + ((*str) & 0x3f); - str += 1; - } - } - buffer[i] = 0; - return buffer; - } - - zpl_u16 *zpl_utf8_to_ucs2_buf(zpl_u8 const *str) { // NOTE: Uses locally persisting buffer - zpl_local_persist zpl_u16 buf[4096]; - return zpl_utf8_to_ucs2(buf, zpl_count_of(buf), str); - } - - zpl_u8 *zpl_ucs2_to_utf8_buf(zpl_u16 const *str) { // NOTE: Uses locally persisting buffer - zpl_local_persist zpl_u8 buf[4096]; - return zpl_ucs2_to_utf8(buf, zpl_count_of(buf), str); - } - - zpl_global zpl_u8 const zpl__utf8_first[256] = { - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x00-0x0F - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x10-0x1F - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x20-0x2F - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x30-0x3F - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x40-0x4F - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x50-0x5F - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x60-0x6F - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x70-0x7F - 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0x80-0x8F - 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0x90-0x9F - 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xA0-0xAF - 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xB0-0xBF - 0xf1, 0xf1, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, // 0xC0-0xCF - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, // 0xD0-0xDF - 0x13, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x23, 0x03, 0x03, // 0xE0-0xEF - 0x34, 0x04, 0x04, 0x04, 0x44, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xF0-0xFF - }; - - - typedef struct zpl_utf8_accept_range { - zpl_u8 lo, hi; - } zpl_utf8_accept_range; - - zpl_global zpl_utf8_accept_range const zpl__utf8_accept_ranges[] = { - { 0x80, 0xbf }, { 0xa0, 0xbf }, { 0x80, 0x9f }, { 0x90, 0xbf }, { 0x80, 0x8f }, - }; - - zpl_isize zpl_utf8_decode(zpl_u8 const *str, zpl_isize str_len, zpl_rune *codepoint_out) { - - zpl_isize width = 0; - zpl_rune codepoint = ZPL_RUNE_INVALID; - - if (str_len > 0) { - zpl_u8 s0 = str[0]; - zpl_u8 x = zpl__utf8_first[s0], sz; - zpl_u8 b1, b2, b3; - zpl_utf8_accept_range accept; - if (x >= 0xf0) { - zpl_rune mask = (cast(zpl_rune) x << 31) >> 31; - codepoint = (cast(zpl_rune) s0 & (~mask)) | (ZPL_RUNE_INVALID & mask); - width = 1; - goto end; - } - if (s0 < 0x80) { - codepoint = s0; - width = 1; - goto end; - } - - sz = x & 7; - accept = zpl__utf8_accept_ranges[x >> 4]; - if (str_len < sz) goto invalid_codepoint; - - b1 = str[1]; - if (b1 < accept.lo || accept.hi < b1) goto invalid_codepoint; - - if (sz == 2) { - codepoint = (cast(zpl_rune) s0 & 0x1f) << 6 | (cast(zpl_rune) b1 & 0x3f); - width = 2; - goto end; - } - - b2 = str[2]; - if (!zpl_is_between(b2, 0x80, 0xbf)) goto invalid_codepoint; - - if (sz == 3) { - codepoint = (cast(zpl_rune) s0 & 0x1f) << 12 | (cast(zpl_rune) b1 & 0x3f) << 6 | (cast(zpl_rune) b2 & 0x3f); - width = 3; - goto end; - } - - b3 = str[3]; - if (!zpl_is_between(b3, 0x80, 0xbf)) goto invalid_codepoint; - - codepoint = (cast(zpl_rune) s0 & 0x07) << 18 | (cast(zpl_rune) b1 & 0x3f) << 12 | (cast(zpl_rune) b2 & 0x3f) << 6 | - (cast(zpl_rune) b3 & 0x3f); - width = 4; - goto end; - - invalid_codepoint: - codepoint = ZPL_RUNE_INVALID; - width = 1; - } - - end: - if (codepoint_out) *codepoint_out = codepoint; - return width; - } - - zpl_isize zpl_utf8_codepoint_size(zpl_u8 const *str, zpl_isize str_len) { - zpl_isize i = 0; - for (; i < str_len && str[i]; i++) { - if ((str[i] & 0xc0) != 0x80) break; - } - return i + 1; - } - - zpl_isize zpl_utf8_encode_rune(zpl_u8 buf[4], zpl_rune r) { - zpl_u32 i = cast(zpl_u32) r; - zpl_u8 mask = 0x3f; - if (i <= (1 << 7) - 1) { - buf[0] = cast(zpl_u8) r; - return 1; - } - if (i <= (1 << 11) - 1) { - buf[0] = 0xc0 | cast(zpl_u8)(r >> 6); - buf[1] = 0x80 | (cast(zpl_u8)(r) & mask); - return 2; - } - - // Invalid or Surrogate range - if (i > ZPL_RUNE_MAX || zpl_is_between(i, 0xd800, 0xdfff)) { - r = ZPL_RUNE_INVALID; - - buf[0] = 0xe0 | cast(zpl_u8)(r >> 12); - buf[1] = 0x80 | (cast(zpl_u8)(r >> 6) & mask); - buf[2] = 0x80 | (cast(zpl_u8)(r) & mask); - return 3; - } - - if (i <= (1 << 16) - 1) { - buf[0] = 0xe0 | cast(zpl_u8)(r >> 12); - buf[1] = 0x80 | (cast(zpl_u8)(r >> 6) & mask); - buf[2] = 0x80 | (cast(zpl_u8)(r) & mask); - return 3; - } - - buf[0] = 0xf0 | cast(zpl_u8)(r >> 18); - buf[1] = 0x80 | (cast(zpl_u8)(r >> 12) & mask); - buf[2] = 0x80 | (cast(zpl_u8)(r >> 6) & mask); - buf[3] = 0x80 | (cast(zpl_u8)(r) & mask); - return 4; - } - - ZPL_END_C_DECLS - // file: source/core/stringlib.c - - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - zpl_string zpl_string_make_reserve(zpl_allocator a, zpl_isize capacity) { - zpl_isize header_size = zpl_size_of(zpl_string_header); - void *ptr = zpl_alloc(a, header_size + capacity + 1); - - zpl_string str; - zpl_string_header *header; - - if (ptr == NULL) return NULL; - zpl_zero_size(ptr, header_size + capacity + 1); - - str = cast(char *) ptr + header_size; - header = ZPL_STRING_HEADER(str); - header->allocator = a; - header->length = 0; - header->capacity = capacity; - str[capacity] = '\0'; - - return str; - } - - - zpl_string zpl_string_make_length(zpl_allocator a, void const *init_str, zpl_isize num_bytes) { - zpl_isize header_size = zpl_size_of(zpl_string_header); - void *ptr = zpl_alloc(a, header_size + num_bytes + 1); - - zpl_string str; - zpl_string_header *header; - - if (ptr == NULL) return NULL; - if (!init_str) zpl_zero_size(ptr, header_size + num_bytes + 1); - - str = cast(char *) ptr + header_size; - header = ZPL_STRING_HEADER(str); - header->allocator = a; - header->length = num_bytes; - header->capacity = num_bytes; - if (num_bytes && init_str) zpl_memcopy(str, init_str, num_bytes); - str[num_bytes] = '\0'; - - return str; - } - - zpl_string zpl_string_sprintf_buf(zpl_allocator a, const char *fmt, ...) { - zpl_local_persist char buf[4096] = { 0 }; - va_list va; - va_start(va, fmt); - zpl_snprintf_va(buf, 4096, fmt, va); - va_end(va); - - return zpl_string_make(a, buf); - } - - zpl_string zpl_string_sprintf(zpl_allocator a, char *buf, zpl_isize num_bytes, const char *fmt, ...) { - va_list va; - va_start(va, fmt); - zpl_snprintf_va(buf, num_bytes, fmt, va); - va_end(va); - - return zpl_string_make(a, buf); - } - - zpl_string zpl_string_append_length(zpl_string str, void const *other, zpl_isize other_len) { - if (other_len > 0) { - zpl_isize curr_len = zpl_string_length(str); - - str = zpl_string_make_space_for(str, other_len); - if (str == NULL) return NULL; - - zpl_memcopy(str + curr_len, other, other_len); - str[curr_len + other_len] = '\0'; - zpl__set_string_length(str, curr_len + other_len); - } - return str; - } - - ZPL_ALWAYS_INLINE zpl_string zpl_string_appendc(zpl_string str, const char *other) { - return zpl_string_append_length(str, other, zpl_strlen(other)); - } - - ZPL_ALWAYS_INLINE zpl_string zpl_string_join(zpl_allocator a, const char **parts, zpl_isize count, const char *glue) { - zpl_string ret; - zpl_isize i; - - ret = zpl_string_make(a, NULL); - - for (i=0; i= add_len) { - return str; - } else { - zpl_isize new_len, old_size, new_size; - void *ptr, *new_ptr; - zpl_allocator a = ZPL_STRING_HEADER(str)->allocator; - zpl_string_header *header; - - new_len = zpl_string_length(str) + add_len; - ptr = ZPL_STRING_HEADER(str); - old_size = zpl_size_of(zpl_string_header) + zpl_string_length(str) + 1; - new_size = zpl_size_of(zpl_string_header) + new_len + 1; - - new_ptr = zpl_resize(a, ptr, old_size, new_size); - if (new_ptr == NULL) return NULL; - - header = cast(zpl_string_header *) new_ptr; - header->allocator = a; - - str = cast(zpl_string)(header + 1); - zpl__set_string_capacity(str, new_len); - - return str; - } - } - - zpl_isize zpl_string_allocation_size(zpl_string const str) { - zpl_isize cap = zpl_string_capacity(str); - return zpl_size_of(zpl_string_header) + cap; - } - - zpl_b32 zpl_string_are_equal(zpl_string const lhs, zpl_string const rhs) { - zpl_isize lhs_len, rhs_len, i; - lhs_len = zpl_string_length(lhs); - rhs_len = zpl_string_length(rhs); - if (lhs_len != rhs_len) return false; - - for (i = 0; i < lhs_len; i++) { - if (lhs[i] != rhs[i]) return false; - } - - return true; - } - - zpl_string zpl_string_trim(zpl_string str, const char *cut_set) { - char *start, *end, *start_pos, *end_pos; - zpl_isize len; - - start_pos = start = str; - end_pos = end = str + zpl_string_length(str) - 1; - - while (start_pos <= end && zpl_char_first_occurence(cut_set, *start_pos)) start_pos++; - while (end_pos > start_pos && zpl_char_first_occurence(cut_set, *end_pos)) end_pos--; - - len = cast(zpl_isize)((start_pos > end_pos) ? 0 : ((end_pos - start_pos) + 1)); - - if (str != start_pos) zpl_memmove(str, start_pos, len); - str[len] = '\0'; - - zpl__set_string_length(str, len); - - return str; - } - - zpl_string zpl_string_append_rune(zpl_string str, zpl_rune r) { - if (r >= 0) { - zpl_u8 buf[8] = { 0 }; - zpl_isize len = zpl_utf8_encode_rune(buf, r); - return zpl_string_append_length(str, buf, len); - } - - return str; - } - - zpl_string zpl_string_append_fmt(zpl_string str, const char *fmt, ...) { - zpl_isize res; - char buf[4096] = { 0 }; - va_list va; - va_start(va, fmt); - res = zpl_snprintf_va(buf, zpl_count_of(buf) - 1, fmt, va) - 1; - va_end(va); - return zpl_string_append_length(str, buf, res); - } - - ZPL_END_C_DECLS - // file: source/core/file.c - - #ifdef ZPL_EDITOR - #include - #endif - - //////////////////////////////////////////////////////////////// - // - // File Handling - // - // - #include - - #ifdef ZPL_SYSTEM_MACOS - #include - #endif - - #ifdef ZPL_SYSTEM_CYGWIN - # include - #endif - - #if defined(ZPL_SYSTEM_WINDOWS) && !defined(ZPL_COMPILER_GCC) - #include - #endif - - ZPL_BEGIN_C_DECLS - - #if defined(ZPL_SYSTEM_WINDOWS) || defined (ZPL_SYSTEM_CYGWIN) - - zpl_internal wchar_t *zpl__alloc_utf8_to_ucs2(zpl_allocator a, char const *text, zpl_isize *w_len_) { - wchar_t *w_text = NULL; - zpl_isize len = 0, w_len = 0, w_len1 = 0; - if (text == NULL) { - if (w_len_) *w_len_ = w_len; - return NULL; - } - len = zpl_strlen(text); - if (len == 0) { - if (w_len_) *w_len_ = w_len; - return NULL; - } - w_len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, text, cast(int) len, NULL, 0); - if (w_len == 0) { - if (w_len_) *w_len_ = w_len; - return NULL; - } - w_text = zpl_alloc_array(a, wchar_t, w_len + 1); - w_len1 = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, text, cast(int) len, w_text, cast(int) w_len); - if (w_len1 == 0) { - zpl_free(a, w_text); - if (w_len_) *w_len_ = 0; - return NULL; - } - w_text[w_len] = 0; - if (w_len_) *w_len_ = w_len; - return w_text; - } - - zpl_internal ZPL_FILE_SEEK_PROC(zpl__win32_file_seek) { - LARGE_INTEGER li_offset; - li_offset.QuadPart = offset; - if (!SetFilePointerEx(fd.p, li_offset, &li_offset, whence)) { return false; } - - if (new_offset) *new_offset = li_offset.QuadPart; - return true; - } - - zpl_internal ZPL_FILE_READ_AT_PROC(zpl__win32_file_read) { - zpl_unused(stop_at_newline); - zpl_b32 result = false; - zpl__win32_file_seek(fd, offset, ZPL_SEEK_WHENCE_BEGIN, NULL); - DWORD size_ = cast(DWORD)(size > ZPL_I32_MAX ? ZPL_I32_MAX : size); - DWORD bytes_read_; - if (ReadFile(fd.p, buffer, size_, &bytes_read_, NULL)) { - if (bytes_read) *bytes_read = bytes_read_; - result = true; - } - - return result; - } - - zpl_internal ZPL_FILE_WRITE_AT_PROC(zpl__win32_file_write) { - DWORD size_ = cast(DWORD)(size > ZPL_I32_MAX ? ZPL_I32_MAX : size); - DWORD bytes_written_; - zpl__win32_file_seek(fd, offset, ZPL_SEEK_WHENCE_BEGIN, NULL); - if (WriteFile(fd.p, buffer, size_, &bytes_written_, NULL)) { - if (bytes_written) *bytes_written = bytes_written_; - return true; - } - return false; - } - - zpl_internal ZPL_FILE_CLOSE_PROC(zpl__win32_file_close) { CloseHandle(fd.p); } - - zpl_file_operations const zpl_default_file_operations = { zpl__win32_file_read, zpl__win32_file_write, - zpl__win32_file_seek, zpl__win32_file_close }; - - ZPL_NEVER_INLINE ZPL_FILE_OPEN_PROC(zpl__win32_file_open) { - DWORD desired_access; - DWORD creation_disposition; - void *handle; - wchar_t *w_text; - - switch (mode & ZPL_FILE_MODES) { - case ZPL_FILE_MODE_READ: - desired_access = GENERIC_READ; - creation_disposition = OPEN_EXISTING; - break; - case ZPL_FILE_MODE_WRITE: - desired_access = GENERIC_WRITE; - creation_disposition = CREATE_ALWAYS; - break; - case ZPL_FILE_MODE_APPEND: - desired_access = GENERIC_WRITE; - creation_disposition = OPEN_ALWAYS; - break; - case ZPL_FILE_MODE_READ | ZPL_FILE_MODE_RW: - desired_access = GENERIC_READ | GENERIC_WRITE; - creation_disposition = OPEN_EXISTING; - break; - case ZPL_FILE_MODE_WRITE | ZPL_FILE_MODE_RW: - desired_access = GENERIC_READ | GENERIC_WRITE; - creation_disposition = CREATE_ALWAYS; - break; - case ZPL_FILE_MODE_APPEND | ZPL_FILE_MODE_RW: - desired_access = GENERIC_READ | GENERIC_WRITE; - creation_disposition = OPEN_ALWAYS; - break; - default: ZPL_PANIC("Invalid file mode"); return ZPL_FILE_ERROR_INVALID; - } - - w_text = zpl__alloc_utf8_to_ucs2(zpl_heap_allocator( ), filename, NULL); - handle = CreateFileW(w_text, desired_access, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, creation_disposition, - FILE_ATTRIBUTE_NORMAL, NULL); - - zpl_free(zpl_heap_allocator( ), w_text); - - if (handle == INVALID_HANDLE_VALUE) { - DWORD err = GetLastError( ); - switch (err) { - case ERROR_FILE_NOT_FOUND: return ZPL_FILE_ERROR_NOT_EXISTS; - case ERROR_FILE_EXISTS: return ZPL_FILE_ERROR_EXISTS; - case ERROR_ALREADY_EXISTS: return ZPL_FILE_ERROR_EXISTS; - case ERROR_ACCESS_DENIED: return ZPL_FILE_ERROR_PERMISSION; - } - return ZPL_FILE_ERROR_INVALID; - } - - if (mode & ZPL_FILE_MODE_APPEND) { - LARGE_INTEGER offset = { 0 }; - if (!SetFilePointerEx(handle, offset, NULL, ZPL_SEEK_WHENCE_END)) { - CloseHandle(handle); - return ZPL_FILE_ERROR_INVALID; - } - } - - fd->p = handle; - *ops = zpl_default_file_operations; - return ZPL_FILE_ERROR_NONE; - } - - #else // POSIX - #include - - zpl_internal ZPL_FILE_SEEK_PROC(zpl__posix_file_seek) { - #if defined(ZPL_SYSTEM_OSX) - zpl_i64 res = lseek(fd.i, offset, whence); - #else // TODO(ZaKlaus): @fixme lseek64 - zpl_i64 res = lseek(fd.i, offset, whence); - #endif - if (res < 0) return false; - if (new_offset) *new_offset = res; - return true; - } - - zpl_internal ZPL_FILE_READ_AT_PROC(zpl__posix_file_read) { - zpl_unused(stop_at_newline); - zpl_isize res = pread(fd.i, buffer, size, offset); - if (res < 0) return false; - if (bytes_read) *bytes_read = res; - return true; - } - - zpl_internal ZPL_FILE_WRITE_AT_PROC(zpl__posix_file_write) { - zpl_isize res; - zpl_i64 curr_offset = 0; - zpl__posix_file_seek(fd, 0, ZPL_SEEK_WHENCE_CURRENT, &curr_offset); - if (curr_offset == offset) { - // NOTE: Writing to stdout et al. doesn't like pwrite for numerous reasons - res = write(cast(int) fd.i, buffer, size); - } else { - res = pwrite(cast(int) fd.i, buffer, size, offset); - } - if (res < 0) return false; - if (bytes_written) *bytes_written = res; - return true; - } - - zpl_internal ZPL_FILE_CLOSE_PROC(zpl__posix_file_close) { close(fd.i); } - - zpl_file_operations const zpl_default_file_operations = { zpl__posix_file_read, zpl__posix_file_write, - zpl__posix_file_seek, zpl__posix_file_close }; - - ZPL_NEVER_INLINE ZPL_FILE_OPEN_PROC(zpl__posix_file_open) { - zpl_i32 os_mode; - switch (mode & ZPL_FILE_MODES) { - case ZPL_FILE_MODE_READ: os_mode = O_RDONLY; break; - case ZPL_FILE_MODE_WRITE: os_mode = O_WRONLY | O_CREAT | O_TRUNC; break; - case ZPL_FILE_MODE_APPEND: os_mode = O_WRONLY | O_APPEND | O_CREAT; break; - case ZPL_FILE_MODE_READ | ZPL_FILE_MODE_RW: os_mode = O_RDWR; break; - case ZPL_FILE_MODE_WRITE | ZPL_FILE_MODE_RW: os_mode = O_RDWR | O_CREAT | O_TRUNC; break; - case ZPL_FILE_MODE_APPEND | ZPL_FILE_MODE_RW: os_mode = O_RDWR | O_APPEND | O_CREAT; break; - default: ZPL_PANIC("Invalid file mode"); return ZPL_FILE_ERROR_INVALID; - } - - fd->i = open(filename, os_mode, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); - if (fd->i < 0) { - // TODO: More file errors - return ZPL_FILE_ERROR_INVALID; - } - - *ops = zpl_default_file_operations; - return ZPL_FILE_ERROR_NONE; - } - - #endif - - zpl_file_error zpl_file_new(zpl_file *f, zpl_file_descriptor fd, zpl_file_operations ops, char const *filename) { - zpl_file_error err = ZPL_FILE_ERROR_NONE; - zpl_isize len = zpl_strlen(filename); - - f->ops = ops; - f->fd = fd; - f->dir = NULL; - f->last_write_time = 0; - f->filename = zpl_alloc_array(zpl_heap_allocator( ), char, len + 1); - zpl_memcopy(cast(char *) f->filename, cast(char *) filename, len + 1); - - return err; - } - - zpl_file_error zpl_file_open_mode(zpl_file *f, zpl_file_mode mode, char const *filename) { - zpl_file file_ = {0}; - *f = file_; - zpl_file_error err; - #if defined(ZPL_SYSTEM_WINDOWS) || defined(ZPL_SYSTEM_CYGWIN) - err = zpl__win32_file_open(&f->fd, &f->ops, mode, filename); - #else - err = zpl__posix_file_open(&f->fd, &f->ops, mode, filename); - #endif - if (err == ZPL_FILE_ERROR_NONE) return zpl_file_new(f, f->fd, f->ops, filename); - return err; - } - - zpl_internal void zpl__dirinfo_free_entry(zpl_dir_entry *entry); - - zpl_file_error zpl_file_close(zpl_file *f) { - if (!f) return ZPL_FILE_ERROR_INVALID; - - if (f->filename) zpl_free(zpl_heap_allocator( ), cast(char *) f->filename); - - #if defined(ZPL_SYSTEM_WINDOWS) - if (f->fd.p == INVALID_HANDLE_VALUE) return ZPL_FILE_ERROR_INVALID; - #else - if (f->fd.i < 0) return ZPL_FILE_ERROR_INVALID; - #endif + pool->free_list = pool->physical_start; + } break; + + case ZPL_ALLOCATION_RESIZE: + // NOTE: Cannot resize + ZPL_PANIC("You cannot resize something allocated by with a pool."); + break; + } + + return ptr; +} + + +// +// Scratch Memory Allocator +// + +void zpl_scratch_memory_init(zpl_scratch_memory *s, void *start, zpl_isize size) { + s->physical_start = start; + s->total_size = size; + s->alloc_point = start; + s->free_point = start; +} + +zpl_b32 zpl_scratch_memory_is_in_use(zpl_scratch_memory *s, void *ptr) { + if (s->free_point == s->alloc_point) return false; + if (s->alloc_point > s->free_point) return ptr >= s->free_point && ptr < s->alloc_point; + return ptr >= s->free_point || ptr < s->alloc_point; +} + +zpl_allocator zpl_scratch_allocator(zpl_scratch_memory *s) { + zpl_allocator a; + a.proc = zpl_scratch_allocator_proc; + a.data = s; + return a; +} + +ZPL_ALLOCATOR_PROC(zpl_scratch_allocator_proc) { + zpl_scratch_memory *s = cast(zpl_scratch_memory *) allocator_data; + void *ptr = NULL; + ZPL_ASSERT_NOT_NULL(s); + + switch (type) { + case ZPL_ALLOCATION_ALLOC: { + void *pt = s->alloc_point; + zpl_allocation_header_ev *header = cast(zpl_allocation_header_ev *) pt; + void *data = zpl_align_forward(header + 1, alignment); + void *end = zpl_pointer_add(s->physical_start, s->total_size); - if (f->is_temp) - { - f->ops.close(f->fd); - return ZPL_FILE_ERROR_NONE; + ZPL_ASSERT(alignment % 4 == 0); + size = ((size + 3) / 4) * 4; + pt = zpl_pointer_add(pt, size); + + // NOTE: Wrap around + if (pt > end) { + header->size = zpl_pointer_diff(header, end) | ZPL_ISIZE_HIGH_BIT; + pt = s->physical_start; + header = cast(zpl_allocation_header_ev *) pt; + data = zpl_align_forward(header + 1, alignment); + pt = zpl_pointer_add(pt, size); } - - if (!f->ops.read_at) f->ops = zpl_default_file_operations; - f->ops.close(f->fd); - - if (f->dir) { - zpl__dirinfo_free_entry(f->dir); - zpl_mfree(f->dir); - f->dir = NULL; + + if (!zpl_scratch_memory_is_in_use(s, pt)) { + zpl_allocation_header_fill(header, pt, zpl_pointer_diff(header, pt)); + s->alloc_point = cast(zpl_u8 *) pt; + ptr = data; } - - return ZPL_FILE_ERROR_NONE; - } - - - zpl_file_error zpl_file_create(zpl_file *f, char const *filename) { - return zpl_file_open_mode(f, ZPL_FILE_MODE_WRITE | ZPL_FILE_MODE_RW, filename); - } - - zpl_file_error zpl_file_open(zpl_file *f, char const *filename) { - return zpl_file_open_mode(f, ZPL_FILE_MODE_READ, filename); - } - - char const *zpl_file_name(zpl_file *f) { return f->filename ? f->filename : ""; } - - zpl_b32 zpl_file_has_changed(zpl_file *f) { - if (f->is_temp) - return false; - zpl_b32 result = false; - zpl_file_time last_write_time = zpl_fs_last_write_time(f->filename); - if (f->last_write_time != last_write_time) { - result = true; - f->last_write_time = last_write_time; - } - return result; - } - - // TODO: Is this a bad idea? - zpl_global zpl_b32 zpl__std_file_set = false; - zpl_global zpl_file zpl__std_files[ZPL_FILE_STANDARD_COUNT] = { { 0 } }; - - #if defined(ZPL_SYSTEM_WINDOWS) || defined(ZPL_SYSTEM_CYGWIN) - - zpl_file *zpl_file_get_standard(zpl_file_standard_type std) { - if (!zpl__std_file_set) { - #define ZPL__SET_STD_FILE(type, v) \ - zpl__std_files[type].fd.p = v; \ - zpl__std_files[type].ops = zpl_default_file_operations - ZPL__SET_STD_FILE(ZPL_FILE_STANDARD_INPUT, GetStdHandle(STD_INPUT_HANDLE)); - ZPL__SET_STD_FILE(ZPL_FILE_STANDARD_OUTPUT, GetStdHandle(STD_OUTPUT_HANDLE)); - ZPL__SET_STD_FILE(ZPL_FILE_STANDARD_ERROR, GetStdHandle(STD_ERROR_HANDLE)); - #undef ZPL__SET_STD_FILE - zpl__std_file_set = true; - } - return &zpl__std_files[std]; - } - - void zpl_file_connect_handle(zpl_file *file, void *handle) { - ZPL_ASSERT_NOT_NULL(file); - ZPL_ASSERT_NOT_NULL(handle); - - if (file->is_temp) - return; - - zpl_zero_item(file); - - file->fd.p = handle; - file->ops = zpl_default_file_operations; - } - - zpl_file_error zpl_file_truncate(zpl_file *f, zpl_i64 size) { - zpl_file_error err = ZPL_FILE_ERROR_NONE; - zpl_i64 prev_offset = zpl_file_tell(f); - zpl_file_seek(f, size); - if (!SetEndOfFile(f)) err = ZPL_FILE_ERROR_TRUNCATION_FAILURE; - zpl_file_seek(f, prev_offset); - return err; - } - - zpl_b32 zpl_fs_exists(char const *name) { - WIN32_FIND_DATAW data; - wchar_t *w_text; - void *handle; - zpl_b32 found = false; - zpl_allocator a = zpl_heap_allocator( ); - - w_text = zpl__alloc_utf8_to_ucs2(a, name, NULL); - if (w_text == NULL) { return false; } - handle = FindFirstFileW(w_text, &data); - zpl_free(a, w_text); - found = handle != INVALID_HANDLE_VALUE; - if (found) FindClose(handle); - return found; - } - - #else // POSIX - - zpl_file *zpl_file_get_standard(zpl_file_standard_type std) { - if (!zpl__std_file_set) { - #define ZPL__SET_STD_FILE(type, v) \ - zpl__std_files[type].fd.i = v; \ - zpl__std_files[type].ops = zpl_default_file_operations - ZPL__SET_STD_FILE(ZPL_FILE_STANDARD_INPUT, 0); - ZPL__SET_STD_FILE(ZPL_FILE_STANDARD_OUTPUT, 1); - ZPL__SET_STD_FILE(ZPL_FILE_STANDARD_ERROR, 2); - #undef ZPL__SET_STD_FILE - zpl__std_file_set = true; - } - return &zpl__std_files[std]; - } - - zpl_file_error zpl_file_truncate(zpl_file *f, zpl_i64 size) { - zpl_file_error err = ZPL_FILE_ERROR_NONE; - int i = ftruncate(f->fd.i, size); - if (i != 0) err = ZPL_FILE_ERROR_TRUNCATION_FAILURE; - return err; - } - - zpl_b32 zpl_fs_exists(char const *name) { return access(name, F_OK) != -1; } - - #endif - - zpl_i64 zpl_file_size(zpl_file *f) { - zpl_i64 size = 0; - zpl_i64 prev_offset = zpl_file_tell(f); - zpl_file_seek_to_end(f); - size = zpl_file_tell(f); - zpl_file_seek(f, prev_offset); - return size; - } - - zpl_file_error zpl_file_temp(zpl_file *file) { - zpl_zero_item(file); - FILE *fd = NULL; - - #if defined(ZPL_SYSTEM_WINDOWS) && !defined(ZPL_COMPILER_GCC) - errno_t errcode = tmpfile_s(&fd); - - if (errcode != 0) { - fd = NULL; - } - #else - fd = tmpfile(); - #endif - - if (fd == NULL) { return ZPL_FILE_ERROR_INVALID; } - - #if defined(ZPL_SYSTEM_WINDOWS) && !defined(ZPL_COMPILER_GCC) - file->fd.i = _get_osfhandle(_fileno(fd)); - #else - file->fd.i = fileno(fd); - #endif - file->ops = zpl_default_file_operations; - file->is_temp = true; - return ZPL_FILE_ERROR_NONE; - } - - zpl_file_contents zpl_file_read_contents(zpl_allocator a, zpl_b32 zero_terminate, char const *filepath) { - zpl_file_contents result = { 0 }; - zpl_file file = { 0 }; - - result.allocator = a; - - if (zpl_file_open(&file, filepath) == ZPL_FILE_ERROR_NONE) { - zpl_isize file_size = cast(zpl_isize) zpl_file_size(&file); - if (file_size > 0) { - result.data = zpl_alloc(a, zero_terminate ? file_size + 1 : file_size); - result.size = file_size; - zpl_file_read_at(&file, result.data, result.size, 0); - if (zero_terminate) { - zpl_u8 *str = cast(zpl_u8 *) result.data; - str[file_size] = '\0'; + + if (flags & ZPL_ALLOCATOR_FLAG_CLEAR_TO_ZERO) zpl_zero_size(ptr, size); + } break; + + case ZPL_ALLOCATION_FREE: { + if (old_memory) { + void *end = zpl_pointer_add(s->physical_start, s->total_size); + if (old_memory < s->physical_start || old_memory >= end) { + ZPL_ASSERT(false); + } else { + // NOTE: Mark as free + zpl_allocation_header_ev *h = zpl_allocation_header(old_memory); + ZPL_ASSERT((h->size & ZPL_ISIZE_HIGH_BIT) == 0); + h->size = h->size | ZPL_ISIZE_HIGH_BIT; + + while (s->free_point != s->alloc_point) { + zpl_allocation_header_ev *header = cast(zpl_allocation_header_ev *) s->free_point; + if ((header->size & ZPL_ISIZE_HIGH_BIT) == 0) break; + + s->free_point = zpl_pointer_add(s->free_point, h->size & (~ZPL_ISIZE_HIGH_BIT)); + if (s->free_point == end) s->free_point = s->physical_start; } } - zpl_file_close(&file); } + } break; + + case ZPL_ALLOCATION_FREE_ALL: + s->alloc_point = s->physical_start; + s->free_point = s->physical_start; + break; + + case ZPL_ALLOCATION_RESIZE: + ptr = zpl_default_resize_align(zpl_scratch_allocator(s), old_memory, old_size, size, alignment); + break; + } + + return ptr; +} - return result; - } - - void zpl_file_free_contents(zpl_file_contents *fc) { - ZPL_ASSERT_NOT_NULL(fc->data); - zpl_free(fc->allocator, fc->data); - fc->data = NULL; - fc->size = 0; - } - - zpl_b32 zpl_file_write_contents(char const* filepath, void const* buffer, zpl_isize size, zpl_file_error* err) { - zpl_file f = { 0 }; - zpl_file_error open_err; - zpl_b32 write_ok; - open_err = zpl_file_open_mode(&f, ZPL_FILE_MODE_WRITE, filepath); - - if (open_err != ZPL_FILE_ERROR_NONE) - { - if (err) - *err = open_err; - - return false; - } - - write_ok = zpl_file_write(&f, buffer, size); - zpl_file_close(&f); - return write_ok; - } - - char *zpl_file_read_lines(zpl_allocator alloc, zpl_array(char *)*lines, char const *filename, zpl_b32 strip_whitespace) { - zpl_file f = { 0 }; - zpl_file_open(&f, filename); - zpl_isize fsize = (zpl_isize)zpl_file_size(&f); - - char *contents = (char *)zpl_alloc(alloc, fsize + 1); - zpl_file_read(&f, contents, fsize); - contents[fsize] = 0; - *lines = zpl_str_split_lines(alloc, contents, strip_whitespace); - zpl_file_close(&f); - - return contents; - } - - #if !defined(_WINDOWS_) && defined(ZPL_SYSTEM_WINDOWS) - ZPL_IMPORT DWORD WINAPI GetFullPathNameA(char const *lpFileName, DWORD nBufferLength, char *lpBuffer, char **lpFilePart); - ZPL_IMPORT DWORD WINAPI GetFullPathNameW(wchar_t const *lpFileName, DWORD nBufferLength, wchar_t *lpBuffer, wchar_t **lpFilePart); - #endif - - ZPL_END_C_DECLS - // file: source/core/file_stream.c - - #ifdef ZPL_EDITOR - #include - #endif - - //////////////////////////////////////////////////////////////// - // - // Memory streaming - // - // - - ZPL_BEGIN_C_DECLS - - typedef struct { - zpl_u8 magic; - zpl_u8 *buf; //< zpl_array OR plain buffer if we can't write - zpl_isize cursor; - zpl_allocator alloc; - - zpl_file_stream_flags flags; - zpl_isize cap; - } zpl__memory_fd; - - #define ZPL__FILE_STREAM_FD_MAGIC 37 - - ZPL_ALWAYS_INLINE zpl_file_descriptor zpl__file_stream_fd_make(zpl__memory_fd* d) { - zpl_file_descriptor fd = {0}; - fd.p = (void*)d; - return fd; - } - - ZPL_ALWAYS_INLINE zpl__memory_fd *zpl__file_stream_from_fd(zpl_file_descriptor fd) { - zpl__memory_fd *d = (zpl__memory_fd*)fd.p; - ZPL_ASSERT(d->magic == ZPL__FILE_STREAM_FD_MAGIC); - return d; - } - - void zpl_file_stream_new(zpl_file* file, zpl_allocator allocator) { - ZPL_ASSERT_NOT_NULL(file); - zpl__memory_fd *d = (zpl__memory_fd*)zpl_alloc(allocator, zpl_size_of(zpl__memory_fd)); - zpl_zero_item(file); - d->magic = ZPL__FILE_STREAM_FD_MAGIC; - d->alloc = allocator; - d->flags = ZPL_FILE_STREAM_CLONE_WRITABLE; - d->cap = 0; - zpl_array_init(d->buf, allocator); - file->ops = zpl_memory_file_operations; - file->fd = zpl__file_stream_fd_make(d); - file->dir = NULL; - file->last_write_time = 0; - file->filename = NULL; - file->is_temp = true; - } - void zpl_file_stream_open(zpl_file* file, zpl_allocator allocator, zpl_u8 *buffer, zpl_isize size, zpl_file_stream_flags flags) { - ZPL_ASSERT_NOT_NULL(file); - zpl__memory_fd *d = (zpl__memory_fd*)zpl_alloc(allocator, zpl_size_of(zpl__memory_fd)); - zpl_zero_item(file); - d->magic = ZPL__FILE_STREAM_FD_MAGIC; - d->alloc = allocator; - d->flags = flags; - if (d->flags & ZPL_FILE_STREAM_CLONE_WRITABLE) { - zpl_array_init_reserve(d->buf, allocator, size); - zpl_memcopy(d->buf, buffer, size); - d->cap = zpl_array_count(d->buf) = size; - } else { - d->buf = buffer; - d->cap = size; - } - file->ops = zpl_memory_file_operations; - file->fd = zpl__file_stream_fd_make(d); - file->dir = NULL; - file->last_write_time = 0; - file->filename = NULL; - file->is_temp = true; - } - - zpl_u8 *zpl_file_stream_buf(zpl_file* file, zpl_isize *size) { - ZPL_ASSERT_NOT_NULL(file); - zpl__memory_fd *d = zpl__file_stream_from_fd(file->fd); - if (size) *size = d->cap; - return d->buf; - } - - zpl_internal ZPL_FILE_SEEK_PROC(zpl__memory_file_seek) { - zpl__memory_fd *d = zpl__file_stream_from_fd(fd); - zpl_isize buflen = d->cap; - - if (whence == ZPL_SEEK_WHENCE_BEGIN) - d->cursor = 0; - else if (whence == ZPL_SEEK_WHENCE_END) - d->cursor = buflen; - - d->cursor = zpl_max(0, zpl_clamp(d->cursor + offset, 0, buflen)); - if (new_offset) *new_offset = d->cursor; - return true; - } - - zpl_internal ZPL_FILE_READ_AT_PROC(zpl__memory_file_read) { - zpl_unused(stop_at_newline); - zpl__memory_fd *d = zpl__file_stream_from_fd(fd); - zpl_memcopy(buffer, d->buf + offset, size); - if (bytes_read) *bytes_read = size; - return true; - } - - zpl_internal ZPL_FILE_WRITE_AT_PROC(zpl__memory_file_write) { - zpl__memory_fd *d = zpl__file_stream_from_fd(fd); - if (!(d->flags & (ZPL_FILE_STREAM_CLONE_WRITABLE|ZPL_FILE_STREAM_WRITABLE))) - return false; - zpl_isize buflen = d->cap; - zpl_isize extralen = zpl_max(0, size-(buflen-offset)); - zpl_isize rwlen = size-extralen; - zpl_isize new_cap = buflen+extralen; - if (d->flags & ZPL_FILE_STREAM_CLONE_WRITABLE) { - if(zpl_array_capacity(d->buf) < new_cap) { - zpl_array_grow(d->buf, (zpl_i64)(new_cap)); +// +// Stack Memory Allocator +// +ZPL_ALLOCATOR_PROC(zpl_stack_allocator_proc) { + zpl_stack_memory *s = cast(zpl_stack_memory *) allocator_data; + void *ptr = NULL; + ZPL_ASSERT_NOT_NULL(s); + zpl_unused(old_size); + zpl_unused(flags); + + switch (type) { + case ZPL_ALLOCATION_ALLOC: { + size += ZPL_STACK_ALLOC_OFFSET; + zpl_u64 alloc_offset = s->allocated; + + void *curr = + cast(zpl_u64 *) zpl_align_forward(cast(zpl_u64 *) zpl_pointer_add(s->physical_start, s->allocated), alignment); + + if (cast(zpl_u64 *) zpl_pointer_add(curr, size) > cast(zpl_u64 *) zpl_pointer_add(s->physical_start, s->total_size)) { + if (s->backing.proc) { + void *old_start = s->physical_start; + s->physical_start = + zpl_resize_align(s->backing, s->physical_start, s->total_size, s->total_size + size, alignment); + curr = cast(zpl_u64 *) + zpl_align_forward(cast(zpl_u64 *) zpl_pointer_add(s->physical_start, s->allocated), alignment); + s->total_size = zpl_pointer_diff(old_start, s->physical_start); + } else { + ZPL_PANIC("Can not resize stack's memory! Allocator not defined!"); } } - zpl_memcopy(d->buf + offset, buffer, rwlen); - - if ((d->flags & ZPL_FILE_STREAM_CLONE_WRITABLE) && extralen > 0) { - zpl_memcopy(d->buf + offset + rwlen, zpl_ptr_add_const(buffer, rwlen), extralen); - d->cap = zpl_array_count(d->buf) = new_cap; - } else { - extralen = 0; + + s->allocated = zpl_pointer_diff(s->physical_start, curr) + size; + + *(zpl_u64 *)curr = alloc_offset; + curr = zpl_pointer_add(curr, ZPL_STACK_ALLOC_OFFSET); + + ptr = curr; + } break; + + case ZPL_ALLOCATION_FREE: { + if (old_memory) { + void *curr = old_memory; + curr = zpl_pointer_sub(curr, ZPL_STACK_ALLOC_OFFSET); + + zpl_u64 alloc_offset = *(zpl_u64 *)curr; + s->allocated = (zpl_usize)alloc_offset; } + } break; + + case ZPL_ALLOCATION_FREE_ALL: { + s->allocated = 0; + } break; + + case ZPL_ALLOCATION_RESIZE: { + ZPL_PANIC("You cannot resize something allocated by a stack."); + } break; + } + return ptr; +} - if (bytes_written) *bytes_written = (rwlen+extralen); - return true; +ZPL_END_C_DECLS +// file: source/core/array.c + +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +ZPL_NEVER_INLINE void *zpl__array_set_capacity(void *array, zpl_isize capacity, zpl_isize element_size) { + zpl_array_header *h = ZPL_ARRAY_HEADER(array); + + ZPL_ASSERT(element_size > 0); + + if (capacity == h->capacity) return array; + + if (capacity < h->count) { + if (h->capacity < capacity) { + zpl_isize new_capacity = ZPL_ARRAY_GROW_FORMULA(h->capacity); + if (new_capacity < capacity) new_capacity = capacity; + zpl__array_set_capacity(array, new_capacity, element_size); } + h->count = capacity; + } + + { + zpl_isize size = zpl_size_of(zpl_array_header) + element_size * capacity; + zpl_array_header *nh = cast(zpl_array_header *) zpl_alloc(h->allocator, size); + zpl_memmove(nh, h, zpl_size_of(zpl_array_header) + element_size * h->count); + nh->allocator = h->allocator; + nh->count = h->count; + nh->data = (char *)nh + 1; + nh->capacity = capacity; + zpl_free(h->allocator, h); + return nh + 1; + } +} - zpl_internal ZPL_FILE_CLOSE_PROC(zpl__memory_file_close) { - zpl__memory_fd *d = zpl__file_stream_from_fd(fd); - zpl_allocator alloc = d->alloc; - if (d->flags & ZPL_FILE_STREAM_CLONE_WRITABLE) - zpl_array_free(d->buf); - zpl_free(alloc, d); +ZPL_END_C_DECLS +// file: source/core/string.c + +//////////////////////////////////////////////////////////////// +// +// Char things +// +// +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +zpl_internal zpl_isize zpl__scan_zpl_i64(const char *text, zpl_i32 base, zpl_i64 *value) { + const char *text_begin = text; + zpl_i64 result = 0; + zpl_b32 negative = false; + + if (*text == '-') { + negative = true; + text++; + } + + if (base == 16 && zpl_strncmp(text, "0x", 2) == 0) text += 2; + + for (;;) { + zpl_i64 v; + if (zpl_char_is_digit(*text)) + v = *text - '0'; + else if (base == 16 && zpl_char_is_hex_digit(*text)) + v = zpl_hex_digit_to_int(*text); + else + break; + + result *= base; + result += v; + text++; + } + + if (value) { + if (negative) result = -result; + *value = result; + } + + return (text - text_begin); +} + +zpl_internal zpl_isize zpl__scan_zpl_u64(const char *text, zpl_i32 base, zpl_u64 *value) { + const char *text_begin = text; + zpl_u64 result = 0; + + if (base == 16 && zpl_strncmp(text, "0x", 2) == 0) text += 2; + + for (;;) { + zpl_u64 v; + if (zpl_char_is_digit(*text)) + v = *text - '0'; + else if (base == 16 && zpl_char_is_hex_digit(*text)) + v = zpl_hex_digit_to_int(*text); + else { + break; } + + result *= base; + result += v; + text++; + } + + if (value) *value = result; + + return (text - text_begin); +} - zpl_file_operations const zpl_memory_file_operations = { zpl__memory_file_read, zpl__memory_file_write, - zpl__memory_file_seek, zpl__memory_file_close }; +// TODO: Make better +zpl_u64 zpl_str_to_u64(const char *str, char **end_ptr, zpl_i32 base) { + zpl_isize len; + zpl_u64 value = 0; + + if (!base) { + if ((zpl_strlen(str) > 2) && (zpl_strncmp(str, "0x", 2) == 0)) + base = 16; + else + base = 10; + } + + len = zpl__scan_zpl_u64(str, base, &value); + if (end_ptr) *end_ptr = (char *)str + len; + return value; +} - ZPL_END_C_DECLS - // file: source/core/file_misc.c +zpl_i64 zpl_str_to_i64(const char *str, char **end_ptr, zpl_i32 base) { + zpl_isize len; + zpl_i64 value; + + if (!base) { + if ((zpl_strlen(str) > 2) && (zpl_strncmp(str, "0x", 2) == 0)) + base = 16; + else + base = 10; + } + + len = zpl__scan_zpl_i64(str, base, &value); + if (end_ptr) *end_ptr = (char *)str + len; + return value; +} - #ifdef ZPL_EDITOR - #include - #endif +// TODO: Are these good enough for characters? +zpl_global const char zpl__num_to_char_table[] = "0123456789" +"ABCDEFGHIJKLMNOPQRSTUVWXYZ" +"abcdefghijklmnopqrstuvwxyz" +"@$"; - #if defined(ZPL_SYSTEM_UNIX) || defined(ZPL_SYSTEM_MACOS) - #include - #endif +void zpl_i64_to_str(zpl_i64 value, char *string, zpl_i32 base) { + char *buf = string; + zpl_b32 negative = false; + zpl_u64 v; + + if (value < 0) { + negative = true; + value = -value; + } + + v = cast(zpl_u64) value; + if (v != 0) { + while (v > 0) { + *buf++ = zpl__num_to_char_table[v % base]; + v /= base; + } + } else { + *buf++ = '0'; + } + if (negative) *buf++ = '-'; + *buf = '\0'; + zpl_strrev(string); +} - #if defined(ZPL_SYSTEM_UNIX) && !defined(ZPL_SYSTEM_FREEBSD) && !defined(ZPL_SYSTEM_OPENBSD) && !defined(ZPL_SYSTEM_CYGWIN) - #include - #endif +void zpl_u64_to_str(zpl_u64 value, char *string, zpl_i32 base) { + char *buf = string; + + if (value) { + while (value > 0) { + *buf++ = zpl__num_to_char_table[value % base]; + value /= base; + } + } else { + *buf++ = '0'; + } + *buf = '\0'; + + zpl_strrev(string); +} - #if defined(ZPL_SYSTEM_WINDOWS) - # include - # include - #endif - - #if defined(ZPL_SYSTEM_CYGWIN) - # include - # include - # include - #endif - - ZPL_BEGIN_C_DECLS +zpl_f64 zpl_str_to_f64(const char *str, char **end_ptr) { + zpl_f64 result, value, sign, scale; + zpl_i32 frac; + + while (zpl_char_is_space(*str)) { str++; } + + sign = 1.0; + if (*str == '-') { + sign = -1.0; + str++; + } else if (*str == '+') { + str++; + } + + for (value = 0.0; zpl_char_is_digit(*str); str++) { value = value * 10.0 + (*str - '0'); } + + if (*str == '.') { + zpl_f64 pow10 = 10.0; + str++; + while (zpl_char_is_digit(*str)) { + value += (*str - '0') / pow10; + pow10 *= 10.0; + str++; + } + } + + frac = 0; + scale = 1.0; + if ((*str == 'e') || (*str == 'E')) { + zpl_u32 exp; + + str++; + if (*str == '-') { + frac = 1; + str++; + } else if (*str == '+') { + str++; + } + + for (exp = 0; zpl_char_is_digit(*str); str++) { exp = exp * 10 + (*str - '0'); } + if (exp > 308) exp = 308; + + while (exp >= 50) { + scale *= 1e50; + exp -= 50; + } + while (exp >= 8) { + scale *= 1e8; + exp -= 8; + } + while (exp > 0) { + scale *= 10.0; + exp -= 1; + } + } + + result = sign * (frac ? (value / scale) : (value * scale)); + + if (end_ptr) *end_ptr = cast(char *) str; + + return result; +} - #if defined(ZPL_SYSTEM_WINDOWS) || defined(ZPL_SYSTEM_CYGWIN) - zpl_file_time zpl_fs_last_write_time(char const *filepath) { - ULARGE_INTEGER li = { 0 }; - FILETIME last_write_time = { 0 }; - WIN32_FILE_ATTRIBUTE_DATA data = { 0 }; - zpl_allocator a = zpl_heap_allocator( ); - wchar_t *w_text = zpl__alloc_utf8_to_ucs2(a, filepath, NULL); - if (w_text == NULL) { return 0; } - if (GetFileAttributesExW(w_text, GetFileExInfoStandard, &data)) last_write_time = data.ftLastWriteTime; +//////////////////////////////////////////////////////////////// +// +// Windows UTF-8 Handling +// +// - zpl_free(a, w_text); - - li.LowPart = last_write_time.dwLowDateTime; - li.HighPart = last_write_time.dwHighDateTime; - return cast(zpl_file_time) li.QuadPart; - } - - zpl_b32 zpl_fs_copy(char const *existing_filename, char const *new_filename, zpl_b32 fail_if_exists) { - zpl_b32 result = false; - zpl_allocator a = zpl_heap_allocator( ); - - wchar_t *w_old = zpl__alloc_utf8_to_ucs2(a, existing_filename, NULL); - if (w_old == NULL) { return false; } - - wchar_t *w_new = zpl__alloc_utf8_to_ucs2(a, new_filename, NULL); - if (w_new != NULL) { result = CopyFileW(w_old, w_new, fail_if_exists); } - - zpl_free(a, w_old); - zpl_free(a, w_new); - return result; - } - - zpl_b32 zpl_fs_move(char const *existing_filename, char const *new_filename) { - zpl_b32 result = false; - zpl_allocator a = zpl_heap_allocator( ); - - wchar_t *w_old = zpl__alloc_utf8_to_ucs2(a, existing_filename, NULL); - if (w_old == NULL) { return false; } - - wchar_t *w_new = zpl__alloc_utf8_to_ucs2(a, new_filename, NULL); - if (w_new != NULL) { result = MoveFileW(w_old, w_new); } - - zpl_free(a, w_old); - zpl_free(a, w_new); - return result; - } - - zpl_b32 zpl_fs_remove(char const *filename) { - zpl_b32 result = false; - zpl_allocator a = zpl_heap_allocator( ); - - wchar_t *w_filename = zpl__alloc_utf8_to_ucs2(a, filename, NULL); - if (w_filename == NULL) { return false; } - - result = DeleteFileW(w_filename); - - zpl_free(a, w_filename); - return result; - } - - #else - - zpl_file_time zpl_fs_last_write_time(char const *filepath) { - time_t result = 0; - struct stat file_stat; - - if (stat(filepath, &file_stat)) result = file_stat.st_mtime; - - return cast(zpl_file_time) result; - } - - #if defined(ZPL_SYSTEM_FREEBSD) - #include - #include - #include - #endif - - - zpl_b32 zpl_fs_copy(char const *existing_filename, char const *new_filename, zpl_b32 fail_if_exists) { - zpl_unused(fail_if_exists); - #if defined(ZPL_SYSTEM_OSX) - return copyfile(existing_filename, new_filename, NULL, COPYFILE_DATA) == 0; - #elif defined(ZPL_SYSTEM_OPENBSD) - ZPL_NOT_IMPLEMENTED; - return 0; - #else - int existing_fd = open(existing_filename, O_RDONLY, 0); - struct stat stat_existing; - fstat(existing_fd, &stat_existing); - - zpl_isize size; - int new_fd = open(new_filename, O_WRONLY | O_CREAT, stat_existing.st_mode); - - #if defined(ZPL_SYSTEM_FREEBSD) - size = sendfile(new_fd, existing_fd, 0, stat_existing.st_size, NULL, 0, 0); - #else - size = sendfile(new_fd, existing_fd, 0, stat_existing.st_size); - #endif - - close(new_fd); - close(existing_fd); - - return size == stat_existing.st_size; - #endif - } - - zpl_b32 zpl_fs_move(char const *existing_filename, char const *new_filename) { - if (link(existing_filename, new_filename) == 0) { return (unlink(existing_filename) != -1); } - return false; - } - - zpl_b32 zpl_fs_remove(char const *filename) { - #if defined(ZPL_SYSTEM_OSX) || defined(ZPL_SYSTEM_EMSCRIPTEN) - return (unlink(filename) != -1); - #else - return (remove(filename) == 0); - #endif - } - - #endif - - char *zpl_path_get_full_name(zpl_allocator a, char const *path) { - #if defined(ZPL_SYSTEM_WINDOWS) - wchar_t *w_path = NULL; - wchar_t *w_fullpath = NULL; - zpl_isize w_len = 0; - zpl_isize new_len = 0; - zpl_isize new_len1 = 0; - char *new_path = 0; - - w_path = zpl__alloc_utf8_to_ucs2(zpl_heap_allocator( ), path, NULL); - if (w_path == NULL) { return NULL; } - - w_len = GetFullPathNameW(w_path, 0, NULL, NULL); - if (w_len == 0) { return NULL; } - - w_fullpath = zpl_alloc_array(zpl_heap_allocator( ), wchar_t, w_len + 1); - GetFullPathNameW(w_path, cast(int) w_len, w_fullpath, NULL); - w_fullpath[w_len] = 0; - - zpl_free(zpl_heap_allocator( ), w_path); - - new_len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, w_fullpath, cast(int) w_len, NULL, 0, NULL, NULL); - - if (new_len == 0) { - zpl_free(zpl_heap_allocator( ), w_fullpath); +zpl_u16 *zpl_utf8_to_ucs2(zpl_u16 *buffer, zpl_isize len, zpl_u8 const *str) { + zpl_rune c; + zpl_isize i = 0; + len--; + while (*str) { + if (i >= len) return NULL; + if (!(*str & 0x80)) { + buffer[i++] = *str++; + } else if ((*str & 0xe0) == 0xc0) { + if (*str < 0xc2) return NULL; + c = (*str++ & 0x1f) << 6; + if ((*str & 0xc0) != 0x80) return NULL; + buffer[i++] = cast(zpl_u16)(c + (*str++ & 0x3f)); + } else if ((*str & 0xf0) == 0xe0) { + if (*str == 0xe0 && (str[1] < 0xa0 || str[1] > 0xbf)) return NULL; + if (*str == 0xed && str[1] > 0x9f) // str[1] < 0x80 is checked below return NULL; - } - - new_path = zpl_alloc_array(a, char, new_len); - new_len1 = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, w_fullpath, cast(int) w_len, new_path, - cast(int) new_len, NULL, NULL); - - if (new_len1 == 0) { - zpl_free(zpl_heap_allocator( ), w_fullpath); - zpl_free(a, new_path); + c = (*str++ & 0x0f) << 12; + if ((*str & 0xc0) != 0x80) return NULL; + c += (*str++ & 0x3f) << 6; + if ((*str & 0xc0) != 0x80) return NULL; + buffer[i++] = cast(zpl_u16)(c + (*str++ & 0x3f)); + } else if ((*str & 0xf8) == 0xf0) { + if (*str > 0xf4) return NULL; + if (*str == 0xf0 && (str[1] < 0x90 || str[1] > 0xbf)) return NULL; + if (*str == 0xf4 && str[1] > 0x8f) // str[1] < 0x80 is checked below return NULL; + c = (*str++ & 0x07) << 18; + if ((*str & 0xc0) != 0x80) return NULL; + c += (*str++ & 0x3f) << 12; + if ((*str & 0xc0) != 0x80) return NULL; + c += (*str++ & 0x3f) << 6; + if ((*str & 0xc0) != 0x80) return NULL; + c += (*str++ & 0x3f); + // UTF-8 encodings of values used in surrogate pairs are invalid + if ((c & 0xfffff800) == 0xd800) return NULL; + if (c >= 0x10000) { + c -= 0x10000; + if (i + 2 > len) return NULL; + buffer[i++] = 0xd800 | (0x3ff & (c >> 10)); + buffer[i++] = 0xdc00 | (0x3ff & (c)); } - - new_path[new_len] = 0; - return new_path; - #else - char *p, *result, *fullpath = NULL; - zpl_isize len; - p = realpath(path, NULL); - fullpath = p; - if (p == NULL) { - // NOTE(bill): File does not exist - fullpath = cast(char *) path; - } - - len = zpl_strlen(fullpath); - - result = zpl_alloc_array(a, char, len + 1); - zpl_memmove(result, fullpath, len); - result[len] = 0; - zpl_free(a, p); - - return result; - #endif + } else { + return NULL; } + } + buffer[i] = 0; + return buffer; +} - zpl_file_error zpl_path_mkdir(char const *path, zpl_i32 mode) { - zpl_i32 error = 0; - #if defined(ZPL_SYSTEM_WINDOWS) - error = _wmkdir((const wchar_t *)zpl_utf8_to_ucs2_buf((const zpl_u8 *)path)); - #else - error = mkdir(path, (mode_t)mode); - #endif - - if (error == 0) { return ZPL_FILE_ERROR_NONE; } - - switch (errno) { - case EPERM: - case EACCES: return ZPL_FILE_ERROR_PERMISSION; - case EEXIST: return ZPL_FILE_ERROR_EXISTS; - case ENAMETOOLONG: return ZPL_FILE_ERROR_NAME_TOO_LONG; - } - - return ZPL_FILE_ERROR_UNKNOWN; +zpl_u8 *zpl_ucs2_to_utf8(zpl_u8 *buffer, zpl_isize len, zpl_u16 const *str) { + zpl_isize i = 0; + len--; + while (*str) { + if (*str < 0x80) { + if (i + 1 > len) return NULL; + buffer[i++] = (char)*str++; + } else if (*str < 0x800) { + if (i + 2 > len) return NULL; + buffer[i++] = cast(char)(0xc0 + (*str >> 6)); + buffer[i++] = cast(char)(0x80 + (*str & 0x3f)); + str += 1; + } else if (*str >= 0xd800 && *str < 0xdc00) { + zpl_rune c; + if (i + 4 > len) return NULL; + c = ((str[0] - 0xd800) << 10) + ((str[1]) - 0xdc00) + 0x10000; + buffer[i++] = cast(char)(0xf0 + (c >> 18)); + buffer[i++] = cast(char)(0x80 + ((c >> 12) & 0x3f)); + buffer[i++] = cast(char)(0x80 + ((c >> 6) & 0x3f)); + buffer[i++] = cast(char)(0x80 + ((c)&0x3f)); + str += 2; + } else if (*str >= 0xdc00 && *str < 0xe000) { + return NULL; + } else { + if (i + 3 > len) return NULL; + buffer[i++] = 0xe0 + (*str >> 12); + buffer[i++] = 0x80 + ((*str >> 6) & 0x3f); + buffer[i++] = 0x80 + ((*str) & 0x3f); + str += 1; } + } + buffer[i] = 0; + return buffer; +} - zpl_file_error zpl_path_rmdir(char const *path) { - zpl_i32 error = 0; - #if defined(ZPL_SYSTEM_WINDOWS) - error = _wrmdir((const wchar_t *)zpl_utf8_to_ucs2_buf((const zpl_u8 *)path)); - #else - error = rmdir(path); - #endif +zpl_u16 *zpl_utf8_to_ucs2_buf(zpl_u8 const *str) { // NOTE: Uses locally persisting buffer + zpl_local_persist zpl_u16 buf[4096]; + return zpl_utf8_to_ucs2(buf, zpl_count_of(buf), str); +} - if (error == 0) { return ZPL_FILE_ERROR_NONE; } +zpl_u8 *zpl_ucs2_to_utf8_buf(zpl_u16 const *str) { // NOTE: Uses locally persisting buffer + zpl_local_persist zpl_u8 buf[4096]; + return zpl_ucs2_to_utf8(buf, zpl_count_of(buf), str); +} - switch (errno) { - case EPERM: - case EACCES: return ZPL_FILE_ERROR_PERMISSION; - case ENOENT: return ZPL_FILE_ERROR_NOT_EXISTS; - case ENOTEMPTY: return ZPL_FILE_ERROR_NOT_EMPTY; - case ENAMETOOLONG: return ZPL_FILE_ERROR_NAME_TOO_LONG; - } +zpl_global zpl_u8 const zpl__utf8_first[256] = { + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x00-0x0F + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x10-0x1F + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x20-0x2F + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x30-0x3F + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x40-0x4F + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x50-0x5F + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x60-0x6F + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x70-0x7F + 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0x80-0x8F + 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0x90-0x9F + 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xA0-0xAF + 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xB0-0xBF + 0xf1, 0xf1, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, // 0xC0-0xCF + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, // 0xD0-0xDF + 0x13, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x23, 0x03, 0x03, // 0xE0-0xEF + 0x34, 0x04, 0x04, 0x04, 0x44, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xF0-0xFF +}; - return ZPL_FILE_ERROR_UNKNOWN; + +typedef struct zpl_utf8_accept_range { + zpl_u8 lo, hi; +} zpl_utf8_accept_range; + +zpl_global zpl_utf8_accept_range const zpl__utf8_accept_ranges[] = { + { 0x80, 0xbf }, { 0xa0, 0xbf }, { 0x80, 0x9f }, { 0x90, 0xbf }, { 0x80, 0x8f }, +}; + +zpl_isize zpl_utf8_decode(zpl_u8 const *str, zpl_isize str_len, zpl_rune *codepoint_out) { + + zpl_isize width = 0; + zpl_rune codepoint = ZPL_RUNE_INVALID; + + if (str_len > 0) { + zpl_u8 s0 = str[0]; + zpl_u8 x = zpl__utf8_first[s0], sz; + zpl_u8 b1, b2, b3; + zpl_utf8_accept_range accept; + if (x >= 0xf0) { + zpl_rune mask = (cast(zpl_rune) x << 31) >> 31; + codepoint = (cast(zpl_rune) s0 & (~mask)) | (ZPL_RUNE_INVALID & mask); + width = 1; + goto end; } - - void zpl__file_direntry(zpl_allocator alloc, char const *dirname, zpl_string *output, zpl_b32 recurse) { - #if defined(ZPL_SYSTEM_UNIX) || defined(ZPL_SYSTEM_OSX) - DIR *d, *cd; - struct dirent *dir; - d = opendir(dirname); - - if (d) { - while ((dir = readdir(d))) { - if (!zpl_strncmp(dir->d_name, "..", 2)) continue; - if (dir->d_name[0] == '.' && dir->d_name[1] == 0) continue; - - zpl_string dirpath = zpl_string_make(alloc, dirname); - dirpath = zpl_string_appendc(dirpath, "/"); - dirpath = zpl_string_appendc(dirpath, dir->d_name); - - *output = zpl_string_appendc(*output, dirpath); - *output = zpl_string_appendc(*output, "\n"); - - if (recurse && (cd = opendir(dirpath)) != NULL) { zpl__file_direntry(alloc, dirpath, output, recurse); } - zpl_string_free(dirpath); - } - } - #elif defined(ZPL_SYSTEM_WINDOWS) - zpl_usize length = zpl_strlen(dirname); - struct _wfinddata_t data; - zpl_intptr findhandle; - - char directory[MAX_PATH] = { 0 }; - zpl_strncpy(directory, dirname, length); - - // keeping it native - for (zpl_usize i = 0; i < length; i++) { - if (directory[i] == '/') directory[i] = '\\'; - } - - // remove trailing slashses - if (directory[length - 1] == '\\') { directory[length - 1] = '\0'; } - - // attach search pattern - zpl_string findpath = zpl_string_make(alloc, directory); - findpath = zpl_string_appendc(findpath, "\\"); - findpath = zpl_string_appendc(findpath, "*"); - - findhandle = _wfindfirst((const wchar_t *)zpl_utf8_to_ucs2_buf((const zpl_u8 *)findpath), &data); - zpl_string_free(findpath); - - if (findhandle != -1) { - do { - char *filename = (char *)zpl_ucs2_to_utf8_buf((const zpl_u16 *)data.name); - if (!zpl_strncmp(filename, "..", 2)) continue; - if (filename[0] == '.' && filename[1] == 0) continue; - - zpl_string dirpath = zpl_string_make(alloc, directory); - dirpath = zpl_string_appendc(dirpath, "\\"); - dirpath = zpl_string_appendc(dirpath, filename); - - *output = zpl_string_appendc(*output, dirpath); - *output = zpl_string_appendc(*output, "\n"); - - if (recurse && (data.attrib & _A_SUBDIR)) { zpl__file_direntry(alloc, dirpath, output, recurse); } - - zpl_string_free(dirpath); - } while (_wfindnext(findhandle, &data) != -1); - _findclose(findhandle); - } - #else - // TODO: Implement other OSes - #endif + if (s0 < 0x80) { + codepoint = s0; + width = 1; + goto end; } - - zpl_string zpl_path_dirlist(zpl_allocator alloc, char const *dirname, zpl_b32 recurse) { - zpl_string buf = zpl_string_make_reserve(alloc, 4); - zpl__file_direntry(alloc, dirname, &buf, recurse); - return buf; + + sz = x & 7; + accept = zpl__utf8_accept_ranges[x >> 4]; + if (str_len < sz) goto invalid_codepoint; + + b1 = str[1]; + if (b1 < accept.lo || accept.hi < b1) goto invalid_codepoint; + + if (sz == 2) { + codepoint = (cast(zpl_rune) s0 & 0x1f) << 6 | (cast(zpl_rune) b1 & 0x3f); + width = 2; + goto end; } + + b2 = str[2]; + if (!zpl_is_between(b2, 0x80, 0xbf)) goto invalid_codepoint; + + if (sz == 3) { + codepoint = (cast(zpl_rune) s0 & 0x1f) << 12 | (cast(zpl_rune) b1 & 0x3f) << 6 | (cast(zpl_rune) b2 & 0x3f); + width = 3; + goto end; + } + + b3 = str[3]; + if (!zpl_is_between(b3, 0x80, 0xbf)) goto invalid_codepoint; + + codepoint = (cast(zpl_rune) s0 & 0x07) << 18 | (cast(zpl_rune) b1 & 0x3f) << 12 | (cast(zpl_rune) b2 & 0x3f) << 6 | + (cast(zpl_rune) b3 & 0x3f); + width = 4; + goto end; + + invalid_codepoint: + codepoint = ZPL_RUNE_INVALID; + width = 1; + } + + end: + if (codepoint_out) *codepoint_out = codepoint; + return width; +} - void zpl_dirinfo_init(zpl_dir_info *dir, char const *path) { - ZPL_ASSERT_NOT_NULL(dir); +zpl_isize zpl_utf8_codepoint_size(zpl_u8 const *str, zpl_isize str_len) { + zpl_isize i = 0; + for (; i < str_len && str[i]; i++) { + if ((str[i] & 0xc0) != 0x80) break; + } + return i + 1; +} - zpl_dir_info dir_ = {0}; - *dir = dir_; - dir->fullpath = (char const*)zpl_malloc(zpl_strlen(path)); - zpl_strcpy((char *)dir->fullpath, path); +zpl_isize zpl_utf8_encode_rune(zpl_u8 buf[4], zpl_rune r) { + zpl_u32 i = cast(zpl_u32) r; + zpl_u8 mask = 0x3f; + if (i <= (1 << 7) - 1) { + buf[0] = cast(zpl_u8) r; + return 1; + } + if (i <= (1 << 11) - 1) { + buf[0] = 0xc0 | cast(zpl_u8)(r >> 6); + buf[1] = 0x80 | (cast(zpl_u8)(r) & mask); + return 2; + } + + // Invalid or Surrogate range + if (i > ZPL_RUNE_MAX || zpl_is_between(i, 0xd800, 0xdfff)) { + r = ZPL_RUNE_INVALID; + + buf[0] = 0xe0 | cast(zpl_u8)(r >> 12); + buf[1] = 0x80 | (cast(zpl_u8)(r >> 6) & mask); + buf[2] = 0x80 | (cast(zpl_u8)(r) & mask); + return 3; + } + + if (i <= (1 << 16) - 1) { + buf[0] = 0xe0 | cast(zpl_u8)(r >> 12); + buf[1] = 0x80 | (cast(zpl_u8)(r >> 6) & mask); + buf[2] = 0x80 | (cast(zpl_u8)(r) & mask); + return 3; + } + + buf[0] = 0xf0 | cast(zpl_u8)(r >> 18); + buf[1] = 0x80 | (cast(zpl_u8)(r >> 12) & mask); + buf[2] = 0x80 | (cast(zpl_u8)(r >> 6) & mask); + buf[3] = 0x80 | (cast(zpl_u8)(r) & mask); + return 4; +} + +ZPL_END_C_DECLS +// file: source/core/stringlib.c + +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +zpl_string zpl_string_make_reserve(zpl_allocator a, zpl_isize capacity) { + zpl_isize header_size = zpl_size_of(zpl_string_header); + void *ptr = zpl_alloc(a, header_size + capacity + 1); + + zpl_string str; + zpl_string_header *header; + + if (ptr == NULL) return NULL; + zpl_zero_size(ptr, header_size + capacity + 1); + + str = cast(char *) ptr + header_size; + header = ZPL_STRING_HEADER(str); + header->allocator = a; + header->length = 0; + header->capacity = capacity; + str[capacity] = '\0'; + + return str; +} - zpl_string dirlist = zpl_path_dirlist(zpl_heap(), path, false); - char **files=zpl_str_split_lines(zpl_heap(), dirlist, false); - dir->filenames = files; - dir->buf = dirlist; +zpl_string zpl_string_make_length(zpl_allocator a, void const *init_str, zpl_isize num_bytes) { + zpl_isize header_size = zpl_size_of(zpl_string_header); + void *ptr = zpl_alloc(a, header_size + num_bytes + 1); + + zpl_string str; + zpl_string_header *header; + + if (ptr == NULL) return NULL; + if (!init_str) zpl_zero_size(ptr, header_size + num_bytes + 1); + + str = cast(char *) ptr + header_size; + header = ZPL_STRING_HEADER(str); + header->allocator = a; + header->length = num_bytes; + header->capacity = num_bytes; + if (num_bytes && init_str) zpl_memcopy(str, init_str, num_bytes); + str[num_bytes] = '\0'; + + return str; +} - zpl_array_init(dir->entries, zpl_heap()); +zpl_string zpl_string_sprintf_buf(zpl_allocator a, const char *fmt, ...) { + zpl_local_persist char buf[4096] = { 0 }; + va_list va; + va_start(va, fmt); + zpl_snprintf_va(buf, 4096, fmt, va); + va_end(va); + + return zpl_string_make(a, buf); +} - for (zpl_i32 i=0; ientries, entry); +zpl_string zpl_string_append_length(zpl_string str, void const *other, zpl_isize other_len) { + if (other_len > 0) { + zpl_isize curr_len = zpl_string_length(str); + + str = zpl_string_make_space_for(str, other_len); + if (str == NULL) return NULL; + + zpl_memcopy(str + curr_len, other, other_len); + str[curr_len + other_len] = '\0'; + zpl__set_string_length(str, curr_len + other_len); + } + return str; +} + +ZPL_ALWAYS_INLINE zpl_string zpl_string_appendc(zpl_string str, const char *other) { + return zpl_string_append_length(str, other, zpl_strlen(other)); +} + +ZPL_ALWAYS_INLINE zpl_string zpl_string_join(zpl_allocator a, const char **parts, zpl_isize count, const char *glue) { + zpl_string ret; + zpl_isize i; + + ret = zpl_string_make(a, NULL); + + for (i=0; i= add_len) { + return str; + } else { + zpl_isize new_len, old_size, new_size; + void *ptr, *new_ptr; + zpl_allocator a = ZPL_STRING_HEADER(str)->allocator; + zpl_string_header *header; + + new_len = zpl_string_length(str) + add_len; + ptr = ZPL_STRING_HEADER(str); + old_size = zpl_size_of(zpl_string_header) + zpl_string_length(str) + 1; + new_size = zpl_size_of(zpl_string_header) + new_len + 1; + + new_ptr = zpl_resize(a, ptr, old_size, new_size); + if (new_ptr == NULL) return NULL; + + header = cast(zpl_string_header *) new_ptr; + header->allocator = a; + + str = cast(zpl_string)(header + 1); + zpl__set_string_capacity(str, new_len); + + return str; + } +} + +zpl_isize zpl_string_allocation_size(zpl_string const str) { + zpl_isize cap = zpl_string_capacity(str); + return zpl_size_of(zpl_string_header) + cap; +} + +zpl_b32 zpl_string_are_equal(zpl_string const lhs, zpl_string const rhs) { + zpl_isize lhs_len, rhs_len, i; + lhs_len = zpl_string_length(lhs); + rhs_len = zpl_string_length(rhs); + if (lhs_len != rhs_len) return false; + + for (i = 0; i < lhs_len; i++) { + if (lhs[i] != rhs[i]) return false; + } + + return true; +} + +zpl_string zpl_string_trim(zpl_string str, const char *cut_set) { + char *start, *end, *start_pos, *end_pos; + zpl_isize len; + + start_pos = start = str; + end_pos = end = str + zpl_string_length(str) - 1; + + while (start_pos <= end && zpl_char_first_occurence(cut_set, *start_pos)) start_pos++; + while (end_pos > start_pos && zpl_char_first_occurence(cut_set, *end_pos)) end_pos--; + + len = cast(zpl_isize)((start_pos > end_pos) ? 0 : ((end_pos - start_pos) + 1)); + + if (str != start_pos) zpl_memmove(str, start_pos, len); + str[len] = '\0'; + + zpl__set_string_length(str, len); + + return str; +} + +zpl_string zpl_string_append_rune(zpl_string str, zpl_rune r) { + if (r >= 0) { + zpl_u8 buf[8] = { 0 }; + zpl_isize len = zpl_utf8_encode_rune(buf, r); + return zpl_string_append_length(str, buf, len); + } + + return str; +} + +zpl_string zpl_string_append_fmt(zpl_string str, const char *fmt, ...) { + zpl_isize res; + char buf[4096] = { 0 }; + va_list va; + va_start(va, fmt); + res = zpl_snprintf_va(buf, zpl_count_of(buf) - 1, fmt, va) - 1; + va_end(va); + return zpl_string_append_length(str, buf, res); +} + +ZPL_END_C_DECLS +// file: source/core/file.c + +#ifdef ZPL_EDITOR +#include +#endif + +//////////////////////////////////////////////////////////////// +// +// File Handling +// +// +#include + +#ifdef ZPL_SYSTEM_MACOS +#include +#endif + +#ifdef ZPL_SYSTEM_CYGWIN +# include +#endif + +#if defined(ZPL_SYSTEM_WINDOWS) && !defined(ZPL_COMPILER_GCC) +#include +#endif + +ZPL_BEGIN_C_DECLS + +#if defined(ZPL_SYSTEM_WINDOWS) || defined (ZPL_SYSTEM_CYGWIN) + +zpl_internal wchar_t *zpl__alloc_utf8_to_ucs2(zpl_allocator a, char const *text, zpl_isize *w_len_) { + wchar_t *w_text = NULL; + zpl_isize len = 0, w_len = 0, w_len1 = 0; + if (text == NULL) { + if (w_len_) *w_len_ = w_len; + return NULL; + } + len = zpl_strlen(text); + if (len == 0) { + if (w_len_) *w_len_ = w_len; + return NULL; + } + w_len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, text, cast(int) len, NULL, 0); + if (w_len == 0) { + if (w_len_) *w_len_ = w_len; + return NULL; + } + w_text = zpl_alloc_array(a, wchar_t, w_len + 1); + w_len1 = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, text, cast(int) len, w_text, cast(int) w_len); + if (w_len1 == 0) { + zpl_free(a, w_text); + if (w_len_) *w_len_ = 0; + return NULL; + } + w_text[w_len] = 0; + if (w_len_) *w_len_ = w_len; + return w_text; +} + +zpl_internal ZPL_FILE_SEEK_PROC(zpl__win32_file_seek) { + LARGE_INTEGER li_offset; + li_offset.QuadPart = offset; + if (!SetFilePointerEx(fd.p, li_offset, &li_offset, whence)) { return false; } + + if (new_offset) *new_offset = li_offset.QuadPart; + return true; +} + +zpl_internal ZPL_FILE_READ_AT_PROC(zpl__win32_file_read) { + zpl_unused(stop_at_newline); + zpl_b32 result = false; + zpl__win32_file_seek(fd, offset, ZPL_SEEK_WHENCE_BEGIN, NULL); + DWORD size_ = cast(DWORD)(size > ZPL_I32_MAX ? ZPL_I32_MAX : size); + DWORD bytes_read_; + if (ReadFile(fd.p, buffer, size_, &bytes_read_, NULL)) { + if (bytes_read) *bytes_read = bytes_read_; + result = true; + } + + return result; +} + +zpl_internal ZPL_FILE_WRITE_AT_PROC(zpl__win32_file_write) { + DWORD size_ = cast(DWORD)(size > ZPL_I32_MAX ? ZPL_I32_MAX : size); + DWORD bytes_written_; + zpl__win32_file_seek(fd, offset, ZPL_SEEK_WHENCE_BEGIN, NULL); + if (WriteFile(fd.p, buffer, size_, &bytes_written_, NULL)) { + if (bytes_written) *bytes_written = bytes_written_; + return true; + } + return false; +} + +zpl_internal ZPL_FILE_CLOSE_PROC(zpl__win32_file_close) { CloseHandle(fd.p); } + +zpl_file_operations const zpl_default_file_operations = { zpl__win32_file_read, zpl__win32_file_write, + zpl__win32_file_seek, zpl__win32_file_close }; + +ZPL_NEVER_INLINE ZPL_FILE_OPEN_PROC(zpl__win32_file_open) { + DWORD desired_access; + DWORD creation_disposition; + void *handle; + wchar_t *w_text; + + switch (mode & ZPL_FILE_MODES) { + case ZPL_FILE_MODE_READ: + desired_access = GENERIC_READ; + creation_disposition = OPEN_EXISTING; + break; + case ZPL_FILE_MODE_WRITE: + desired_access = GENERIC_WRITE; + creation_disposition = CREATE_ALWAYS; + break; + case ZPL_FILE_MODE_APPEND: + desired_access = GENERIC_WRITE; + creation_disposition = OPEN_ALWAYS; + break; + case ZPL_FILE_MODE_READ | ZPL_FILE_MODE_RW: + desired_access = GENERIC_READ | GENERIC_WRITE; + creation_disposition = OPEN_EXISTING; + break; + case ZPL_FILE_MODE_WRITE | ZPL_FILE_MODE_RW: + desired_access = GENERIC_READ | GENERIC_WRITE; + creation_disposition = CREATE_ALWAYS; + break; + case ZPL_FILE_MODE_APPEND | ZPL_FILE_MODE_RW: + desired_access = GENERIC_READ | GENERIC_WRITE; + creation_disposition = OPEN_ALWAYS; + break; + default: ZPL_PANIC("Invalid file mode"); return ZPL_FILE_ERROR_INVALID; + } + + w_text = zpl__alloc_utf8_to_ucs2(zpl_heap_allocator( ), filename, NULL); + handle = CreateFileW(w_text, desired_access, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, creation_disposition, + FILE_ATTRIBUTE_NORMAL, NULL); + + zpl_free(zpl_heap_allocator( ), w_text); + + if (handle == INVALID_HANDLE_VALUE) { + DWORD err = GetLastError( ); + switch (err) { + case ERROR_FILE_NOT_FOUND: return ZPL_FILE_ERROR_NOT_EXISTS; + case ERROR_FILE_EXISTS: return ZPL_FILE_ERROR_EXISTS; + case ERROR_ALREADY_EXISTS: return ZPL_FILE_ERROR_EXISTS; + case ERROR_ACCESS_DENIED: return ZPL_FILE_ERROR_PERMISSION; + } + return ZPL_FILE_ERROR_INVALID; + } + + if (mode & ZPL_FILE_MODE_APPEND) { + LARGE_INTEGER offset = { 0 }; + if (!SetFilePointerEx(handle, offset, NULL, ZPL_SEEK_WHENCE_END)) { + CloseHandle(handle); + return ZPL_FILE_ERROR_INVALID; + } + } + + fd->p = handle; + *ops = zpl_default_file_operations; + return ZPL_FILE_ERROR_NONE; +} + +#else // POSIX +#include + +zpl_internal ZPL_FILE_SEEK_PROC(zpl__posix_file_seek) { +#if defined(ZPL_SYSTEM_OSX) + zpl_i64 res = lseek(fd.i, offset, whence); +#else // TODO(ZaKlaus): @fixme lseek64 + zpl_i64 res = lseek(fd.i, offset, whence); +#endif + if (res < 0) return false; + if (new_offset) *new_offset = res; + return true; +} + +zpl_internal ZPL_FILE_READ_AT_PROC(zpl__posix_file_read) { + zpl_unused(stop_at_newline); + zpl_isize res = pread(fd.i, buffer, size, offset); + if (res < 0) return false; + if (bytes_read) *bytes_read = res; + return true; +} + +zpl_internal ZPL_FILE_WRITE_AT_PROC(zpl__posix_file_write) { + zpl_isize res; + zpl_i64 curr_offset = 0; + zpl__posix_file_seek(fd, 0, ZPL_SEEK_WHENCE_CURRENT, &curr_offset); + if (curr_offset == offset) { + // NOTE: Writing to stdout et al. doesn't like pwrite for numerous reasons + res = write(cast(int) fd.i, buffer, size); + } else { + res = pwrite(cast(int) fd.i, buffer, size, offset); + } + if (res < 0) return false; + if (bytes_written) *bytes_written = res; + return true; +} + +zpl_internal ZPL_FILE_CLOSE_PROC(zpl__posix_file_close) { close(fd.i); } + +zpl_file_operations const zpl_default_file_operations = { zpl__posix_file_read, zpl__posix_file_write, + zpl__posix_file_seek, zpl__posix_file_close }; + +ZPL_NEVER_INLINE ZPL_FILE_OPEN_PROC(zpl__posix_file_open) { + zpl_i32 os_mode; + switch (mode & ZPL_FILE_MODES) { + case ZPL_FILE_MODE_READ: os_mode = O_RDONLY; break; + case ZPL_FILE_MODE_WRITE: os_mode = O_WRONLY | O_CREAT | O_TRUNC; break; + case ZPL_FILE_MODE_APPEND: os_mode = O_WRONLY | O_APPEND | O_CREAT; break; + case ZPL_FILE_MODE_READ | ZPL_FILE_MODE_RW: os_mode = O_RDWR; break; + case ZPL_FILE_MODE_WRITE | ZPL_FILE_MODE_RW: os_mode = O_RDWR | O_CREAT | O_TRUNC; break; + case ZPL_FILE_MODE_APPEND | ZPL_FILE_MODE_RW: os_mode = O_RDWR | O_APPEND | O_CREAT; break; + default: ZPL_PANIC("Invalid file mode"); return ZPL_FILE_ERROR_INVALID; + } + + fd->i = open(filename, os_mode, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); + if (fd->i < 0) { + // TODO: More file errors + return ZPL_FILE_ERROR_INVALID; + } + + *ops = zpl_default_file_operations; + return ZPL_FILE_ERROR_NONE; +} + +#endif + +zpl_file_error zpl_file_new(zpl_file *f, zpl_file_descriptor fd, zpl_file_operations ops, char const *filename) { + zpl_file_error err = ZPL_FILE_ERROR_NONE; + zpl_isize len = zpl_strlen(filename); + + f->ops = ops; + f->fd = fd; + f->dir = NULL; + f->last_write_time = 0; + f->filename = zpl_alloc_array(zpl_heap_allocator( ), char, len + 1); + zpl_memcopy(cast(char *) f->filename, cast(char *) filename, len + 1); + + return err; +} + +zpl_file_error zpl_file_open_mode(zpl_file *f, zpl_file_mode mode, char const *filename) { + zpl_file file_ = {0}; + *f = file_; + zpl_file_error err; +#if defined(ZPL_SYSTEM_WINDOWS) || defined(ZPL_SYSTEM_CYGWIN) + err = zpl__win32_file_open(&f->fd, &f->ops, mode, filename); +#else + err = zpl__posix_file_open(&f->fd, &f->ops, mode, filename); +#endif + if (err == ZPL_FILE_ERROR_NONE) return zpl_file_new(f, f->fd, f->ops, filename); + return err; +} + +zpl_internal void zpl__dirinfo_free_entry(zpl_dir_entry *entry); + +zpl_file_error zpl_file_close(zpl_file *f) { + if (!f) return ZPL_FILE_ERROR_INVALID; + + if (f->filename) zpl_free(zpl_heap_allocator( ), cast(char *) f->filename); + +#if defined(ZPL_SYSTEM_WINDOWS) + if (f->fd.p == INVALID_HANDLE_VALUE) return ZPL_FILE_ERROR_INVALID; +#else + if (f->fd.i < 0) return ZPL_FILE_ERROR_INVALID; +#endif + + if (f->is_temp) + { + f->ops.close(f->fd); + return ZPL_FILE_ERROR_NONE; + } + + if (!f->ops.read_at) f->ops = zpl_default_file_operations; + f->ops.close(f->fd); + + if (f->dir) { + zpl__dirinfo_free_entry(f->dir); + zpl_mfree(f->dir); + f->dir = NULL; + } + + return ZPL_FILE_ERROR_NONE; +} + + +zpl_file_error zpl_file_create(zpl_file *f, char const *filename) { + return zpl_file_open_mode(f, ZPL_FILE_MODE_WRITE | ZPL_FILE_MODE_RW, filename); +} + +zpl_file_error zpl_file_open(zpl_file *f, char const *filename) { + return zpl_file_open_mode(f, ZPL_FILE_MODE_READ, filename); +} + +char const *zpl_file_name(zpl_file *f) { return f->filename ? f->filename : ""; } + +zpl_b32 zpl_file_has_changed(zpl_file *f) { + if (f->is_temp) + return false; + zpl_b32 result = false; + zpl_file_time last_write_time = zpl_fs_last_write_time(f->filename); + if (f->last_write_time != last_write_time) { + result = true; + f->last_write_time = last_write_time; + } + return result; +} + +// TODO: Is this a bad idea? +zpl_global zpl_b32 zpl__std_file_set = false; +zpl_global zpl_file zpl__std_files[ZPL_FILE_STANDARD_COUNT] = { { 0 } }; + +#if defined(ZPL_SYSTEM_WINDOWS) || defined(ZPL_SYSTEM_CYGWIN) + +zpl_file *zpl_file_get_standard(zpl_file_standard_type std) { + if (!zpl__std_file_set) { +#define ZPL__SET_STD_FILE(type, v) \ +zpl__std_files[type].fd.p = v; \ +zpl__std_files[type].ops = zpl_default_file_operations + ZPL__SET_STD_FILE(ZPL_FILE_STANDARD_INPUT, GetStdHandle(STD_INPUT_HANDLE)); + ZPL__SET_STD_FILE(ZPL_FILE_STANDARD_OUTPUT, GetStdHandle(STD_OUTPUT_HANDLE)); + ZPL__SET_STD_FILE(ZPL_FILE_STANDARD_ERROR, GetStdHandle(STD_ERROR_HANDLE)); +#undef ZPL__SET_STD_FILE + zpl__std_file_set = true; + } + return &zpl__std_files[std]; +} + +void zpl_file_connect_handle(zpl_file *file, void *handle) { + ZPL_ASSERT_NOT_NULL(file); + ZPL_ASSERT_NOT_NULL(handle); + + if (file->is_temp) + return; + + zpl_zero_item(file); + + file->fd.p = handle; + file->ops = zpl_default_file_operations; +} + +zpl_file_error zpl_file_truncate(zpl_file *f, zpl_i64 size) { + zpl_file_error err = ZPL_FILE_ERROR_NONE; + zpl_i64 prev_offset = zpl_file_tell(f); + zpl_file_seek(f, size); + if (!SetEndOfFile(f)) err = ZPL_FILE_ERROR_TRUNCATION_FAILURE; + zpl_file_seek(f, prev_offset); + return err; +} + +zpl_b32 zpl_fs_exists(char const *name) { + WIN32_FIND_DATAW data; + wchar_t *w_text; + void *handle; + zpl_b32 found = false; + zpl_allocator a = zpl_heap_allocator( ); + + w_text = zpl__alloc_utf8_to_ucs2(a, name, NULL); + if (w_text == NULL) { return false; } + handle = FindFirstFileW(w_text, &data); + zpl_free(a, w_text); + found = handle != INVALID_HANDLE_VALUE; + if (found) FindClose(handle); + return found; +} + +#else // POSIX + +zpl_file *zpl_file_get_standard(zpl_file_standard_type std) { + if (!zpl__std_file_set) { +#define ZPL__SET_STD_FILE(type, v) \ +zpl__std_files[type].fd.i = v; \ +zpl__std_files[type].ops = zpl_default_file_operations + ZPL__SET_STD_FILE(ZPL_FILE_STANDARD_INPUT, 0); + ZPL__SET_STD_FILE(ZPL_FILE_STANDARD_OUTPUT, 1); + ZPL__SET_STD_FILE(ZPL_FILE_STANDARD_ERROR, 2); +#undef ZPL__SET_STD_FILE + zpl__std_file_set = true; + } + return &zpl__std_files[std]; +} + +zpl_file_error zpl_file_truncate(zpl_file *f, zpl_i64 size) { + zpl_file_error err = ZPL_FILE_ERROR_NONE; + int i = ftruncate(f->fd.i, size); + if (i != 0) err = ZPL_FILE_ERROR_TRUNCATION_FAILURE; + return err; +} + +zpl_b32 zpl_fs_exists(char const *name) { return access(name, F_OK) != -1; } + +#endif + +zpl_i64 zpl_file_size(zpl_file *f) { + zpl_i64 size = 0; + zpl_i64 prev_offset = zpl_file_tell(f); + zpl_file_seek_to_end(f); + size = zpl_file_tell(f); + zpl_file_seek(f, prev_offset); + return size; +} + +zpl_file_error zpl_file_temp(zpl_file *file) { + zpl_zero_item(file); + FILE *fd = NULL; + +#if defined(ZPL_SYSTEM_WINDOWS) && !defined(ZPL_COMPILER_GCC) + errno_t errcode = tmpfile_s(&fd); + + if (errcode != 0) { + fd = NULL; + } +#else + fd = tmpfile(); +#endif + + if (fd == NULL) { return ZPL_FILE_ERROR_INVALID; } + +#if defined(ZPL_SYSTEM_WINDOWS) && !defined(ZPL_COMPILER_GCC) + file->fd.i = _get_osfhandle(_fileno(fd)); +#else + file->fd.i = fileno(fd); +#endif + file->ops = zpl_default_file_operations; + file->is_temp = true; + return ZPL_FILE_ERROR_NONE; +} + +zpl_file_contents zpl_file_read_contents(zpl_allocator a, zpl_b32 zero_terminate, char const *filepath) { + zpl_file_contents result = { 0 }; + zpl_file file = { 0 }; + + result.allocator = a; + + if (zpl_file_open(&file, filepath) == ZPL_FILE_ERROR_NONE) { + zpl_isize file_size = cast(zpl_isize) zpl_file_size(&file); + if (file_size > 0) { + result.data = zpl_alloc(a, zero_terminate ? file_size + 1 : file_size); + result.size = file_size; + zpl_file_read_at(&file, result.data, result.size, 0); + if (zero_terminate) { + zpl_u8 *str = cast(zpl_u8 *) result.data; + str[file_size] = '\0'; } } + zpl_file_close(&file); + } + + return result; +} - zpl_internal void zpl__dirinfo_free_entry(zpl_dir_entry *entry) { - if (entry->dir_info) { - zpl_dirinfo_free(entry->dir_info); - zpl_mfree(entry->dir_info); - entry->dir_info = NULL; - } +void zpl_file_free_contents(zpl_file_contents *fc) { + ZPL_ASSERT_NOT_NULL(fc->data); + zpl_free(fc->allocator, fc->data); + fc->data = NULL; + fc->size = 0; +} + +zpl_b32 zpl_file_write_contents(char const* filepath, void const* buffer, zpl_isize size, zpl_file_error* err) { + zpl_file f = { 0 }; + zpl_file_error open_err; + zpl_b32 write_ok; + open_err = zpl_file_open_mode(&f, ZPL_FILE_MODE_WRITE, filepath); + + if (open_err != ZPL_FILE_ERROR_NONE) + { + if (err) + *err = open_err; + + return false; + } + + write_ok = zpl_file_write(&f, buffer, size); + zpl_file_close(&f); + return write_ok; +} + +char *zpl_file_read_lines(zpl_allocator alloc, zpl_array(char *)*lines, char const *filename, zpl_b32 strip_whitespace) { + zpl_file f = { 0 }; + zpl_file_open(&f, filename); + zpl_isize fsize = (zpl_isize)zpl_file_size(&f); + + char *contents = (char *)zpl_alloc(alloc, fsize + 1); + zpl_file_read(&f, contents, fsize); + contents[fsize] = 0; + *lines = zpl_str_split_lines(alloc, contents, strip_whitespace); + zpl_file_close(&f); + + return contents; +} + +#if !defined(_WINDOWS_) && defined(ZPL_SYSTEM_WINDOWS) +ZPL_IMPORT DWORD WINAPI GetFullPathNameA(char const *lpFileName, DWORD nBufferLength, char *lpBuffer, char **lpFilePart); +ZPL_IMPORT DWORD WINAPI GetFullPathNameW(wchar_t const *lpFileName, DWORD nBufferLength, wchar_t *lpBuffer, wchar_t **lpFilePart); +#endif + +ZPL_END_C_DECLS +// file: source/core/file_stream.c + +#ifdef ZPL_EDITOR +#include +#endif + +//////////////////////////////////////////////////////////////// +// +// Memory streaming +// +// + +ZPL_BEGIN_C_DECLS + +typedef struct { + zpl_u8 magic; + zpl_u8 *buf; //< zpl_array OR plain buffer if we can't write + zpl_isize cursor; + zpl_allocator alloc; + + zpl_file_stream_flags flags; + zpl_isize cap; +} zpl__memory_fd; + +#define ZPL__FILE_STREAM_FD_MAGIC 37 + +ZPL_ALWAYS_INLINE zpl_file_descriptor zpl__file_stream_fd_make(zpl__memory_fd* d) { + zpl_file_descriptor fd = {0}; + fd.p = (void*)d; + return fd; +} + +ZPL_ALWAYS_INLINE zpl__memory_fd *zpl__file_stream_from_fd(zpl_file_descriptor fd) { + zpl__memory_fd *d = (zpl__memory_fd*)fd.p; + ZPL_ASSERT(d->magic == ZPL__FILE_STREAM_FD_MAGIC); + return d; +} + +void zpl_file_stream_new(zpl_file* file, zpl_allocator allocator) { + ZPL_ASSERT_NOT_NULL(file); + zpl__memory_fd *d = (zpl__memory_fd*)zpl_alloc(allocator, zpl_size_of(zpl__memory_fd)); + zpl_zero_item(file); + d->magic = ZPL__FILE_STREAM_FD_MAGIC; + d->alloc = allocator; + d->flags = ZPL_FILE_STREAM_CLONE_WRITABLE; + d->cap = 0; + zpl_array_init(d->buf, allocator); + file->ops = zpl_memory_file_operations; + file->fd = zpl__file_stream_fd_make(d); + file->dir = NULL; + file->last_write_time = 0; + file->filename = NULL; + file->is_temp = true; +} +void zpl_file_stream_open(zpl_file* file, zpl_allocator allocator, zpl_u8 *buffer, zpl_isize size, zpl_file_stream_flags flags) { + ZPL_ASSERT_NOT_NULL(file); + zpl__memory_fd *d = (zpl__memory_fd*)zpl_alloc(allocator, zpl_size_of(zpl__memory_fd)); + zpl_zero_item(file); + d->magic = ZPL__FILE_STREAM_FD_MAGIC; + d->alloc = allocator; + d->flags = flags; + if (d->flags & ZPL_FILE_STREAM_CLONE_WRITABLE) { + zpl_array_init_reserve(d->buf, allocator, size); + zpl_memcopy(d->buf, buffer, size); + d->cap = zpl_array_count(d->buf) = size; + } else { + d->buf = buffer; + d->cap = size; + } + file->ops = zpl_memory_file_operations; + file->fd = zpl__file_stream_fd_make(d); + file->dir = NULL; + file->last_write_time = 0; + file->filename = NULL; + file->is_temp = true; +} + +zpl_u8 *zpl_file_stream_buf(zpl_file* file, zpl_isize *size) { + ZPL_ASSERT_NOT_NULL(file); + zpl__memory_fd *d = zpl__file_stream_from_fd(file->fd); + if (size) *size = d->cap; + return d->buf; +} + +zpl_internal ZPL_FILE_SEEK_PROC(zpl__memory_file_seek) { + zpl__memory_fd *d = zpl__file_stream_from_fd(fd); + zpl_isize buflen = d->cap; + + if (whence == ZPL_SEEK_WHENCE_BEGIN) + d->cursor = 0; + else if (whence == ZPL_SEEK_WHENCE_END) + d->cursor = buflen; + + d->cursor = zpl_max(0, zpl_clamp(d->cursor + offset, 0, buflen)); + if (new_offset) *new_offset = d->cursor; + return true; +} + +zpl_internal ZPL_FILE_READ_AT_PROC(zpl__memory_file_read) { + zpl_unused(stop_at_newline); + zpl__memory_fd *d = zpl__file_stream_from_fd(fd); + zpl_memcopy(buffer, d->buf + offset, size); + if (bytes_read) *bytes_read = size; + return true; +} + +zpl_internal ZPL_FILE_WRITE_AT_PROC(zpl__memory_file_write) { + zpl__memory_fd *d = zpl__file_stream_from_fd(fd); + if (!(d->flags & (ZPL_FILE_STREAM_CLONE_WRITABLE|ZPL_FILE_STREAM_WRITABLE))) + return false; + zpl_isize buflen = d->cap; + zpl_isize extralen = zpl_max(0, size-(buflen-offset)); + zpl_isize rwlen = size-extralen; + zpl_isize new_cap = buflen+extralen; + if (d->flags & ZPL_FILE_STREAM_CLONE_WRITABLE) { + if(zpl_array_capacity(d->buf) < new_cap) { + zpl_array_grow(d->buf, (zpl_i64)(new_cap)); } + } + zpl_memcopy(d->buf + offset, buffer, rwlen); + + if ((d->flags & ZPL_FILE_STREAM_CLONE_WRITABLE) && extralen > 0) { + zpl_memcopy(d->buf + offset + rwlen, zpl_ptr_add_const(buffer, rwlen), extralen); + d->cap = zpl_array_count(d->buf) = new_cap; + } else { + extralen = 0; + } + + if (bytes_written) *bytes_written = (rwlen+extralen); + return true; +} - void zpl_dirinfo_free(zpl_dir_info *dir) { - ZPL_ASSERT_NOT_NULL(dir); +zpl_internal ZPL_FILE_CLOSE_PROC(zpl__memory_file_close) { + zpl__memory_fd *d = zpl__file_stream_from_fd(fd); + zpl_allocator alloc = d->alloc; + if (d->flags & ZPL_FILE_STREAM_CLONE_WRITABLE) + zpl_array_free(d->buf); + zpl_free(alloc, d); +} - for (zpl_isize i = 0; i < zpl_array_count(dir->entries); ++i) { - zpl__dirinfo_free_entry(dir->entries + i); - } +zpl_file_operations const zpl_memory_file_operations = { zpl__memory_file_read, zpl__memory_file_write, + zpl__memory_file_seek, zpl__memory_file_close }; - zpl_array_free(dir->entries); - zpl_array_free(dir->filenames); - zpl_string_free(dir->buf); - zpl_mfree((void *)dir->fullpath); +ZPL_END_C_DECLS +// file: source/core/file_misc.c + +#ifdef ZPL_EDITOR +#include +#endif + +#if defined(ZPL_SYSTEM_UNIX) || defined(ZPL_SYSTEM_MACOS) +#include +#endif + +#if defined(ZPL_SYSTEM_UNIX) && !defined(ZPL_SYSTEM_FREEBSD) && !defined(ZPL_SYSTEM_OPENBSD) && !defined(ZPL_SYSTEM_CYGWIN) +#include +#endif + +#if defined(ZPL_SYSTEM_WINDOWS) +# include +# include +#endif + +#if defined(ZPL_SYSTEM_CYGWIN) +# include +# include +# include +#endif + +ZPL_BEGIN_C_DECLS + + +#if defined(ZPL_SYSTEM_WINDOWS) || defined(ZPL_SYSTEM_CYGWIN) +zpl_file_time zpl_fs_last_write_time(char const *filepath) { + ULARGE_INTEGER li = { 0 }; + FILETIME last_write_time = { 0 }; + WIN32_FILE_ATTRIBUTE_DATA data = { 0 }; + zpl_allocator a = zpl_heap_allocator( ); + + wchar_t *w_text = zpl__alloc_utf8_to_ucs2(a, filepath, NULL); + if (w_text == NULL) { return 0; } + if (GetFileAttributesExW(w_text, GetFileExInfoStandard, &data)) last_write_time = data.ftLastWriteTime; + + zpl_free(a, w_text); + + li.LowPart = last_write_time.dwLowDateTime; + li.HighPart = last_write_time.dwHighDateTime; + return cast(zpl_file_time) li.QuadPart; +} + +zpl_b32 zpl_fs_copy(char const *existing_filename, char const *new_filename, zpl_b32 fail_if_exists) { + zpl_b32 result = false; + zpl_allocator a = zpl_heap_allocator( ); + + wchar_t *w_old = zpl__alloc_utf8_to_ucs2(a, existing_filename, NULL); + if (w_old == NULL) { return false; } + + wchar_t *w_new = zpl__alloc_utf8_to_ucs2(a, new_filename, NULL); + if (w_new != NULL) { result = CopyFileW(w_old, w_new, fail_if_exists); } + + zpl_free(a, w_old); + zpl_free(a, w_new); + return result; +} + +zpl_b32 zpl_fs_move(char const *existing_filename, char const *new_filename) { + zpl_b32 result = false; + zpl_allocator a = zpl_heap_allocator( ); + + wchar_t *w_old = zpl__alloc_utf8_to_ucs2(a, existing_filename, NULL); + if (w_old == NULL) { return false; } + + wchar_t *w_new = zpl__alloc_utf8_to_ucs2(a, new_filename, NULL); + if (w_new != NULL) { result = MoveFileW(w_old, w_new); } + + zpl_free(a, w_old); + zpl_free(a, w_new); + return result; +} + +zpl_b32 zpl_fs_remove(char const *filename) { + zpl_b32 result = false; + zpl_allocator a = zpl_heap_allocator( ); + + wchar_t *w_filename = zpl__alloc_utf8_to_ucs2(a, filename, NULL); + if (w_filename == NULL) { return false; } + + result = DeleteFileW(w_filename); + + zpl_free(a, w_filename); + return result; +} + +#else + +zpl_file_time zpl_fs_last_write_time(char const *filepath) { + time_t result = 0; + struct stat file_stat; + + if (stat(filepath, &file_stat)) result = file_stat.st_mtime; + + return cast(zpl_file_time) result; +} + +#if defined(ZPL_SYSTEM_FREEBSD) +#include +#include +#include +#endif + + +zpl_b32 zpl_fs_copy(char const *existing_filename, char const *new_filename, zpl_b32 fail_if_exists) { + zpl_unused(fail_if_exists); +#if defined(ZPL_SYSTEM_OSX) + return copyfile(existing_filename, new_filename, NULL, COPYFILE_DATA) == 0; +#elif defined(ZPL_SYSTEM_OPENBSD) + ZPL_NOT_IMPLEMENTED; + return 0; +#else + int existing_fd = open(existing_filename, O_RDONLY, 0); + struct stat stat_existing; + fstat(existing_fd, &stat_existing); + + zpl_isize size; + int new_fd = open(new_filename, O_WRONLY | O_CREAT, stat_existing.st_mode); + +#if defined(ZPL_SYSTEM_FREEBSD) + size = sendfile(new_fd, existing_fd, 0, stat_existing.st_size, NULL, 0, 0); +#else + size = sendfile(new_fd, existing_fd, 0, stat_existing.st_size); +#endif + + close(new_fd); + close(existing_fd); + + return size == stat_existing.st_size; +#endif +} + +zpl_b32 zpl_fs_move(char const *existing_filename, char const *new_filename) { + if (link(existing_filename, new_filename) == 0) { return (unlink(existing_filename) != -1); } + return false; +} + +zpl_b32 zpl_fs_remove(char const *filename) { +#if defined(ZPL_SYSTEM_OSX) || defined(ZPL_SYSTEM_EMSCRIPTEN) + return (unlink(filename) != -1); +#else + return (remove(filename) == 0); +#endif +} + +#endif + +char *zpl_path_get_full_name(zpl_allocator a, char const *path) { +#if defined(ZPL_SYSTEM_WINDOWS) + wchar_t *w_path = NULL; + wchar_t *w_fullpath = NULL; + zpl_isize w_len = 0; + zpl_isize new_len = 0; + zpl_isize new_len1 = 0; + char *new_path = 0; + + w_path = zpl__alloc_utf8_to_ucs2(zpl_heap_allocator( ), path, NULL); + if (w_path == NULL) { return NULL; } + + w_len = GetFullPathNameW(w_path, 0, NULL, NULL); + if (w_len == 0) { return NULL; } + + w_fullpath = zpl_alloc_array(zpl_heap_allocator( ), wchar_t, w_len + 1); + GetFullPathNameW(w_path, cast(int) w_len, w_fullpath, NULL); + w_fullpath[w_len] = 0; + + zpl_free(zpl_heap_allocator( ), w_path); + + new_len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, w_fullpath, cast(int) w_len, NULL, 0, NULL, NULL); + + if (new_len == 0) { + zpl_free(zpl_heap_allocator( ), w_fullpath); + return NULL; + } + + new_path = zpl_alloc_array(a, char, new_len); + new_len1 = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, w_fullpath, cast(int) w_len, new_path, + cast(int) new_len, NULL, NULL); + + if (new_len1 == 0) { + zpl_free(zpl_heap_allocator( ), w_fullpath); + zpl_free(a, new_path); + return NULL; + } + + new_path[new_len] = 0; + return new_path; +#else + char *p, *result, *fullpath = NULL; + zpl_isize len; + p = realpath(path, NULL); + fullpath = p; + if (p == NULL) { + // NOTE(bill): File does not exist + fullpath = cast(char *) path; + } + + len = zpl_strlen(fullpath); + + result = zpl_alloc_array(a, char, len + 1); + zpl_memmove(result, fullpath, len); + result[len] = 0; + zpl_free(a, p); + + return result; +#endif +} + +zpl_file_error zpl_path_mkdir(char const *path, zpl_i32 mode) { + zpl_i32 error = 0; +#if defined(ZPL_SYSTEM_WINDOWS) + error = _wmkdir((const wchar_t *)zpl_utf8_to_ucs2_buf((const zpl_u8 *)path)); +#else + error = mkdir(path, (mode_t)mode); +#endif + + if (error == 0) { return ZPL_FILE_ERROR_NONE; } + + switch (errno) { + case EPERM: + case EACCES: return ZPL_FILE_ERROR_PERMISSION; + case EEXIST: return ZPL_FILE_ERROR_EXISTS; + case ENAMETOOLONG: return ZPL_FILE_ERROR_NAME_TOO_LONG; + } + + return ZPL_FILE_ERROR_UNKNOWN; +} + +zpl_file_error zpl_path_rmdir(char const *path) { + zpl_i32 error = 0; +#if defined(ZPL_SYSTEM_WINDOWS) + error = _wrmdir((const wchar_t *)zpl_utf8_to_ucs2_buf((const zpl_u8 *)path)); +#else + error = rmdir(path); +#endif + + if (error == 0) { return ZPL_FILE_ERROR_NONE; } + + switch (errno) { + case EPERM: + case EACCES: return ZPL_FILE_ERROR_PERMISSION; + case ENOENT: return ZPL_FILE_ERROR_NOT_EXISTS; + case ENOTEMPTY: return ZPL_FILE_ERROR_NOT_EMPTY; + case ENAMETOOLONG: return ZPL_FILE_ERROR_NAME_TOO_LONG; + } + + return ZPL_FILE_ERROR_UNKNOWN; +} + +void zpl__file_direntry(zpl_allocator alloc, char const *dirname, zpl_string *output, zpl_b32 recurse) { +#if defined(ZPL_SYSTEM_UNIX) || defined(ZPL_SYSTEM_OSX) + DIR *d, *cd; + struct dirent *dir; + d = opendir(dirname); + + if (d) { + while ((dir = readdir(d))) { + if (!zpl_strncmp(dir->d_name, "..", 2)) continue; + if (dir->d_name[0] == '.' && dir->d_name[1] == 0) continue; + + zpl_string dirpath = zpl_string_make(alloc, dirname); + dirpath = zpl_string_appendc(dirpath, "/"); + dirpath = zpl_string_appendc(dirpath, dir->d_name); + + *output = zpl_string_appendc(*output, dirpath); + *output = zpl_string_appendc(*output, "\n"); + + if (recurse && (cd = opendir(dirpath)) != NULL) { zpl__file_direntry(alloc, dirpath, output, recurse); } + zpl_string_free(dirpath); } + } +#elif defined(ZPL_SYSTEM_WINDOWS) + zpl_usize length = zpl_strlen(dirname); + struct _wfinddata_t data; + zpl_intptr findhandle; + + char directory[MAX_PATH] = { 0 }; + zpl_strncpy(directory, dirname, length); + + // keeping it native + for (zpl_usize i = 0; i < length; i++) { + if (directory[i] == '/') directory[i] = '\\'; + } + + // remove trailing slashses + if (directory[length - 1] == '\\') { directory[length - 1] = '\0'; } + + // attach search pattern + zpl_string findpath = zpl_string_make(alloc, directory); + findpath = zpl_string_appendc(findpath, "\\"); + findpath = zpl_string_appendc(findpath, "*"); + + findhandle = _wfindfirst((const wchar_t *)zpl_utf8_to_ucs2_buf((const zpl_u8 *)findpath), &data); + zpl_string_free(findpath); + + if (findhandle != -1) { + do { + char *filename = (char *)zpl_ucs2_to_utf8_buf((const zpl_u16 *)data.name); + if (!zpl_strncmp(filename, "..", 2)) continue; + if (filename[0] == '.' && filename[1] == 0) continue; + + zpl_string dirpath = zpl_string_make(alloc, directory); + dirpath = zpl_string_appendc(dirpath, "\\"); + dirpath = zpl_string_appendc(dirpath, filename); + + *output = zpl_string_appendc(*output, dirpath); + *output = zpl_string_appendc(*output, "\n"); + + if (recurse && (data.attrib & _A_SUBDIR)) { zpl__file_direntry(alloc, dirpath, output, recurse); } + + zpl_string_free(dirpath); + } while (_wfindnext(findhandle, &data) != -1); + _findclose(findhandle); + } +#else + // TODO: Implement other OSes +#endif +} + +zpl_string zpl_path_dirlist(zpl_allocator alloc, char const *dirname, zpl_b32 recurse) { + zpl_string buf = zpl_string_make_reserve(alloc, 4); + zpl__file_direntry(alloc, dirname, &buf, recurse); + return buf; +} + +void zpl_dirinfo_init(zpl_dir_info *dir, char const *path) { + ZPL_ASSERT_NOT_NULL(dir); + + zpl_dir_info dir_ = {0}; + *dir = dir_; + dir->fullpath = (char const*)zpl_malloc(zpl_strlen(path)); + zpl_strcpy((char *)dir->fullpath, path); + + + zpl_string dirlist = zpl_path_dirlist(zpl_heap(), path, false); + char **files=zpl_str_split_lines(zpl_heap(), dirlist, false); + dir->filenames = files; + dir->buf = dirlist; + + zpl_array_init(dir->entries, zpl_heap()); + + for (zpl_i32 i=0; ientries, entry); + } +} + +zpl_internal void zpl__dirinfo_free_entry(zpl_dir_entry *entry) { + if (entry->dir_info) { + zpl_dirinfo_free(entry->dir_info); + zpl_mfree(entry->dir_info); + entry->dir_info = NULL; + } +} + +void zpl_dirinfo_free(zpl_dir_info *dir) { + ZPL_ASSERT_NOT_NULL(dir); + + for (zpl_isize i = 0; i < zpl_array_count(dir->entries); ++i) { + zpl__dirinfo_free_entry(dir->entries + i); + } + + zpl_array_free(dir->entries); + zpl_array_free(dir->filenames); + zpl_string_free(dir->buf); + zpl_mfree((void *)dir->fullpath); +} - zpl_u8 zpl_fs_get_type(char const *path) { - #ifdef ZPL_SYSTEM_WINDOWS - DWORD attrs = GetFileAttributesW((const wchar_t *)zpl_utf8_to_ucs2_buf((const zpl_u8 *)path)); - - if (attrs == INVALID_FILE_ATTRIBUTES) { - return ZPL_DIR_TYPE_UNKNOWN; - } - - if (attrs & FILE_ATTRIBUTE_DIRECTORY) { - return ZPL_DIR_TYPE_FOLDER; - } - else { - return ZPL_DIR_TYPE_FILE; - } - - #else - struct stat s; - if( stat(path,&s) == 0 ) - { - if( s.st_mode & S_IFDIR ) - { - return ZPL_DIR_TYPE_FOLDER; - } - else - { - return ZPL_DIR_TYPE_FILE; - } - } - #endif - - return ZPL_DIR_TYPE_UNKNOWN; +zpl_u8 zpl_fs_get_type(char const *path) { +#ifdef ZPL_SYSTEM_WINDOWS + DWORD attrs = GetFileAttributesW((const wchar_t *)zpl_utf8_to_ucs2_buf((const zpl_u8 *)path)); + + if (attrs == INVALID_FILE_ATTRIBUTES) { + return ZPL_DIR_TYPE_UNKNOWN; + } + + if (attrs & FILE_ATTRIBUTE_DIRECTORY) { + return ZPL_DIR_TYPE_FOLDER; + } + else { + return ZPL_DIR_TYPE_FILE; + } + +#else + struct stat s; + if( stat(path,&s) == 0 ) + { + if( s.st_mode & S_IFDIR ) + { + return ZPL_DIR_TYPE_FOLDER; } - - void zpl_dirinfo_step(zpl_dir_entry *entry) { - if (entry->dir_info) { - zpl__dirinfo_free_entry(entry); - } - - entry->dir_info = (zpl_dir_info *)zpl_malloc(sizeof(zpl_dir_info)); - zpl_dir_info dir_ = {0}; - *entry->dir_info = dir_; - - zpl_local_persist char buf[128] = {0}; - char const *path = entry->filename; - - if (entry->type != ZPL_DIR_TYPE_FOLDER) { - zpl_path_fix_slashes((char *)path); - char const* slash = zpl_char_last_occurence(path, ZPL_PATH_SEPARATOR); - zpl_strncpy(buf, path, slash-path); - path = buf; - } - - zpl_dirinfo_init(entry->dir_info, path); + else + { + return ZPL_DIR_TYPE_FILE; } + } +#endif + + return ZPL_DIR_TYPE_UNKNOWN; +} - void zpl_file_dirinfo_refresh(zpl_file *file) { - if (file->is_temp) - return; +void zpl_dirinfo_step(zpl_dir_entry *entry) { + if (entry->dir_info) { + zpl__dirinfo_free_entry(entry); + } + + entry->dir_info = (zpl_dir_info *)zpl_malloc(sizeof(zpl_dir_info)); + zpl_dir_info dir_ = {0}; + *entry->dir_info = dir_; + + zpl_local_persist char buf[128] = {0}; + char const *path = entry->filename; + + if (entry->type != ZPL_DIR_TYPE_FOLDER) { + zpl_path_fix_slashes((char *)path); + char const* slash = zpl_char_last_occurence(path, ZPL_PATH_SEPARATOR); + zpl_strncpy(buf, path, slash-path); + path = buf; + } + + zpl_dirinfo_init(entry->dir_info, path); +} - if (file->dir) { - zpl__dirinfo_free_entry(file->dir); - zpl_mfree(file->dir); - file->dir = NULL; - } +void zpl_file_dirinfo_refresh(zpl_file *file) { + if (file->is_temp) + return; + + if (file->dir) { + zpl__dirinfo_free_entry(file->dir); + zpl_mfree(file->dir); + file->dir = NULL; + } + + file->dir = (zpl_dir_entry *)zpl_malloc(sizeof(zpl_dir_entry)); + zpl_dir_entry dir_ = {0}; + *file->dir = dir_; + file->dir->filename = file->filename; + file->dir->type = ZPL_DIR_TYPE_FILE; + + zpl_dirinfo_step(file->dir); +} - file->dir = (zpl_dir_entry *)zpl_malloc(sizeof(zpl_dir_entry)); - zpl_dir_entry dir_ = {0}; - *file->dir = dir_; - file->dir->filename = file->filename; - file->dir->type = ZPL_DIR_TYPE_FILE; +void zpl_path_fix_slashes(char *path) { +#ifdef ZPL_SYSTEM_WINDOWS + char *p = path; + + while (*p != '\0') { + if (*p == '/') + *p = '\\'; + + ++p; + } +#endif +} - zpl_dirinfo_step(file->dir); +ZPL_END_C_DECLS +// file: source/core/print.c + +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +zpl_isize zpl_printf_va(char const *fmt, va_list va) { + return zpl_fprintf_va(zpl_file_get_standard(ZPL_FILE_STANDARD_OUTPUT), fmt, va); +} + +zpl_isize zpl_printf_err_va(char const *fmt, va_list va) { + return zpl_fprintf_va(zpl_file_get_standard(ZPL_FILE_STANDARD_ERROR), fmt, va); +} + +zpl_isize zpl_fprintf_va(struct zpl_file *f, char const *fmt, va_list va) { + zpl_local_persist char buf[4096]; + zpl_isize len = zpl_snprintf_va(buf, zpl_size_of(buf), fmt, va); + zpl_file_write(f, buf, len - 1); // NOTE: prevent extra whitespace + return len; +} + +char *zpl_bprintf_va(char const *fmt, va_list va) { + zpl_local_persist char buffer[4096]; + zpl_snprintf_va(buffer, zpl_size_of(buffer), fmt, va); + return buffer; +} + +zpl_isize zpl_printf(char const *fmt, ...) { + zpl_isize res; + va_list va; + va_start(va, fmt); + res = zpl_printf_va(fmt, va); + va_end(va); + return res; +} + +zpl_isize zpl_printf_err(char const *fmt, ...) { + zpl_isize res; + va_list va; + va_start(va, fmt); + res = zpl_printf_err_va(fmt, va); + va_end(va); + return res; +} + +zpl_isize zpl_fprintf(struct zpl_file *f, char const *fmt, ...) { + zpl_isize res; + va_list va; + va_start(va, fmt); + res = zpl_fprintf_va(f, fmt, va); + va_end(va); + return res; +} + +char *zpl_bprintf(char const *fmt, ...) { + va_list va; + char *str; + va_start(va, fmt); + str = zpl_bprintf_va(fmt, va); + va_end(va); + return str; +} + +zpl_isize zpl_snprintf(char *str, zpl_isize n, char const *fmt, ...) { + zpl_isize res; + va_list va; + va_start(va, fmt); + res = zpl_snprintf_va(str, n, fmt, va); + va_end(va); + return res; +} + + +enum { + ZPL_FMT_MINUS = ZPL_BIT(0), + ZPL_FMT_PLUS = ZPL_BIT(1), + ZPL_FMT_ALT = ZPL_BIT(2), + ZPL_FMT_SPACE = ZPL_BIT(3), + ZPL_FMT_ZERO = ZPL_BIT(4), + + ZPL_FMT_CHAR = ZPL_BIT(5), + ZPL_FMT_SHORT = ZPL_BIT(6), + ZPL_FMT_INT = ZPL_BIT(7), + ZPL_FMT_LONG = ZPL_BIT(8), + ZPL_FMT_LLONG = ZPL_BIT(9), + ZPL_FMT_SIZE = ZPL_BIT(10), + ZPL_FMT_INTPTR = ZPL_BIT(11), + + ZPL_FMT_UNSIGNED = ZPL_BIT(12), + ZPL_FMT_LOWER = ZPL_BIT(13), + ZPL_FMT_UPPER = ZPL_BIT(14), + ZPL_FMT_WIDTH = ZPL_BIT(15), + + ZPL_FMT_DONE = ZPL_BIT(30), + + ZPL_FMT_INTS = + ZPL_FMT_CHAR | ZPL_FMT_SHORT | ZPL_FMT_INT | + ZPL_FMT_LONG | ZPL_FMT_LLONG | ZPL_FMT_SIZE | ZPL_FMT_INTPTR +}; + +typedef struct { + zpl_i32 base; + zpl_i32 flags; + zpl_i32 width; + zpl_i32 precision; +} zpl__format_info; + +zpl_internal zpl_isize zpl__print_string(char *text, zpl_isize max_len, zpl__format_info *info, char const *str) { + zpl_isize res = 0, len = 0; + zpl_isize remaining = max_len; + + if (str == NULL && max_len >= 4) { + res += zpl_strlcpy(text, "(null)", 6); + return res; + } + + if (info && info->precision >= 0) + len = zpl_strnlen(str, info->precision); + else + len = zpl_strlen(str); + + if (info && (info->width == 0 && info->flags & ZPL_FMT_WIDTH)) { + return res; + } + + if (info && (info->width == 0 || info->flags & ZPL_FMT_MINUS)) { + if (info->precision > 0) len = info->precision < len ? info->precision : len; + + res += zpl_strlcpy(text, str, len); + + if (info->width > res) { + zpl_isize padding = info->width - len; + char pad = (info->flags & ZPL_FMT_ZERO) ? '0' : ' '; + while (padding-- > 0 && remaining-- > 0) *text++ = pad, res++; } - - void zpl_path_fix_slashes(char *path) { - #ifdef ZPL_SYSTEM_WINDOWS - char *p = path; - - while (*p != '\0') { - if (*p == '/') - *p = '\\'; - - ++p; - } - #endif + } else { + if (info && (info->width > res)) { + zpl_isize padding = info->width - len; + char pad = (info->flags & ZPL_FMT_ZERO) ? '0' : ' '; + while (padding-- > 0 && remaining-- > 0) *text++ = pad, res++; } + + res += zpl_strlcpy(text, str, len); + } + + if (info) { + if (info->flags & ZPL_FMT_UPPER) + zpl_str_to_upper(text); + else if (info->flags & ZPL_FMT_LOWER) + zpl_str_to_lower(text); + } + + return res; +} - ZPL_END_C_DECLS - // file: source/core/print.c +zpl_internal zpl_isize zpl__print_char(char *text, zpl_isize max_len, zpl__format_info *info, char arg) { + char str[2] = ""; + str[0] = arg; + return zpl__print_string(text, max_len, info, str); +} - #ifdef ZPL_EDITOR - #include - #endif +zpl_internal zpl_isize zpl__print_i64(char *text, zpl_isize max_len, zpl__format_info *info, zpl_i64 value) { + char num[130]; + zpl_i64_to_str(value, num, info ? info->base : 10); + return zpl__print_string(text, max_len, info, num); +} - ZPL_BEGIN_C_DECLS +zpl_internal zpl_isize zpl__print_u64(char *text, zpl_isize max_len, zpl__format_info *info, zpl_u64 value) { + char num[130]; + zpl_u64_to_str(value, num, info ? info->base : 10); + return zpl__print_string(text, max_len, info, num); +} - zpl_isize zpl_printf_va(char const *fmt, va_list va) { - return zpl_fprintf_va(zpl_file_get_standard(ZPL_FILE_STANDARD_OUTPUT), fmt, va); +zpl_internal zpl_isize zpl__print_f64(char *text, zpl_isize max_len, zpl__format_info *info, zpl_f64 arg) { + // TODO: Handle exponent notation + zpl_isize width, len, remaining = max_len; + char *text_begin = text; + + if (arg) { + zpl_u64 value; + if (arg < 0) { + if (remaining > 1) *text = '-', remaining--; + text++; + arg = -arg; + } else if (info->flags & ZPL_FMT_MINUS) { + if (remaining > 1) *text = '+', remaining--; + text++; } - - zpl_isize zpl_printf_err_va(char const *fmt, va_list va) { - return zpl_fprintf_va(zpl_file_get_standard(ZPL_FILE_STANDARD_ERROR), fmt, va); - } - - zpl_isize zpl_fprintf_va(struct zpl_file *f, char const *fmt, va_list va) { - zpl_local_persist char buf[4096]; - zpl_isize len = zpl_snprintf_va(buf, zpl_size_of(buf), fmt, va); - zpl_file_write(f, buf, len - 1); // NOTE: prevent extra whitespace - return len; - } - - char *zpl_bprintf_va(char const *fmt, va_list va) { - zpl_local_persist char buffer[4096]; - zpl_snprintf_va(buffer, zpl_size_of(buffer), fmt, va); - return buffer; - } - - zpl_isize zpl_printf(char const *fmt, ...) { - zpl_isize res; - va_list va; - va_start(va, fmt); - res = zpl_printf_va(fmt, va); - va_end(va); - return res; - } - - zpl_isize zpl_printf_err(char const *fmt, ...) { - zpl_isize res; - va_list va; - va_start(va, fmt); - res = zpl_printf_err_va(fmt, va); - va_end(va); - return res; - } - - zpl_isize zpl_fprintf(struct zpl_file *f, char const *fmt, ...) { - zpl_isize res; - va_list va; - va_start(va, fmt); - res = zpl_fprintf_va(f, fmt, va); - va_end(va); - return res; - } - - char *zpl_bprintf(char const *fmt, ...) { - va_list va; - char *str; - va_start(va, fmt); - str = zpl_bprintf_va(fmt, va); - va_end(va); - return str; - } - - zpl_isize zpl_snprintf(char *str, zpl_isize n, char const *fmt, ...) { - zpl_isize res; - va_list va; - va_start(va, fmt); - res = zpl_snprintf_va(str, n, fmt, va); - va_end(va); - return res; - } - - - enum { - ZPL_FMT_MINUS = ZPL_BIT(0), - ZPL_FMT_PLUS = ZPL_BIT(1), - ZPL_FMT_ALT = ZPL_BIT(2), - ZPL_FMT_SPACE = ZPL_BIT(3), - ZPL_FMT_ZERO = ZPL_BIT(4), - - ZPL_FMT_CHAR = ZPL_BIT(5), - ZPL_FMT_SHORT = ZPL_BIT(6), - ZPL_FMT_INT = ZPL_BIT(7), - ZPL_FMT_LONG = ZPL_BIT(8), - ZPL_FMT_LLONG = ZPL_BIT(9), - ZPL_FMT_SIZE = ZPL_BIT(10), - ZPL_FMT_INTPTR = ZPL_BIT(11), - - ZPL_FMT_UNSIGNED = ZPL_BIT(12), - ZPL_FMT_LOWER = ZPL_BIT(13), - ZPL_FMT_UPPER = ZPL_BIT(14), - ZPL_FMT_WIDTH = ZPL_BIT(15), - - ZPL_FMT_DONE = ZPL_BIT(30), - - ZPL_FMT_INTS = - ZPL_FMT_CHAR | ZPL_FMT_SHORT | ZPL_FMT_INT | - ZPL_FMT_LONG | ZPL_FMT_LLONG | ZPL_FMT_SIZE | ZPL_FMT_INTPTR - }; - - typedef struct { - zpl_i32 base; - zpl_i32 flags; - zpl_i32 width; - zpl_i32 precision; - } zpl__format_info; - - zpl_internal zpl_isize zpl__print_string(char *text, zpl_isize max_len, zpl__format_info *info, char const *str) { - zpl_isize res = 0, len = 0; - zpl_isize remaining = max_len; - - if (str == NULL && max_len >= 4) { - res += zpl_strlcpy(text, "(null)", 6); - return res; - } - - if (info && info->precision >= 0) - len = zpl_strnlen(str, info->precision); - else - len = zpl_strlen(str); - - if (info && (info->width == 0 && info->flags & ZPL_FMT_WIDTH)) { - return res; - } - - if (info && (info->width == 0 || info->flags & ZPL_FMT_MINUS)) { - if (info->precision > 0) len = info->precision < len ? info->precision : len; - - res += zpl_strlcpy(text, str, len); - - if (info->width > res) { - zpl_isize padding = info->width - len; - char pad = (info->flags & ZPL_FMT_ZERO) ? '0' : ' '; - while (padding-- > 0 && remaining-- > 0) *text++ = pad, res++; - } - } else { - if (info && (info->width > res)) { - zpl_isize padding = info->width - len; - char pad = (info->flags & ZPL_FMT_ZERO) ? '0' : ' '; - while (padding-- > 0 && remaining-- > 0) *text++ = pad, res++; - } - - res += zpl_strlcpy(text, str, len); - } - - if (info) { - if (info->flags & ZPL_FMT_UPPER) - zpl_str_to_upper(text); - else if (info->flags & ZPL_FMT_LOWER) - zpl_str_to_lower(text); - } - - return res; - } - - zpl_internal zpl_isize zpl__print_char(char *text, zpl_isize max_len, zpl__format_info *info, char arg) { - char str[2] = ""; - str[0] = arg; - return zpl__print_string(text, max_len, info, str); - } - - zpl_internal zpl_isize zpl__print_i64(char *text, zpl_isize max_len, zpl__format_info *info, zpl_i64 value) { - char num[130]; - zpl_i64_to_str(value, num, info ? info->base : 10); - return zpl__print_string(text, max_len, info, num); - } - - zpl_internal zpl_isize zpl__print_u64(char *text, zpl_isize max_len, zpl__format_info *info, zpl_u64 value) { - char num[130]; - zpl_u64_to_str(value, num, info ? info->base : 10); - return zpl__print_string(text, max_len, info, num); - } - - zpl_internal zpl_isize zpl__print_f64(char *text, zpl_isize max_len, zpl__format_info *info, zpl_f64 arg) { - // TODO: Handle exponent notation - zpl_isize width, len, remaining = max_len; - char *text_begin = text; - - if (arg) { - zpl_u64 value; - if (arg < 0) { - if (remaining > 1) *text = '-', remaining--; - text++; - arg = -arg; - } else if (info->flags & ZPL_FMT_MINUS) { - if (remaining > 1) *text = '+', remaining--; - text++; - } - - value = cast(zpl_u64) arg; + + value = cast(zpl_u64) arg; + len = zpl__print_u64(text, remaining, NULL, value); + text += len; + + if (len >= remaining) + remaining = zpl_min(remaining, 1); + else + remaining -= len; + arg -= value; + + if (info->precision < 0) info->precision = 6; + + if ((info->flags & ZPL_FMT_ALT) || info->precision > 0) { + zpl_i64 mult = 10; + if (remaining > 1) *text = '.', remaining--; + text++; + while (info->precision-- > 0) { + value = cast(zpl_u64)(arg * mult); len = zpl__print_u64(text, remaining, NULL, value); text += len; - if (len >= remaining) remaining = zpl_min(remaining, 1); else remaining -= len; - arg -= value; - - if (info->precision < 0) info->precision = 6; - - if ((info->flags & ZPL_FMT_ALT) || info->precision > 0) { - zpl_i64 mult = 10; - if (remaining > 1) *text = '.', remaining--; - text++; - while (info->precision-- > 0) { - value = cast(zpl_u64)(arg * mult); - len = zpl__print_u64(text, remaining, NULL, value); - text += len; - if (len >= remaining) - remaining = zpl_min(remaining, 1); - else - remaining -= len; - arg -= cast(zpl_f64) value / mult; - mult *= 10; - } - } - } else { - if (remaining > 1) *text = '0', remaining--; - text++; - if (info->flags & ZPL_FMT_ALT) { - if (remaining > 1) *text = '.', remaining--; - text++; - } + arg -= cast(zpl_f64) value / mult; + mult *= 10; } - - width = info->width - (text - text_begin); - if (width > 0) { - char fill = (info->flags & ZPL_FMT_ZERO) ? '0' : ' '; - char *end = text + remaining - 1; - len = (text - text_begin); - - for (len = (text - text_begin); len--;) { - if ((text_begin + len + width) < end) *(text_begin + len + width) = *(text_begin + len); - } - - len = width; - text += len; - if (len >= remaining) - remaining = zpl_min(remaining, 1); - else - remaining -= len; - - while (len--) { - if (text_begin + len < end) text_begin[len] = fill; - } - } - - return (text - text_begin); } - - ZPL_NEVER_INLINE zpl_isize zpl_snprintf_va(char *text, zpl_isize max_len, char const *fmt, va_list va) { - char const *text_begin = text; - zpl_isize remaining = max_len, res; - - while (*fmt) { - zpl__format_info info = { 0 }; - zpl_isize len = 0; - info.precision = -1; - - while (*fmt && *fmt != '%' && remaining) *text++ = *fmt++; - - if (*fmt == '%') { - do { - switch (*++fmt) { - case '-': {info.flags |= ZPL_FMT_MINUS; break;} - case '+': {info.flags |= ZPL_FMT_PLUS; break;} - case '#': {info.flags |= ZPL_FMT_ALT; break;} - case ' ': {info.flags |= ZPL_FMT_SPACE; break;} - case '0': {info.flags |= (ZPL_FMT_ZERO|ZPL_FMT_WIDTH); break;} - default: {info.flags |= ZPL_FMT_DONE; break;} - } - } while (!(info.flags & ZPL_FMT_DONE)); - } - - // NOTE: Optional Width - if (*fmt == '*') { - int width = va_arg(va, int); - if (width < 0) { - info.flags |= ZPL_FMT_MINUS; - info.width = -width; - } else { - info.width = width; - } - info.flags |= ZPL_FMT_WIDTH; - fmt++; - } else { - info.width = cast(zpl_i32) zpl_str_to_i64(fmt, cast(char **) & fmt, 10); - if (info.width != 0) { - info.flags |= ZPL_FMT_WIDTH; - } - } - - // NOTE: Optional Precision - if (*fmt == '.') { - fmt++; - if (*fmt == '*') { - info.precision = va_arg(va, int); - fmt++; - } else { - info.precision = cast(zpl_i32) zpl_str_to_i64(fmt, cast(char **) & fmt, 10); - } - info.flags &= ~ZPL_FMT_ZERO; - } - - switch (*fmt++) { - case 'h': - if (*fmt == 'h') { // hh => char - info.flags |= ZPL_FMT_CHAR; - fmt++; - } else { // h => short - info.flags |= ZPL_FMT_SHORT; - } - break; - - case 'l': - if (*fmt == 'l') { // ll => long long - info.flags |= ZPL_FMT_LLONG; - fmt++; - } else { // l => long - info.flags |= ZPL_FMT_LONG; - } - break; - - break; - - case 'z': // NOTE: zpl_usize - info.flags |= ZPL_FMT_UNSIGNED; - // fallthrough - case 't': // NOTE: zpl_isize - info.flags |= ZPL_FMT_SIZE; - break; - - default: fmt--; break; - } - - switch (*fmt) { - case 'u': - info.flags |= ZPL_FMT_UNSIGNED; - // fallthrough - case 'd': - case 'i': info.base = 10; break; - - case 'o': info.base = 8; break; - - case 'x': - info.base = 16; - info.flags |= (ZPL_FMT_UNSIGNED | ZPL_FMT_LOWER); - break; - - case 'X': - info.base = 16; - info.flags |= (ZPL_FMT_UNSIGNED | ZPL_FMT_UPPER); - break; - - case 'f': - case 'F': - case 'g': - case 'G': len = zpl__print_f64(text, remaining, &info, va_arg(va, zpl_f64)); break; - - case 'a': - case 'A': - // TODO: - break; - - case 'c': len = zpl__print_char(text, remaining, &info, cast(char) va_arg(va, int)); break; - - case 's': len = zpl__print_string(text, remaining, &info, va_arg(va, char *)); break; - - case 'p': - info.base = 16; - info.flags |= (ZPL_FMT_LOWER | ZPL_FMT_UNSIGNED | ZPL_FMT_ALT | ZPL_FMT_INTPTR); - break; - - case '%': len = zpl__print_char(text, remaining, &info, '%'); break; - - default: fmt--; break; - } - - fmt++; - - if (info.base != 0) { - if (info.flags & ZPL_FMT_UNSIGNED) { - zpl_u64 value = 0; - switch (info.flags & ZPL_FMT_INTS) { - case ZPL_FMT_CHAR: value = cast(zpl_u64) cast(zpl_u8) va_arg(va, int); break; - case ZPL_FMT_SHORT: value = cast(zpl_u64) cast(zpl_u16) va_arg(va, int); break; - case ZPL_FMT_LONG: value = cast(zpl_u64) va_arg(va, unsigned long); break; - case ZPL_FMT_LLONG: value = cast(zpl_u64) va_arg(va, unsigned long long); break; - case ZPL_FMT_SIZE: value = cast(zpl_u64) va_arg(va, zpl_usize); break; - case ZPL_FMT_INTPTR: value = cast(zpl_u64) va_arg(va, zpl_uintptr); break; - default: value = cast(zpl_u64) va_arg(va, unsigned int); break; - } - - len = zpl__print_u64(text, remaining, &info, value); - - } else { - zpl_i64 value = 0; - switch (info.flags & ZPL_FMT_INTS) { - case ZPL_FMT_CHAR: value = cast(zpl_i64) cast(zpl_i8) va_arg(va, int); break; - case ZPL_FMT_SHORT: value = cast(zpl_i64) cast(zpl_i16) va_arg(va, int); break; - case ZPL_FMT_LONG: value = cast(zpl_i64) va_arg(va, long); break; - case ZPL_FMT_LLONG: value = cast(zpl_i64) va_arg(va, long long); break; - case ZPL_FMT_SIZE: value = cast(zpl_i64) va_arg(va, zpl_usize); break; - case ZPL_FMT_INTPTR: value = cast(zpl_i64) va_arg(va, zpl_uintptr); break; - default: value = cast(zpl_i64) va_arg(va, int); break; - } - - len = zpl__print_i64(text, remaining, &info, value); - } - } - - text += len; - if (len >= remaining) - remaining = zpl_min(remaining, 1); - else - remaining -= len; - } - - *text++ = '\0'; - res = (text - text_begin); - return (res >= max_len || res < 0) ? -1 : res; + } else { + if (remaining > 1) *text = '0', remaining--; + text++; + if (info->flags & ZPL_FMT_ALT) { + if (remaining > 1) *text = '.', remaining--; + text++; } - - ZPL_END_C_DECLS - // file: source/core/time.c - - #ifdef ZPL_EDITOR - #include - #endif - - #if defined(ZPL_SYSTEM_MACOS) || ZPL_SYSTEM_UNIX - #include - #include - #endif - - #if defined(ZPL_SYSTEM_MACOS) - #include - #include - #include - #endif - - #if defined(ZPL_SYSTEM_EMSCRIPTEN) - #include - #endif - - #if defined(ZPL_SYSTEM_WINDOWS) - #include - #endif - - ZPL_BEGIN_C_DECLS - - //! @} - //$$ - //////////////////////////////////////////////////////////////// - // - // Time - // - // - - #if defined(ZPL_COMPILER_MSVC) && !defined(__clang__) - zpl_u64 zpl_rdtsc(void) { return __rdtsc( ); } - #elif defined(__i386__) - zpl_u64 zpl_rdtsc(void) { - zpl_u64 x; - __asm__ volatile(".byte 0x0f, 0x31" : "=A"(x)); - return x; - } - #elif defined(__x86_64__) - zpl_u64 zpl_rdtsc(void) { - zpl_u32 hi, lo; - __asm__ __volatile__("rdtsc" : "=a"(lo), "=d"(hi)); - return (cast(zpl_u64) lo) | ((cast(zpl_u64) hi) << 32); - } - #elif defined(__powerpc__) - zpl_u64 zpl_rdtsc(void) { - zpl_u64 result = 0; - zpl_u32 upper, lower, tmp; - __asm__ volatile("0: \n" - "\tmftbu %0 \n" - "\tmftb %1 \n" - "\tmftbu %2 \n" - "\tcmpw %2,%0 \n" - "\tbne 0b \n" - : "=r"(upper), "=r"(lower), "=r"(tmp)); - result = upper; - result = result << 32; - result = result | lower; - - return result; - } - #elif defined(ZPL_SYSTEM_EMSCRIPTEN) - zpl_u64 zpl_rdtsc(void) { - return (zpl_u64)(emscripten_get_now() * 1e+6); - } - #elif defined(ZPL_CPU_ARM) - zpl_u64 zpl_rdtsc(void) { - #if defined(__aarch64__) - int64_t r = 0; - asm volatile("mrs %0, cntvct_el0" : "=r"(r)); - #elif (__ARM_ARCH >= 6) - uint32_t r = 0; - uint32_t pmccntr; - uint32_t pmuseren; - uint32_t pmcntenset; - - // Read the user mode perf monitor counter access permissions. - asm volatile("mrc p15, 0, %0, c9, c14, 0" : "=r"(pmuseren)); - if (pmuseren & 1) { // Allows reading perfmon counters for user mode code. - asm volatile("mrc p15, 0, %0, c9, c12, 1" : "=r"(pmcntenset)); - if (pmcntenset & 0x80000000ul) { // Is it counting? - asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r"(pmccntr)); - // The counter is set up to count every 64th cycle - return ((int64_t)pmccntr) * 64; // Should optimize to << 6 - } - } - #else - #error "No suitable method for zpl_rdtsc for this cpu type" - #endif - - return r; - } - #endif - - #if defined(ZPL_SYSTEM_WINDOWS) || defined(ZPL_SYSTEM_CYGWIN) - - zpl_u64 zpl_time_rel_ms(void) { - zpl_local_persist LARGE_INTEGER win32_perf_count_freq = { 0 }; - zpl_u64 result; - LARGE_INTEGER counter; - zpl_local_persist LARGE_INTEGER win32_perf_counter = { 0 }; - if (!win32_perf_count_freq.QuadPart) { - QueryPerformanceFrequency(&win32_perf_count_freq); - ZPL_ASSERT(win32_perf_count_freq.QuadPart != 0); - QueryPerformanceCounter(&win32_perf_counter); - } - - QueryPerformanceCounter(&counter); - - result = (counter.QuadPart - win32_perf_counter.QuadPart) * 1000 / (win32_perf_count_freq.QuadPart); - return result; - } - - zpl_u64 zpl_time_utc_ms(void) { - FILETIME ft; - ULARGE_INTEGER li; - - GetSystemTimeAsFileTime(&ft); - li.LowPart = ft.dwLowDateTime; - li.HighPart = ft.dwHighDateTime; - - return li.QuadPart / 1000; - } - - zpl_u64 zpl_time_tz_ms(void) { - FILETIME ft; - SYSTEMTIME st, lst; - ULARGE_INTEGER li; - - GetSystemTime(&st); - SystemTimeToTzSpecificLocalTime(NULL, &st, &lst); - SystemTimeToFileTime(&lst, &ft); - li.LowPart = ft.dwLowDateTime; - li.HighPart = ft.dwHighDateTime; - - return li.QuadPart / 1000; - } - - void zpl_sleep_ms(zpl_u32 ms) { Sleep(ms); } - - #else - - #if defined(ZPL_SYSTEM_LINUX) || defined(ZPL_SYSTEM_FREEBSD) || defined(ZPL_SYSTEM_OPENBSD) || defined(ZPL_SYSTEM_EMSCRIPTEN) - zpl_u64 zpl__unix_gettime(void) { - struct timespec t; - zpl_u64 result; - - clock_gettime(1 /*CLOCK_MONOTONIC*/, &t); - result = 1000 * t.tv_sec + 1.0e-6 * t.tv_nsec; - return result; - } - #endif - - zpl_u64 zpl_time_rel_ms(void) { - #if defined(ZPL_SYSTEM_OSX) - zpl_u64 result; - - zpl_local_persist zpl_u64 timebase = 0; - zpl_local_persist zpl_u64 timestart = 0; - - if (!timestart) { - mach_timebase_info_data_t tb = { 0 }; - mach_timebase_info(&tb); - timebase = tb.numer; - timebase /= tb.denom; - timestart = mach_absolute_time(); - } - - // NOTE: mach_absolute_time() returns things in nanoseconds - result = 1.0e-6 * (mach_absolute_time() - timestart) * timebase; - return result; - #else - zpl_local_persist zpl_u64 unix_timestart = 0.0; - - if (!unix_timestart) { unix_timestart = zpl__unix_gettime( ); } - - zpl_u64 now = zpl__unix_gettime( ); - - return (now - unix_timestart); - #endif - } - - zpl_u64 zpl_time_utc_ms(void) { - struct timespec t; - #if defined(ZPL_SYSTEM_OSX) - clock_serv_t cclock; - mach_timespec_t mts; - host_get_clock_service(mach_host_self( ), CALENDAR_CLOCK, &cclock); - clock_get_time(cclock, &mts); - mach_port_deallocate(mach_task_self( ), cclock); - t.tv_sec = mts.tv_sec; - t.tv_nsec = mts.tv_nsec; - #else - clock_gettime(0 /*CLOCK_REALTIME*/, &t); - #endif - return ((zpl_u64)t.tv_sec * 1000 + t.tv_nsec * 1e-6 + ZPL__UNIX_TO_WIN32_EPOCH); - } - - void zpl_sleep_ms(zpl_u32 ms) { - struct timespec req = { cast(time_t)(ms * 1e-3), cast(long)((ms % 1000) * 1e6) }; - struct timespec rem = { 0, 0 }; - nanosleep(&req, &rem); - } - - zpl_u64 zpl_time_tz_ms(void) { - struct tm t; - zpl_u64 result = zpl_time_utc_ms() - ZPL__UNIX_TO_WIN32_EPOCH; - zpl_u16 ms = result % 1000; - result *= 1e-3; - localtime_r((const time_t*)&result, &t); - result = (zpl_u64)mktime(&t); - return (result - timezone + t.tm_isdst * 3600) * 1000 + ms + ZPL__UNIX_TO_WIN32_EPOCH; - } - #endif - - zpl_f64 zpl_time_rel(void) { - return (zpl_f64)(zpl_time_rel_ms() * 1e-3); + } + + width = info->width - (text - text_begin); + if (width > 0) { + char fill = (info->flags & ZPL_FMT_ZERO) ? '0' : ' '; + char *end = text + remaining - 1; + len = (text - text_begin); + + for (len = (text - text_begin); len--;) { + if ((text_begin + len + width) < end) *(text_begin + len + width) = *(text_begin + len); } - - zpl_f64 zpl_time_utc(void) { - return (zpl_f64)(zpl_time_utc_ms() * 1e-3); + + len = width; + text += len; + if (len >= remaining) + remaining = zpl_min(remaining, 1); + else + remaining -= len; + + while (len--) { + if (text_begin + len < end) text_begin[len] = fill; } + } + + return (text - text_begin); +} - zpl_f64 zpl_time_tz(void) { - return (zpl_f64)(zpl_time_tz_ms() * 1e-3); - } - - - - ZPL_END_C_DECLS - // file: source/core/random.c - - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - #if defined(ZPL_MODULE_THREADING) - zpl_global zpl_atomic32 zpl__random_shared_counter = {0}; - #else - zpl_global zpl_i32 zpl__random_shared_counter = 0; - #endif - - zpl_internal zpl_u32 zpl__get_noise_from_time(void) { - zpl_u32 accum = 0; - zpl_f64 start, remaining, end, curr = 0; - zpl_u64 interval = 100000ll; - - start = zpl_time_rel(); - remaining = (interval - cast(zpl_u64)(interval*start)%interval) / cast(zpl_f64)interval; - end = start + remaining; - +ZPL_NEVER_INLINE zpl_isize zpl_snprintf_va(char *text, zpl_isize max_len, char const *fmt, va_list va) { + char const *text_begin = text; + zpl_isize remaining = max_len, res; + + while (*fmt) { + zpl__format_info info = { 0 }; + zpl_isize len = 0; + info.precision = -1; + + while (*fmt && *fmt != '%' && remaining) *text++ = *fmt++; + + if (*fmt == '%') { do { - curr = zpl_time_rel(); - accum += cast(zpl_u32)curr; - } while (curr >= end); - return accum; + switch (*++fmt) { + case '-': {info.flags |= ZPL_FMT_MINUS; break;} + case '+': {info.flags |= ZPL_FMT_PLUS; break;} + case '#': {info.flags |= ZPL_FMT_ALT; break;} + case ' ': {info.flags |= ZPL_FMT_SPACE; break;} + case '0': {info.flags |= (ZPL_FMT_ZERO|ZPL_FMT_WIDTH); break;} + default: {info.flags |= ZPL_FMT_DONE; break;} + } + } while (!(info.flags & ZPL_FMT_DONE)); } - - // NOTE: Partly from http://preshing.com/20121224/how-to-generate-a-sequence-of-unique-random-integers/ - // But the generation is even more random-er-est - - zpl_internal ZPL_ALWAYS_INLINE zpl_u32 zpl__permute_qpr(zpl_u32 x) { - zpl_local_persist zpl_u32 const prime = 4294967291; // 2^32 - 5 - if (x >= prime) { - return x; + + // NOTE: Optional Width + if (*fmt == '*') { + int width = va_arg(va, int); + if (width < 0) { + info.flags |= ZPL_FMT_MINUS; + info.width = -width; } else { - zpl_u32 residue = cast(zpl_u32)(cast(zpl_u64) x * x) % prime; - if (x <= prime / 2) - return residue; - else - return prime - residue; + info.width = width; + } + info.flags |= ZPL_FMT_WIDTH; + fmt++; + } else { + info.width = cast(zpl_i32) zpl_str_to_i64(fmt, cast(char **) & fmt, 10); + if (info.width != 0) { + info.flags |= ZPL_FMT_WIDTH; } } - - zpl_internal ZPL_ALWAYS_INLINE zpl_u32 zpl__permute_with_offset(zpl_u32 x, zpl_u32 offset) { - return (zpl__permute_qpr(x) + offset) ^ 0x5bf03635; + + // NOTE: Optional Precision + if (*fmt == '.') { + fmt++; + if (*fmt == '*') { + info.precision = va_arg(va, int); + fmt++; + } else { + info.precision = cast(zpl_i32) zpl_str_to_i64(fmt, cast(char **) & fmt, 10); + } + info.flags &= ~ZPL_FMT_ZERO; } + + switch (*fmt++) { + case 'h': + if (*fmt == 'h') { // hh => char + info.flags |= ZPL_FMT_CHAR; + fmt++; + } else { // h => short + info.flags |= ZPL_FMT_SHORT; + } + break; + + case 'l': + if (*fmt == 'l') { // ll => long long + info.flags |= ZPL_FMT_LLONG; + fmt++; + } else { // l => long + info.flags |= ZPL_FMT_LONG; + } + break; + + break; + + case 'z': // NOTE: zpl_usize + info.flags |= ZPL_FMT_UNSIGNED; + // fallthrough + case 't': // NOTE: zpl_isize + info.flags |= ZPL_FMT_SIZE; + break; + + default: fmt--; break; + } + + switch (*fmt) { + case 'u': + info.flags |= ZPL_FMT_UNSIGNED; + // fallthrough + case 'd': + case 'i': info.base = 10; break; + + case 'o': info.base = 8; break; + + case 'x': + info.base = 16; + info.flags |= (ZPL_FMT_UNSIGNED | ZPL_FMT_LOWER); + break; + + case 'X': + info.base = 16; + info.flags |= (ZPL_FMT_UNSIGNED | ZPL_FMT_UPPER); + break; + + case 'f': + case 'F': + case 'g': + case 'G': len = zpl__print_f64(text, remaining, &info, va_arg(va, zpl_f64)); break; + + case 'a': + case 'A': + // TODO: + break; + + case 'c': len = zpl__print_char(text, remaining, &info, cast(char) va_arg(va, int)); break; + + case 's': len = zpl__print_string(text, remaining, &info, va_arg(va, char *)); break; + + case 'p': + info.base = 16; + info.flags |= (ZPL_FMT_LOWER | ZPL_FMT_UNSIGNED | ZPL_FMT_ALT | ZPL_FMT_INTPTR); + break; + + case '%': len = zpl__print_char(text, remaining, &info, '%'); break; + + default: fmt--; break; + } + + fmt++; + + if (info.base != 0) { + if (info.flags & ZPL_FMT_UNSIGNED) { + zpl_u64 value = 0; + switch (info.flags & ZPL_FMT_INTS) { + case ZPL_FMT_CHAR: value = cast(zpl_u64) cast(zpl_u8) va_arg(va, int); break; + case ZPL_FMT_SHORT: value = cast(zpl_u64) cast(zpl_u16) va_arg(va, int); break; + case ZPL_FMT_LONG: value = cast(zpl_u64) va_arg(va, unsigned long); break; + case ZPL_FMT_LLONG: value = cast(zpl_u64) va_arg(va, unsigned long long); break; + case ZPL_FMT_SIZE: value = cast(zpl_u64) va_arg(va, zpl_usize); break; + case ZPL_FMT_INTPTR: value = cast(zpl_u64) va_arg(va, zpl_uintptr); break; + default: value = cast(zpl_u64) va_arg(va, unsigned int); break; + } + + len = zpl__print_u64(text, remaining, &info, value); + + } else { + zpl_i64 value = 0; + switch (info.flags & ZPL_FMT_INTS) { + case ZPL_FMT_CHAR: value = cast(zpl_i64) cast(zpl_i8) va_arg(va, int); break; + case ZPL_FMT_SHORT: value = cast(zpl_i64) cast(zpl_i16) va_arg(va, int); break; + case ZPL_FMT_LONG: value = cast(zpl_i64) va_arg(va, long); break; + case ZPL_FMT_LLONG: value = cast(zpl_i64) va_arg(va, long long); break; + case ZPL_FMT_SIZE: value = cast(zpl_i64) va_arg(va, zpl_usize); break; + case ZPL_FMT_INTPTR: value = cast(zpl_i64) va_arg(va, zpl_uintptr); break; + default: value = cast(zpl_i64) va_arg(va, int); break; + } + + len = zpl__print_i64(text, remaining, &info, value); + } + } + + text += len; + if (len >= remaining) + remaining = zpl_min(remaining, 1); + else + remaining -= len; + } + + *text++ = '\0'; + res = (text - text_begin); + return (res >= max_len || res < 0) ? -1 : res; +} + +ZPL_END_C_DECLS +// file: source/core/time.c + +#ifdef ZPL_EDITOR +#include +#endif + +#if defined(ZPL_SYSTEM_MACOS) || ZPL_SYSTEM_UNIX +#include +#include +#endif + +#if defined(ZPL_SYSTEM_MACOS) +#include +#include +#include +#endif + +#if defined(ZPL_SYSTEM_EMSCRIPTEN) +#include +#endif + +#if defined(ZPL_SYSTEM_WINDOWS) +#include +#endif + +ZPL_BEGIN_C_DECLS + +//! @} +//$$ +//////////////////////////////////////////////////////////////// +// +// Time +// +// + +#if defined(ZPL_COMPILER_MSVC) && !defined(__clang__) +zpl_u64 zpl_rdtsc(void) { return __rdtsc( ); } +#elif defined(__i386__) +zpl_u64 zpl_rdtsc(void) { + zpl_u64 x; + __asm__ volatile(".byte 0x0f, 0x31" : "=A"(x)); + return x; +} +#elif defined(__x86_64__) +zpl_u64 zpl_rdtsc(void) { + zpl_u32 hi, lo; + __asm__ __volatile__("rdtsc" : "=a"(lo), "=d"(hi)); + return (cast(zpl_u64) lo) | ((cast(zpl_u64) hi) << 32); +} +#elif defined(__powerpc__) +zpl_u64 zpl_rdtsc(void) { + zpl_u64 result = 0; + zpl_u32 upper, lower, tmp; + __asm__ volatile("0: \n" + "\tmftbu %0 \n" + "\tmftb %1 \n" + "\tmftbu %2 \n" + "\tcmpw %2,%0 \n" + "\tbne 0b \n" + : "=r"(upper), "=r"(lower), "=r"(tmp)); + result = upper; + result = result << 32; + result = result | lower; + + return result; +} +#elif defined(ZPL_SYSTEM_EMSCRIPTEN) +zpl_u64 zpl_rdtsc(void) { + return (zpl_u64)(emscripten_get_now() * 1e+6); +} +#elif defined(ZPL_CPU_ARM) +zpl_u64 zpl_rdtsc(void) { +#if defined(__aarch64__) + int64_t r = 0; + asm volatile("mrs %0, cntvct_el0" : "=r"(r)); +#elif (__ARM_ARCH >= 6) + uint32_t r = 0; + uint32_t pmccntr; + uint32_t pmuseren; + uint32_t pmcntenset; + + // Read the user mode perf monitor counter access permissions. + asm volatile("mrc p15, 0, %0, c9, c14, 0" : "=r"(pmuseren)); + if (pmuseren & 1) { // Allows reading perfmon counters for user mode code. + asm volatile("mrc p15, 0, %0, c9, c12, 1" : "=r"(pmcntenset)); + if (pmcntenset & 0x80000000ul) { // Is it counting? + asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r"(pmccntr)); + // The counter is set up to count every 64th cycle + return ((int64_t)pmccntr) * 64; // Should optimize to << 6 + } + } +#else +#error "No suitable method for zpl_rdtsc for this cpu type" +#endif + + return r; +} +#endif + +#if defined(ZPL_SYSTEM_WINDOWS) || defined(ZPL_SYSTEM_CYGWIN) + +zpl_u64 zpl_time_rel_ms(void) { + zpl_local_persist LARGE_INTEGER win32_perf_count_freq = { 0 }; + zpl_u64 result; + LARGE_INTEGER counter; + zpl_local_persist LARGE_INTEGER win32_perf_counter = { 0 }; + if (!win32_perf_count_freq.QuadPart) { + QueryPerformanceFrequency(&win32_perf_count_freq); + ZPL_ASSERT(win32_perf_count_freq.QuadPart != 0); + QueryPerformanceCounter(&win32_perf_counter); + } + + QueryPerformanceCounter(&counter); + + result = (counter.QuadPart - win32_perf_counter.QuadPart) * 1000 / (win32_perf_count_freq.QuadPart); + return result; +} + +zpl_u64 zpl_time_utc_ms(void) { + FILETIME ft; + ULARGE_INTEGER li; + + GetSystemTimeAsFileTime(&ft); + li.LowPart = ft.dwLowDateTime; + li.HighPart = ft.dwHighDateTime; + + return li.QuadPart / 1000; +} + +zpl_u64 zpl_time_tz_ms(void) { + FILETIME ft; + SYSTEMTIME st, lst; + ULARGE_INTEGER li; + + GetSystemTime(&st); + SystemTimeToTzSpecificLocalTime(NULL, &st, &lst); + SystemTimeToFileTime(&lst, &ft); + li.LowPart = ft.dwLowDateTime; + li.HighPart = ft.dwHighDateTime; + + return li.QuadPart / 1000; +} + +void zpl_sleep_ms(zpl_u32 ms) { Sleep(ms); } + +#else + +#if defined(ZPL_SYSTEM_LINUX) || defined(ZPL_SYSTEM_FREEBSD) || defined(ZPL_SYSTEM_OPENBSD) || defined(ZPL_SYSTEM_EMSCRIPTEN) +zpl_u64 zpl__unix_gettime(void) { + struct timespec t; + zpl_u64 result; + + clock_gettime(1 /*CLOCK_MONOTONIC*/, &t); + result = 1000 * t.tv_sec + 1.0e-6 * t.tv_nsec; + return result; +} +#endif + +zpl_u64 zpl_time_rel_ms(void) { +#if defined(ZPL_SYSTEM_OSX) + zpl_u64 result; + + zpl_local_persist zpl_u64 timebase = 0; + zpl_local_persist zpl_u64 timestart = 0; + + if (!timestart) { + mach_timebase_info_data_t tb = { 0 }; + mach_timebase_info(&tb); + timebase = tb.numer; + timebase /= tb.denom; + timestart = mach_absolute_time(); + } + + // NOTE: mach_absolute_time() returns things in nanoseconds + result = 1.0e-6 * (mach_absolute_time() - timestart) * timebase; + return result; +#else + zpl_local_persist zpl_u64 unix_timestart = 0.0; + + if (!unix_timestart) { unix_timestart = zpl__unix_gettime( ); } + + zpl_u64 now = zpl__unix_gettime( ); + + return (now - unix_timestart); +#endif +} + +zpl_u64 zpl_time_utc_ms(void) { + struct timespec t; +#if defined(ZPL_SYSTEM_OSX) + clock_serv_t cclock; + mach_timespec_t mts; + host_get_clock_service(mach_host_self( ), CALENDAR_CLOCK, &cclock); + clock_get_time(cclock, &mts); + mach_port_deallocate(mach_task_self( ), cclock); + t.tv_sec = mts.tv_sec; + t.tv_nsec = mts.tv_nsec; +#else + clock_gettime(0 /*CLOCK_REALTIME*/, &t); +#endif + return ((zpl_u64)t.tv_sec * 1000 + t.tv_nsec * 1e-6 + ZPL__UNIX_TO_WIN32_EPOCH); +} + +void zpl_sleep_ms(zpl_u32 ms) { + struct timespec req = { cast(time_t)(ms * 1e-3), cast(long)((ms % 1000) * 1e6) }; + struct timespec rem = { 0, 0 }; + nanosleep(&req, &rem); +} + +zpl_u64 zpl_time_tz_ms(void) { + struct tm t; + zpl_u64 result = zpl_time_utc_ms() - ZPL__UNIX_TO_WIN32_EPOCH; + zpl_u16 ms = result % 1000; + result *= 1e-3; + localtime_r((const time_t*)&result, &t); + result = (zpl_u64)mktime(&t); + return (result - timezone + t.tm_isdst * 3600) * 1000 + ms + ZPL__UNIX_TO_WIN32_EPOCH; +} +#endif + +zpl_f64 zpl_time_rel(void) { + return (zpl_f64)(zpl_time_rel_ms() * 1e-3); +} + +zpl_f64 zpl_time_utc(void) { + return (zpl_f64)(zpl_time_utc_ms() * 1e-3); +} + +zpl_f64 zpl_time_tz(void) { + return (zpl_f64)(zpl_time_tz_ms() * 1e-3); +} - void zpl_random_init(zpl_random *r) { - zpl_u64 time, tick; - zpl_isize i, j; - zpl_u32 x = 0; - r->value = 0; - r->offsets[0] = zpl__get_noise_from_time(); - #ifdef ZPL_MODULE_THREADING - r->offsets[1] = zpl_atomic32_fetch_add(&zpl__random_shared_counter, 1); - r->offsets[2] = zpl_thread_current_id(); - r->offsets[3] = zpl_thread_current_id() * 3 + 1; - #else - r->offsets[1] = zpl__random_shared_counter++; - r->offsets[2] = 0; - r->offsets[3] = 1; - #endif - time = zpl_time_tz_ms(); - r->offsets[4] = cast(zpl_u32)(time >> 32); - r->offsets[5] = cast(zpl_u32)time; - r->offsets[6] = zpl__get_noise_from_time(); - tick = zpl_rdtsc(); - r->offsets[7] = cast(zpl_u32)(tick ^ (tick >> 32)); +ZPL_END_C_DECLS +// file: source/core/random.c - for (j = 0; j < 4; j++) { - for (i = 0; i < zpl_count_of(r->offsets); i++) { - r->offsets[i] = x = zpl__permute_with_offset(x, r->offsets[i]); +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +#if defined(ZPL_MODULE_THREADING) +zpl_global zpl_atomic32 zpl__random_shared_counter = {0}; +#else +zpl_global zpl_i32 zpl__random_shared_counter = 0; +#endif + +zpl_internal zpl_u32 zpl__get_noise_from_time(void) { + zpl_u32 accum = 0; + zpl_f64 start, remaining, end, curr = 0; + zpl_u64 interval = 100000ll; + + start = zpl_time_rel(); + remaining = (interval - cast(zpl_u64)(interval*start)%interval) / cast(zpl_f64)interval; + end = start + remaining; + + do { + curr = zpl_time_rel(); + accum += cast(zpl_u32)curr; + } while (curr >= end); + return accum; +} + +// NOTE: Partly from http://preshing.com/20121224/how-to-generate-a-sequence-of-unique-random-integers/ +// But the generation is even more random-er-est + +zpl_internal ZPL_ALWAYS_INLINE zpl_u32 zpl__permute_qpr(zpl_u32 x) { + zpl_local_persist zpl_u32 const prime = 4294967291; // 2^32 - 5 + if (x >= prime) { + return x; + } else { + zpl_u32 residue = cast(zpl_u32)(cast(zpl_u64) x * x) % prime; + if (x <= prime / 2) + return residue; + else + return prime - residue; + } +} + +zpl_internal ZPL_ALWAYS_INLINE zpl_u32 zpl__permute_with_offset(zpl_u32 x, zpl_u32 offset) { + return (zpl__permute_qpr(x) + offset) ^ 0x5bf03635; +} + + +void zpl_random_init(zpl_random *r) { + zpl_u64 time, tick; + zpl_isize i, j; + zpl_u32 x = 0; + r->value = 0; + + r->offsets[0] = zpl__get_noise_from_time(); +#ifdef ZPL_MODULE_THREADING + r->offsets[1] = zpl_atomic32_fetch_add(&zpl__random_shared_counter, 1); + r->offsets[2] = zpl_thread_current_id(); + r->offsets[3] = zpl_thread_current_id() * 3 + 1; +#else + r->offsets[1] = zpl__random_shared_counter++; + r->offsets[2] = 0; + r->offsets[3] = 1; +#endif + time = zpl_time_tz_ms(); + r->offsets[4] = cast(zpl_u32)(time >> 32); + r->offsets[5] = cast(zpl_u32)time; + r->offsets[6] = zpl__get_noise_from_time(); + tick = zpl_rdtsc(); + r->offsets[7] = cast(zpl_u32)(tick ^ (tick >> 32)); + + for (j = 0; j < 4; j++) { + for (i = 0; i < zpl_count_of(r->offsets); i++) { + r->offsets[i] = x = zpl__permute_with_offset(x, r->offsets[i]); + } + } +} + +zpl_u32 zpl_random_gen_u32(zpl_random *r) { + zpl_u32 x = r->value; + zpl_u32 carry = 1; + zpl_isize i; + for (i = 0; i < zpl_count_of(r->offsets); i++) { + x = zpl__permute_with_offset(x, r->offsets[i]); + if (carry > 0) { + carry = ++r->offsets[i] ? 0 : 1; + } + } + + r->value = x; + return x; +} + +zpl_u32 zpl_random_gen_u32_unique(zpl_random *r) { + zpl_u32 x = r->value; + zpl_isize i; + r->value++; + for (i = 0; i < zpl_count_of(r->offsets); i++) { + x = zpl__permute_with_offset(x, r->offsets[i]); + } + + return x; +} + +zpl_u64 zpl_random_gen_u64(zpl_random *r) { + return ((cast(zpl_u64)zpl_random_gen_u32(r)) << 32) | zpl_random_gen_u32(r); +} + + +zpl_isize zpl_random_gen_isize(zpl_random *r) { + zpl_u64 u = zpl_random_gen_u64(r); + return *cast(zpl_isize *)&u; +} + + +zpl_i64 zpl_random_range_i64(zpl_random *r, zpl_i64 lower_inc, zpl_i64 higher_inc) { + zpl_u64 u = zpl_random_gen_u64(r); + zpl_i64 i = *cast(zpl_i64 *)&u; + zpl_i64 diff = higher_inc-lower_inc+1; + i %= diff; + i += lower_inc; + return i; +} + +zpl_isize zpl_random_range_isize(zpl_random *r, zpl_isize lower_inc, zpl_isize higher_inc) { + zpl_u64 u = zpl_random_gen_u64(r); + zpl_isize i = *cast(zpl_isize *)&u; + zpl_isize diff = higher_inc-lower_inc+1; + i %= diff; + i += lower_inc; + return i; +} + +ZPL_ALWAYS_INLINE zpl_f64 zpl__random_copy_sign64(zpl_f64 x, zpl_f64 y) { + zpl_i64 ix=0, iy=0; + zpl_memcopy(&ix, &x, zpl_size_of(zpl_i64)); + zpl_memcopy(&iy, &y, zpl_size_of(zpl_i64)); + + ix &= 0x7fffffffffffffff; + ix |= iy & 0x8000000000000000; + + zpl_f64 r = 0.0; + zpl_memcopy(&r, &ix, zpl_size_of(zpl_f64)); + return r; +} + +ZPL_ALWAYS_INLINE zpl_f64 zpl__random_floor64 (zpl_f64 x) { return cast(zpl_f64)((x >= 0.0) ? cast(zpl_i64)x : cast(zpl_i64)(x-0.9999999999999999)); } +ZPL_ALWAYS_INLINE zpl_f64 zpl__random_ceil64 (zpl_f64 x) { return cast(zpl_f64)((x < 0) ? cast(zpl_i64)x : (cast(zpl_i64)x)+1); } +ZPL_ALWAYS_INLINE zpl_f64 zpl__random_round64 (zpl_f64 x) { return cast(zpl_f64)((x >= 0.0) ? zpl__random_floor64(x + 0.5) : zpl__random_ceil64(x - 0.5)); } +ZPL_ALWAYS_INLINE zpl_f64 zpl__random_remainder64(zpl_f64 x, zpl_f64 y) { return x - (zpl__random_round64(x/y)*y); } +ZPL_ALWAYS_INLINE zpl_f64 zpl__random_abs64 (zpl_f64 x) { return x < 0 ? -x : x; } +ZPL_ALWAYS_INLINE zpl_f64 zpl__random_sign64 (zpl_f64 x) { return x < 0 ? -1.0 : +1.0; } + +ZPL_ALWAYS_INLINE zpl_f64 zpl__random_mod64(zpl_f64 x, zpl_f64 y) { + zpl_f64 result; + y = zpl__random_abs64(y); + result = zpl__random_remainder64(zpl__random_abs64(x), y); + if (zpl__random_sign64(result)) result += y; + return zpl__random_copy_sign64(result, x); +} + +zpl_f64 zpl_random_range_f64(zpl_random *r, zpl_f64 lower_inc, zpl_f64 higher_inc) { + zpl_u64 u = zpl_random_gen_u64(r); + zpl_f64 f = 0; + zpl_memcopy(&f, &u, zpl_size_of(zpl_f64)); + zpl_f64 diff = higher_inc-lower_inc+1.0; + f = zpl__random_mod64(f, diff); + f += lower_inc; + return f; +} + +ZPL_END_C_DECLS +// file: source/core/misc.c + +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +#if defined(ZPL_SYSTEM_UNIX) || defined(ZPL_SYSTEM_MACOS) +#include +#endif + +#if defined(ZPL_SYSTEM_WINDOWS) +void zpl_exit(zpl_u32 code) { ExitProcess(code); } +#else +void zpl_exit(zpl_u32 code) { exit(code); } +#endif + +void zpl_yield(void) { +#if defined(ZPL_SYSTEM_WINDOWS) + Sleep(0); +#else + sched_yield(); +#endif +} + +const char *zpl_get_env(const char *name) { + char *buffer = NULL; + const char *ptr = zpl_get_env_buf(name); + + if (ptr == NULL) { + return NULL; + } + + zpl_isize ptr_size = zpl_strlen(ptr); + buffer = (char *)zpl_malloc(ptr_size * sizeof(char)+1); + zpl_memcopy((char *)buffer, ptr, ptr_size+1); + return buffer; +} + +const char *zpl_get_env_buf(const char *name) { +#ifdef ZPL_SYSTEM_WINDOWS + zpl_local_persist wchar_t wbuffer[32767] = {0}; + zpl_local_persist char buffer[32767] = {0}; + + if (!GetEnvironmentVariableW( + cast(LPCWSTR)zpl_utf8_to_ucs2_buf(cast(const zpl_u8 *)name), + cast(LPWSTR)wbuffer, 32767)) { + return NULL; + } + + zpl_ucs2_to_utf8(cast(zpl_u8*)buffer, 32767, cast(const zpl_u16*)wbuffer); + + return (const char *)buffer; +#else + return (const char *)getenv(name); +#endif +} + +zpl_string zpl_get_env_str(const char *name) { + const char *buf = zpl_get_env_buf(name); + + if (buf == NULL) { + return NULL; + } + + zpl_string str = zpl_string_make(zpl_heap(), buf); + return str; +} + +void zpl_set_env(const char *name, const char *value) { +#if defined(ZPL_SYSTEM_WINDOWS) + SetEnvironmentVariableA(name, value); +#else + setenv(name, value, 1); +#endif +} + +void zpl_unset_env(const char *name) { +#if defined(ZPL_SYSTEM_WINDOWS) + SetEnvironmentVariableA(name, NULL); +#else + unsetenv(name); +#endif +} + +#if !defined(ZPL_SYSTEM_WINDOWS) +extern char **environ; +#endif + +zpl_u32 zpl_system_command(const char *command, zpl_usize buffer_len, char *buffer) { +#if defined(ZPL_SYSTEM_EMSCRIPTEN) + ZPL_PANIC("zpl_system_command not supported"); +#else + +#if defined(ZPL_SYSTEM_WINDOWS) + FILE *handle = _popen(command, "r"); +#else + FILE *handle = popen(command, "r"); +#endif + + if(!handle) return 0; + + int c; + zpl_usize i=0; + while ((c = getc(handle)) != EOF && i++ < buffer_len) { + *buffer++ = c; + } + +#if defined(ZPL_SYSTEM_WINDOWS) + _pclose(handle); +#else + pclose(handle); +#endif + +#endif + + return 1; +} + +zpl_string zpl_system_command_str(const char *command, zpl_allocator backing) { +#if defined(ZPL_SYSTEM_EMSCRIPTEN) + ZPL_PANIC("zpl_system_command not supported"); +#else + +#if defined(ZPL_SYSTEM_WINDOWS) + FILE *handle = _popen(command, "r"); +#else + FILE *handle = popen(command, "r"); +#endif + + if(!handle) return NULL; + + zpl_string output = zpl_string_make_reserve(backing, 4); + + int c; + while ((c = getc(handle)) != EOF) { + char ins[2] = {(char)c,0}; + output = zpl_string_appendc(output, ins); + } + +#if defined(ZPL_SYSTEM_WINDOWS) + _pclose(handle); +#else + pclose(handle); +#endif + return output; +#endif + return NULL; +} + +ZPL_END_C_DECLS +// file: source/core/sort.c + +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +#define ZPL__COMPARE_PROC(Type) \ +zpl_global zpl_isize Type##__cmp_offset; \ +ZPL_COMPARE_PROC(Type##__cmp) { \ +Type const p = *cast(Type const *) zpl_pointer_add_const(a, Type##__cmp_offset); \ +Type const q = *cast(Type const *) zpl_pointer_add_const(b, Type##__cmp_offset); \ +return p < q ? -1 : p > q; \ +} \ +ZPL_COMPARE_PROC_PTR(Type##_cmp(zpl_isize offset)) { \ +Type##__cmp_offset = offset; \ +return &Type##__cmp; \ +} + +ZPL__COMPARE_PROC(zpl_u8); +ZPL__COMPARE_PROC(zpl_i16); +ZPL__COMPARE_PROC(zpl_i32); +ZPL__COMPARE_PROC(zpl_i64); +ZPL__COMPARE_PROC(zpl_isize); +ZPL__COMPARE_PROC(zpl_f32); +ZPL__COMPARE_PROC(zpl_f64); + +// NOTE: str_cmp is special as it requires a funny type and funny comparison +zpl_global zpl_isize zpl__str_cmp_offset; +ZPL_COMPARE_PROC(zpl__str_cmp) { + char const *p = *cast(char const **) zpl_pointer_add_const(a, zpl__str_cmp_offset); + char const *q = *cast(char const **) zpl_pointer_add_const(b, zpl__str_cmp_offset); + return zpl_strcmp(p, q); +} +ZPL_COMPARE_PROC_PTR(zpl_str_cmp(zpl_isize offset)) { + zpl__str_cmp_offset = offset; + return &zpl__str_cmp; +} + +#undef ZPL__COMPARE_PROC + +// TODO: Make user definable? +#define ZPL__SORT_STACK_SIZE 64 +#define zpl__SORT_INSERT_SORT_TRESHOLD 8 + +#define ZPL__SORT_PUSH(_base, _limit) \ +do { \ +stack_ptr[0] = (_base); \ +stack_ptr[1] = (_limit); \ +stack_ptr += 2; \ +} while (0) + +#define ZPL__SORT_POP(_base, _limit) \ +do { \ +stack_ptr -= 2; \ +(_base) = stack_ptr[0]; \ +(_limit) = stack_ptr[1]; \ +} while (0) + +void zpl_sort(void *base_, zpl_isize count, zpl_isize size, zpl_compare_proc cmp) { + zpl_u8 *i, *j; + zpl_u8 *base = cast(zpl_u8 *) base_; + zpl_u8 *limit = base + count * size; + zpl_isize threshold = zpl__SORT_INSERT_SORT_TRESHOLD * size; + + // NOTE: Prepare the stack + zpl_u8 *stack[ZPL__SORT_STACK_SIZE] = { 0 }; + zpl_u8 **stack_ptr = stack; + + for (;;) { + if ((limit - base) > threshold) { + // NOTE: Quick sort + i = base + size; + j = limit - size; + + zpl_memswap(((limit - base) / size / 2) * size + base, base, size); + if (cmp(i, j) > 0) zpl_memswap(i, j, size); + if (cmp(base, j) > 0) zpl_memswap(base, j, size); + if (cmp(i, base) > 0) zpl_memswap(i, base, size); + + for (;;) { + do + i += size; + while (cmp(i, base) < 0); + do + j -= size; + while (cmp(j, base) > 0); + if (i > j) break; + zpl_memswap(i, j, size); + } + + zpl_memswap(base, j, size); + + if (j - base > limit - i) { + ZPL__SORT_PUSH(base, j); + base = i; + } else { + ZPL__SORT_PUSH(i, limit); + limit = j; + } + } else { + // NOTE: Insertion sort + for (j = base, i = j + size; i < limit; j = i, i += size) { + for (; cmp(j, j + size) > 0; j -= size) { + zpl_memswap(j, j + size, size); + if (j == base) break; + } + } + + if (stack_ptr == stack) break; // NOTE: Sorting is done! + ZPL__SORT_POP(base, limit); + } + } +} + +#undef ZPL__SORT_PUSH +#undef ZPL__SORT_POP + +#define ZPL_RADIX_SORT_PROC_GEN(Type) \ +ZPL_RADIX_SORT_PROC(Type) { \ +zpl_##Type *source = items; \ +zpl_##Type *dest = temp; \ +zpl_isize byte_index, i, byte_max = 8 * zpl_size_of(zpl_##Type); \ +for (byte_index = 0; byte_index < byte_max; byte_index += 8) { \ +zpl_isize offsets[256] = { 0 }; \ +zpl_isize total = 0; \ +/* NOTE: First pass - count how many of each key */ \ +for (i = 0; i < count; i++) { \ +zpl_##Type radix_value = source[i]; \ +zpl_##Type radix_piece = (radix_value >> byte_index) & 0xff; \ +offsets[radix_piece]++; \ +} \ +/* NOTE: Change counts to offsets */ \ +for (i = 0; i < zpl_count_of(offsets); i++) { \ +zpl_isize skcount = offsets[i]; \ +offsets[i] = total; \ +total += skcount; \ +} \ +/* NOTE: Second pass - place elements into the right location */ \ +for (i = 0; i < count; i++) { \ +zpl_##Type radix_value = source[i]; \ +zpl_##Type radix_piece = (radix_value >> byte_index) & 0xff; \ +dest[offsets[radix_piece]++] = source[i]; \ +} \ +zpl_swap(zpl_##Type *, source, dest); \ +} \ +} + +ZPL_RADIX_SORT_PROC_GEN(u8); +ZPL_RADIX_SORT_PROC_GEN(u16); +ZPL_RADIX_SORT_PROC_GEN(u32); +ZPL_RADIX_SORT_PROC_GEN(u64); + +void zpl_shuffle(void *base, zpl_isize count, zpl_isize size) { + zpl_u8 *a; + zpl_isize i, j; + zpl_random random; + zpl_random_init(&random); + + a = cast(zpl_u8 *) base + (count - 1) * size; + for (i = count; i > 1; i--) { + j = zpl_random_gen_isize(&random) % i; + zpl_memswap(a, cast(zpl_u8 *) base + j * size, size); + a -= size; + } +} + +void zpl_reverse(void *base, zpl_isize count, zpl_isize size) { + zpl_isize i, j = count - 1; + for (i = 0; i < j; i++, j++) zpl_memswap(cast(zpl_u8 *) base + i * size, cast(zpl_u8 *) base + j * size, size); +} + +ZPL_END_C_DECLS +#endif + +#if defined(ZPL_MODULE_TIMER) +// file: source/timer.c + +//////////////////////////////////////////////////////////////// +// +// Timer +// +// +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +zpl_timer *zpl_timer_add(zpl_timer_pool pool) { + ZPL_ASSERT(pool); + + zpl_timer t = { 0 }; + zpl_array_append(pool, t); + return pool + (zpl_array_count(pool) - 1); +} + +void zpl_timer_set(zpl_timer *t, zpl_f64 duration, zpl_i32 count, zpl_timer_cb cb) { + ZPL_ASSERT(t); + + t->duration = duration; + t->remaining_calls = t->initial_calls = count; + t->callback = cb; + t->enabled = false; +} + +void zpl_timer_start(zpl_timer *t, zpl_f64 delay_start) { + ZPL_ASSERT(t && !t->enabled); + + t->enabled = true; + t->remaining_calls = t->initial_calls; + t->next_call_ts = zpl_time_rel( ) + delay_start; +} + +void zpl_timer_stop(zpl_timer *t) { + ZPL_ASSERT(t && t->enabled); + + t->enabled = false; +} + +void zpl_timer_update(zpl_timer_pool pool) { + ZPL_ASSERT(pool); + + zpl_f64 now = zpl_time_rel( ); + + for (zpl_isize i = 0; i < zpl_array_count(pool); ++i) { + zpl_timer *t = pool + i; + + if (t->enabled) { + if (t->remaining_calls > 0 || t->initial_calls == -1) { + if (t->next_call_ts <= now) { + if (t->initial_calls != -1) { --t->remaining_calls; } + + if (t->remaining_calls == 0) { + t->enabled = false; + } else { + t->next_call_ts = now + t->duration; + } + + t->callback(t->user_data); } } } + } +} - zpl_u32 zpl_random_gen_u32(zpl_random *r) { - zpl_u32 x = r->value; - zpl_u32 carry = 1; - zpl_isize i; - for (i = 0; i < zpl_count_of(r->offsets); i++) { - x = zpl__permute_with_offset(x, r->offsets[i]); - if (carry > 0) { - carry = ++r->offsets[i] ? 0 : 1; - } - } +ZPL_END_C_DECLS +#endif - r->value = x; - return x; +#if defined(ZPL_MODULE_HASHING) +// file: source/hashing.c + +//////////////////////////////////////////////////////////////// +// +// Hashing functions +// +// + +#ifdef ZPL_EDITOR +#include "../zpl.h" +#endif + +ZPL_BEGIN_C_DECLS + +zpl_u32 zpl_adler32(void const *data, zpl_isize len) { + zpl_u32 const MOD_ALDER = 65521; + zpl_u32 a = 1, b = 0; + zpl_isize i, block_len; + zpl_u8 const *bytes = cast(zpl_u8 const *) data; + + block_len = len % 5552; + + while (len) { + for (i = 0; i + 7 < block_len; i += 8) { + a += bytes[0], b += a; + a += bytes[1], b += a; + a += bytes[2], b += a; + a += bytes[3], b += a; + a += bytes[4], b += a; + a += bytes[5], b += a; + a += bytes[6], b += a; + a += bytes[7], b += a; + + bytes += 8; } + for (; i < block_len; i++) a += *bytes++, b += a; + + a %= MOD_ALDER, b %= MOD_ALDER; + len -= block_len; + block_len = 5552; + } + + return (b << 16) | a; +} - zpl_u32 zpl_random_gen_u32_unique(zpl_random *r) { - zpl_u32 x = r->value; - zpl_isize i; - r->value++; - for (i = 0; i < zpl_count_of(r->offsets); i++) { - x = zpl__permute_with_offset(x, r->offsets[i]); - } +zpl_global zpl_u32 const zpl__crc32_table[256] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, + 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, + 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, + 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, + 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, + 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, + 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, + 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, + 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, + 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, + 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, + 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, + 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, + 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, + 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, +}; - return x; +zpl_global zpl_u64 const zpl__crc64_table[256] = { + 0x0000000000000000ull, 0x7ad870c830358979ull, 0xf5b0e190606b12f2ull, 0x8f689158505e9b8bull, 0xc038e5739841b68full, 0xbae095bba8743ff6ull, + 0x358804e3f82aa47dull, 0x4f50742bc81f2d04ull, 0xab28ecb46814fe75ull, 0xd1f09c7c5821770cull, 0x5e980d24087fec87ull, 0x24407dec384a65feull, + 0x6b1009c7f05548faull, 0x11c8790fc060c183ull, 0x9ea0e857903e5a08ull, 0xe478989fa00bd371ull, 0x7d08ff3b88be6f81ull, 0x07d08ff3b88be6f8ull, + 0x88b81eabe8d57d73ull, 0xf2606e63d8e0f40aull, 0xbd301a4810ffd90eull, 0xc7e86a8020ca5077ull, 0x4880fbd87094cbfcull, 0x32588b1040a14285ull, + 0xd620138fe0aa91f4ull, 0xacf86347d09f188dull, 0x2390f21f80c18306ull, 0x594882d7b0f40a7full, 0x1618f6fc78eb277bull, 0x6cc0863448deae02ull, + 0xe3a8176c18803589ull, 0x997067a428b5bcf0ull, 0xfa11fe77117cdf02ull, 0x80c98ebf2149567bull, + 0x0fa11fe77117cdf0ull, 0x75796f2f41224489ull, 0x3a291b04893d698dull, 0x40f16bccb908e0f4ull, 0xcf99fa94e9567b7full, 0xb5418a5cd963f206ull, + 0x513912c379682177ull, 0x2be1620b495da80eull, 0xa489f35319033385ull, 0xde51839b2936bafcull, 0x9101f7b0e12997f8ull, 0xebd98778d11c1e81ull, + 0x64b116208142850aull, 0x1e6966e8b1770c73ull, 0x8719014c99c2b083ull, 0xfdc17184a9f739faull, 0x72a9e0dcf9a9a271ull, 0x08719014c99c2b08ull, + 0x4721e43f0183060cull, 0x3df994f731b68f75ull, 0xb29105af61e814feull, 0xc849756751dd9d87ull, 0x2c31edf8f1d64ef6ull, 0x56e99d30c1e3c78full, + 0xd9810c6891bd5c04ull, 0xa3597ca0a188d57dull, 0xec09088b6997f879ull, 0x96d1784359a27100ull, 0x19b9e91b09fcea8bull, 0x636199d339c963f2ull, + 0xdf7adabd7a6e2d6full, 0xa5a2aa754a5ba416ull, 0x2aca3b2d1a053f9dull, 0x50124be52a30b6e4ull, 0x1f423fcee22f9be0ull, 0x659a4f06d21a1299ull, + 0xeaf2de5e82448912ull, 0x902aae96b271006bull, 0x74523609127ad31aull, 0x0e8a46c1224f5a63ull, 0x81e2d7997211c1e8ull, 0xfb3aa75142244891ull, + 0xb46ad37a8a3b6595ull, 0xceb2a3b2ba0eececull, 0x41da32eaea507767ull, 0x3b024222da65fe1eull, 0xa2722586f2d042eeull, 0xd8aa554ec2e5cb97ull, + 0x57c2c41692bb501cull, 0x2d1ab4dea28ed965ull, 0x624ac0f56a91f461ull, 0x1892b03d5aa47d18ull, 0x97fa21650afae693ull, 0xed2251ad3acf6feaull, + 0x095ac9329ac4bc9bull, 0x7382b9faaaf135e2ull, 0xfcea28a2faafae69ull, 0x8632586aca9a2710ull, 0xc9622c4102850a14ull, 0xb3ba5c8932b0836dull, + 0x3cd2cdd162ee18e6ull, 0x460abd1952db919full, 0x256b24ca6b12f26dull, 0x5fb354025b277b14ull, 0xd0dbc55a0b79e09full, 0xaa03b5923b4c69e6ull, + 0xe553c1b9f35344e2ull, 0x9f8bb171c366cd9bull, 0x10e3202993385610ull, 0x6a3b50e1a30ddf69ull, 0x8e43c87e03060c18ull, 0xf49bb8b633338561ull, + 0x7bf329ee636d1eeaull, 0x012b592653589793ull, 0x4e7b2d0d9b47ba97ull, 0x34a35dc5ab7233eeull, 0xbbcbcc9dfb2ca865ull, 0xc113bc55cb19211cull, + 0x5863dbf1e3ac9decull, 0x22bbab39d3991495ull, 0xadd33a6183c78f1eull, 0xd70b4aa9b3f20667ull, 0x985b3e827bed2b63ull, 0xe2834e4a4bd8a21aull, + 0x6debdf121b863991ull, 0x1733afda2bb3b0e8ull, 0xf34b37458bb86399ull, 0x8993478dbb8deae0ull, 0x06fbd6d5ebd3716bull, 0x7c23a61ddbe6f812ull, + 0x3373d23613f9d516ull, 0x49aba2fe23cc5c6full, 0xc6c333a67392c7e4ull, 0xbc1b436e43a74e9dull, 0x95ac9329ac4bc9b5ull, 0xef74e3e19c7e40ccull, + 0x601c72b9cc20db47ull, 0x1ac40271fc15523eull, 0x5594765a340a7f3aull, 0x2f4c0692043ff643ull, 0xa02497ca54616dc8ull, 0xdafce7026454e4b1ull, + 0x3e847f9dc45f37c0ull, 0x445c0f55f46abeb9ull, 0xcb349e0da4342532ull, 0xb1eceec59401ac4bull, 0xfebc9aee5c1e814full, 0x8464ea266c2b0836ull, + 0x0b0c7b7e3c7593bdull, 0x71d40bb60c401ac4ull, 0xe8a46c1224f5a634ull, 0x927c1cda14c02f4dull, 0x1d148d82449eb4c6ull, 0x67ccfd4a74ab3dbfull, + 0x289c8961bcb410bbull, 0x5244f9a98c8199c2ull, 0xdd2c68f1dcdf0249ull, 0xa7f41839ecea8b30ull, 0x438c80a64ce15841ull, 0x3954f06e7cd4d138ull, + 0xb63c61362c8a4ab3ull, 0xcce411fe1cbfc3caull, 0x83b465d5d4a0eeceull, 0xf96c151de49567b7ull, 0x76048445b4cbfc3cull, 0x0cdcf48d84fe7545ull, + 0x6fbd6d5ebd3716b7ull, 0x15651d968d029fceull, 0x9a0d8ccedd5c0445ull, 0xe0d5fc06ed698d3cull, 0xaf85882d2576a038ull, 0xd55df8e515432941ull, + 0x5a3569bd451db2caull, 0x20ed197575283bb3ull, 0xc49581ead523e8c2ull, 0xbe4df122e51661bbull, 0x3125607ab548fa30ull, 0x4bfd10b2857d7349ull, + 0x04ad64994d625e4dull, 0x7e7514517d57d734ull, 0xf11d85092d094cbfull, 0x8bc5f5c11d3cc5c6ull, 0x12b5926535897936ull, 0x686de2ad05bcf04full, + 0xe70573f555e26bc4ull, 0x9ddd033d65d7e2bdull, 0xd28d7716adc8cfb9ull, 0xa85507de9dfd46c0ull, 0x273d9686cda3dd4bull, 0x5de5e64efd965432ull, + 0xb99d7ed15d9d8743ull, 0xc3450e196da80e3aull, 0x4c2d9f413df695b1ull, 0x36f5ef890dc31cc8ull, 0x79a59ba2c5dc31ccull, 0x037deb6af5e9b8b5ull, + 0x8c157a32a5b7233eull, 0xf6cd0afa9582aa47ull, 0x4ad64994d625e4daull, 0x300e395ce6106da3ull, 0xbf66a804b64ef628ull, 0xc5bed8cc867b7f51ull, + 0x8aeeace74e645255ull, 0xf036dc2f7e51db2cull, 0x7f5e4d772e0f40a7ull, 0x05863dbf1e3ac9deull, 0xe1fea520be311aafull, 0x9b26d5e88e0493d6ull, + 0x144e44b0de5a085dull, 0x6e963478ee6f8124ull, 0x21c640532670ac20ull, 0x5b1e309b16452559ull, 0xd476a1c3461bbed2ull, 0xaeaed10b762e37abull, + 0x37deb6af5e9b8b5bull, 0x4d06c6676eae0222ull, 0xc26e573f3ef099a9ull, 0xb8b627f70ec510d0ull, 0xf7e653dcc6da3dd4ull, 0x8d3e2314f6efb4adull, + 0x0256b24ca6b12f26ull, 0x788ec2849684a65full, 0x9cf65a1b368f752eull, 0xe62e2ad306bafc57ull, 0x6946bb8b56e467dcull, 0x139ecb4366d1eea5ull, + 0x5ccebf68aecec3a1ull, 0x2616cfa09efb4ad8ull, 0xa97e5ef8cea5d153ull, 0xd3a62e30fe90582aull, 0xb0c7b7e3c7593bd8ull, 0xca1fc72bf76cb2a1ull, + 0x45775673a732292aull, 0x3faf26bb9707a053ull, 0x70ff52905f188d57ull, 0x0a2722586f2d042eull, 0x854fb3003f739fa5ull, 0xff97c3c80f4616dcull, + 0x1bef5b57af4dc5adull, 0x61372b9f9f784cd4ull, 0xee5fbac7cf26d75full, 0x9487ca0fff135e26ull, 0xdbd7be24370c7322ull, 0xa10fceec0739fa5bull, + 0x2e675fb4576761d0ull, 0x54bf2f7c6752e8a9ull, 0xcdcf48d84fe75459ull, 0xb71738107fd2dd20ull, 0x387fa9482f8c46abull, 0x42a7d9801fb9cfd2ull, + 0x0df7adabd7a6e2d6ull, 0x772fdd63e7936bafull, 0xf8474c3bb7cdf024ull, 0x829f3cf387f8795dull, 0x66e7a46c27f3aa2cull, 0x1c3fd4a417c62355ull, + 0x935745fc4798b8deull, 0xe98f353477ad31a7ull, 0xa6df411fbfb21ca3ull, 0xdc0731d78f8795daull, 0x536fa08fdfd90e51ull, 0x29b7d047efec8728ull, +}; + +zpl_u32 zpl_crc32(void const *data, zpl_isize len) { + zpl_isize remaining; + zpl_u32 result = ~(cast(zpl_u32) 0); + zpl_u8 const *c = cast(zpl_u8 const *) data; + for (remaining = len; remaining--; c++) result = (result >> 8) ^ (zpl__crc32_table[(result ^ *c) & 0xff]); + return ~result; +} + +zpl_u64 zpl_crc64(void const *data, zpl_isize len) { + zpl_isize remaining; + zpl_u64 result = (cast(zpl_u64)0); + zpl_u8 const *c = cast(zpl_u8 const *) data; + for (remaining = len; remaining--; c++) result = (result >> 8) ^ (zpl__crc64_table[(result ^ *c) & 0xff]); + return result; +} + +zpl_u32 zpl_fnv32(void const *data, zpl_isize len) { + zpl_isize i; + zpl_u32 h = 0x811c9dc5; + zpl_u8 const *c = cast(zpl_u8 const *) data; + + for (i = 0; i < len; i++) h = (h * 0x01000193) ^ c[i]; + + return h; +} + +zpl_u64 zpl_fnv64(void const *data, zpl_isize len) { + zpl_isize i; + zpl_u64 h = 0xcbf29ce484222325ull; + zpl_u8 const *c = cast(zpl_u8 const *) data; + + for (i = 0; i < len; i++) h = (h * 0x100000001b3ll) ^ c[i]; + + return h; +} + +zpl_u32 zpl_fnv32a(void const *data, zpl_isize len) { + zpl_isize i; + zpl_u32 h = 0x811c9dc5; + zpl_u8 const *c = cast(zpl_u8 const *) data; + + for (i = 0; i < len; i++) h = (h ^ c[i]) * 0x01000193; + + return h; +} + +zpl_u64 zpl_fnv64a(void const *data, zpl_isize len) { + zpl_isize i; + zpl_u64 h = 0xcbf29ce484222325ull; + zpl_u8 const *c = cast(zpl_u8 const *) data; + + for (i = 0; i < len; i++) h = (h ^ c[i]) * 0x100000001b3ll; + + return h; +} + +// base64 implementation based on https://nachtimwald.com/2017/11/18/base64-encode-and-decode-in-c/ +// +zpl_global zpl_u8 zpl__base64_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + +/* generated table based on: */ +#if 0 +void zpl__base64_decode_table() { + zpl_i32 inv[80]; + zpl_isize i; + + zpl_memset(inv, -1, zpl_size_of(inv)); + + for (i=0; i < zpl_size_of(zpl__base64_chars)-1; i++) { + inv[zpl__base64_chars[i]-43] = i; + } +} +#endif +/* === */ +zpl_global zpl_i32 zpl__base64_dec_table[] = { + 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51 }; + +zpl_isize zpl__base64_encoded_size(zpl_isize len) { + zpl_isize ret = len; + + if (len % 3 != 0) { + ret += 3 - (len % 3); + } + + ret /= 3; + ret *= 4; + + return ret; +} + +zpl_isize zpl__base64_decoded_size(void const *data) { + zpl_isize len, ret, i; + const zpl_u8 *s = cast(const zpl_u8 *)data; + + if (s == NULL) { + return 0; + } + + len = zpl_strlen(cast(const char*)s); + ret = len / 4 * 3; + + for (i=len; i-- > 0;) { + if (s[i] == '=') { + ret--; + } else { + break; } + } + + return ret; +} - zpl_u64 zpl_random_gen_u64(zpl_random *r) { - return ((cast(zpl_u64)zpl_random_gen_u32(r)) << 32) | zpl_random_gen_u32(r); - } +zpl_b32 zpl__base64_valid_char(zpl_u8 c) { + if (c >= '0' && c <= '9') + return true; + if (c >= 'A' && c <= 'Z') + return true; + if (c >= 'a' && c <= 'z') + return true; + if (c == '+' || c == '/' || c == '=') + return true; + + return false; +} +zpl_u8 *zpl_base64_encode(zpl_allocator a, void const *data, zpl_isize len) { + const zpl_u8 *s = cast(const zpl_u8*)data; + zpl_u8 *ret = NULL; + zpl_isize enc_len, i, j, v; + + if (data == NULL || len == 0) { + return NULL; + } + + enc_len = zpl__base64_encoded_size(len); + ret = cast(zpl_u8 *)zpl_alloc(a, enc_len+1); + ret[enc_len] = 0; + + for (i=0, j=0; i < len; i+=3, j+=4) { + v = s[i]; + v = (i+1 < len) ? (v << 8 | s[i+1]) : (v << 8); + v = (i+2 < len) ? (v << 8 | s[i+2]) : (v << 8); + + ret[j] = zpl__base64_chars[(v >> 18) & 0x3F]; + ret[j+1] = zpl__base64_chars[(v >> 12) & 0x3F]; + + if (i+1 < len) + ret[j+2] = zpl__base64_chars[(v >> 6) & 0x3F]; + + else ret[j+2] = '='; + + if (i+2 < len) + ret[j+3] = zpl__base64_chars[v & 0x3F]; + + else ret[j+3] = '='; + + } + + return ret; +} - zpl_isize zpl_random_gen_isize(zpl_random *r) { - zpl_u64 u = zpl_random_gen_u64(r); - return *cast(zpl_isize *)&u; - } - - - zpl_i64 zpl_random_range_i64(zpl_random *r, zpl_i64 lower_inc, zpl_i64 higher_inc) { - zpl_u64 u = zpl_random_gen_u64(r); - zpl_i64 i = *cast(zpl_i64 *)&u; - zpl_i64 diff = higher_inc-lower_inc+1; - i %= diff; - i += lower_inc; - return i; - } - - zpl_isize zpl_random_range_isize(zpl_random *r, zpl_isize lower_inc, zpl_isize higher_inc) { - zpl_u64 u = zpl_random_gen_u64(r); - zpl_isize i = *cast(zpl_isize *)&u; - zpl_isize diff = higher_inc-lower_inc+1; - i %= diff; - i += lower_inc; - return i; - } - - ZPL_ALWAYS_INLINE zpl_f64 zpl__random_copy_sign64(zpl_f64 x, zpl_f64 y) { - zpl_i64 ix=0, iy=0; - zpl_memcopy(&ix, &x, zpl_size_of(zpl_i64)); - zpl_memcopy(&iy, &y, zpl_size_of(zpl_i64)); - - ix &= 0x7fffffffffffffff; - ix |= iy & 0x8000000000000000; - - zpl_f64 r = 0.0; - zpl_memcopy(&r, &ix, zpl_size_of(zpl_f64)); - return r; - } - - ZPL_ALWAYS_INLINE zpl_f64 zpl__random_floor64 (zpl_f64 x) { return cast(zpl_f64)((x >= 0.0) ? cast(zpl_i64)x : cast(zpl_i64)(x-0.9999999999999999)); } - ZPL_ALWAYS_INLINE zpl_f64 zpl__random_ceil64 (zpl_f64 x) { return cast(zpl_f64)((x < 0) ? cast(zpl_i64)x : (cast(zpl_i64)x)+1); } - ZPL_ALWAYS_INLINE zpl_f64 zpl__random_round64 (zpl_f64 x) { return cast(zpl_f64)((x >= 0.0) ? zpl__random_floor64(x + 0.5) : zpl__random_ceil64(x - 0.5)); } - ZPL_ALWAYS_INLINE zpl_f64 zpl__random_remainder64(zpl_f64 x, zpl_f64 y) { return x - (zpl__random_round64(x/y)*y); } - ZPL_ALWAYS_INLINE zpl_f64 zpl__random_abs64 (zpl_f64 x) { return x < 0 ? -x : x; } - ZPL_ALWAYS_INLINE zpl_f64 zpl__random_sign64 (zpl_f64 x) { return x < 0 ? -1.0 : +1.0; } - - ZPL_ALWAYS_INLINE zpl_f64 zpl__random_mod64(zpl_f64 x, zpl_f64 y) { - zpl_f64 result; - y = zpl__random_abs64(y); - result = zpl__random_remainder64(zpl__random_abs64(x), y); - if (zpl__random_sign64(result)) result += y; - return zpl__random_copy_sign64(result, x); - } - - zpl_f64 zpl_random_range_f64(zpl_random *r, zpl_f64 lower_inc, zpl_f64 higher_inc) { - zpl_u64 u = zpl_random_gen_u64(r); - zpl_f64 f = 0; - zpl_memcopy(&f, &u, zpl_size_of(zpl_f64)); - zpl_f64 diff = higher_inc-lower_inc+1.0; - f = zpl__random_mod64(f, diff); - f += lower_inc; - return f; - } - - ZPL_END_C_DECLS - // file: source/core/misc.c - - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - #if defined(ZPL_SYSTEM_UNIX) || defined(ZPL_SYSTEM_MACOS) - #include - #endif - - #if defined(ZPL_SYSTEM_WINDOWS) - void zpl_exit(zpl_u32 code) { ExitProcess(code); } - #else - void zpl_exit(zpl_u32 code) { exit(code); } - #endif - - void zpl_yield(void) { - #if defined(ZPL_SYSTEM_WINDOWS) - Sleep(0); - #else - sched_yield(); - #endif - } - - const char *zpl_get_env(const char *name) { - char *buffer = NULL; - const char *ptr = zpl_get_env_buf(name); - - if (ptr == NULL) { - return NULL; - } - - zpl_isize ptr_size = zpl_strlen(ptr); - buffer = (char *)zpl_malloc(ptr_size * sizeof(char)+1); - zpl_memcopy((char *)buffer, ptr, ptr_size+1); - return buffer; - } - - const char *zpl_get_env_buf(const char *name) { - #ifdef ZPL_SYSTEM_WINDOWS - zpl_local_persist wchar_t wbuffer[32767] = {0}; - zpl_local_persist char buffer[32767] = {0}; - - if (!GetEnvironmentVariableW( - cast(LPCWSTR)zpl_utf8_to_ucs2_buf(cast(const zpl_u8 *)name), - cast(LPWSTR)wbuffer, 32767)) { - return NULL; - } - - zpl_ucs2_to_utf8(cast(zpl_u8*)buffer, 32767, cast(const zpl_u16*)wbuffer); - - return (const char *)buffer; - #else - return (const char *)getenv(name); - #endif - } - - zpl_string zpl_get_env_str(const char *name) { - const char *buf = zpl_get_env_buf(name); - - if (buf == NULL) { - return NULL; - } - - zpl_string str = zpl_string_make(zpl_heap(), buf); - return str; - } - - void zpl_set_env(const char *name, const char *value) { - #if defined(ZPL_SYSTEM_WINDOWS) - SetEnvironmentVariableA(name, value); - #else - setenv(name, value, 1); - #endif - } - - void zpl_unset_env(const char *name) { - #if defined(ZPL_SYSTEM_WINDOWS) - SetEnvironmentVariableA(name, NULL); - #else - unsetenv(name); - #endif - } - - #if !defined(ZPL_SYSTEM_WINDOWS) - extern char **environ; - #endif - - zpl_u32 zpl_system_command(const char *command, zpl_usize buffer_len, char *buffer) { - #if defined(ZPL_SYSTEM_EMSCRIPTEN) - ZPL_PANIC("zpl_system_command not supported"); - #else - - #if defined(ZPL_SYSTEM_WINDOWS) - FILE *handle = _popen(command, "r"); - #else - FILE *handle = popen(command, "r"); - #endif - - if(!handle) return 0; - - int c; - zpl_usize i=0; - while ((c = getc(handle)) != EOF && i++ < buffer_len) { - *buffer++ = c; - } - - #if defined(ZPL_SYSTEM_WINDOWS) - _pclose(handle); - #else - pclose(handle); - #endif - - #endif - - return 1; - } - - zpl_string zpl_system_command_str(const char *command, zpl_allocator backing) { - #if defined(ZPL_SYSTEM_EMSCRIPTEN) - ZPL_PANIC("zpl_system_command not supported"); - #else - - #if defined(ZPL_SYSTEM_WINDOWS) - FILE *handle = _popen(command, "r"); - #else - FILE *handle = popen(command, "r"); - #endif - - if(!handle) return NULL; - - zpl_string output = zpl_string_make_reserve(backing, 4); - - int c; - while ((c = getc(handle)) != EOF) { - char ins[2] = {(char)c,0}; - output = zpl_string_appendc(output, ins); - } - - #if defined(ZPL_SYSTEM_WINDOWS) - _pclose(handle); - #else - pclose(handle); - #endif - return output; - #endif +zpl_u8 *zpl_base64_decode(zpl_allocator a, void const *data, zpl_isize len) { + const zpl_u8 *s = cast(const zpl_u8*)data; + zpl_u8 *ret = NULL; + zpl_isize alen, i, j, v; + + if (data == NULL) { + return NULL; + } + + alen = zpl__base64_decoded_size(s); + ret = cast(zpl_u8 *)zpl_alloc(a, alen+1); + + ZPL_ASSERT_NOT_NULL(ret); + + ret[alen] = 0; + + for (i=0; i> 16) & 0xFF; + + if (s[i+2] != '=') + ret[j+1] = (v >> 8) & 0xFF; + + if (s[i+3] != '=') + ret[j+2] = v & 0xFF; + } + + return ret; +} + +zpl_u32 zpl_murmur32_seed(void const *data, zpl_isize len, zpl_u32 seed) { + zpl_u32 const c1 = 0xcc9e2d51; + zpl_u32 const c2 = 0x1b873593; + zpl_u32 const r1 = 15; + zpl_u32 const r2 = 13; + zpl_u32 const m = 5; + zpl_u32 const n = 0xe6546b64; + + zpl_isize i, nblocks = len / 4; + zpl_u32 hash = seed, k1 = 0; + zpl_u32 const *blocks = cast(zpl_u32 const *) data; + zpl_u8 const *tail = cast(zpl_u8 const *)(data) + nblocks * 4; + + for (i = 0; i < nblocks; i++) { + zpl_u32 k = blocks[i]; + k *= c1; + k = (k << r1) | (k >> (32 - r1)); + k *= c2; + + hash ^= k; + hash = ((hash << r2) | (hash >> (32 - r2))) * m + n; + } + + switch (len & 3) { + case 3: k1 ^= tail[2] << 16; + case 2: k1 ^= tail[1] << 8; + case 1: + k1 ^= tail[0]; + + k1 *= c1; + k1 = (k1 << r1) | (k1 >> (32 - r1)); + k1 *= c2; + hash ^= k1; + } + + hash ^= len; + hash ^= (hash >> 16); + hash *= 0x85ebca6b; + hash ^= (hash >> 13); + hash *= 0xc2b2ae35; + hash ^= (hash >> 16); + + return hash; +} + +zpl_u64 zpl_murmur64_seed(void const *data_, zpl_isize len, zpl_u64 seed) { + zpl_u64 const m = 0xc6a4a7935bd1e995ULL; + zpl_i32 const r = 47; + + zpl_u64 h = seed ^ (len * m); + + zpl_u64 const *data = cast(zpl_u64 const *) data_; + zpl_u8 const *data2 = cast(zpl_u8 const *) data_; + zpl_u64 const *end = data + (len / 8); + + while (data != end) { + zpl_u64 k = *data++; + + k *= m; + k ^= k >> r; + k *= m; + + h ^= k; + h *= m; + } + + switch (len & 7) { + case 7: h ^= cast(zpl_u64)(data2[6]) << 48; + case 6: h ^= cast(zpl_u64)(data2[5]) << 40; + case 5: h ^= cast(zpl_u64)(data2[4]) << 32; + case 4: h ^= cast(zpl_u64)(data2[3]) << 24; + case 3: h ^= cast(zpl_u64)(data2[2]) << 16; + case 2: h ^= cast(zpl_u64)(data2[1]) << 8; + case 1: h ^= cast(zpl_u64)(data2[0]); + h *= m; + }; + + h ^= h >> r; + h *= m; + h ^= h >> r; + + return h; +} + +ZPL_END_C_DECLS +#endif + +#if defined(ZPL_MODULE_REGEX) +// file: source/regex.c + +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +typedef enum zplreOp { + ZPL_RE_OP_BEGIN_CAPTURE, + ZPL_RE_OP_END_CAPTURE, + + ZPL_RE_OP_BEGINNING_OF_LINE, + ZPL_RE_OP_END_OF_LINE, + + ZPL_RE_OP_EXACT_MATCH, + ZPL_RE_OP_META_MATCH, + + ZPL_RE_OP_ANY, + ZPL_RE_OP_ANY_OF, + ZPL_RE_OP_ANY_BUT, + + ZPL_RE_OP_ZERO_OR_MORE, + ZPL_RE_OP_ONE_OR_MORE, + ZPL_RE_OP_ZERO_OR_MORE_SHORTEST, + ZPL_RE_OP_ONE_OR_MORE_SHORTEST, + ZPL_RE_OP_ZERO_OR_ONE, + + ZPL_RE_OP_BRANCH_START, + ZPL_RE_OP_BRANCH_END +} zplreOp; + +typedef enum zplreCode { + ZPL_RE_CODE_NULL = 0x0000, + ZPL_RE_CODE_WHITESPACE = 0x0100, + ZPL_RE_CODE_NOT_WHITESPACE = 0x0200, + ZPL_RE_CODE_DIGIT = 0x0300, + ZPL_RE_CODE_NOT_DIGIT = 0x0400, + ZPL_RE_CODE_ALPHA = 0x0500, + ZPL_RE_CODE_LOWER = 0x0600, + ZPL_RE_CODE_UPPER = 0x0700, + ZPL_RE_CODE_WORD = 0x0800, + ZPL_RE_CODE_NOT_WORD = 0x0900, + + ZPL_RE_CODE_XDIGIT = 0x0a00, + ZPL_RE_CODE_PRINTABLE = 0x0b00, +} zplreCode; + +typedef struct { + zpl_isize op, offset; +} zpl_re_ctx; + +enum { + ZPL_RE__NO_MATCH = -1, + ZPL_RE__INTERNAL_FAILURE = -2, +}; + +static char const ZPL_RE__META_CHARS[] = "^$()[].*+?|\\"; +static char const ZPL_RE__WHITESPACE[] = " \r\t\n\v\f"; +#define ZPL_RE__LITERAL(str) (str), zpl_size_of(str)-1 + +static zpl_re_ctx zpl_re__exec_single(zpl_re *re, zpl_isize op, char const *str, zpl_isize str_len, zpl_isize offset, zpl_re_capture *captures, zpl_isize max_capture_count); +static zpl_re_ctx zpl_re__exec(zpl_re *re, zpl_isize op, char const *str, zpl_isize str_len, zpl_isize offset, zpl_re_capture *captures, zpl_isize max_capture_count); + +static zpl_re_ctx zpl_re__ctx_no_match(zpl_isize op) { + zpl_re_ctx c; + c.op = op; + c.offset = ZPL_RE__NO_MATCH; + return c; +} + +static zpl_re_ctx zpl_re__ctx_internal_failure(zpl_isize op) { + zpl_re_ctx c; + c.op = op; + c.offset = ZPL_RE__INTERNAL_FAILURE; + return c; +} + +static zpl_u8 zpl_re__hex(char const *s) { + return ((zpl_char_to_hex_digit(*s) << 4) & 0xf0) | (zpl_char_to_hex_digit(*(s+1)) & 0x0f); +} + +static zpl_isize zpl_re__strfind(char const *s, zpl_isize len, char c, zpl_isize offset) { + if (offset < len) { + char const *found = (char const *)zpl_memchr(s+offset, c, len-offset); + if (found) + return found - s; + } + + return -1; +} + +static zpl_b32 zpl_re__match_escape(char c, int code) { + switch (code) { + case ZPL_RE_CODE_NULL: return c == 0; + case ZPL_RE_CODE_WHITESPACE: return zpl_re__strfind(ZPL_RE__LITERAL(ZPL_RE__WHITESPACE), c, 0) >= 0; + case ZPL_RE_CODE_NOT_WHITESPACE: return zpl_re__strfind(ZPL_RE__LITERAL(ZPL_RE__WHITESPACE), c, 0) < 0; + case ZPL_RE_CODE_DIGIT: return (c >= '0' && c <= '9'); + case ZPL_RE_CODE_NOT_DIGIT: return !(c >= '0' && c <= '9'); + case ZPL_RE_CODE_ALPHA: return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); + case ZPL_RE_CODE_LOWER: return (c >= 'a' && c <= 'z'); + case ZPL_RE_CODE_UPPER: return (c >= 'A' && c <= 'Z'); + + /* TODO(bill): Make better? */ + case ZPL_RE_CODE_WORD: return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_'; + case ZPL_RE_CODE_NOT_WORD: return !((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_'); + + /* TODO(bill): Maybe replace with between tests? */ + case ZPL_RE_CODE_XDIGIT: return zpl_re__strfind(ZPL_RE__LITERAL("0123456789ABCDEFabcdef"), c, 0) >= 0; + case ZPL_RE_CODE_PRINTABLE: return c >= 0x20 && c <= 0x7e; + default: break; + } + + return 0; +} + +static zpl_re_ctx zpl_re__consume(zpl_re *re, zpl_isize op, char const *str, zpl_isize str_len, zpl_isize offset, zpl_re_capture *captures, zpl_isize max_capture_count, zpl_b32 is_greedy) +{ + zpl_re_ctx c, best_c, next_c; + + c.op = op; + c.offset = offset; + + best_c.op = ZPL_RE__NO_MATCH; + best_c.offset = offset; + + for (;;) { + c = zpl_re__exec_single(re, op, str, str_len, c.offset, 0, 0); + if (c.offset > str_len || c.offset == -1) break; + if (c.op >= re->buf_len) return c; + + next_c = zpl_re__exec(re, c.op, str, str_len, c.offset, captures, max_capture_count); + if (next_c.offset <= str_len) { + if (captures) + zpl_re__exec(re, c.op, str, str_len, c.offset, captures, max_capture_count); + + best_c = next_c; + if (!is_greedy) break; } + + if (best_c.op > re->buf_len) + best_c.op = c.op; + + } + + return best_c; +} - ZPL_END_C_DECLS - // file: source/core/sort.c - - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - #define ZPL__COMPARE_PROC(Type) \ - zpl_global zpl_isize Type##__cmp_offset; \ - ZPL_COMPARE_PROC(Type##__cmp) { \ - Type const p = *cast(Type const *) zpl_pointer_add_const(a, Type##__cmp_offset); \ - Type const q = *cast(Type const *) zpl_pointer_add_const(b, Type##__cmp_offset); \ - return p < q ? -1 : p > q; \ - } \ - ZPL_COMPARE_PROC_PTR(Type##_cmp(zpl_isize offset)) { \ - Type##__cmp_offset = offset; \ - return &Type##__cmp; \ - } - - ZPL__COMPARE_PROC(zpl_u8); - ZPL__COMPARE_PROC(zpl_i16); - ZPL__COMPARE_PROC(zpl_i32); - ZPL__COMPARE_PROC(zpl_i64); - ZPL__COMPARE_PROC(zpl_isize); - ZPL__COMPARE_PROC(zpl_f32); - ZPL__COMPARE_PROC(zpl_f64); - - // NOTE: str_cmp is special as it requires a funny type and funny comparison - zpl_global zpl_isize zpl__str_cmp_offset; - ZPL_COMPARE_PROC(zpl__str_cmp) { - char const *p = *cast(char const **) zpl_pointer_add_const(a, zpl__str_cmp_offset); - char const *q = *cast(char const **) zpl_pointer_add_const(b, zpl__str_cmp_offset); - return zpl_strcmp(p, q); - } - ZPL_COMPARE_PROC_PTR(zpl_str_cmp(zpl_isize offset)) { - zpl__str_cmp_offset = offset; - return &zpl__str_cmp; - } - - #undef ZPL__COMPARE_PROC - - // TODO: Make user definable? - #define ZPL__SORT_STACK_SIZE 64 - #define zpl__SORT_INSERT_SORT_TRESHOLD 8 - - #define ZPL__SORT_PUSH(_base, _limit) \ - do { \ - stack_ptr[0] = (_base); \ - stack_ptr[1] = (_limit); \ - stack_ptr += 2; \ - } while (0) - - #define ZPL__SORT_POP(_base, _limit) \ - do { \ - stack_ptr -= 2; \ - (_base) = stack_ptr[0]; \ - (_limit) = stack_ptr[1]; \ - } while (0) - - void zpl_sort(void *base_, zpl_isize count, zpl_isize size, zpl_compare_proc cmp) { - zpl_u8 *i, *j; - zpl_u8 *base = cast(zpl_u8 *) base_; - zpl_u8 *limit = base + count * size; - zpl_isize threshold = zpl__SORT_INSERT_SORT_TRESHOLD * size; - - // NOTE: Prepare the stack - zpl_u8 *stack[ZPL__SORT_STACK_SIZE] = { 0 }; - zpl_u8 **stack_ptr = stack; - - for (;;) { - if ((limit - base) > threshold) { - // NOTE: Quick sort - i = base + size; - j = limit - size; - - zpl_memswap(((limit - base) / size / 2) * size + base, base, size); - if (cmp(i, j) > 0) zpl_memswap(i, j, size); - if (cmp(base, j) > 0) zpl_memswap(base, j, size); - if (cmp(i, base) > 0) zpl_memswap(i, base, size); - - for (;;) { - do - i += size; - while (cmp(i, base) < 0); - do - j -= size; - while (cmp(j, base) > 0); - if (i > j) break; - zpl_memswap(i, j, size); - } - - zpl_memswap(base, j, size); - - if (j - base > limit - i) { - ZPL__SORT_PUSH(base, j); - base = i; - } else { - ZPL__SORT_PUSH(i, limit); - limit = j; - } - } else { - // NOTE: Insertion sort - for (j = base, i = j + size; i < limit; j = i, i += size) { - for (; cmp(j, j + size) > 0; j -= size) { - zpl_memswap(j, j + size, size); - if (j == base) break; - } - } - - if (stack_ptr == stack) break; // NOTE: Sorting is done! - ZPL__SORT_POP(base, limit); - } +static zpl_re_ctx zpl_re__exec_single(zpl_re *re, zpl_isize op, char const *str, zpl_isize str_len, zpl_isize offset, zpl_re_capture *captures, zpl_isize max_capture_count) { + zpl_re_ctx ctx; + zpl_isize buffer_len; + zpl_isize match_len; + zpl_isize next_op; + zpl_isize skip; + + switch (re->buf[op++]) { + case ZPL_RE_OP_BEGIN_CAPTURE: { + zpl_u8 capture = re->buf[op++]; + if (captures && (capture < max_capture_count)) + captures[capture].str = str + offset; + } break; + + case ZPL_RE_OP_END_CAPTURE: { + zpl_u8 capture = re->buf[op++]; + if (captures && (capture < max_capture_count)) + captures[capture].len = (str + offset) - captures[capture].str; + } break; + + case ZPL_RE_OP_BEGINNING_OF_LINE: { + if (offset != 0) + return zpl_re__ctx_no_match(op); + } break; + + case ZPL_RE_OP_END_OF_LINE: { + if (offset != str_len) + return zpl_re__ctx_no_match(op); + } break; + + case ZPL_RE_OP_BRANCH_START: { + skip = re->buf[op++]; + ctx = zpl_re__exec(re, op, str, str_len, offset, captures, max_capture_count); + if (ctx.offset <= str_len) { + offset = ctx.offset; + op = ctx.op; + } else { + ctx = zpl_re__exec(re, op + skip, str, str_len, offset, captures, max_capture_count); + offset = ctx.offset; + op = ctx.op; } - } - - #undef ZPL__SORT_PUSH - #undef ZPL__SORT_POP - - #define ZPL_RADIX_SORT_PROC_GEN(Type) \ - ZPL_RADIX_SORT_PROC(Type) { \ - zpl_##Type *source = items; \ - zpl_##Type *dest = temp; \ - zpl_isize byte_index, i, byte_max = 8 * zpl_size_of(zpl_##Type); \ - for (byte_index = 0; byte_index < byte_max; byte_index += 8) { \ - zpl_isize offsets[256] = { 0 }; \ - zpl_isize total = 0; \ - /* NOTE: First pass - count how many of each key */ \ - for (i = 0; i < count; i++) { \ - zpl_##Type radix_value = source[i]; \ - zpl_##Type radix_piece = (radix_value >> byte_index) & 0xff; \ - offsets[radix_piece]++; \ - } \ - /* NOTE: Change counts to offsets */ \ - for (i = 0; i < zpl_count_of(offsets); i++) { \ - zpl_isize skcount = offsets[i]; \ - offsets[i] = total; \ - total += skcount; \ - } \ - /* NOTE: Second pass - place elements into the right location */ \ - for (i = 0; i < count; i++) { \ - zpl_##Type radix_value = source[i]; \ - zpl_##Type radix_piece = (radix_value >> byte_index) & 0xff; \ - dest[offsets[radix_piece]++] = source[i]; \ - } \ - zpl_swap(zpl_##Type *, source, dest); \ - } \ - } - - ZPL_RADIX_SORT_PROC_GEN(u8); - ZPL_RADIX_SORT_PROC_GEN(u16); - ZPL_RADIX_SORT_PROC_GEN(u32); - ZPL_RADIX_SORT_PROC_GEN(u64); - - void zpl_shuffle(void *base, zpl_isize count, zpl_isize size) { - zpl_u8 *a; - zpl_isize i, j; - zpl_random random; - zpl_random_init(&random); - - a = cast(zpl_u8 *) base + (count - 1) * size; - for (i = count; i > 1; i--) { - j = zpl_random_gen_isize(&random) % i; - zpl_memswap(a, cast(zpl_u8 *) base + j * size, size); - a -= size; - } - } - - void zpl_reverse(void *base, zpl_isize count, zpl_isize size) { - zpl_isize i, j = count - 1; - for (i = 0; i < j; i++, j++) zpl_memswap(cast(zpl_u8 *) base + i * size, cast(zpl_u8 *) base + j * size, size); - } - - ZPL_END_C_DECLS - #endif - - #if defined(ZPL_MODULE_TIMER) - // file: source/timer.c - - //////////////////////////////////////////////////////////////// - // - // Timer - // - // - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - zpl_timer *zpl_timer_add(zpl_timer_pool pool) { - ZPL_ASSERT(pool); - - zpl_timer t = { 0 }; - zpl_array_append(pool, t); - return pool + (zpl_array_count(pool) - 1); - } - - void zpl_timer_set(zpl_timer *t, zpl_f64 duration, zpl_i32 count, zpl_timer_cb cb) { - ZPL_ASSERT(t); - - t->duration = duration; - t->remaining_calls = t->initial_calls = count; - t->callback = cb; - t->enabled = false; - } - - void zpl_timer_start(zpl_timer *t, zpl_f64 delay_start) { - ZPL_ASSERT(t && !t->enabled); - - t->enabled = true; - t->remaining_calls = t->initial_calls; - t->next_call_ts = zpl_time_rel( ) + delay_start; - } - - void zpl_timer_stop(zpl_timer *t) { - ZPL_ASSERT(t && t->enabled); - - t->enabled = false; - } - - void zpl_timer_update(zpl_timer_pool pool) { - ZPL_ASSERT(pool); - - zpl_f64 now = zpl_time_rel( ); - - for (zpl_isize i = 0; i < zpl_array_count(pool); ++i) { - zpl_timer *t = pool + i; - - if (t->enabled) { - if (t->remaining_calls > 0 || t->initial_calls == -1) { - if (t->next_call_ts <= now) { - if (t->initial_calls != -1) { --t->remaining_calls; } - - if (t->remaining_calls == 0) { - t->enabled = false; - } else { - t->next_call_ts = now + t->duration; - } - - t->callback(t->user_data); - } - } - } - } - } - - ZPL_END_C_DECLS - #endif - - #if defined(ZPL_MODULE_HASHING) - // file: source/hashing.c - - //////////////////////////////////////////////////////////////// - // - // Hashing functions - // - // - - #ifdef ZPL_EDITOR - #include "../zpl.h" - #endif - - ZPL_BEGIN_C_DECLS - - zpl_u32 zpl_adler32(void const *data, zpl_isize len) { - zpl_u32 const MOD_ALDER = 65521; - zpl_u32 a = 1, b = 0; - zpl_isize i, block_len; - zpl_u8 const *bytes = cast(zpl_u8 const *) data; - - block_len = len % 5552; - - while (len) { - for (i = 0; i + 7 < block_len; i += 8) { - a += bytes[0], b += a; - a += bytes[1], b += a; - a += bytes[2], b += a; - a += bytes[3], b += a; - a += bytes[4], b += a; - a += bytes[5], b += a; - a += bytes[6], b += a; - a += bytes[7], b += a; - - bytes += 8; - } - for (; i < block_len; i++) a += *bytes++, b += a; - - a %= MOD_ALDER, b %= MOD_ALDER; - len -= block_len; - block_len = 5552; - } - - return (b << 16) | a; - } - - zpl_global zpl_u32 const zpl__crc32_table[256] = { - 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, - 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, - 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, - 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, - 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, - 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, - 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, - 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, - 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, - 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, - 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, - 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, - 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, - 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, - 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, - 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, - 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, - 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, - 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, - 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, - 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, - 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, - 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, - 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, - 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, - 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, - 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, - 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, - 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, - }; - - zpl_global zpl_u64 const zpl__crc64_table[256] = { - 0x0000000000000000ull, 0x7ad870c830358979ull, 0xf5b0e190606b12f2ull, 0x8f689158505e9b8bull, 0xc038e5739841b68full, 0xbae095bba8743ff6ull, - 0x358804e3f82aa47dull, 0x4f50742bc81f2d04ull, 0xab28ecb46814fe75ull, 0xd1f09c7c5821770cull, 0x5e980d24087fec87ull, 0x24407dec384a65feull, - 0x6b1009c7f05548faull, 0x11c8790fc060c183ull, 0x9ea0e857903e5a08ull, 0xe478989fa00bd371ull, 0x7d08ff3b88be6f81ull, 0x07d08ff3b88be6f8ull, - 0x88b81eabe8d57d73ull, 0xf2606e63d8e0f40aull, 0xbd301a4810ffd90eull, 0xc7e86a8020ca5077ull, 0x4880fbd87094cbfcull, 0x32588b1040a14285ull, - 0xd620138fe0aa91f4ull, 0xacf86347d09f188dull, 0x2390f21f80c18306ull, 0x594882d7b0f40a7full, 0x1618f6fc78eb277bull, 0x6cc0863448deae02ull, - 0xe3a8176c18803589ull, 0x997067a428b5bcf0ull, 0xfa11fe77117cdf02ull, 0x80c98ebf2149567bull, - 0x0fa11fe77117cdf0ull, 0x75796f2f41224489ull, 0x3a291b04893d698dull, 0x40f16bccb908e0f4ull, 0xcf99fa94e9567b7full, 0xb5418a5cd963f206ull, - 0x513912c379682177ull, 0x2be1620b495da80eull, 0xa489f35319033385ull, 0xde51839b2936bafcull, 0x9101f7b0e12997f8ull, 0xebd98778d11c1e81ull, - 0x64b116208142850aull, 0x1e6966e8b1770c73ull, 0x8719014c99c2b083ull, 0xfdc17184a9f739faull, 0x72a9e0dcf9a9a271ull, 0x08719014c99c2b08ull, - 0x4721e43f0183060cull, 0x3df994f731b68f75ull, 0xb29105af61e814feull, 0xc849756751dd9d87ull, 0x2c31edf8f1d64ef6ull, 0x56e99d30c1e3c78full, - 0xd9810c6891bd5c04ull, 0xa3597ca0a188d57dull, 0xec09088b6997f879ull, 0x96d1784359a27100ull, 0x19b9e91b09fcea8bull, 0x636199d339c963f2ull, - 0xdf7adabd7a6e2d6full, 0xa5a2aa754a5ba416ull, 0x2aca3b2d1a053f9dull, 0x50124be52a30b6e4ull, 0x1f423fcee22f9be0ull, 0x659a4f06d21a1299ull, - 0xeaf2de5e82448912ull, 0x902aae96b271006bull, 0x74523609127ad31aull, 0x0e8a46c1224f5a63ull, 0x81e2d7997211c1e8ull, 0xfb3aa75142244891ull, - 0xb46ad37a8a3b6595ull, 0xceb2a3b2ba0eececull, 0x41da32eaea507767ull, 0x3b024222da65fe1eull, 0xa2722586f2d042eeull, 0xd8aa554ec2e5cb97ull, - 0x57c2c41692bb501cull, 0x2d1ab4dea28ed965ull, 0x624ac0f56a91f461ull, 0x1892b03d5aa47d18ull, 0x97fa21650afae693ull, 0xed2251ad3acf6feaull, - 0x095ac9329ac4bc9bull, 0x7382b9faaaf135e2ull, 0xfcea28a2faafae69ull, 0x8632586aca9a2710ull, 0xc9622c4102850a14ull, 0xb3ba5c8932b0836dull, - 0x3cd2cdd162ee18e6ull, 0x460abd1952db919full, 0x256b24ca6b12f26dull, 0x5fb354025b277b14ull, 0xd0dbc55a0b79e09full, 0xaa03b5923b4c69e6ull, - 0xe553c1b9f35344e2ull, 0x9f8bb171c366cd9bull, 0x10e3202993385610ull, 0x6a3b50e1a30ddf69ull, 0x8e43c87e03060c18ull, 0xf49bb8b633338561ull, - 0x7bf329ee636d1eeaull, 0x012b592653589793ull, 0x4e7b2d0d9b47ba97ull, 0x34a35dc5ab7233eeull, 0xbbcbcc9dfb2ca865ull, 0xc113bc55cb19211cull, - 0x5863dbf1e3ac9decull, 0x22bbab39d3991495ull, 0xadd33a6183c78f1eull, 0xd70b4aa9b3f20667ull, 0x985b3e827bed2b63ull, 0xe2834e4a4bd8a21aull, - 0x6debdf121b863991ull, 0x1733afda2bb3b0e8ull, 0xf34b37458bb86399ull, 0x8993478dbb8deae0ull, 0x06fbd6d5ebd3716bull, 0x7c23a61ddbe6f812ull, - 0x3373d23613f9d516ull, 0x49aba2fe23cc5c6full, 0xc6c333a67392c7e4ull, 0xbc1b436e43a74e9dull, 0x95ac9329ac4bc9b5ull, 0xef74e3e19c7e40ccull, - 0x601c72b9cc20db47ull, 0x1ac40271fc15523eull, 0x5594765a340a7f3aull, 0x2f4c0692043ff643ull, 0xa02497ca54616dc8ull, 0xdafce7026454e4b1ull, - 0x3e847f9dc45f37c0ull, 0x445c0f55f46abeb9ull, 0xcb349e0da4342532ull, 0xb1eceec59401ac4bull, 0xfebc9aee5c1e814full, 0x8464ea266c2b0836ull, - 0x0b0c7b7e3c7593bdull, 0x71d40bb60c401ac4ull, 0xe8a46c1224f5a634ull, 0x927c1cda14c02f4dull, 0x1d148d82449eb4c6ull, 0x67ccfd4a74ab3dbfull, - 0x289c8961bcb410bbull, 0x5244f9a98c8199c2ull, 0xdd2c68f1dcdf0249ull, 0xa7f41839ecea8b30ull, 0x438c80a64ce15841ull, 0x3954f06e7cd4d138ull, - 0xb63c61362c8a4ab3ull, 0xcce411fe1cbfc3caull, 0x83b465d5d4a0eeceull, 0xf96c151de49567b7ull, 0x76048445b4cbfc3cull, 0x0cdcf48d84fe7545ull, - 0x6fbd6d5ebd3716b7ull, 0x15651d968d029fceull, 0x9a0d8ccedd5c0445ull, 0xe0d5fc06ed698d3cull, 0xaf85882d2576a038ull, 0xd55df8e515432941ull, - 0x5a3569bd451db2caull, 0x20ed197575283bb3ull, 0xc49581ead523e8c2ull, 0xbe4df122e51661bbull, 0x3125607ab548fa30ull, 0x4bfd10b2857d7349ull, - 0x04ad64994d625e4dull, 0x7e7514517d57d734ull, 0xf11d85092d094cbfull, 0x8bc5f5c11d3cc5c6ull, 0x12b5926535897936ull, 0x686de2ad05bcf04full, - 0xe70573f555e26bc4ull, 0x9ddd033d65d7e2bdull, 0xd28d7716adc8cfb9ull, 0xa85507de9dfd46c0ull, 0x273d9686cda3dd4bull, 0x5de5e64efd965432ull, - 0xb99d7ed15d9d8743ull, 0xc3450e196da80e3aull, 0x4c2d9f413df695b1ull, 0x36f5ef890dc31cc8ull, 0x79a59ba2c5dc31ccull, 0x037deb6af5e9b8b5ull, - 0x8c157a32a5b7233eull, 0xf6cd0afa9582aa47ull, 0x4ad64994d625e4daull, 0x300e395ce6106da3ull, 0xbf66a804b64ef628ull, 0xc5bed8cc867b7f51ull, - 0x8aeeace74e645255ull, 0xf036dc2f7e51db2cull, 0x7f5e4d772e0f40a7ull, 0x05863dbf1e3ac9deull, 0xe1fea520be311aafull, 0x9b26d5e88e0493d6ull, - 0x144e44b0de5a085dull, 0x6e963478ee6f8124ull, 0x21c640532670ac20ull, 0x5b1e309b16452559ull, 0xd476a1c3461bbed2ull, 0xaeaed10b762e37abull, - 0x37deb6af5e9b8b5bull, 0x4d06c6676eae0222ull, 0xc26e573f3ef099a9ull, 0xb8b627f70ec510d0ull, 0xf7e653dcc6da3dd4ull, 0x8d3e2314f6efb4adull, - 0x0256b24ca6b12f26ull, 0x788ec2849684a65full, 0x9cf65a1b368f752eull, 0xe62e2ad306bafc57ull, 0x6946bb8b56e467dcull, 0x139ecb4366d1eea5ull, - 0x5ccebf68aecec3a1ull, 0x2616cfa09efb4ad8ull, 0xa97e5ef8cea5d153ull, 0xd3a62e30fe90582aull, 0xb0c7b7e3c7593bd8ull, 0xca1fc72bf76cb2a1ull, - 0x45775673a732292aull, 0x3faf26bb9707a053ull, 0x70ff52905f188d57ull, 0x0a2722586f2d042eull, 0x854fb3003f739fa5ull, 0xff97c3c80f4616dcull, - 0x1bef5b57af4dc5adull, 0x61372b9f9f784cd4ull, 0xee5fbac7cf26d75full, 0x9487ca0fff135e26ull, 0xdbd7be24370c7322ull, 0xa10fceec0739fa5bull, - 0x2e675fb4576761d0ull, 0x54bf2f7c6752e8a9ull, 0xcdcf48d84fe75459ull, 0xb71738107fd2dd20ull, 0x387fa9482f8c46abull, 0x42a7d9801fb9cfd2ull, - 0x0df7adabd7a6e2d6ull, 0x772fdd63e7936bafull, 0xf8474c3bb7cdf024ull, 0x829f3cf387f8795dull, 0x66e7a46c27f3aa2cull, 0x1c3fd4a417c62355ull, - 0x935745fc4798b8deull, 0xe98f353477ad31a7ull, 0xa6df411fbfb21ca3ull, 0xdc0731d78f8795daull, 0x536fa08fdfd90e51ull, 0x29b7d047efec8728ull, - }; - - zpl_u32 zpl_crc32(void const *data, zpl_isize len) { - zpl_isize remaining; - zpl_u32 result = ~(cast(zpl_u32) 0); - zpl_u8 const *c = cast(zpl_u8 const *) data; - for (remaining = len; remaining--; c++) result = (result >> 8) ^ (zpl__crc32_table[(result ^ *c) & 0xff]); - return ~result; - } - - zpl_u64 zpl_crc64(void const *data, zpl_isize len) { - zpl_isize remaining; - zpl_u64 result = (cast(zpl_u64)0); - zpl_u8 const *c = cast(zpl_u8 const *) data; - for (remaining = len; remaining--; c++) result = (result >> 8) ^ (zpl__crc64_table[(result ^ *c) & 0xff]); - return result; - } - - zpl_u32 zpl_fnv32(void const *data, zpl_isize len) { - zpl_isize i; - zpl_u32 h = 0x811c9dc5; - zpl_u8 const *c = cast(zpl_u8 const *) data; - - for (i = 0; i < len; i++) h = (h * 0x01000193) ^ c[i]; - - return h; - } - - zpl_u64 zpl_fnv64(void const *data, zpl_isize len) { - zpl_isize i; - zpl_u64 h = 0xcbf29ce484222325ull; - zpl_u8 const *c = cast(zpl_u8 const *) data; - - for (i = 0; i < len; i++) h = (h * 0x100000001b3ll) ^ c[i]; - - return h; - } - - zpl_u32 zpl_fnv32a(void const *data, zpl_isize len) { - zpl_isize i; - zpl_u32 h = 0x811c9dc5; - zpl_u8 const *c = cast(zpl_u8 const *) data; - - for (i = 0; i < len; i++) h = (h ^ c[i]) * 0x01000193; - - return h; - } - - zpl_u64 zpl_fnv64a(void const *data, zpl_isize len) { - zpl_isize i; - zpl_u64 h = 0xcbf29ce484222325ull; - zpl_u8 const *c = cast(zpl_u8 const *) data; - - for (i = 0; i < len; i++) h = (h ^ c[i]) * 0x100000001b3ll; - - return h; - } - - // base64 implementation based on https://nachtimwald.com/2017/11/18/base64-encode-and-decode-in-c/ - // - zpl_global zpl_u8 zpl__base64_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - - - /* generated table based on: */ - #if 0 - void zpl__base64_decode_table() { - zpl_i32 inv[80]; - zpl_isize i; - - zpl_memset(inv, -1, zpl_size_of(inv)); - - for (i=0; i < zpl_size_of(zpl__base64_chars)-1; i++) { - inv[zpl__base64_chars[i]-43] = i; - } - } - #endif - /* === */ - zpl_global zpl_i32 zpl__base64_dec_table[] = { - 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, - 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, - 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, - 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, - 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, - 43, 44, 45, 46, 47, 48, 49, 50, 51 }; - - zpl_isize zpl__base64_encoded_size(zpl_isize len) { - zpl_isize ret = len; - - if (len % 3 != 0) { - ret += 3 - (len % 3); - } - - ret /= 3; - ret *= 4; - - return ret; - } - - zpl_isize zpl__base64_decoded_size(void const *data) { - zpl_isize len, ret, i; - const zpl_u8 *s = cast(const zpl_u8 *)data; - - if (s == NULL) { - return 0; - } - - len = zpl_strlen(cast(const char*)s); - ret = len / 4 * 3; - - for (i=len; i-- > 0;) { - if (s[i] == '=') { - ret--; - } else { - break; - } - } - - return ret; - } - - zpl_b32 zpl__base64_valid_char(zpl_u8 c) { - if (c >= '0' && c <= '9') - return true; - if (c >= 'A' && c <= 'Z') - return true; - if (c >= 'a' && c <= 'z') - return true; - if (c == '+' || c == '/' || c == '=') - return true; - - return false; - } - - zpl_u8 *zpl_base64_encode(zpl_allocator a, void const *data, zpl_isize len) { - const zpl_u8 *s = cast(const zpl_u8*)data; - zpl_u8 *ret = NULL; - zpl_isize enc_len, i, j, v; - - if (data == NULL || len == 0) { - return NULL; - } - - enc_len = zpl__base64_encoded_size(len); - ret = cast(zpl_u8 *)zpl_alloc(a, enc_len+1); - ret[enc_len] = 0; - - for (i=0, j=0; i < len; i+=3, j+=4) { - v = s[i]; - v = (i+1 < len) ? (v << 8 | s[i+1]) : (v << 8); - v = (i+2 < len) ? (v << 8 | s[i+2]) : (v << 8); - - ret[j] = zpl__base64_chars[(v >> 18) & 0x3F]; - ret[j+1] = zpl__base64_chars[(v >> 12) & 0x3F]; - - if (i+1 < len) - ret[j+2] = zpl__base64_chars[(v >> 6) & 0x3F]; - - else ret[j+2] = '='; - - if (i+2 < len) - ret[j+3] = zpl__base64_chars[v & 0x3F]; - - else ret[j+3] = '='; - - } - - return ret; - } - - zpl_u8 *zpl_base64_decode(zpl_allocator a, void const *data, zpl_isize len) { - const zpl_u8 *s = cast(const zpl_u8*)data; - zpl_u8 *ret = NULL; - zpl_isize alen, i, j, v; - - if (data == NULL) { - return NULL; - } - - alen = zpl__base64_decoded_size(s); - ret = cast(zpl_u8 *)zpl_alloc(a, alen+1); - - ZPL_ASSERT_NOT_NULL(ret); - - ret[alen] = 0; - - for (i=0; i> 16) & 0xFF; - - if (s[i+2] != '=') - ret[j+1] = (v >> 8) & 0xFF; - - if (s[i+3] != '=') - ret[j+2] = v & 0xFF; - } - - return ret; - } - - zpl_u32 zpl_murmur32_seed(void const *data, zpl_isize len, zpl_u32 seed) { - zpl_u32 const c1 = 0xcc9e2d51; - zpl_u32 const c2 = 0x1b873593; - zpl_u32 const r1 = 15; - zpl_u32 const r2 = 13; - zpl_u32 const m = 5; - zpl_u32 const n = 0xe6546b64; - - zpl_isize i, nblocks = len / 4; - zpl_u32 hash = seed, k1 = 0; - zpl_u32 const *blocks = cast(zpl_u32 const *) data; - zpl_u8 const *tail = cast(zpl_u8 const *)(data) + nblocks * 4; - - for (i = 0; i < nblocks; i++) { - zpl_u32 k = blocks[i]; - k *= c1; - k = (k << r1) | (k >> (32 - r1)); - k *= c2; - - hash ^= k; - hash = ((hash << r2) | (hash >> (32 - r2))) * m + n; - } - - switch (len & 3) { - case 3: k1 ^= tail[2] << 16; - case 2: k1 ^= tail[1] << 8; - case 1: - k1 ^= tail[0]; - - k1 *= c1; - k1 = (k1 << r1) | (k1 >> (32 - r1)); - k1 *= c2; - hash ^= k1; - } - - hash ^= len; - hash ^= (hash >> 16); - hash *= 0x85ebca6b; - hash ^= (hash >> 13); - hash *= 0xc2b2ae35; - hash ^= (hash >> 16); - - return hash; - } - - zpl_u64 zpl_murmur64_seed(void const *data_, zpl_isize len, zpl_u64 seed) { - zpl_u64 const m = 0xc6a4a7935bd1e995ULL; - zpl_i32 const r = 47; - - zpl_u64 h = seed ^ (len * m); - - zpl_u64 const *data = cast(zpl_u64 const *) data_; - zpl_u8 const *data2 = cast(zpl_u8 const *) data_; - zpl_u64 const *end = data + (len / 8); - - while (data != end) { - zpl_u64 k = *data++; - - k *= m; - k ^= k >> r; - k *= m; - - h ^= k; - h *= m; - } - - switch (len & 7) { - case 7: h ^= cast(zpl_u64)(data2[6]) << 48; - case 6: h ^= cast(zpl_u64)(data2[5]) << 40; - case 5: h ^= cast(zpl_u64)(data2[4]) << 32; - case 4: h ^= cast(zpl_u64)(data2[3]) << 24; - case 3: h ^= cast(zpl_u64)(data2[2]) << 16; - case 2: h ^= cast(zpl_u64)(data2[1]) << 8; - case 1: h ^= cast(zpl_u64)(data2[0]); - h *= m; - }; - - h ^= h >> r; - h *= m; - h ^= h >> r; - - return h; - } - - ZPL_END_C_DECLS - #endif - - #if defined(ZPL_MODULE_REGEX) - // file: source/regex.c - - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - typedef enum zplreOp { - ZPL_RE_OP_BEGIN_CAPTURE, - ZPL_RE_OP_END_CAPTURE, - - ZPL_RE_OP_BEGINNING_OF_LINE, - ZPL_RE_OP_END_OF_LINE, - - ZPL_RE_OP_EXACT_MATCH, - ZPL_RE_OP_META_MATCH, - - ZPL_RE_OP_ANY, - ZPL_RE_OP_ANY_OF, - ZPL_RE_OP_ANY_BUT, - - ZPL_RE_OP_ZERO_OR_MORE, - ZPL_RE_OP_ONE_OR_MORE, - ZPL_RE_OP_ZERO_OR_MORE_SHORTEST, - ZPL_RE_OP_ONE_OR_MORE_SHORTEST, - ZPL_RE_OP_ZERO_OR_ONE, - - ZPL_RE_OP_BRANCH_START, - ZPL_RE_OP_BRANCH_END - } zplreOp; - - typedef enum zplreCode { - ZPL_RE_CODE_NULL = 0x0000, - ZPL_RE_CODE_WHITESPACE = 0x0100, - ZPL_RE_CODE_NOT_WHITESPACE = 0x0200, - ZPL_RE_CODE_DIGIT = 0x0300, - ZPL_RE_CODE_NOT_DIGIT = 0x0400, - ZPL_RE_CODE_ALPHA = 0x0500, - ZPL_RE_CODE_LOWER = 0x0600, - ZPL_RE_CODE_UPPER = 0x0700, - ZPL_RE_CODE_WORD = 0x0800, - ZPL_RE_CODE_NOT_WORD = 0x0900, - - ZPL_RE_CODE_XDIGIT = 0x0a00, - ZPL_RE_CODE_PRINTABLE = 0x0b00, - } zplreCode; - - typedef struct { - zpl_isize op, offset; - } zpl_re_ctx; - - enum { - ZPL_RE__NO_MATCH = -1, - ZPL_RE__INTERNAL_FAILURE = -2, - }; - - static char const ZPL_RE__META_CHARS[] = "^$()[].*+?|\\"; - static char const ZPL_RE__WHITESPACE[] = " \r\t\n\v\f"; - #define ZPL_RE__LITERAL(str) (str), zpl_size_of(str)-1 - - static zpl_re_ctx zpl_re__exec_single(zpl_re *re, zpl_isize op, char const *str, zpl_isize str_len, zpl_isize offset, zpl_re_capture *captures, zpl_isize max_capture_count); - static zpl_re_ctx zpl_re__exec(zpl_re *re, zpl_isize op, char const *str, zpl_isize str_len, zpl_isize offset, zpl_re_capture *captures, zpl_isize max_capture_count); - - static zpl_re_ctx zpl_re__ctx_no_match(zpl_isize op) { - zpl_re_ctx c; - c.op = op; - c.offset = ZPL_RE__NO_MATCH; - return c; - } - - static zpl_re_ctx zpl_re__ctx_internal_failure(zpl_isize op) { - zpl_re_ctx c; - c.op = op; - c.offset = ZPL_RE__INTERNAL_FAILURE; - return c; - } - - static zpl_u8 zpl_re__hex(char const *s) { - return ((zpl_char_to_hex_digit(*s) << 4) & 0xf0) | (zpl_char_to_hex_digit(*(s+1)) & 0x0f); - } - - static zpl_isize zpl_re__strfind(char const *s, zpl_isize len, char c, zpl_isize offset) { - if (offset < len) { - char const *found = (char const *)zpl_memchr(s+offset, c, len-offset); - if (found) - return found - s; - } - - return -1; - } - - static zpl_b32 zpl_re__match_escape(char c, int code) { - switch (code) { - case ZPL_RE_CODE_NULL: return c == 0; - case ZPL_RE_CODE_WHITESPACE: return zpl_re__strfind(ZPL_RE__LITERAL(ZPL_RE__WHITESPACE), c, 0) >= 0; - case ZPL_RE_CODE_NOT_WHITESPACE: return zpl_re__strfind(ZPL_RE__LITERAL(ZPL_RE__WHITESPACE), c, 0) < 0; - case ZPL_RE_CODE_DIGIT: return (c >= '0' && c <= '9'); - case ZPL_RE_CODE_NOT_DIGIT: return !(c >= '0' && c <= '9'); - case ZPL_RE_CODE_ALPHA: return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); - case ZPL_RE_CODE_LOWER: return (c >= 'a' && c <= 'z'); - case ZPL_RE_CODE_UPPER: return (c >= 'A' && c <= 'Z'); - - /* TODO(bill): Make better? */ - case ZPL_RE_CODE_WORD: return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_'; - case ZPL_RE_CODE_NOT_WORD: return !((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_'); - - /* TODO(bill): Maybe replace with between tests? */ - case ZPL_RE_CODE_XDIGIT: return zpl_re__strfind(ZPL_RE__LITERAL("0123456789ABCDEFabcdef"), c, 0) >= 0; - case ZPL_RE_CODE_PRINTABLE: return c >= 0x20 && c <= 0x7e; - default: break; - } - - return 0; - } - - static zpl_re_ctx zpl_re__consume(zpl_re *re, zpl_isize op, char const *str, zpl_isize str_len, zpl_isize offset, zpl_re_capture *captures, zpl_isize max_capture_count, zpl_b32 is_greedy) - { - zpl_re_ctx c, best_c, next_c; - - c.op = op; - c.offset = offset; - - best_c.op = ZPL_RE__NO_MATCH; - best_c.offset = offset; - - for (;;) { - c = zpl_re__exec_single(re, op, str, str_len, c.offset, 0, 0); - if (c.offset > str_len || c.offset == -1) break; - if (c.op >= re->buf_len) return c; - - next_c = zpl_re__exec(re, c.op, str, str_len, c.offset, captures, max_capture_count); - if (next_c.offset <= str_len) { - if (captures) - zpl_re__exec(re, c.op, str, str_len, c.offset, captures, max_capture_count); - - best_c = next_c; - if (!is_greedy) break; - } - - if (best_c.op > re->buf_len) - best_c.op = c.op; - - } - - return best_c; - } - - static zpl_re_ctx zpl_re__exec_single(zpl_re *re, zpl_isize op, char const *str, zpl_isize str_len, zpl_isize offset, zpl_re_capture *captures, zpl_isize max_capture_count) { - zpl_re_ctx ctx; - zpl_isize buffer_len; - zpl_isize match_len; - zpl_isize next_op; - zpl_isize skip; - - switch (re->buf[op++]) { - case ZPL_RE_OP_BEGIN_CAPTURE: { - zpl_u8 capture = re->buf[op++]; - if (captures && (capture < max_capture_count)) - captures[capture].str = str + offset; - } break; - - case ZPL_RE_OP_END_CAPTURE: { - zpl_u8 capture = re->buf[op++]; - if (captures && (capture < max_capture_count)) - captures[capture].len = (str + offset) - captures[capture].str; - } break; - - case ZPL_RE_OP_BEGINNING_OF_LINE: { - if (offset != 0) - return zpl_re__ctx_no_match(op); - } break; - - case ZPL_RE_OP_END_OF_LINE: { - if (offset != str_len) - return zpl_re__ctx_no_match(op); - } break; - - case ZPL_RE_OP_BRANCH_START: { - skip = re->buf[op++]; - ctx = zpl_re__exec(re, op, str, str_len, offset, captures, max_capture_count); - if (ctx.offset <= str_len) { - offset = ctx.offset; - op = ctx.op; - } else { - ctx = zpl_re__exec(re, op + skip, str, str_len, offset, captures, max_capture_count); - offset = ctx.offset; - op = ctx.op; - } - } break; - - case ZPL_RE_OP_BRANCH_END: { - skip = re->buf[op++]; - op += skip; - } break; - - case ZPL_RE_OP_ANY: { - if (offset < str_len) { - offset++; - break; - } - return zpl_re__ctx_no_match(op); - } break; - - case ZPL_RE_OP_ANY_OF: { - zpl_isize i; - char cin = str[offset]; - buffer_len = re->buf[op++]; - - if (offset >= str_len) - return zpl_re__ctx_no_match(op + buffer_len); - - for (i = 0; i < buffer_len; i++) { - char cmatch = (char)re->buf[op+i]; - if (!cmatch) { - i++; - if (zpl_re__match_escape(cin, re->buf[op+i] << 8)) - break; - } else if (cin == cmatch) { - break; - } - } - - if (i == buffer_len) - return zpl_re__ctx_no_match(op + buffer_len); - - offset++; - op += buffer_len; - } break; - - case ZPL_RE_OP_ANY_BUT: { - zpl_isize i; - char cin = str[offset]; - buffer_len = re->buf[op++]; - - if (offset >= str_len) - return zpl_re__ctx_no_match(op + buffer_len); - - for (i = 0; i < buffer_len; i++) { - char cmatch = (char)re->buf[op + i]; - if (!cmatch) { - i++; - if (zpl_re__match_escape(cin, re->buf[op+i] << 8)) - return zpl_re__ctx_no_match(op + buffer_len); - } else if (cin == cmatch) { - return zpl_re__ctx_no_match(op + buffer_len); - } - } - - offset++; - op += buffer_len; - } break; - - case ZPL_RE_OP_EXACT_MATCH: { - match_len = re->buf[op++]; - - if ((match_len > (str_len - offset)) || - zpl_strncmp(str+offset, (const char*)re->buf + op, match_len) != 0) - return zpl_re__ctx_no_match(op + match_len); - - op += match_len; - offset += match_len; - } break; - - case ZPL_RE_OP_META_MATCH: { - char cin = (char)re->buf[op++]; - char cmatch = str[offset++]; - - if (!cin) { - if (zpl_re__match_escape(cmatch, re->buf[op++] << 8)) - break; - } - else if (cin == cmatch) break; - - return zpl_re__ctx_no_match(op); - } break; - - case ZPL_RE_OP_ZERO_OR_MORE: { - ctx = zpl_re__consume(re, op, str, str_len, offset, captures, max_capture_count, 1); - offset = ctx.offset; - op = ctx.op; - } break; - - case ZPL_RE_OP_ONE_OR_MORE: { - ctx = zpl_re__exec_single(re, op, str, str_len, offset, captures, max_capture_count); - - if (ctx.offset > str_len) - return ctx; - - ctx = zpl_re__consume(re, op, str, str_len, offset, captures, max_capture_count, 1); - offset = ctx.offset; - op = ctx.op; - } break; - - case ZPL_RE_OP_ZERO_OR_MORE_SHORTEST: { - ctx = zpl_re__consume(re, op, str, str_len, offset, captures, max_capture_count, 0); - offset = ctx.offset; - op = ctx.op; - } break; - - case ZPL_RE_OP_ONE_OR_MORE_SHORTEST: { - ctx = zpl_re__exec_single(re, op, str, str_len, offset, captures, max_capture_count); - - if (ctx.offset > str_len) - return ctx; - - ctx = zpl_re__consume(re, op, str, str_len, offset, captures, max_capture_count, 0); - offset = ctx.offset; - op = ctx.op; - } break; - - case ZPL_RE_OP_ZERO_OR_ONE: { - ctx = zpl_re__exec_single(re, op, str, str_len, offset, captures, max_capture_count); - - if (ctx.offset <= str_len) { - zpl_re_ctx possible_ctx = zpl_re__exec(re, ctx.op, str, str_len, ctx.offset, captures, max_capture_count); - - if (possible_ctx.offset <= str_len) { - op = possible_ctx.op; - offset = possible_ctx.offset; - break; - } - } - - next_op = ctx.op; - ctx = zpl_re__exec(re, next_op, str, str_len, offset, captures, max_capture_count); - - if (ctx.offset <= str_len) { - op = ctx.op; - offset = ctx.offset; - break; - } - return zpl_re__ctx_no_match(op); - } break; - - default: { - return zpl_re__ctx_internal_failure(op); - } break; - } - - ctx.op = op; - ctx.offset = offset; - - return ctx; - } - - static zpl_re_ctx zpl_re__exec(zpl_re *re, zpl_isize op, char const *str, zpl_isize str_len, zpl_isize offset, zpl_re_capture *captures, zpl_isize max_capture_count) { - zpl_re_ctx c; - c.op = op; - c.offset = offset; - - while (c.op < re->buf_len) { - c = zpl_re__exec_single(re, c.op, str, str_len, c.offset, captures, max_capture_count); - - if (c.offset > str_len || c.offset == -1) - break; - } - - return c; - } - - static zpl_regex_error zpl_re__emit_ops(zpl_re *re, zpl_isize op_count, ...) { - va_list va; - - if (re->buf_len + op_count > re->buf_cap) { - if (!re->can_realloc) { - return ZPL_RE_ERROR_TOO_LONG; - } - else { - zpl_isize new_cap = (re->buf_cap*2) + op_count; - re->buf = (char *)zpl_resize(re->backing, re->buf, re->buf_cap, new_cap); - re->buf_cap = new_cap; - } - } - - va_start(va, op_count); - for (zpl_isize i = 0; i < op_count; i++) - { - zpl_i32 v = va_arg(va, zpl_i32); - if (v > 256) - return ZPL_RE_ERROR_TOO_LONG; - re->buf[re->buf_len++] = (char)v; - } - va_end(va); - - return ZPL_RE_ERROR_NONE; - } - - static zpl_regex_error zpl_re__emit_ops_buffer(zpl_re *re, zpl_isize op_count, char const *buffer) { - if (re->buf_len + op_count > re->buf_cap) { - if (!re->can_realloc) { - return ZPL_RE_ERROR_TOO_LONG; - } - else { - zpl_isize new_cap = (re->buf_cap*2) + op_count; - re->buf = (char *)zpl_resize(re->backing, re->buf, re->buf_cap, new_cap); - re->buf_cap = new_cap; - } - } - - for (zpl_isize i = 0; i < op_count; i++) - { - re->buf[re->buf_len++] = buffer[i]; - } - - return ZPL_RE_ERROR_NONE; - } - - static int zpl_re__encode_escape(char code) { - switch (code) { - default: break; /* NOTE(bill): It's a normal character */ - - /* TODO(bill): Are there anymore? */ - case 't': return '\t'; - case 'n': return '\n'; - case 'r': return '\r'; - case 'f': return '\f'; - case 'v': return '\v'; - - case '0': return ZPL_RE_CODE_NULL; - - case 's': return ZPL_RE_CODE_WHITESPACE; - case 'S': return ZPL_RE_CODE_NOT_WHITESPACE; - - case 'd': return ZPL_RE_CODE_DIGIT; - case 'D': return ZPL_RE_CODE_NOT_DIGIT; - - case 'a': return ZPL_RE_CODE_ALPHA; - case 'l': return ZPL_RE_CODE_LOWER; - case 'u': return ZPL_RE_CODE_UPPER; - - case 'w': return ZPL_RE_CODE_WORD; - case 'W': return ZPL_RE_CODE_NOT_WORD; - - case 'x': return ZPL_RE_CODE_XDIGIT; - case 'p': return ZPL_RE_CODE_PRINTABLE; - } - return code; - } - - static zpl_regex_error zpl_re__parse_group(zpl_re *re, char const *pattern, zpl_isize len, zpl_isize offset, zpl_isize *new_offset) { - zpl_regex_error err = ZPL_RE_ERROR_NONE; - char buffer[256] = {0}; - zpl_isize buffer_len = 0, buffer_cap = zpl_size_of(buffer); - zpl_b32 closed = 0; - zplreOp op = ZPL_RE_OP_ANY_OF; - - if (pattern[offset] == '^') { + } break; + + case ZPL_RE_OP_BRANCH_END: { + skip = re->buf[op++]; + op += skip; + } break; + + case ZPL_RE_OP_ANY: { + if (offset < str_len) { offset++; - op = ZPL_RE_OP_ANY_BUT; + break; } - - while(!closed && - err == ZPL_RE_ERROR_NONE && - offset < len) - { - if (pattern[offset] == ']') { - err = zpl_re__emit_ops(re, 2, (zpl_i32)op, (zpl_i32)buffer_len); - if (err) break; - - err = zpl_re__emit_ops_buffer(re, buffer_len, (const char*)buffer); - if (err) break; - offset++; - closed = 1; + return zpl_re__ctx_no_match(op); + } break; + + case ZPL_RE_OP_ANY_OF: { + zpl_isize i; + char cin = str[offset]; + buffer_len = re->buf[op++]; + + if (offset >= str_len) + return zpl_re__ctx_no_match(op + buffer_len); + + for (i = 0; i < buffer_len; i++) { + char cmatch = (char)re->buf[op+i]; + if (!cmatch) { + i++; + if (zpl_re__match_escape(cin, re->buf[op+i] << 8)) + break; + } else if (cin == cmatch) { break; } - - if (buffer_len >= buffer_cap) - return ZPL_RE_ERROR_TOO_LONG; - - if (pattern[offset] == '\\') { - offset++; - - if ((offset + 1 < len) && zpl_char_is_hex_digit(*(pattern+offset))) { - buffer[buffer_len++] = zpl_re__hex((pattern+offset)); - offset++; - } - else if (offset < len) { - zpl_i32 code = zpl_re__encode_escape(pattern[offset]); - - if (!code || code > 0xff) { - buffer[buffer_len++] = 0; - - if (buffer_len >= buffer_cap) - return ZPL_RE_ERROR_TOO_LONG; - - buffer[buffer_len++] = (code >> 8) & 0xff; - } - else { - buffer[buffer_len++] = code & 0xff; - } - } + } + + if (i == buffer_len) + return zpl_re__ctx_no_match(op + buffer_len); + + offset++; + op += buffer_len; + } break; + + case ZPL_RE_OP_ANY_BUT: { + zpl_isize i; + char cin = str[offset]; + buffer_len = re->buf[op++]; + + if (offset >= str_len) + return zpl_re__ctx_no_match(op + buffer_len); + + for (i = 0; i < buffer_len; i++) { + char cmatch = (char)re->buf[op + i]; + if (!cmatch) { + i++; + if (zpl_re__match_escape(cin, re->buf[op+i] << 8)) + return zpl_re__ctx_no_match(op + buffer_len); + } else if (cin == cmatch) { + return zpl_re__ctx_no_match(op + buffer_len); } - else { - buffer[buffer_len++] = (unsigned char)pattern[offset]; + } + + offset++; + op += buffer_len; + } break; + + case ZPL_RE_OP_EXACT_MATCH: { + match_len = re->buf[op++]; + + if ((match_len > (str_len - offset)) || + zpl_strncmp(str+offset, (const char*)re->buf + op, match_len) != 0) + return zpl_re__ctx_no_match(op + match_len); + + op += match_len; + offset += match_len; + } break; + + case ZPL_RE_OP_META_MATCH: { + char cin = (char)re->buf[op++]; + char cmatch = str[offset++]; + + if (!cin) { + if (zpl_re__match_escape(cmatch, re->buf[op++] << 8)) + break; + } + else if (cin == cmatch) break; + + return zpl_re__ctx_no_match(op); + } break; + + case ZPL_RE_OP_ZERO_OR_MORE: { + ctx = zpl_re__consume(re, op, str, str_len, offset, captures, max_capture_count, 1); + offset = ctx.offset; + op = ctx.op; + } break; + + case ZPL_RE_OP_ONE_OR_MORE: { + ctx = zpl_re__exec_single(re, op, str, str_len, offset, captures, max_capture_count); + + if (ctx.offset > str_len) + return ctx; + + ctx = zpl_re__consume(re, op, str, str_len, offset, captures, max_capture_count, 1); + offset = ctx.offset; + op = ctx.op; + } break; + + case ZPL_RE_OP_ZERO_OR_MORE_SHORTEST: { + ctx = zpl_re__consume(re, op, str, str_len, offset, captures, max_capture_count, 0); + offset = ctx.offset; + op = ctx.op; + } break; + + case ZPL_RE_OP_ONE_OR_MORE_SHORTEST: { + ctx = zpl_re__exec_single(re, op, str, str_len, offset, captures, max_capture_count); + + if (ctx.offset > str_len) + return ctx; + + ctx = zpl_re__consume(re, op, str, str_len, offset, captures, max_capture_count, 0); + offset = ctx.offset; + op = ctx.op; + } break; + + case ZPL_RE_OP_ZERO_OR_ONE: { + ctx = zpl_re__exec_single(re, op, str, str_len, offset, captures, max_capture_count); + + if (ctx.offset <= str_len) { + zpl_re_ctx possible_ctx = zpl_re__exec(re, ctx.op, str, str_len, ctx.offset, captures, max_capture_count); + + if (possible_ctx.offset <= str_len) { + op = possible_ctx.op; + offset = possible_ctx.offset; + break; } + } + + next_op = ctx.op; + ctx = zpl_re__exec(re, next_op, str, str_len, offset, captures, max_capture_count); + + if (ctx.offset <= str_len) { + op = ctx.op; + offset = ctx.offset; + break; + } + return zpl_re__ctx_no_match(op); + } break; + + default: { + return zpl_re__ctx_internal_failure(op); + } break; + } + + ctx.op = op; + ctx.offset = offset; + + return ctx; +} +static zpl_re_ctx zpl_re__exec(zpl_re *re, zpl_isize op, char const *str, zpl_isize str_len, zpl_isize offset, zpl_re_capture *captures, zpl_isize max_capture_count) { + zpl_re_ctx c; + c.op = op; + c.offset = offset; + + while (c.op < re->buf_len) { + c = zpl_re__exec_single(re, c.op, str, str_len, c.offset, captures, max_capture_count); + + if (c.offset > str_len || c.offset == -1) + break; + } + + return c; +} + +static zpl_regex_error zpl_re__emit_ops(zpl_re *re, zpl_isize op_count, ...) { + va_list va; + + if (re->buf_len + op_count > re->buf_cap) { + if (!re->can_realloc) { + return ZPL_RE_ERROR_TOO_LONG; + } + else { + zpl_isize new_cap = (re->buf_cap*2) + op_count; + re->buf = (char *)zpl_resize(re->backing, re->buf, re->buf_cap, new_cap); + re->buf_cap = new_cap; + } + } + + va_start(va, op_count); + for (zpl_isize i = 0; i < op_count; i++) + { + zpl_i32 v = va_arg(va, zpl_i32); + if (v > 256) + return ZPL_RE_ERROR_TOO_LONG; + re->buf[re->buf_len++] = (char)v; + } + va_end(va); + + return ZPL_RE_ERROR_NONE; +} + +static zpl_regex_error zpl_re__emit_ops_buffer(zpl_re *re, zpl_isize op_count, char const *buffer) { + if (re->buf_len + op_count > re->buf_cap) { + if (!re->can_realloc) { + return ZPL_RE_ERROR_TOO_LONG; + } + else { + zpl_isize new_cap = (re->buf_cap*2) + op_count; + re->buf = (char *)zpl_resize(re->backing, re->buf, re->buf_cap, new_cap); + re->buf_cap = new_cap; + } + } + + for (zpl_isize i = 0; i < op_count; i++) + { + re->buf[re->buf_len++] = buffer[i]; + } + + return ZPL_RE_ERROR_NONE; +} + +static int zpl_re__encode_escape(char code) { + switch (code) { + default: break; /* NOTE(bill): It's a normal character */ + + /* TODO(bill): Are there anymore? */ + case 't': return '\t'; + case 'n': return '\n'; + case 'r': return '\r'; + case 'f': return '\f'; + case 'v': return '\v'; + + case '0': return ZPL_RE_CODE_NULL; + + case 's': return ZPL_RE_CODE_WHITESPACE; + case 'S': return ZPL_RE_CODE_NOT_WHITESPACE; + + case 'd': return ZPL_RE_CODE_DIGIT; + case 'D': return ZPL_RE_CODE_NOT_DIGIT; + + case 'a': return ZPL_RE_CODE_ALPHA; + case 'l': return ZPL_RE_CODE_LOWER; + case 'u': return ZPL_RE_CODE_UPPER; + + case 'w': return ZPL_RE_CODE_WORD; + case 'W': return ZPL_RE_CODE_NOT_WORD; + + case 'x': return ZPL_RE_CODE_XDIGIT; + case 'p': return ZPL_RE_CODE_PRINTABLE; + } + return code; +} + +static zpl_regex_error zpl_re__parse_group(zpl_re *re, char const *pattern, zpl_isize len, zpl_isize offset, zpl_isize *new_offset) { + zpl_regex_error err = ZPL_RE_ERROR_NONE; + char buffer[256] = {0}; + zpl_isize buffer_len = 0, buffer_cap = zpl_size_of(buffer); + zpl_b32 closed = 0; + zplreOp op = ZPL_RE_OP_ANY_OF; + + if (pattern[offset] == '^') { + offset++; + op = ZPL_RE_OP_ANY_BUT; + } + + while(!closed && + err == ZPL_RE_ERROR_NONE && + offset < len) + { + if (pattern[offset] == ']') { + err = zpl_re__emit_ops(re, 2, (zpl_i32)op, (zpl_i32)buffer_len); + if (err) break; + + err = zpl_re__emit_ops_buffer(re, buffer_len, (const char*)buffer); + if (err) break; + offset++; + closed = 1; + break; + } + + if (buffer_len >= buffer_cap) + return ZPL_RE_ERROR_TOO_LONG; + + if (pattern[offset] == '\\') { + offset++; + + if ((offset + 1 < len) && zpl_char_is_hex_digit(*(pattern+offset))) { + buffer[buffer_len++] = zpl_re__hex((pattern+offset)); offset++; } - - if (err) return err; - if (!closed) return ZPL_RE_ERROR_MISMATCHED_BLOCKS; - if (new_offset) *new_offset = offset; - return ZPL_RE_ERROR_NONE; + else if (offset < len) { + zpl_i32 code = zpl_re__encode_escape(pattern[offset]); + + if (!code || code > 0xff) { + buffer[buffer_len++] = 0; + + if (buffer_len >= buffer_cap) + return ZPL_RE_ERROR_TOO_LONG; + + buffer[buffer_len++] = (code >> 8) & 0xff; + } + else { + buffer[buffer_len++] = code & 0xff; + } + } } + else { + buffer[buffer_len++] = (unsigned char)pattern[offset]; + } + + offset++; + } + + if (err) return err; + if (!closed) return ZPL_RE_ERROR_MISMATCHED_BLOCKS; + if (new_offset) *new_offset = offset; + return ZPL_RE_ERROR_NONE; +} - static zpl_regex_error zpl_re__compile_quantifier(zpl_re *re, zpl_isize last_buf_len, unsigned char quantifier) { - zpl_regex_error err; - zpl_isize move_size; +static zpl_regex_error zpl_re__compile_quantifier(zpl_re *re, zpl_isize last_buf_len, unsigned char quantifier) { + zpl_regex_error err; + zpl_isize move_size; + + if ((re->buf[last_buf_len] == ZPL_RE_OP_EXACT_MATCH) && + (re->buf[last_buf_len+1] > 1)) + { + unsigned char last_char = re->buf[re->buf_len-1]; + + re->buf[last_buf_len+1]--; + re->buf_len--; + err = zpl_re__emit_ops(re, 4, (zpl_i32)quantifier, (zpl_i32)ZPL_RE_OP_EXACT_MATCH, 1, (zpl_i32)last_char); + if (err) return err; + return ZPL_RE_ERROR_NONE; + } + + move_size = re->buf_len - last_buf_len + 1; + + err = zpl_re__emit_ops(re, 1, 0); + if (err) return err; + + zpl_memmove(re->buf+last_buf_len+1, re->buf+last_buf_len, move_size); + re->buf[last_buf_len] = quantifier; + + return ZPL_RE_ERROR_NONE; +} - if ((re->buf[last_buf_len] == ZPL_RE_OP_EXACT_MATCH) && - (re->buf[last_buf_len+1] > 1)) - { - unsigned char last_char = re->buf[re->buf_len-1]; - - re->buf[last_buf_len+1]--; - re->buf_len--; - err = zpl_re__emit_ops(re, 4, (zpl_i32)quantifier, (zpl_i32)ZPL_RE_OP_EXACT_MATCH, 1, (zpl_i32)last_char); +static zpl_regex_error zpl_re__parse(zpl_re *re, char const *pattern, zpl_isize len, zpl_isize offset, zpl_isize level, zpl_isize *new_offset) { + zpl_regex_error err = ZPL_RE_ERROR_NONE; + zpl_isize last_buf_len = re->buf_len; + zpl_isize branch_begin = re->buf_len; + zpl_isize branch_op = -1; + + while (offset < len) { + switch (pattern[offset++]) { + case '^': { + err = zpl_re__emit_ops(re, 1, ZPL_RE_OP_BEGINNING_OF_LINE); if (err) return err; + } break; + + case '$': { + err = zpl_re__emit_ops(re, 1, ZPL_RE_OP_END_OF_LINE); + if (err) return err; + } break; + + case '(': { + zpl_isize capture = re->capture_count++; + last_buf_len = re->buf_len; + err = zpl_re__emit_ops(re, 2, ZPL_RE_OP_BEGIN_CAPTURE, (zpl_i32)capture); + if (err) return err; + + err = zpl_re__parse(re, pattern, len, offset, level+1, &offset); + + if ((offset > len) || (pattern[offset-1] != ')')) + return ZPL_RE_ERROR_MISMATCHED_CAPTURES; + + err = zpl_re__emit_ops(re, 2, ZPL_RE_OP_END_CAPTURE, (zpl_i32)capture); + if (err) return err; + } break; + + case ')': { + if (branch_op != -1) + re->buf[branch_op + 1] = (unsigned char)(re->buf_len - (branch_op+2)); + + if (level == 0) + return ZPL_RE_ERROR_MISMATCHED_CAPTURES; + + if (new_offset) *new_offset = offset; return ZPL_RE_ERROR_NONE; - } - - move_size = re->buf_len - last_buf_len + 1; - - err = zpl_re__emit_ops(re, 1, 0); - if (err) return err; - - zpl_memmove(re->buf+last_buf_len+1, re->buf+last_buf_len, move_size); - re->buf[last_buf_len] = quantifier; - - return ZPL_RE_ERROR_NONE; - } - - static zpl_regex_error zpl_re__parse(zpl_re *re, char const *pattern, zpl_isize len, zpl_isize offset, zpl_isize level, zpl_isize *new_offset) { - zpl_regex_error err = ZPL_RE_ERROR_NONE; - zpl_isize last_buf_len = re->buf_len; - zpl_isize branch_begin = re->buf_len; - zpl_isize branch_op = -1; - - while (offset < len) { - switch (pattern[offset++]) { - case '^': { - err = zpl_re__emit_ops(re, 1, ZPL_RE_OP_BEGINNING_OF_LINE); - if (err) return err; - } break; - - case '$': { - err = zpl_re__emit_ops(re, 1, ZPL_RE_OP_END_OF_LINE); - if (err) return err; - } break; - - case '(': { - zpl_isize capture = re->capture_count++; - last_buf_len = re->buf_len; - err = zpl_re__emit_ops(re, 2, ZPL_RE_OP_BEGIN_CAPTURE, (zpl_i32)capture); - if (err) return err; - - err = zpl_re__parse(re, pattern, len, offset, level+1, &offset); - - if ((offset > len) || (pattern[offset-1] != ')')) - return ZPL_RE_ERROR_MISMATCHED_CAPTURES; - - err = zpl_re__emit_ops(re, 2, ZPL_RE_OP_END_CAPTURE, (zpl_i32)capture); - if (err) return err; - } break; - - case ')': { - if (branch_op != -1) - re->buf[branch_op + 1] = (unsigned char)(re->buf_len - (branch_op+2)); - - if (level == 0) - return ZPL_RE_ERROR_MISMATCHED_CAPTURES; - - if (new_offset) *new_offset = offset; - return ZPL_RE_ERROR_NONE; - } break; - - case '[': { - last_buf_len = re->buf_len; - err = zpl_re__parse_group(re, pattern, len, offset, &offset); - if (offset > len) - return err; - } break; - - /* NOTE(bill): Branching magic! */ - case '|': { - if (branch_begin >= re->buf_len) { - return ZPL_RE_ERROR_BRANCH_FAILURE; - } else { - zpl_isize size = re->buf_len - branch_begin; - err = zpl_re__emit_ops(re, 4, 0, 0, ZPL_RE_OP_BRANCH_END, 0); - if (err) return err; - - zpl_memmove(re->buf + branch_begin + 2, re->buf + branch_begin, size); - re->buf[branch_begin] = ZPL_RE_OP_BRANCH_START; - re->buf[branch_begin+1] = (size+2) & 0xff; - branch_op = re->buf_len-2; - } - } break; - - case '.': { - last_buf_len = re->buf_len; - err = zpl_re__emit_ops(re, 1, ZPL_RE_OP_ANY); - if (err) return err; - } break; - - case '*': - case '+': - { - unsigned char quantifier = ZPL_RE_OP_ONE_OR_MORE; - if (pattern[offset-1] == '*') - quantifier = ZPL_RE_OP_ZERO_OR_MORE; - - if (last_buf_len >= re->buf_len) - return ZPL_RE_ERROR_INVALID_QUANTIFIER; - if ((re->buf[last_buf_len] < ZPL_RE_OP_EXACT_MATCH) || - (re->buf[last_buf_len] > ZPL_RE_OP_ANY_BUT)) - return ZPL_RE_ERROR_INVALID_QUANTIFIER; - - if ((offset < len) && (pattern[offset] == '?')) { - quantifier = ZPL_RE_OP_ONE_OR_MORE_SHORTEST; - offset++; - } - - err = zpl_re__compile_quantifier(re, last_buf_len, quantifier); - if (err) return err; - } break; - - case '?': { - if (last_buf_len >= re->buf_len) - return ZPL_RE_ERROR_INVALID_QUANTIFIER; - if ((re->buf[last_buf_len] < ZPL_RE_OP_EXACT_MATCH) || - (re->buf[last_buf_len] > ZPL_RE_OP_ANY_BUT)) - return ZPL_RE_ERROR_INVALID_QUANTIFIER; - - err = zpl_re__compile_quantifier(re, last_buf_len, - (unsigned char)ZPL_RE_OP_ZERO_OR_ONE); - if (err) return err; - } break; - - case '\\': { - last_buf_len = re->buf_len; - if ((offset+1 < len) && zpl_char_is_hex_digit(*(pattern+offset))) { - unsigned char hex_value = zpl_re__hex((pattern+offset)); - offset += 2; - err = zpl_re__emit_ops(re, 2, ZPL_RE_OP_META_MATCH, (int)hex_value); - if (err) return err; - } else if (offset < len) { - int code = zpl_re__encode_escape(pattern[offset++]); - if (!code || (code > 0xff)) { - err = zpl_re__emit_ops(re, 3, ZPL_RE_OP_META_MATCH, 0, (int)((code >> 8) & 0xff)); - if (err) return err; - } else { - err = zpl_re__emit_ops(re, 2, ZPL_RE_OP_META_MATCH, (int)code); - if (err) return err; - } - } - } break; - - /* NOTE(bill): Exact match */ - default: { - char const *match_start; - zpl_isize size = 0; - offset--; - match_start = pattern+offset; - while ((offset < len) && - (zpl_re__strfind(ZPL_RE__LITERAL(ZPL_RE__META_CHARS), pattern[offset], 0) < 0)) { - size++, offset++; - } - - last_buf_len = re->buf_len; - err = zpl_re__emit_ops(re, 2, ZPL_RE_OP_EXACT_MATCH, (int)size); - if (err) return err; - err = zpl_re__emit_ops_buffer(re, size, (char const *)match_start); - if (err) return err; - } break; - } - } - - if (new_offset) *new_offset = offset; - return ZPL_RE_ERROR_NONE; - } - - zpl_regex_error zpl_re_compile_from_buffer(zpl_re *re, char const *pattern, zpl_isize pattern_len, void *buffer, zpl_isize buffer_len) { - zpl_regex_error err; - re->capture_count = 0; - re->buf = (char *)buffer; - re->buf_len = 0; - re->buf_cap = re->buf_len; - re->can_realloc = 0; - - err = zpl_re__parse(re, pattern, pattern_len, 0, 0, 0); - return err; - } - - zpl_regex_error zpl_re_compile(zpl_re *re, zpl_allocator backing, char const *pattern, zpl_isize pattern_len) { - zpl_regex_error err; - zpl_isize cap = pattern_len+128; - zpl_isize offset = 0; - - re->backing = backing; - re->capture_count = 0; - re->buf = (char *)zpl_alloc(backing, cap); - re->buf_len = 0; - re->buf_cap = cap; - re->can_realloc = 1; - - err = zpl_re__parse(re, pattern, pattern_len, 0, 0, &offset); - - if (offset != pattern_len) - zpl_free(backing, re->buf); - - return err; - } - - zpl_isize zpl_re_capture_count(zpl_re *re) { return re->capture_count; } - - zpl_b32 zpl_re_match(zpl_re *re, char const *str, zpl_isize len, zpl_re_capture *captures, zpl_isize max_capture_count, zpl_isize *offset) { - if (re && re->buf_len > 0) { - if (re->buf[0] == ZPL_RE_OP_BEGINNING_OF_LINE) { - zpl_re_ctx c = zpl_re__exec(re, 0, str, len, 0, captures, max_capture_count); - if (c.offset >= 0 && c.offset <= len) { if (offset) *offset = c.offset; return 1; }; - if (c.offset == ZPL_RE__INTERNAL_FAILURE) return 0; + } break; + + case '[': { + last_buf_len = re->buf_len; + err = zpl_re__parse_group(re, pattern, len, offset, &offset); + if (offset > len) + return err; + } break; + + /* NOTE(bill): Branching magic! */ + case '|': { + if (branch_begin >= re->buf_len) { + return ZPL_RE_ERROR_BRANCH_FAILURE; } else { - zpl_isize i; - for (i = 0; i < len; i++) { - zpl_re_ctx c = zpl_re__exec(re, 0, str, len, i, captures, max_capture_count); - if (c.offset >= 0 && c.offset <= len) { if (offset) *offset = c.offset; return 1; }; - if (c.offset == ZPL_RE__INTERNAL_FAILURE) return 0; + zpl_isize size = re->buf_len - branch_begin; + err = zpl_re__emit_ops(re, 4, 0, 0, ZPL_RE_OP_BRANCH_END, 0); + if (err) return err; + + zpl_memmove(re->buf + branch_begin + 2, re->buf + branch_begin, size); + re->buf[branch_begin] = ZPL_RE_OP_BRANCH_START; + re->buf[branch_begin+1] = (size+2) & 0xff; + branch_op = re->buf_len-2; + } + } break; + + case '.': { + last_buf_len = re->buf_len; + err = zpl_re__emit_ops(re, 1, ZPL_RE_OP_ANY); + if (err) return err; + } break; + + case '*': + case '+': + { + unsigned char quantifier = ZPL_RE_OP_ONE_OR_MORE; + if (pattern[offset-1] == '*') + quantifier = ZPL_RE_OP_ZERO_OR_MORE; + + if (last_buf_len >= re->buf_len) + return ZPL_RE_ERROR_INVALID_QUANTIFIER; + if ((re->buf[last_buf_len] < ZPL_RE_OP_EXACT_MATCH) || + (re->buf[last_buf_len] > ZPL_RE_OP_ANY_BUT)) + return ZPL_RE_ERROR_INVALID_QUANTIFIER; + + if ((offset < len) && (pattern[offset] == '?')) { + quantifier = ZPL_RE_OP_ONE_OR_MORE_SHORTEST; + offset++; + } + + err = zpl_re__compile_quantifier(re, last_buf_len, quantifier); + if (err) return err; + } break; + + case '?': { + if (last_buf_len >= re->buf_len) + return ZPL_RE_ERROR_INVALID_QUANTIFIER; + if ((re->buf[last_buf_len] < ZPL_RE_OP_EXACT_MATCH) || + (re->buf[last_buf_len] > ZPL_RE_OP_ANY_BUT)) + return ZPL_RE_ERROR_INVALID_QUANTIFIER; + + err = zpl_re__compile_quantifier(re, last_buf_len, + (unsigned char)ZPL_RE_OP_ZERO_OR_ONE); + if (err) return err; + } break; + + case '\\': { + last_buf_len = re->buf_len; + if ((offset+1 < len) && zpl_char_is_hex_digit(*(pattern+offset))) { + unsigned char hex_value = zpl_re__hex((pattern+offset)); + offset += 2; + err = zpl_re__emit_ops(re, 2, ZPL_RE_OP_META_MATCH, (int)hex_value); + if (err) return err; + } else if (offset < len) { + int code = zpl_re__encode_escape(pattern[offset++]); + if (!code || (code > 0xff)) { + err = zpl_re__emit_ops(re, 3, ZPL_RE_OP_META_MATCH, 0, (int)((code >> 8) & 0xff)); + if (err) return err; + } else { + err = zpl_re__emit_ops(re, 2, ZPL_RE_OP_META_MATCH, (int)code); + if (err) return err; } } - return 0; - } - return 1; + } break; + + /* NOTE(bill): Exact match */ + default: { + char const *match_start; + zpl_isize size = 0; + offset--; + match_start = pattern+offset; + while ((offset < len) && + (zpl_re__strfind(ZPL_RE__LITERAL(ZPL_RE__META_CHARS), pattern[offset], 0) < 0)) { + size++, offset++; + } + + last_buf_len = re->buf_len; + err = zpl_re__emit_ops(re, 2, ZPL_RE_OP_EXACT_MATCH, (int)size); + if (err) return err; + err = zpl_re__emit_ops_buffer(re, size, (char const *)match_start); + if (err) return err; + } break; } + } + + if (new_offset) *new_offset = offset; + return ZPL_RE_ERROR_NONE; +} +zpl_regex_error zpl_re_compile_from_buffer(zpl_re *re, char const *pattern, zpl_isize pattern_len, void *buffer, zpl_isize buffer_len) { + zpl_regex_error err; + re->capture_count = 0; + re->buf = (char *)buffer; + re->buf_len = 0; + re->buf_cap = re->buf_len; + re->can_realloc = 0; + + err = zpl_re__parse(re, pattern, pattern_len, 0, 0, 0); + return err; +} - zpl_b32 zpl_re_match_all(zpl_re *re, char const *str, zpl_isize str_len, zpl_isize max_capture_count, - zpl_re_capture **out_captures) - { - char *end = (char *)str + str_len; - char *p = (char *)str; +zpl_regex_error zpl_re_compile(zpl_re *re, zpl_allocator backing, char const *pattern, zpl_isize pattern_len) { + zpl_regex_error err; + zpl_isize cap = pattern_len+128; + zpl_isize offset = 0; + + re->backing = backing; + re->capture_count = 0; + re->buf = (char *)zpl_alloc(backing, cap); + re->buf_len = 0; + re->buf_cap = cap; + re->can_realloc = 1; + + err = zpl_re__parse(re, pattern, pattern_len, 0, 0, &offset); + + if (offset != pattern_len) + zpl_free(backing, re->buf); + + return err; +} - zpl_buffer_make(zpl_re_capture, cps, zpl_heap(), max_capture_count); +zpl_isize zpl_re_capture_count(zpl_re *re) { return re->capture_count; } - zpl_isize offset = 0; - - while (p < end) - { - zpl_b32 ok = zpl_re_match(re, p, end - p, cps, max_capture_count, &offset); - if (!ok) { - zpl_buffer_free(cps); - return false; - } - - p += offset; - - for (zpl_isize i = 0; i < max_capture_count; i++) { - zpl_array_append(*out_captures, cps[i]); - } +zpl_b32 zpl_re_match(zpl_re *re, char const *str, zpl_isize len, zpl_re_capture *captures, zpl_isize max_capture_count, zpl_isize *offset) { + if (re && re->buf_len > 0) { + if (re->buf[0] == ZPL_RE_OP_BEGINNING_OF_LINE) { + zpl_re_ctx c = zpl_re__exec(re, 0, str, len, 0, captures, max_capture_count); + if (c.offset >= 0 && c.offset <= len) { if (offset) *offset = c.offset; return 1; }; + if (c.offset == ZPL_RE__INTERNAL_FAILURE) return 0; + } else { + zpl_isize i; + for (i = 0; i < len; i++) { + zpl_re_ctx c = zpl_re__exec(re, 0, str, len, i, captures, max_capture_count); + if (c.offset >= 0 && c.offset <= len) { if (offset) *offset = c.offset; return 1; }; + if (c.offset == ZPL_RE__INTERNAL_FAILURE) return 0; } + } + return 0; + } + return 1; +} + +zpl_b32 zpl_re_match_all(zpl_re *re, char const *str, zpl_isize str_len, zpl_isize max_capture_count, + zpl_re_capture **out_captures) +{ + char *end = (char *)str + str_len; + char *p = (char *)str; + + zpl_buffer_make(zpl_re_capture, cps, zpl_heap(), max_capture_count); + + zpl_isize offset = 0; + + while (p < end) + { + zpl_b32 ok = zpl_re_match(re, p, end - p, cps, max_capture_count, &offset); + if (!ok) { zpl_buffer_free(cps); - - return true; - } - - ZPL_END_C_DECLS - #endif - - #if defined(ZPL_MODULE_DLL) - // file: source/dll.c - - #ifdef ZPL_EDITOR - #include - #endif - - #if defined(ZPL_SYSTEM_UNIX) || defined(ZPL_SYSTEM_MACOS) - #include - #endif - - ZPL_BEGIN_C_DECLS - - //////////////////////////////////////////////////////////////// - // - // DLL Handling - // - // - - #if defined(ZPL_SYSTEM_WINDOWS) - zpl_dll_handle zpl_dll_load(char const *filepath) { - return cast(zpl_dll_handle) LoadLibraryA(filepath); - } - - void zpl_dll_unload(zpl_dll_handle dll) { - FreeLibrary(cast(HMODULE) dll); - } - - zpl_dll_proc zpl_dll_proc_address(zpl_dll_handle dll, char const *proc_name) { - return cast(zpl_dll_proc) GetProcAddress(cast(HMODULE) dll, proc_name); - } - - #else // POSIX - - zpl_dll_handle zpl_dll_load(char const *filepath) { - return cast(zpl_dll_handle) dlopen(filepath, RTLD_LAZY | RTLD_GLOBAL); - } - - void zpl_dll_unload(zpl_dll_handle dll) { - dlclose(dll); - } - - zpl_dll_proc zpl_dll_proc_address(zpl_dll_handle dll, char const *proc_name) { - return cast(zpl_dll_proc) dlsym(dll, proc_name); - } - - #endif - - ZPL_END_C_DECLS - #endif - - #if defined(ZPL_MODULE_OPTS) - // file: source/opts.c - - //////////////////////////////////////////////////////////////// - // - // CLI Options - // - // - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - void zpl_opts_init(zpl_opts *opts, zpl_allocator a, char const *app) { - zpl_opts opts_ = { 0 }; - *opts = opts_; - opts->alloc = a; - opts->appname = app; - - zpl_array_init(opts->entries, a); - zpl_array_init(opts->positioned, a); - zpl_array_init(opts->errors, a); - } - - void zpl_opts_free(zpl_opts *opts) { - for (zpl_i32 i = 0; i < zpl_array_count(opts->entries); ++i) { - zpl_opts_entry *e = opts->entries + i; - if (e->type == ZPL_OPTS_STRING) { - zpl_string_free(e->text); - } - } - - zpl_array_free(opts->entries); - zpl_array_free(opts->positioned); - zpl_array_free(opts->errors); - } - - void zpl_opts_add(zpl_opts *opts, char const *name, char const *lname, const char *desc, zpl_u8 type) { - zpl_opts_entry e = { 0 }; - - e.name = name; - e.lname = lname; - e.desc = desc; - e.type = type; - e.met = false; - e.pos = false; - - zpl_array_append(opts->entries, e); - } - - zpl_opts_entry *zpl__opts_find(zpl_opts *opts, char const *name, zpl_usize len, zpl_b32 longname) { - zpl_opts_entry *e = 0; - - for (int i = 0; i < zpl_array_count(opts->entries); ++i) { - e = opts->entries + i; - char const *n = (longname ? e->lname : e->name); - - if (zpl_strnlen(name, len) == zpl_strlen(n) && !zpl_strncmp(n, name, len)) { return e; } - } - - return NULL; - } - - void zpl_opts_positional_add(zpl_opts *opts, char const *name) { - zpl_opts_entry *e = zpl__opts_find(opts, name, zpl_strlen(name), true); - - if (e) { - e->pos = true; - zpl_array_append_at(opts->positioned, e, 0); - } - } - - zpl_b32 zpl_opts_positionals_filled(zpl_opts *opts) { return zpl_array_count(opts->positioned) == 0; } - - zpl_string zpl_opts_string(zpl_opts *opts, char const *name, char const *fallback) { - zpl_opts_entry *e = zpl__opts_find(opts, name, zpl_strlen(name), true); - - return (char *)((e && e->met) ? e->text : fallback); - } - - zpl_f64 zpl_opts_real(zpl_opts *opts, char const *name, zpl_f64 fallback) { - zpl_opts_entry *e = zpl__opts_find(opts, name, zpl_strlen(name), true); - - return (e && e->met) ? e->real : fallback; - } - - zpl_i64 zpl_opts_integer(zpl_opts *opts, char const *name, zpl_i64 fallback) { - zpl_opts_entry *e = zpl__opts_find(opts, name, zpl_strlen(name), true); - - return (e && e->met) ? e->integer : fallback; - } - - void zpl__opts_set_value(zpl_opts *opts, zpl_opts_entry *t, char *b) { - t->met = true; - - switch (t->type) { - case ZPL_OPTS_STRING: { - t->text = zpl_string_make(opts->alloc, b); - } break; - - case ZPL_OPTS_FLOAT: { - t->real = zpl_str_to_f64(b, NULL); - } break; - - case ZPL_OPTS_INT: { - t->integer = zpl_str_to_i64(b, NULL, 10); - } break; - } - - for (zpl_isize i=0; i < zpl_array_count(opts->positioned); i++) { - if (!zpl_strcmp(opts->positioned[i]->lname, t->lname)) { - zpl_array_remove_at(opts->positioned, i); - break; - } - } - } - - zpl_b32 zpl_opts_has_arg(zpl_opts *opts, char const *name) { - zpl_opts_entry *e = zpl__opts_find(opts, name, zpl_strlen(name), true); - - if (e) { return e->met; } - return false; } - - void zpl_opts_print_help(zpl_opts *opts) { - zpl_printf("USAGE: %s", opts->appname); - - for (zpl_isize i = zpl_array_count(opts->entries); i >= 0; --i) { - zpl_opts_entry *e = opts->entries + i; - - if (e->pos == (zpl_b32) true) { zpl_printf(" [%s]", e->lname); } - } - - zpl_printf("\nOPTIONS:\n"); - - for (zpl_isize i = 0; i < zpl_array_count(opts->entries); ++i) { - zpl_opts_entry *e = opts->entries + i; - - zpl_printf("\t-%s, --%s: %s\n", e->name, e->lname, e->desc); - } + + p += offset; + + for (zpl_isize i = 0; i < max_capture_count; i++) { + zpl_array_append(*out_captures, cps[i]); } + } + + zpl_buffer_free(cps); + + return true; +} - void zpl_opts_print_errors(zpl_opts *opts) { - for (int i = 0; i < zpl_array_count(opts->errors); ++i) { - zpl_opts_err *err = (opts->errors + i); +ZPL_END_C_DECLS +#endif - zpl_printf("ERROR: "); +#if defined(ZPL_MODULE_DLL) +// file: source/dll.c - switch (err->type) { - case ZPL_OPTS_ERR_OPTION: zpl_printf("Invalid option \"%s\"", err->val); break; +#ifdef ZPL_EDITOR +#include +#endif - case ZPL_OPTS_ERR_VALUE: zpl_printf("Invalid value \"%s\"", err->val); break; +#if defined(ZPL_SYSTEM_UNIX) || defined(ZPL_SYSTEM_MACOS) +#include +#endif - case ZPL_OPTS_ERR_MISSING_VALUE: zpl_printf("Missing value for option \"%s\"", err->val); break; +ZPL_BEGIN_C_DECLS - case ZPL_OPTS_ERR_EXTRA_VALUE: zpl_printf("Extra value for option \"%s\"", err->val); break; +//////////////////////////////////////////////////////////////// +// +// DLL Handling +// +// + +#if defined(ZPL_SYSTEM_WINDOWS) +zpl_dll_handle zpl_dll_load(char const *filepath) { + return cast(zpl_dll_handle) LoadLibraryA(filepath); +} + +void zpl_dll_unload(zpl_dll_handle dll) { + FreeLibrary(cast(HMODULE) dll); +} + +zpl_dll_proc zpl_dll_proc_address(zpl_dll_handle dll, char const *proc_name) { + return cast(zpl_dll_proc) GetProcAddress(cast(HMODULE) dll, proc_name); +} + +#else // POSIX + +zpl_dll_handle zpl_dll_load(char const *filepath) { + return cast(zpl_dll_handle) dlopen(filepath, RTLD_LAZY | RTLD_GLOBAL); +} + +void zpl_dll_unload(zpl_dll_handle dll) { + dlclose(dll); +} + +zpl_dll_proc zpl_dll_proc_address(zpl_dll_handle dll, char const *proc_name) { + return cast(zpl_dll_proc) dlsym(dll, proc_name); +} + +#endif + +ZPL_END_C_DECLS +#endif + +#if defined(ZPL_MODULE_OPTS) +// file: source/opts.c + +//////////////////////////////////////////////////////////////// +// +// CLI Options +// +// +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +void zpl_opts_init(zpl_opts *opts, zpl_allocator a, char const *app) { + zpl_opts opts_ = { 0 }; + *opts = opts_; + opts->alloc = a; + opts->appname = app; + + zpl_array_init(opts->entries, a); + zpl_array_init(opts->positioned, a); + zpl_array_init(opts->errors, a); +} + +void zpl_opts_free(zpl_opts *opts) { + for (zpl_i32 i = 0; i < zpl_array_count(opts->entries); ++i) { + zpl_opts_entry *e = opts->entries + i; + if (e->type == ZPL_OPTS_STRING) { + zpl_string_free(e->text); + } + } + + zpl_array_free(opts->entries); + zpl_array_free(opts->positioned); + zpl_array_free(opts->errors); +} + +void zpl_opts_add(zpl_opts *opts, char const *name, char const *lname, const char *desc, zpl_u8 type) { + zpl_opts_entry e = { 0 }; + + e.name = name; + e.lname = lname; + e.desc = desc; + e.type = type; + e.met = false; + e.pos = false; + + zpl_array_append(opts->entries, e); +} + +zpl_opts_entry *zpl__opts_find(zpl_opts *opts, char const *name, zpl_usize len, zpl_b32 longname) { + zpl_opts_entry *e = 0; + + for (int i = 0; i < zpl_array_count(opts->entries); ++i) { + e = opts->entries + i; + char const *n = (longname ? e->lname : e->name); + + if (zpl_strnlen(name, len) == zpl_strlen(n) && !zpl_strncmp(n, name, len)) { return e; } + } + + return NULL; +} + +void zpl_opts_positional_add(zpl_opts *opts, char const *name) { + zpl_opts_entry *e = zpl__opts_find(opts, name, zpl_strlen(name), true); + + if (e) { + e->pos = true; + zpl_array_append_at(opts->positioned, e, 0); + } +} + +zpl_b32 zpl_opts_positionals_filled(zpl_opts *opts) { return zpl_array_count(opts->positioned) == 0; } + +zpl_string zpl_opts_string(zpl_opts *opts, char const *name, char const *fallback) { + zpl_opts_entry *e = zpl__opts_find(opts, name, zpl_strlen(name), true); + + return (char *)((e && e->met) ? e->text : fallback); +} + +zpl_f64 zpl_opts_real(zpl_opts *opts, char const *name, zpl_f64 fallback) { + zpl_opts_entry *e = zpl__opts_find(opts, name, zpl_strlen(name), true); + + return (e && e->met) ? e->real : fallback; +} + +zpl_i64 zpl_opts_integer(zpl_opts *opts, char const *name, zpl_i64 fallback) { + zpl_opts_entry *e = zpl__opts_find(opts, name, zpl_strlen(name), true); + + return (e && e->met) ? e->integer : fallback; +} + +void zpl__opts_set_value(zpl_opts *opts, zpl_opts_entry *t, char *b) { + t->met = true; + + switch (t->type) { + case ZPL_OPTS_STRING: { + t->text = zpl_string_make(opts->alloc, b); + } break; + + case ZPL_OPTS_FLOAT: { + t->real = zpl_str_to_f64(b, NULL); + } break; + + case ZPL_OPTS_INT: { + t->integer = zpl_str_to_i64(b, NULL, 10); + } break; + } + + for (zpl_isize i=0; i < zpl_array_count(opts->positioned); i++) { + if (!zpl_strcmp(opts->positioned[i]->lname, t->lname)) { + zpl_array_remove_at(opts->positioned, i); + break; + } + } +} + +zpl_b32 zpl_opts_has_arg(zpl_opts *opts, char const *name) { + zpl_opts_entry *e = zpl__opts_find(opts, name, zpl_strlen(name), true); + + if (e) { return e->met; } + + return false; +} + +void zpl_opts_print_help(zpl_opts *opts) { + zpl_printf("USAGE: %s", opts->appname); + + for (zpl_isize i = zpl_array_count(opts->entries); i >= 0; --i) { + zpl_opts_entry *e = opts->entries + i; + + if (e->pos == (zpl_b32) true) { zpl_printf(" [%s]", e->lname); } + } + + zpl_printf("\nOPTIONS:\n"); + + for (zpl_isize i = 0; i < zpl_array_count(opts->entries); ++i) { + zpl_opts_entry *e = opts->entries + i; + + zpl_printf("\t-%s, --%s: %s\n", e->name, e->lname, e->desc); + } +} + +void zpl_opts_print_errors(zpl_opts *opts) { + for (int i = 0; i < zpl_array_count(opts->errors); ++i) { + zpl_opts_err *err = (opts->errors + i); + + zpl_printf("ERROR: "); + + switch (err->type) { + case ZPL_OPTS_ERR_OPTION: zpl_printf("Invalid option \"%s\"", err->val); break; + + case ZPL_OPTS_ERR_VALUE: zpl_printf("Invalid value \"%s\"", err->val); break; + + case ZPL_OPTS_ERR_MISSING_VALUE: zpl_printf("Missing value for option \"%s\"", err->val); break; + + case ZPL_OPTS_ERR_EXTRA_VALUE: zpl_printf("Extra value for option \"%s\"", err->val); break; + } + + zpl_printf("\n"); + } +} + +void zpl__opts_push_error(zpl_opts *opts, char *b, zpl_u8 errtype) { + zpl_opts_err err = { 0 }; + err.val = b; + err.type = errtype; + zpl_array_append(opts->errors, err); +} + +zpl_b32 zpl_opts_compile(zpl_opts *opts, int argc, char **argv) { + zpl_b32 had_errors = false; + for (int i = 1; i < argc; ++i) { + char *p = argv[i]; + + if (*p) { + p = zpl_str_trim(p, false); + if (*p == '-') { + zpl_opts_entry *t = 0; + zpl_b32 checkln = false; + if (*(p + 1) == '-') { + checkln = true; + ++p; } - - zpl_printf("\n"); - } - } - - void zpl__opts_push_error(zpl_opts *opts, char *b, zpl_u8 errtype) { - zpl_opts_err err = { 0 }; - err.val = b; - err.type = errtype; - zpl_array_append(opts->errors, err); - } - - zpl_b32 zpl_opts_compile(zpl_opts *opts, int argc, char **argv) { - zpl_b32 had_errors = false; - for (int i = 1; i < argc; ++i) { - char *p = argv[i]; - - if (*p) { - p = zpl_str_trim(p, false); - if (*p == '-') { - zpl_opts_entry *t = 0; - zpl_b32 checkln = false; - if (*(p + 1) == '-') { - checkln = true; - ++p; - } - - char *b = p + 1, *e = b; - - while (zpl_char_is_alphanumeric(*e)) { ++e; } - - t = zpl__opts_find(opts, b, (e - b), checkln); - - if (t) { - char *ob = b; - b = e; - - /**/ if (*e == '=') { - if (t->type == ZPL_OPTS_FLAG) { - *e = '\0'; - zpl__opts_push_error(opts, ob, ZPL_OPTS_ERR_EXTRA_VALUE); - had_errors = true; - continue; - } - - b = e = e + 1; - } else if (*e == '\0') { - char *sp = argv[i+1]; - - if (sp && *sp != '-' && (zpl_array_count(opts->positioned) < 1 || t->type != ZPL_OPTS_FLAG)) { - if (t->type == ZPL_OPTS_FLAG) { - zpl__opts_push_error(opts, b, ZPL_OPTS_ERR_EXTRA_VALUE); - had_errors = true; - continue; - } - - p = sp; - b = e = sp; - ++i; - } else { - if (t->type != ZPL_OPTS_FLAG) { - zpl__opts_push_error(opts, ob, ZPL_OPTS_ERR_MISSING_VALUE); - had_errors = true; - continue; - } - t->met = true; - continue; - } - } - - e = zpl_str_control_skip(e, '\0'); - zpl__opts_set_value(opts, t, b); - } else { - zpl__opts_push_error(opts, b, ZPL_OPTS_ERR_OPTION); + + char *b = p + 1, *e = b; + + while (zpl_char_is_alphanumeric(*e)) { ++e; } + + t = zpl__opts_find(opts, b, (e - b), checkln); + + if (t) { + char *ob = b; + b = e; + + /**/ if (*e == '=') { + if (t->type == ZPL_OPTS_FLAG) { + *e = '\0'; + zpl__opts_push_error(opts, ob, ZPL_OPTS_ERR_EXTRA_VALUE); had_errors = true; + continue; + } + + b = e = e + 1; + } else if (*e == '\0') { + char *sp = argv[i+1]; + + if (sp && *sp != '-' && (zpl_array_count(opts->positioned) < 1 || t->type != ZPL_OPTS_FLAG)) { + if (t->type == ZPL_OPTS_FLAG) { + zpl__opts_push_error(opts, b, ZPL_OPTS_ERR_EXTRA_VALUE); + had_errors = true; + continue; + } + + p = sp; + b = e = sp; + ++i; + } else { + if (t->type != ZPL_OPTS_FLAG) { + zpl__opts_push_error(opts, ob, ZPL_OPTS_ERR_MISSING_VALUE); + had_errors = true; + continue; + } + t->met = true; + continue; } - } else if (zpl_array_count(opts->positioned)) { - zpl_opts_entry *l = zpl_array_back(opts->positioned); - zpl_array_pop(opts->positioned); - zpl__opts_set_value(opts, l, p); - } else { - zpl__opts_push_error(opts, p, ZPL_OPTS_ERR_VALUE); - had_errors = true; } - } - } - return !had_errors; - } - - ZPL_END_C_DECLS - #endif - - #if defined(ZPL_MODULE_PROCESS) - // file: source/process.c - - //////////////////////////////////////////////////////////////// - // - // Process creation and manipulation methods - // - // - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - static ZPL_ALWAYS_INLINE void zpl__pr_close_file_handle(zpl_file *f) { - ZPL_ASSERT_NOT_NULL(f); - f->fd.p = NULL; - } - - static ZPL_ALWAYS_INLINE void zpl__pr_close_file_handles(zpl_pr *process) { - ZPL_ASSERT_NOT_NULL(process); - - zpl__pr_close_file_handle(&process->in); - zpl__pr_close_file_handle(&process->out); - zpl__pr_close_file_handle(&process->err); - - process->f_stdin = process->f_stdout = process->f_stderr = NULL; - - #ifdef ZPL_SYSTEM_WINDOWS - process->win32_handle = NULL; - #else - ZPL_NOT_IMPLEMENTED; - #endif - } - - enum { - ZPL_PR_HANDLE_MODE_READ, - ZPL_PR_HANDLE_MODE_WRITE, - ZPL_PR_HANDLE_MODES, - }; - - void *zpl__pr_open_handle(zpl_u8 type, const char *mode, void **handle) { - #ifdef ZPL_SYSTEM_WINDOWS - void *pipes[ZPL_PR_HANDLE_MODES]; - zpl_i32 fd; - - const zpl_u32 flag_inherit = 0x00000001; - SECURITY_ATTRIBUTES sa = {zpl_size_of(sa), 0, 1}; - - if (!CreatePipe(&pipes[0], &pipes[1], cast(LPSECURITY_ATTRIBUTES)&sa, 0)) { - return NULL; - } - - if (!SetHandleInformation(pipes[type], flag_inherit, 0)) { - return NULL; - } - - fd = _open_osfhandle(cast(zpl_intptr)pipes[type], 0); - - if (fd != -1) { - *handle = pipes[1-type]; - return _fdopen(fd, mode); - } - - return NULL; - #else - ZPL_NOT_IMPLEMENTED; - return NULL; - #endif - } - - zpl_i32 zpl_pr_create(zpl_pr *process, const char **args, zpl_isize argc, zpl_pr_si si, zpl_pr_opts options) { - ZPL_ASSERT_NOT_NULL(process); - zpl_zero_item(process); - - #ifdef ZPL_SYSTEM_WINDOWS - zpl_string cli, env; - zpl_b32 c_env=false; - STARTUPINFOW psi = {0}; - PROCESS_INFORMATION pi = {0}; - zpl_i32 err_code = 0; - zpl_allocator a = zpl_heap(); - const zpl_u32 use_std_handles = 0x00000100; - - psi.cb = zpl_size_of(psi); - psi.dwFlags = use_std_handles | si.flags; - - if (options & ZPL_PR_OPTS_CUSTOM_ENV) { - env = zpl_string_join(zpl_heap(), cast(const char**)si.env, si.env_count, "\0\0"); - env = zpl_string_appendc(env, "\0"); - c_env = true; - } - else if (!(options & ZPL_PR_OPTS_INHERIT_ENV)) { - env = (zpl_string)"\0\0\0\0"; - } else { - env = (zpl_string)NULL; - } - - process->f_stdin = zpl__pr_open_handle(ZPL_PR_HANDLE_MODE_WRITE, "wb", &psi.hStdInput); - process->f_stdout = zpl__pr_open_handle(ZPL_PR_HANDLE_MODE_READ, "rb", &psi.hStdOutput); - - if (options & ZPL_PR_OPTS_COMBINE_STD_OUTPUT) { - process->f_stderr = process->f_stdout; - psi.hStdError = psi.hStdOutput; - } else { - process->f_stderr = zpl__pr_open_handle(ZPL_PR_HANDLE_MODE_READ, "rb", &psi.hStdError); - } - - cli = zpl_string_join(zpl_heap(), args, argc, " "); - - psi.dwX = si.posx; - psi.dwY = si.posy; - psi.dwXSize = si.resx; - psi.dwYSize = si.resy; - psi.dwXCountChars = si.bufx; - psi.dwYCountChars = si.bufy; - psi.dwFillAttribute = si.fill_attr; - psi.wShowWindow = si.show_window; - - wchar_t *w_cli = zpl__alloc_utf8_to_ucs2(a, cli, NULL); - wchar_t *w_workdir = zpl__alloc_utf8_to_ucs2(a, si.workdir, NULL); - - if (!CreateProcessW( - NULL, - w_cli, - NULL, - NULL, - 1, - 0, - env, - w_workdir, - cast(LPSTARTUPINFOW)&psi, - cast(LPPROCESS_INFORMATION)&pi - )) { - err_code = -1; - goto pr_free_data; - } - - process->win32_handle = pi.hProcess; - CloseHandle(pi.hThread); - - zpl_file_connect_handle(&process->in, process->f_stdin); - zpl_file_connect_handle(&process->out, process->f_stdout); - zpl_file_connect_handle(&process->err, process->f_stderr); - - pr_free_data: - zpl_string_free(cli); - zpl_free(a, w_cli); - zpl_free(a, w_workdir); - - if (c_env) - zpl_string_free(env); - - return err_code; - - #else - ZPL_NOT_IMPLEMENTED; - return -1; - #endif - } - - - zpl_i32 zpl_pr_join(zpl_pr *process) { - zpl_i32 ret_code; - - ZPL_ASSERT_NOT_NULL(process); - - #ifdef ZPL_SYSTEM_WINDOWS - if (process->f_stdin) { - fclose(cast(FILE *)process->f_stdin); - } - - WaitForSingleObject(process->win32_handle, INFINITE); - - if (!GetExitCodeProcess(process->win32_handle, cast(LPDWORD)&ret_code)) { - zpl_pr_destroy(process); - return -1; - } - - zpl_pr_destroy(process); - - return ret_code; - #else - ZPL_NOT_IMPLEMENTED; - ret_code = -1; - return ret_code; - #endif - } - - void zpl_pr_destroy(zpl_pr *process) { - ZPL_ASSERT_NOT_NULL(process); - - #ifdef ZPL_SYSTEM_WINDOWS - if (process->f_stdin) { - fclose(cast(FILE *)process->f_stdin); - } - - fclose(cast(FILE *)process->f_stdout); - - if (process->f_stderr != process->f_stdout) { - fclose(cast(FILE *)process->f_stderr); - } - - CloseHandle(process->win32_handle); - - zpl__pr_close_file_handles(process); - #else - ZPL_NOT_IMPLEMENTED; - #endif - } - - void zpl_pr_terminate(zpl_pr *process, zpl_i32 err_code) { - ZPL_ASSERT_NOT_NULL(process); - - #ifdef ZPL_SYSTEM_WINDOWS - TerminateProcess(process->win32_handle, cast(UINT)err_code); - zpl_pr_destroy(process); - #else - ZPL_NOT_IMPLEMENTED; - #endif - } - - ZPL_END_C_DECLS - #endif - - #if defined(ZPL_MODULE_MATH) - // file: source/math.c - - #ifdef ZPL_EDITOR - #include - #endif - - - #if !defined(ZPL_NO_MATH_H) - #include - #endif - - ZPL_BEGIN_C_DECLS - - //////////////////////////////////////////////////////////////// - // - // Math - // - - zpl_f32 zpl_to_radians(zpl_f32 degrees) { return degrees * ZPL_TAU / 360.0f; } - zpl_f32 zpl_to_degrees(zpl_f32 radians) { return radians * 360.0f / ZPL_TAU; } - - zpl_f32 zpl_angle_diff(zpl_f32 radians_a, zpl_f32 radians_b) { - zpl_f32 delta = zpl_mod(radians_b - radians_a, ZPL_TAU); - delta = zpl_mod(delta + 1.5f * ZPL_TAU, ZPL_TAU); - delta -= 0.5f * ZPL_TAU; - return delta; - } - - zpl_f32 zpl_copy_sign(zpl_f32 x, zpl_f32 y) { - zpl_i32 ix, iy; - zpl_f32 r; - zpl_memcopy(&ix, &x, zpl_size_of(x)); - zpl_memcopy(&iy, &y, zpl_size_of(y)); - - ix &= 0x7fffffff; - ix |= iy & 0x80000000; - zpl_memcopy(&r, &ix, zpl_size_of(ix)); - return r; - } - - zpl_f32 zpl_remainder(zpl_f32 x, zpl_f32 y) { return x - (zpl_round(x / y) * y); } - - zpl_f32 zpl_mod(zpl_f32 x, zpl_f32 y) { - zpl_f32 result; - y = zpl_abs(y); - result = zpl_remainder(zpl_abs(x), y); - if (zpl_sign(result)) result += y; - return zpl_copy_sign(result, x); - } - - zpl_f64 zpl_copy_sign64(zpl_f64 x, zpl_f64 y) { - zpl_i64 ix, iy; - zpl_f64 r; - zpl_memcopy(&ix, &x, zpl_size_of(x)); - zpl_memcopy(&iy, &y, zpl_size_of(y)); - - ix &= 0x7fffffffffffffff; - ix |= iy & 0x8000000000000000; - zpl_memcopy(&r, &ix, zpl_size_of(ix)); - return r; - } - - zpl_f64 zpl_floor64(zpl_f64 x) { return cast(zpl_f64)((x >= 0.0) ? cast(zpl_i64) x : cast(zpl_i64)(x - 0.9999999999999999)); } - zpl_f64 zpl_ceil64(zpl_f64 x) { return cast(zpl_f64)((x < 0) ? cast(zpl_i64) x : (cast(zpl_i64) x) + 1); } - zpl_f64 zpl_round64(zpl_f64 x) { return cast(zpl_f64)((x >= 0.0) ? zpl_floor64(x + 0.5) : zpl_ceil64(x - 0.5)); } - zpl_f64 zpl_remainder64(zpl_f64 x, zpl_f64 y) { return x - (zpl_round64(x / y) * y); } - zpl_f64 zpl_abs64(zpl_f64 x) { return x < 0 ? -x : x; } - zpl_f64 zpl_sign64(zpl_f64 x) { return x < 0 ? -1.0 : +1.0; } - - zpl_f64 zpl_mod64(zpl_f64 x, zpl_f64 y) { - zpl_f64 result; - y = zpl_abs64(y); - result = zpl_remainder64(zpl_abs64(x), y); - if (zpl_sign64(result)) result += y; - return zpl_copy_sign64(result, x); - } - - zpl_f32 zpl_quake_rsqrt(zpl_f32 a) { - union { - int i; - zpl_f32 f; - } t; - zpl_f32 x2; - zpl_f32 const three_halfs = 1.5f; - - x2 = a * 0.5f; - t.f = a; - t.i = 0x5f375a86 - (t.i >> 1); /* What the fuck? */ - t.f = t.f * (three_halfs - (x2 * t.f * t.f)); /* 1st iteration */ - t.f = t.f * (three_halfs - (x2 * t.f * t.f)); /* 2nd iteration, this can be removed */ - - return t.f; - } - - #if defined(ZPL_NO_MATH_H) - #if defined(_MSC_VER) - - zpl_f32 zpl_rsqrt(zpl_f32 a) { return _mm_cvtss_f32(_mm_rsqrt_ss(_mm_set_ss(a))); } - zpl_f32 zpl_sqrt(zpl_f32 a) { return _mm_cvtss_f32(_mm_sqrt_ss(_mm_set_ss(a))); }; - - zpl_f32 zpl_sin(zpl_f32 a) { - static zpl_f32 const a0 = +1.91059300966915117e-31f; - static zpl_f32 const a1 = +1.00086760103908896f; - static zpl_f32 const a2 = -1.21276126894734565e-2f; - static zpl_f32 const a3 = -1.38078780785773762e-1f; - static zpl_f32 const a4 = -2.67353392911981221e-2f; - static zpl_f32 const a5 = +2.08026600266304389e-2f; - static zpl_f32 const a6 = -3.03996055049204407e-3f; - static zpl_f32 const a7 = +1.38235642404333740e-4f; - return a0 + a * (a1 + a * (a2 + a * (a3 + a * (a4 + a * (a5 + a * (a6 + a * a7)))))); - } - - zpl_f32 zpl_cos(zpl_f32 a) { - static zpl_f32 const a0 = +1.00238601909309722f; - static zpl_f32 const a1 = -3.81919947353040024e-2f; - static zpl_f32 const a2 = -3.94382342128062756e-1f; - static zpl_f32 const a3 = -1.18134036025221444e-1f; - static zpl_f32 const a4 = +1.07123798512170878e-1f; - static zpl_f32 const a5 = -1.86637164165180873e-2f; - static zpl_f32 const a6 = +9.90140908664079833e-4f; - static zpl_f32 const a7 = -5.23022132118824778e-14f; - return a0 + a * (a1 + a * (a2 + a * (a3 + a * (a4 + a * (a5 + a * (a6 + a * a7)))))); - } - - zpl_f32 zpl_tan(zpl_f32 radians) { - zpl_f32 rr = radians * radians; - zpl_f32 a = 9.5168091e-03f; - a *= rr; - a += 2.900525e-03f; - a *= rr; - a += 2.45650893e-02f; - a *= rr; - a += 5.33740603e-02f; - a *= rr; - a += 1.333923995e-01f; - a *= rr; - a += 3.333314036e-01f; - a *= rr; - a += 1.0f; - a *= radians; - return a; - } - - zpl_f32 zpl_arcsin(zpl_f32 a) { return zpl_arctan2(a, zpl_sqrt((1.0f + a) * (1.0f - a))); } - zpl_f32 zpl_arccos(zpl_f32 a) { return zpl_arctan2(zpl_sqrt((1.0f + a) * (1.0f - a)), a); } - - zpl_f32 zpl_arctan(zpl_f32 a) { - zpl_f32 u = a * a; - zpl_f32 u2 = u * u; - zpl_f32 u3 = u2 * u; - zpl_f32 u4 = u3 * u; - zpl_f32 f = 1.0f + 0.33288950512027f * u - 0.08467922817644f * u2 + 0.03252232640125f * u3 - 0.00749305860992f * u4; - return a / f; - } - - zpl_f32 zpl_arctan2(zpl_f32 y, zpl_f32 x) { - if (zpl_abs(x) > zpl_abs(y)) { - zpl_f32 a = zpl_arctan(y / x); - if (x > 0.0f) - return a; - else - return y > 0.0f ? a + ZPL_TAU_OVER_2 : a - ZPL_TAU_OVER_2; - } else { - zpl_f32 a = zpl_arctan(x / y); - if (x > 0.0f) - return y > 0.0f ? ZPL_TAU_OVER_4 - a : -ZPL_TAU_OVER_4 - a; - else - return y > 0.0f ? ZPL_TAU_OVER_4 + a : -ZPL_TAU_OVER_4 + a; - } - } - - zpl_f32 zpl_exp(zpl_f32 a) { - union { - zpl_f32 f; - int i; - } u, v; - u.i = (int)(6051102 * a + 1056478197); - v.i = (int)(1056478197 - 6051102 * a); - return u.f / v.f; - } - - zpl_f32 zpl_log(zpl_f32 a) { - union { - zpl_f32 f; - int i; - } u = { a }; - return (u.i - 1064866805) * 8.262958405176314e-8f; /* 1 / 12102203.0; */ - } - - zpl_f32 zpl_pow(zpl_f32 a, zpl_f32 b) { - int flipped = 0, e; - zpl_f32 f, r = 1.0f; - if (b < 0) { - flipped = 1; - b = -b; - } - - e = (int)b; - f = zpl_exp(b - e); - - while (e) { - if (e & 1) r *= a; - a *= a; - e >>= 1; - } - - r *= f; - return flipped ? 1.0f / r : r; - } - - #else - - zpl_f32 zpl_rsqrt(zpl_f32 a) { return 1.0f / __builtin_sqrt(a); } - zpl_f32 zpl_sqrt(zpl_f32 a) { return __builtin_sqrt(a); } - zpl_f32 zpl_sin(zpl_f32 radians) { return __builtin_sinf(radians); } - zpl_f32 zpl_cos(zpl_f32 radians) { return __builtin_cosf(radians); } - zpl_f32 zpl_tan(zpl_f32 radians) { return __builtin_tanf(radians); } - zpl_f32 zpl_arcsin(zpl_f32 a) { return __builtin_asinf(a); } - zpl_f32 zpl_arccos(zpl_f32 a) { return __builtin_acosf(a); } - zpl_f32 zpl_arctan(zpl_f32 a) { return __builtin_atanf(a); } - zpl_f32 zpl_arctan2(zpl_f32 y, zpl_f32 x) { return __builtin_atan2f(y, x); } - - zpl_f32 zpl_exp(zpl_f32 x) { return __builtin_expf(x); } - zpl_f32 zpl_log(zpl_f32 x) { return __builtin_logf(x); } - - // TODO: Should this be zpl_exp(y * zpl_log(x)) ??? - zpl_f32 zpl_pow(zpl_f32 x, zpl_f32 y) { return __builtin_powf(x, y); } - - #endif - #else - zpl_f32 zpl_rsqrt(zpl_f32 a) { return 1.0f / sqrtf(a); } - zpl_f32 zpl_sqrt(zpl_f32 a) { return sqrtf(a); }; - zpl_f32 zpl_sin(zpl_f32 radians) { return sinf(radians); }; - zpl_f32 zpl_cos(zpl_f32 radians) { return cosf(radians); }; - zpl_f32 zpl_tan(zpl_f32 radians) { return tanf(radians); }; - zpl_f32 zpl_arcsin(zpl_f32 a) { return asinf(a); }; - zpl_f32 zpl_arccos(zpl_f32 a) { return acosf(a); }; - zpl_f32 zpl_arctan(zpl_f32 a) { return atanf(a); }; - zpl_f32 zpl_arctan2(zpl_f32 y, zpl_f32 x) { return atan2f(y, x); }; - - zpl_f32 zpl_exp(zpl_f32 x) { return expf(x); } - zpl_f32 zpl_log(zpl_f32 x) { return logf(x); } - zpl_f32 zpl_pow(zpl_f32 x, zpl_f32 y) { return powf(x, y); } - #endif - - zpl_f32 zpl_exp2(zpl_f32 x) { return zpl_exp(ZPL_LOG_TWO * x); } - zpl_f32 zpl_log2(zpl_f32 x) { return zpl_log(x) / ZPL_LOG_TWO; } - - zpl_f32 zpl_fast_exp(zpl_f32 x) { - /* NOTE: Only works in the range -1 <= x <= +1 */ - zpl_f32 e = 1.0f + x * (1.0f + x * 0.5f * (1.0f + x * 0.3333333333f * (1.0f + x * 0.25f * (1.0f + x * 0.2f)))); - return e; - } - - zpl_f32 zpl_fast_exp2(zpl_f32 x) { return zpl_fast_exp(ZPL_LOG_TWO * x); } - - zpl_f32 zpl_round(zpl_f32 x) { return (float)((x >= 0.0f) ? zpl_floor(x + 0.5f) : zpl_ceil(x - 0.5f)); } - zpl_f32 zpl_floor(zpl_f32 x) { return (float)((x >= 0.0f) ? (int)x : (int)(x - 0.9999999999999999f)); } - zpl_f32 zpl_ceil(zpl_f32 x) { return (float)((x < 0.0f) ? (int)x : ((int)x) + 1); } - - zpl_f32 zpl_half_to_float(zpl_half value) { - union { - unsigned int i; - zpl_f32 f; - } result; - int s = (value >> 15) & 0x001; - int e = (value >> 10) & 0x01f; - int m = value & 0x3ff; - - if (e == 0) { - if (m == 0) { - /* Plus or minus zero */ - result.i = (unsigned int)(s << 31); - return result.f; + + e = zpl_str_control_skip(e, '\0'); + zpl__opts_set_value(opts, t, b); } else { - /* Denormalized number */ - while (!(m & 0x00000400)) { - m <<= 1; - e -= 1; - } - - e += 1; - m &= ~0x00000400; - } - } else if (e == 31) { - if (m == 0) { - /* Positive or negative infinity */ - result.i = (unsigned int)((s << 31) | 0x7f800000); - return result.f; - } else { - /* Nan */ - result.i = (unsigned int)((s << 31) | 0x7f800000 | (m << 13)); - return result.f; + zpl__opts_push_error(opts, b, ZPL_OPTS_ERR_OPTION); + had_errors = true; } + } else if (zpl_array_count(opts->positioned)) { + zpl_opts_entry *l = zpl_array_back(opts->positioned); + zpl_array_pop(opts->positioned); + zpl__opts_set_value(opts, l, p); + } else { + zpl__opts_push_error(opts, p, ZPL_OPTS_ERR_VALUE); + had_errors = true; } + } + } + return !had_errors; +} - e = e + (127 - 15); - m = m << 13; +ZPL_END_C_DECLS +#endif - result.i = (unsigned int)((s << 31) | (e << 23) | m); +#if defined(ZPL_MODULE_PROCESS) +// file: source/process.c + +//////////////////////////////////////////////////////////////// +// +// Process creation and manipulation methods +// +// +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +static ZPL_ALWAYS_INLINE void zpl__pr_close_file_handle(zpl_file *f) { + ZPL_ASSERT_NOT_NULL(f); + f->fd.p = NULL; +} + +static ZPL_ALWAYS_INLINE void zpl__pr_close_file_handles(zpl_pr *process) { + ZPL_ASSERT_NOT_NULL(process); + + zpl__pr_close_file_handle(&process->in); + zpl__pr_close_file_handle(&process->out); + zpl__pr_close_file_handle(&process->err); + + process->f_stdin = process->f_stdout = process->f_stderr = NULL; + +#ifdef ZPL_SYSTEM_WINDOWS + process->win32_handle = NULL; +#else + ZPL_NOT_IMPLEMENTED; +#endif +} + +enum { + ZPL_PR_HANDLE_MODE_READ, + ZPL_PR_HANDLE_MODE_WRITE, + ZPL_PR_HANDLE_MODES, +}; + +void *zpl__pr_open_handle(zpl_u8 type, const char *mode, void **handle) { +#ifdef ZPL_SYSTEM_WINDOWS + void *pipes[ZPL_PR_HANDLE_MODES]; + zpl_i32 fd; + + const zpl_u32 flag_inherit = 0x00000001; + SECURITY_ATTRIBUTES sa = {zpl_size_of(sa), 0, 1}; + + if (!CreatePipe(&pipes[0], &pipes[1], cast(LPSECURITY_ATTRIBUTES)&sa, 0)) { + return NULL; + } + + if (!SetHandleInformation(pipes[type], flag_inherit, 0)) { + return NULL; + } + + fd = _open_osfhandle(cast(zpl_intptr)pipes[type], 0); + + if (fd != -1) { + *handle = pipes[1-type]; + return _fdopen(fd, mode); + } + + return NULL; +#else + ZPL_NOT_IMPLEMENTED; + return NULL; +#endif +} + +zpl_i32 zpl_pr_create(zpl_pr *process, const char **args, zpl_isize argc, zpl_pr_si si, zpl_pr_opts options) { + ZPL_ASSERT_NOT_NULL(process); + zpl_zero_item(process); + +#ifdef ZPL_SYSTEM_WINDOWS + zpl_string cli, env; + zpl_b32 c_env=false; + STARTUPINFOW psi = {0}; + PROCESS_INFORMATION pi = {0}; + zpl_i32 err_code = 0; + zpl_allocator a = zpl_heap(); + const zpl_u32 use_std_handles = 0x00000100; + + psi.cb = zpl_size_of(psi); + psi.dwFlags = use_std_handles | si.flags; + + if (options & ZPL_PR_OPTS_CUSTOM_ENV) { + env = zpl_string_join(zpl_heap(), cast(const char**)si.env, si.env_count, "\0\0"); + env = zpl_string_appendc(env, "\0"); + c_env = true; + } + else if (!(options & ZPL_PR_OPTS_INHERIT_ENV)) { + env = (zpl_string)"\0\0\0\0"; + } else { + env = (zpl_string)NULL; + } + + process->f_stdin = zpl__pr_open_handle(ZPL_PR_HANDLE_MODE_WRITE, "wb", &psi.hStdInput); + process->f_stdout = zpl__pr_open_handle(ZPL_PR_HANDLE_MODE_READ, "rb", &psi.hStdOutput); + + if (options & ZPL_PR_OPTS_COMBINE_STD_OUTPUT) { + process->f_stderr = process->f_stdout; + psi.hStdError = psi.hStdOutput; + } else { + process->f_stderr = zpl__pr_open_handle(ZPL_PR_HANDLE_MODE_READ, "rb", &psi.hStdError); + } + + cli = zpl_string_join(zpl_heap(), args, argc, " "); + + psi.dwX = si.posx; + psi.dwY = si.posy; + psi.dwXSize = si.resx; + psi.dwYSize = si.resy; + psi.dwXCountChars = si.bufx; + psi.dwYCountChars = si.bufy; + psi.dwFillAttribute = si.fill_attr; + psi.wShowWindow = si.show_window; + + wchar_t *w_cli = zpl__alloc_utf8_to_ucs2(a, cli, NULL); + wchar_t *w_workdir = zpl__alloc_utf8_to_ucs2(a, si.workdir, NULL); + + if (!CreateProcessW( + NULL, + w_cli, + NULL, + NULL, + 1, + 0, + env, + w_workdir, + cast(LPSTARTUPINFOW)&psi, + cast(LPPROCESS_INFORMATION)&pi + )) { + err_code = -1; + goto pr_free_data; + } + + process->win32_handle = pi.hProcess; + CloseHandle(pi.hThread); + + zpl_file_connect_handle(&process->in, process->f_stdin); + zpl_file_connect_handle(&process->out, process->f_stdout); + zpl_file_connect_handle(&process->err, process->f_stderr); + + pr_free_data: + zpl_string_free(cli); + zpl_free(a, w_cli); + zpl_free(a, w_workdir); + + if (c_env) + zpl_string_free(env); + + return err_code; + +#else + ZPL_NOT_IMPLEMENTED; + return -1; +#endif +} + + +zpl_i32 zpl_pr_join(zpl_pr *process) { + zpl_i32 ret_code; + + ZPL_ASSERT_NOT_NULL(process); + +#ifdef ZPL_SYSTEM_WINDOWS + if (process->f_stdin) { + fclose(cast(FILE *)process->f_stdin); + } + + WaitForSingleObject(process->win32_handle, INFINITE); + + if (!GetExitCodeProcess(process->win32_handle, cast(LPDWORD)&ret_code)) { + zpl_pr_destroy(process); + return -1; + } + + zpl_pr_destroy(process); + + return ret_code; +#else + ZPL_NOT_IMPLEMENTED; + ret_code = -1; + return ret_code; +#endif +} + +void zpl_pr_destroy(zpl_pr *process) { + ZPL_ASSERT_NOT_NULL(process); + +#ifdef ZPL_SYSTEM_WINDOWS + if (process->f_stdin) { + fclose(cast(FILE *)process->f_stdin); + } + + fclose(cast(FILE *)process->f_stdout); + + if (process->f_stderr != process->f_stdout) { + fclose(cast(FILE *)process->f_stderr); + } + + CloseHandle(process->win32_handle); + + zpl__pr_close_file_handles(process); +#else + ZPL_NOT_IMPLEMENTED; +#endif +} + +void zpl_pr_terminate(zpl_pr *process, zpl_i32 err_code) { + ZPL_ASSERT_NOT_NULL(process); + +#ifdef ZPL_SYSTEM_WINDOWS + TerminateProcess(process->win32_handle, cast(UINT)err_code); + zpl_pr_destroy(process); +#else + ZPL_NOT_IMPLEMENTED; +#endif +} + +ZPL_END_C_DECLS +#endif + +#if defined(ZPL_MODULE_MATH) +// file: source/math.c + +#ifdef ZPL_EDITOR +#include +#endif + + +#if !defined(ZPL_NO_MATH_H) +#include +#endif + +ZPL_BEGIN_C_DECLS + +//////////////////////////////////////////////////////////////// +// +// Math +// + +zpl_f32 zpl_to_radians(zpl_f32 degrees) { return degrees * ZPL_TAU / 360.0f; } +zpl_f32 zpl_to_degrees(zpl_f32 radians) { return radians * 360.0f / ZPL_TAU; } + +zpl_f32 zpl_angle_diff(zpl_f32 radians_a, zpl_f32 radians_b) { + zpl_f32 delta = zpl_mod(radians_b - radians_a, ZPL_TAU); + delta = zpl_mod(delta + 1.5f * ZPL_TAU, ZPL_TAU); + delta -= 0.5f * ZPL_TAU; + return delta; +} + +zpl_f32 zpl_copy_sign(zpl_f32 x, zpl_f32 y) { + zpl_i32 ix, iy; + zpl_f32 r; + zpl_memcopy(&ix, &x, zpl_size_of(x)); + zpl_memcopy(&iy, &y, zpl_size_of(y)); + + ix &= 0x7fffffff; + ix |= iy & 0x80000000; + zpl_memcopy(&r, &ix, zpl_size_of(ix)); + return r; +} + +zpl_f32 zpl_remainder(zpl_f32 x, zpl_f32 y) { return x - (zpl_round(x / y) * y); } + +zpl_f32 zpl_mod(zpl_f32 x, zpl_f32 y) { + zpl_f32 result; + y = zpl_abs(y); + result = zpl_remainder(zpl_abs(x), y); + if (zpl_sign(result)) result += y; + return zpl_copy_sign(result, x); +} + +zpl_f64 zpl_copy_sign64(zpl_f64 x, zpl_f64 y) { + zpl_i64 ix, iy; + zpl_f64 r; + zpl_memcopy(&ix, &x, zpl_size_of(x)); + zpl_memcopy(&iy, &y, zpl_size_of(y)); + + ix &= 0x7fffffffffffffff; + ix |= iy & 0x8000000000000000; + zpl_memcopy(&r, &ix, zpl_size_of(ix)); + return r; +} + +zpl_f64 zpl_floor64(zpl_f64 x) { return cast(zpl_f64)((x >= 0.0) ? cast(zpl_i64) x : cast(zpl_i64)(x - 0.9999999999999999)); } +zpl_f64 zpl_ceil64(zpl_f64 x) { return cast(zpl_f64)((x < 0) ? cast(zpl_i64) x : (cast(zpl_i64) x) + 1); } +zpl_f64 zpl_round64(zpl_f64 x) { return cast(zpl_f64)((x >= 0.0) ? zpl_floor64(x + 0.5) : zpl_ceil64(x - 0.5)); } +zpl_f64 zpl_remainder64(zpl_f64 x, zpl_f64 y) { return x - (zpl_round64(x / y) * y); } +zpl_f64 zpl_abs64(zpl_f64 x) { return x < 0 ? -x : x; } +zpl_f64 zpl_sign64(zpl_f64 x) { return x < 0 ? -1.0 : +1.0; } + +zpl_f64 zpl_mod64(zpl_f64 x, zpl_f64 y) { + zpl_f64 result; + y = zpl_abs64(y); + result = zpl_remainder64(zpl_abs64(x), y); + if (zpl_sign64(result)) result += y; + return zpl_copy_sign64(result, x); +} + +zpl_f32 zpl_quake_rsqrt(zpl_f32 a) { + union { + int i; + zpl_f32 f; + } t; + zpl_f32 x2; + zpl_f32 const three_halfs = 1.5f; + + x2 = a * 0.5f; + t.f = a; + t.i = 0x5f375a86 - (t.i >> 1); /* What the fuck? */ + t.f = t.f * (three_halfs - (x2 * t.f * t.f)); /* 1st iteration */ + t.f = t.f * (three_halfs - (x2 * t.f * t.f)); /* 2nd iteration, this can be removed */ + + return t.f; +} + +#if defined(ZPL_NO_MATH_H) +#if defined(_MSC_VER) + +zpl_f32 zpl_rsqrt(zpl_f32 a) { return _mm_cvtss_f32(_mm_rsqrt_ss(_mm_set_ss(a))); } +zpl_f32 zpl_sqrt(zpl_f32 a) { return _mm_cvtss_f32(_mm_sqrt_ss(_mm_set_ss(a))); }; + +zpl_f32 zpl_sin(zpl_f32 a) { + static zpl_f32 const a0 = +1.91059300966915117e-31f; + static zpl_f32 const a1 = +1.00086760103908896f; + static zpl_f32 const a2 = -1.21276126894734565e-2f; + static zpl_f32 const a3 = -1.38078780785773762e-1f; + static zpl_f32 const a4 = -2.67353392911981221e-2f; + static zpl_f32 const a5 = +2.08026600266304389e-2f; + static zpl_f32 const a6 = -3.03996055049204407e-3f; + static zpl_f32 const a7 = +1.38235642404333740e-4f; + return a0 + a * (a1 + a * (a2 + a * (a3 + a * (a4 + a * (a5 + a * (a6 + a * a7)))))); +} + +zpl_f32 zpl_cos(zpl_f32 a) { + static zpl_f32 const a0 = +1.00238601909309722f; + static zpl_f32 const a1 = -3.81919947353040024e-2f; + static zpl_f32 const a2 = -3.94382342128062756e-1f; + static zpl_f32 const a3 = -1.18134036025221444e-1f; + static zpl_f32 const a4 = +1.07123798512170878e-1f; + static zpl_f32 const a5 = -1.86637164165180873e-2f; + static zpl_f32 const a6 = +9.90140908664079833e-4f; + static zpl_f32 const a7 = -5.23022132118824778e-14f; + return a0 + a * (a1 + a * (a2 + a * (a3 + a * (a4 + a * (a5 + a * (a6 + a * a7)))))); +} + +zpl_f32 zpl_tan(zpl_f32 radians) { + zpl_f32 rr = radians * radians; + zpl_f32 a = 9.5168091e-03f; + a *= rr; + a += 2.900525e-03f; + a *= rr; + a += 2.45650893e-02f; + a *= rr; + a += 5.33740603e-02f; + a *= rr; + a += 1.333923995e-01f; + a *= rr; + a += 3.333314036e-01f; + a *= rr; + a += 1.0f; + a *= radians; + return a; +} + +zpl_f32 zpl_arcsin(zpl_f32 a) { return zpl_arctan2(a, zpl_sqrt((1.0f + a) * (1.0f - a))); } +zpl_f32 zpl_arccos(zpl_f32 a) { return zpl_arctan2(zpl_sqrt((1.0f + a) * (1.0f - a)), a); } + +zpl_f32 zpl_arctan(zpl_f32 a) { + zpl_f32 u = a * a; + zpl_f32 u2 = u * u; + zpl_f32 u3 = u2 * u; + zpl_f32 u4 = u3 * u; + zpl_f32 f = 1.0f + 0.33288950512027f * u - 0.08467922817644f * u2 + 0.03252232640125f * u3 - 0.00749305860992f * u4; + return a / f; +} + +zpl_f32 zpl_arctan2(zpl_f32 y, zpl_f32 x) { + if (zpl_abs(x) > zpl_abs(y)) { + zpl_f32 a = zpl_arctan(y / x); + if (x > 0.0f) + return a; + else + return y > 0.0f ? a + ZPL_TAU_OVER_2 : a - ZPL_TAU_OVER_2; + } else { + zpl_f32 a = zpl_arctan(x / y); + if (x > 0.0f) + return y > 0.0f ? ZPL_TAU_OVER_4 - a : -ZPL_TAU_OVER_4 - a; + else + return y > 0.0f ? ZPL_TAU_OVER_4 + a : -ZPL_TAU_OVER_4 + a; + } +} + +zpl_f32 zpl_exp(zpl_f32 a) { + union { + zpl_f32 f; + int i; + } u, v; + u.i = (int)(6051102 * a + 1056478197); + v.i = (int)(1056478197 - 6051102 * a); + return u.f / v.f; +} + +zpl_f32 zpl_log(zpl_f32 a) { + union { + zpl_f32 f; + int i; + } u = { a }; + return (u.i - 1064866805) * 8.262958405176314e-8f; /* 1 / 12102203.0; */ +} + +zpl_f32 zpl_pow(zpl_f32 a, zpl_f32 b) { + int flipped = 0, e; + zpl_f32 f, r = 1.0f; + if (b < 0) { + flipped = 1; + b = -b; + } + + e = (int)b; + f = zpl_exp(b - e); + + while (e) { + if (e & 1) r *= a; + a *= a; + e >>= 1; + } + + r *= f; + return flipped ? 1.0f / r : r; +} + +#else + +zpl_f32 zpl_rsqrt(zpl_f32 a) { return 1.0f / __builtin_sqrt(a); } +zpl_f32 zpl_sqrt(zpl_f32 a) { return __builtin_sqrt(a); } +zpl_f32 zpl_sin(zpl_f32 radians) { return __builtin_sinf(radians); } +zpl_f32 zpl_cos(zpl_f32 radians) { return __builtin_cosf(radians); } +zpl_f32 zpl_tan(zpl_f32 radians) { return __builtin_tanf(radians); } +zpl_f32 zpl_arcsin(zpl_f32 a) { return __builtin_asinf(a); } +zpl_f32 zpl_arccos(zpl_f32 a) { return __builtin_acosf(a); } +zpl_f32 zpl_arctan(zpl_f32 a) { return __builtin_atanf(a); } +zpl_f32 zpl_arctan2(zpl_f32 y, zpl_f32 x) { return __builtin_atan2f(y, x); } + +zpl_f32 zpl_exp(zpl_f32 x) { return __builtin_expf(x); } +zpl_f32 zpl_log(zpl_f32 x) { return __builtin_logf(x); } + +// TODO: Should this be zpl_exp(y * zpl_log(x)) ??? +zpl_f32 zpl_pow(zpl_f32 x, zpl_f32 y) { return __builtin_powf(x, y); } + +#endif +#else +zpl_f32 zpl_rsqrt(zpl_f32 a) { return 1.0f / sqrtf(a); } +zpl_f32 zpl_sqrt(zpl_f32 a) { return sqrtf(a); }; +zpl_f32 zpl_sin(zpl_f32 radians) { return sinf(radians); }; +zpl_f32 zpl_cos(zpl_f32 radians) { return cosf(radians); }; +zpl_f32 zpl_tan(zpl_f32 radians) { return tanf(radians); }; +zpl_f32 zpl_arcsin(zpl_f32 a) { return asinf(a); }; +zpl_f32 zpl_arccos(zpl_f32 a) { return acosf(a); }; +zpl_f32 zpl_arctan(zpl_f32 a) { return atanf(a); }; +zpl_f32 zpl_arctan2(zpl_f32 y, zpl_f32 x) { return atan2f(y, x); }; + +zpl_f32 zpl_exp(zpl_f32 x) { return expf(x); } +zpl_f32 zpl_log(zpl_f32 x) { return logf(x); } +zpl_f32 zpl_pow(zpl_f32 x, zpl_f32 y) { return powf(x, y); } +#endif + +zpl_f32 zpl_exp2(zpl_f32 x) { return zpl_exp(ZPL_LOG_TWO * x); } +zpl_f32 zpl_log2(zpl_f32 x) { return zpl_log(x) / ZPL_LOG_TWO; } + +zpl_f32 zpl_fast_exp(zpl_f32 x) { + /* NOTE: Only works in the range -1 <= x <= +1 */ + zpl_f32 e = 1.0f + x * (1.0f + x * 0.5f * (1.0f + x * 0.3333333333f * (1.0f + x * 0.25f * (1.0f + x * 0.2f)))); + return e; +} + +zpl_f32 zpl_fast_exp2(zpl_f32 x) { return zpl_fast_exp(ZPL_LOG_TWO * x); } + +zpl_f32 zpl_round(zpl_f32 x) { return (float)((x >= 0.0f) ? zpl_floor(x + 0.5f) : zpl_ceil(x - 0.5f)); } +zpl_f32 zpl_floor(zpl_f32 x) { return (float)((x >= 0.0f) ? (int)x : (int)(x - 0.9999999999999999f)); } +zpl_f32 zpl_ceil(zpl_f32 x) { return (float)((x < 0.0f) ? (int)x : ((int)x) + 1); } + +zpl_f32 zpl_half_to_float(zpl_half value) { + union { + unsigned int i; + zpl_f32 f; + } result; + int s = (value >> 15) & 0x001; + int e = (value >> 10) & 0x01f; + int m = value & 0x3ff; + + if (e == 0) { + if (m == 0) { + /* Plus or minus zero */ + result.i = (unsigned int)(s << 31); + return result.f; + } else { + /* Denormalized number */ + while (!(m & 0x00000400)) { + m <<= 1; + e -= 1; + } + + e += 1; + m &= ~0x00000400; + } + } else if (e == 31) { + if (m == 0) { + /* Positive or negative infinity */ + result.i = (unsigned int)((s << 31) | 0x7f800000); + return result.f; + } else { + /* Nan */ + result.i = (unsigned int)((s << 31) | 0x7f800000 | (m << 13)); return result.f; } + } + + e = e + (127 - 15); + m = m << 13; + + result.i = (unsigned int)((s << 31) | (e << 23) | m); + return result.f; +} - zpl_half zpl_float_to_half(zpl_f32 value) { - union { - unsigned int i; - zpl_f32 f; - } v; - int i, s, e, m; - - v.f = value; - i = (int)v.i; - - s = (i >> 16) & 0x00008000; - e = ((i >> 23) & 0x000000ff) - (127 - 15); - m = i & 0x007fffff; - - if (e <= 0) { - if (e < -10) return (zpl_half)s; - m = (m | 0x00800000) >> (1 - e); - - if (m & 0x00001000) m += 0x00002000; - - return (zpl_half)(s | (m >> 13)); - } else if (e == 0xff - (127 - 15)) { - if (m == 0) { - return (zpl_half)(s | 0x7c00); /* NOTE: infinity */ - } else { - /* NOTE: NAN */ - m >>= 13; - return (zpl_half)(s | 0x7c00 | m | (m == 0)); - } - } else { - if (m & 0x00001000) { - m += 0x00002000; - if (m & 0x00800000) { - m = 0; - e += 1; - } - } - - if (e > 30) { - zpl_f32 volatile f = 1e12f; - int j; - for (j = 0; j < 10; j++) f *= f; /* NOTE: Cause overflow */ - - return (zpl_half)(s | 0x7c00); - } - - return (zpl_half)(s | (e << 10) | (m >> 13)); +zpl_half zpl_float_to_half(zpl_f32 value) { + union { + unsigned int i; + zpl_f32 f; + } v; + int i, s, e, m; + + v.f = value; + i = (int)v.i; + + s = (i >> 16) & 0x00008000; + e = ((i >> 23) & 0x000000ff) - (127 - 15); + m = i & 0x007fffff; + + if (e <= 0) { + if (e < -10) return (zpl_half)s; + m = (m | 0x00800000) >> (1 - e); + + if (m & 0x00001000) m += 0x00002000; + + return (zpl_half)(s | (m >> 13)); + } else if (e == 0xff - (127 - 15)) { + if (m == 0) { + return (zpl_half)(s | 0x7c00); /* NOTE: infinity */ + } else { + /* NOTE: NAN */ + m >>= 13; + return (zpl_half)(s | 0x7c00 | m | (m == 0)); + } + } else { + if (m & 0x00001000) { + m += 0x00002000; + if (m & 0x00800000) { + m = 0; + e += 1; } } - - #define ZPL_VEC2_2OP(a, c, post) \ - a->x = c.x post; \ - a->y = c.y post; - - #define ZPL_VEC2_3OP(a, b, op, c, post) \ - a->x = b.x op c.x post; \ - a->y = b.y op c.y post; - - #define ZPL_VEC3_2OP(a, c, post) \ - a->x = c.x post; \ - a->y = c.y post; \ - a->z = c.z post; - - #define ZPL_VEC3_3OP(a, b, op, c, post) \ - a->x = b.x op c.x post; \ - a->y = b.y op c.y post; \ - a->z = b.z op c.z post; - - #define ZPL_VEC4_2OP(a, c, post) \ - a->x = c.x post; \ - a->y = c.y post; \ - a->z = c.z post; \ - a->w = c.w post; - - #define ZPL_VEC4_3OP(a, b, op, c, post) \ - a->x = b.x op c.x post; \ - a->y = b.y op c.y post; \ - a->z = b.z op c.z post; \ - a->w = b.w op c.w post; - - zpl_vec2 zpl_vec2f_zero(void) { - zpl_vec2 v = { 0, 0 }; - return v; - } - zpl_vec2 zpl_vec2f(zpl_f32 x, zpl_f32 y) { - zpl_vec2 v; - v.x = x; - v.y = y; - return v; - } - zpl_vec2 zpl_vec2fv(zpl_f32 x[2]) { - zpl_vec2 v; - v.x = x[0]; - v.y = x[1]; - return v; - } - - zpl_vec3 zpl_vec3f_zero(void) { - zpl_vec3 v = { 0, 0, 0 }; - return v; - } - zpl_vec3 zpl_vec3f(zpl_f32 x, zpl_f32 y, zpl_f32 z) { - zpl_vec3 v; - v.x = x; - v.y = y; - v.z = z; - return v; - } - zpl_vec3 zpl_vec3fv(zpl_f32 x[3]) { - zpl_vec3 v; - v.x = x[0]; - v.y = x[1]; - v.z = x[2]; - return v; - } - - zpl_vec4 zpl_vec4f_zero(void) { - zpl_vec4 v = { 0, 0, 0, 0 }; - return v; - } - zpl_vec4 zpl_vec4f(zpl_f32 x, zpl_f32 y, zpl_f32 z, zpl_f32 w) { - zpl_vec4 v; - v.x = x; - v.y = y; - v.z = z; - v.w = w; - return v; - } - zpl_vec4 zpl_vec4fv(zpl_f32 x[4]) { - zpl_vec4 v; - v.x = x[0]; - v.y = x[1]; - v.z = x[2]; - v.w = x[3]; - return v; - } - - zpl_f32 zpl_vec2_max(zpl_vec2 v) { return zpl_max(v.x, v.y); } - zpl_f32 zpl_vec2_side(zpl_vec2 p, zpl_vec2 q, zpl_vec2 r) { return ((q.x - p.x) * (r.y - p.y) - (r.x - p.x) * (q.y - p.y)); } - - void zpl_vec2_add(zpl_vec2 *d, zpl_vec2 v0, zpl_vec2 v1) { ZPL_VEC2_3OP(d, v0, +, v1, +0); } - void zpl_vec2_sub(zpl_vec2 *d, zpl_vec2 v0, zpl_vec2 v1) { ZPL_VEC2_3OP(d, v0, -, v1, +0); } - void zpl_vec2_mul(zpl_vec2 *d, zpl_vec2 v, zpl_f32 s) { ZPL_VEC2_2OP(d, v, *s); } - void zpl_vec2_div(zpl_vec2 *d, zpl_vec2 v, zpl_f32 s) { ZPL_VEC2_2OP(d, v, / s); } - - zpl_f32 zpl_vec3_max(zpl_vec3 v) { return zpl_max3(v.x, v.y, v.z); } - - void zpl_vec3_add(zpl_vec3 *d, zpl_vec3 v0, zpl_vec3 v1) { ZPL_VEC3_3OP(d, v0, +, v1, +0); } - void zpl_vec3_sub(zpl_vec3 *d, zpl_vec3 v0, zpl_vec3 v1) { ZPL_VEC3_3OP(d, v0, -, v1, +0); } - void zpl_vec3_mul(zpl_vec3 *d, zpl_vec3 v, zpl_f32 s) { ZPL_VEC3_2OP(d, v, *s); } - void zpl_vec3_div(zpl_vec3 *d, zpl_vec3 v, zpl_f32 s) { ZPL_VEC3_2OP(d, v, / s); } - - void zpl_vec4_add(zpl_vec4 *d, zpl_vec4 v0, zpl_vec4 v1) { ZPL_VEC4_3OP(d, v0, +, v1, +0); } - void zpl_vec4_sub(zpl_vec4 *d, zpl_vec4 v0, zpl_vec4 v1) { ZPL_VEC4_3OP(d, v0, -, v1, +0); } - void zpl_vec4_mul(zpl_vec4 *d, zpl_vec4 v, zpl_f32 s) { ZPL_VEC4_2OP(d, v, *s); } - void zpl_vec4_div(zpl_vec4 *d, zpl_vec4 v, zpl_f32 s) { ZPL_VEC4_2OP(d, v, / s); } - - void zpl_vec2_addeq(zpl_vec2 *d, zpl_vec2 v) { ZPL_VEC2_3OP(d, (*d), +, v, +0); } - void zpl_vec2_subeq(zpl_vec2 *d, zpl_vec2 v) { ZPL_VEC2_3OP(d, (*d), -, v, +0); } - void zpl_vec2_muleq(zpl_vec2 *d, zpl_f32 s) { ZPL_VEC2_2OP(d, (*d), *s); } - void zpl_vec2_diveq(zpl_vec2 *d, zpl_f32 s) { ZPL_VEC2_2OP(d, (*d), / s); } - - void zpl_vec3_addeq(zpl_vec3 *d, zpl_vec3 v) { ZPL_VEC3_3OP(d, (*d), +, v, +0); } - void zpl_vec3_subeq(zpl_vec3 *d, zpl_vec3 v) { ZPL_VEC3_3OP(d, (*d), -, v, +0); } - void zpl_vec3_muleq(zpl_vec3 *d, zpl_f32 s) { ZPL_VEC3_2OP(d, (*d), *s); } - void zpl_vec3_diveq(zpl_vec3 *d, zpl_f32 s) { ZPL_VEC3_2OP(d, (*d), / s); } - - void zpl_vec4_addeq(zpl_vec4 *d, zpl_vec4 v) { ZPL_VEC4_3OP(d, (*d), +, v, +0); } - void zpl_vec4_subeq(zpl_vec4 *d, zpl_vec4 v) { ZPL_VEC4_3OP(d, (*d), -, v, +0); } - void zpl_vec4_muleq(zpl_vec4 *d, zpl_f32 s) { ZPL_VEC4_2OP(d, (*d), *s); } - void zpl_vec4_diveq(zpl_vec4 *d, zpl_f32 s) { ZPL_VEC4_2OP(d, (*d), / s); } - - #undef ZPL_VEC2_2OP - #undef ZPL_VEC2_3OP - #undef ZPL_VEC3_3OP - #undef ZPL_VEC3_2OP - #undef ZPL_VEC4_2OP - #undef ZPL_VEC4_3OP - - zpl_f32 zpl_vec2_dot(zpl_vec2 v0, zpl_vec2 v1) { return v0.x * v1.x + v0.y * v1.y; } - zpl_f32 zpl_vec3_dot(zpl_vec3 v0, zpl_vec3 v1) { return v0.x * v1.x + v0.y * v1.y + v0.z * v1.z; } - zpl_f32 zpl_vec4_dot(zpl_vec4 v0, zpl_vec4 v1) { return v0.x * v1.x + v0.y * v1.y + v0.z * v1.z + v0.w * v1.w; } - - void zpl_vec2_cross(zpl_f32 *d, zpl_vec2 v0, zpl_vec2 v1) { *d = v0.x * v1.y - v1.x * v0.y; } - void zpl_vec3_cross(zpl_vec3 *d, zpl_vec3 v0, zpl_vec3 v1) { - d->x = v0.y * v1.z - v0.z * v1.y; - d->y = v0.z * v1.x - v0.x * v1.z; - d->z = v0.x * v1.y - v0.y * v1.x; - } - - zpl_f32 zpl_vec2_mag2(zpl_vec2 v) { return zpl_vec2_dot(v, v); } - zpl_f32 zpl_vec3_mag2(zpl_vec3 v) { return zpl_vec3_dot(v, v); } - zpl_f32 zpl_vec4_mag2(zpl_vec4 v) { return zpl_vec4_dot(v, v); } - - /* TODO: Create custom sqrt function */ - zpl_f32 zpl_vec2_mag(zpl_vec2 v) { return zpl_sqrt(zpl_vec2_dot(v, v)); } - zpl_f32 zpl_vec3_mag(zpl_vec3 v) { return zpl_sqrt(zpl_vec3_dot(v, v)); } - zpl_f32 zpl_vec4_mag(zpl_vec4 v) { return zpl_sqrt(zpl_vec4_dot(v, v)); } - - void zpl_vec2_norm(zpl_vec2 *d, zpl_vec2 v) { - zpl_f32 inv_mag = zpl_rsqrt(zpl_vec2_dot(v, v)); - zpl_vec2_mul(d, v, inv_mag); - } - void zpl_vec3_norm(zpl_vec3 *d, zpl_vec3 v) { - zpl_f32 mag = zpl_vec3_mag(v); - zpl_vec3_div(d, v, mag); - } - void zpl_vec4_norm(zpl_vec4 *d, zpl_vec4 v) { - zpl_f32 mag = zpl_vec4_mag(v); - zpl_vec4_div(d, v, mag); - } - - void zpl_vec2_norm0(zpl_vec2 *d, zpl_vec2 v) { - zpl_f32 mag = zpl_vec2_mag(v); - if (mag > 0) - zpl_vec2_div(d, v, mag); - else - *d = zpl_vec2f_zero( ); - } - void zpl_vec3_norm0(zpl_vec3 *d, zpl_vec3 v) { - zpl_f32 mag = zpl_vec3_mag(v); - if (mag > 0) - zpl_vec3_div(d, v, mag); - else - *d = zpl_vec3f_zero( ); - } - void zpl_vec4_norm0(zpl_vec4 *d, zpl_vec4 v) { - zpl_f32 mag = zpl_vec4_mag(v); - if (mag > 0) - zpl_vec4_div(d, v, mag); - else - *d = zpl_vec4f_zero( ); - } - - void zpl_vec2_reflect(zpl_vec2 *d, zpl_vec2 i, zpl_vec2 n) { - zpl_vec2 b = n; - zpl_vec2_muleq(&b, 2.0f * zpl_vec2_dot(n, i)); - zpl_vec2_sub(d, i, b); - } - - void zpl_vec3_reflect(zpl_vec3 *d, zpl_vec3 i, zpl_vec3 n) { - zpl_vec3 b = n; - zpl_vec3_muleq(&b, 2.0f * zpl_vec3_dot(n, i)); - zpl_vec3_sub(d, i, b); - } - - void zpl_vec2_refract(zpl_vec2 *d, zpl_vec2 i, zpl_vec2 n, zpl_f32 eta) { - zpl_vec2 a, b; - zpl_f32 dv, k; - - dv = zpl_vec2_dot(n, i); - k = 1.0f - eta * eta * (1.0f - dv * dv); - zpl_vec2_mul(&a, i, eta); - zpl_vec2_mul(&b, n, eta * dv * zpl_sqrt(k)); - zpl_vec2_sub(d, a, b); - zpl_vec2_muleq(d, (float)(k >= 0.0f)); - } - - void zpl_vec3_refract(zpl_vec3 *d, zpl_vec3 i, zpl_vec3 n, zpl_f32 eta) { - zpl_vec3 a, b; - zpl_f32 dv, k; - - dv = zpl_vec3_dot(n, i); - k = 1.0f - eta * eta * (1.0f - dv * dv); - zpl_vec3_mul(&a, i, eta); - zpl_vec3_mul(&b, n, eta * dv * zpl_sqrt(k)); - zpl_vec3_sub(d, a, b); - zpl_vec3_muleq(d, (float)(k >= 0.0f)); - } - - zpl_f32 zpl_vec2_aspect_ratio(zpl_vec2 v) { return (v.y < 0.0001f) ? 0.0f : v.x / v.y; } - - void zpl_mat2_transpose(zpl_mat2 *m) { zpl_float22_transpose(zpl_float22_m(m)); } - void zpl_mat2_identity(zpl_mat2 *m) { zpl_float22_identity(zpl_float22_m(m)); } - void zpl_mat2_mul(zpl_mat2 *out, zpl_mat2 *m1, zpl_mat2 *m2) { - zpl_float22_mul(zpl_float22_m(out), zpl_float22_m(m1), zpl_float22_m(m2)); - } - - void zpl_float22_identity(zpl_f32 m[2][2]) { - m[0][0] = 1; - m[0][1] = 0; - m[1][0] = 0; - m[1][1] = 1; - } - - void zpl_mat2_copy(zpl_mat2* out, zpl_mat2* m) { - zpl_memcopy(out, m, sizeof(zpl_mat3)); - } - - void zpl_mat2_mul_vec2(zpl_vec2 *out, zpl_mat2 *m, zpl_vec2 in) { zpl_float22_mul_vec2(out, zpl_float22_m(m), in); } - - zpl_mat2 *zpl_mat2_v(zpl_vec2 m[2]) { return (zpl_mat2 *)m; } - zpl_mat2 *zpl_mat2_f(zpl_f32 m[2][2]) { return (zpl_mat2 *)m; } - - zpl_float2 *zpl_float22_m(zpl_mat2 *m) { return (zpl_float2 *)m; } - zpl_float2 *zpl_float22_v(zpl_vec2 m[2]) { return (zpl_float2 *)m; } - zpl_float2 *zpl_float22_4(zpl_f32 m[4]) { return (zpl_float2 *)m; } - - void zpl_float22_transpose(zpl_f32 (*vec)[2]) { - int i, j; - for (j = 0; j < 2; j++) { - for (i = j + 1; i < 2; i++) { - zpl_f32 t = vec[i][j]; - vec[i][j] = vec[j][i]; - vec[j][i] = t; - } - } - } - - void zpl_float22_mul(zpl_f32 (*out)[2], zpl_f32 (*mat1)[2], zpl_f32 (*mat2)[2]) { - int i, j; - zpl_f32 temp1[2][2], temp2[2][2]; - if (mat1 == out) { - zpl_memcopy(temp1, mat1, sizeof(temp1)); - mat1 = temp1; - } - if (mat2 == out) { - zpl_memcopy(temp2, mat2, sizeof(temp2)); - mat2 = temp2; - } - for (j = 0; j < 2; j++) { - for (i = 0; i < 2; i++) { out[j][i] = mat1[0][i] * mat2[j][0] + mat1[1][i] * mat2[j][1]; } - } - } - - void zpl_float22_mul_vec2(zpl_vec2 *out, zpl_f32 m[2][2], zpl_vec2 v) { - out->x = m[0][0] * v.x + m[0][1] * v.y; - out->y = m[1][0] * v.x + m[1][1] * v.y; - } - - zpl_f32 zpl_mat2_determinate(zpl_mat2 *m) { - zpl_float2 *e = zpl_float22_m(m); - return e[0][0] * e[1][1] - e[1][0] * e[0][1]; - } - - void zpl_mat2_inverse(zpl_mat2 *out, zpl_mat2 *in) { - zpl_float2 *o = zpl_float22_m(out); - zpl_float2 *i = zpl_float22_m(in); - - zpl_f32 ood = 1.0f / zpl_mat2_determinate(in); - - o[0][0] = +i[1][1] * ood; - o[0][1] = -i[0][1] * ood; - o[1][0] = -i[1][0] * ood; - o[1][1] = +i[0][0] * ood; - } - - void zpl_mat3_transpose(zpl_mat3 *m) { zpl_float33_transpose(zpl_float33_m(m)); } - void zpl_mat3_identity(zpl_mat3 *m) { zpl_float33_identity(zpl_float33_m(m)); } - - void zpl_mat3_copy(zpl_mat3* out, zpl_mat3* m) { - zpl_memcopy(out, m, sizeof(zpl_mat3)); - } - - void zpl_mat3_mul(zpl_mat3 *out, zpl_mat3 *m1, zpl_mat3 *m2) { - zpl_float33_mul(zpl_float33_m(out), zpl_float33_m(m1), zpl_float33_m(m2)); - } - - void zpl_float33_identity(zpl_f32 m[3][3]) { - m[0][0] = 1; - m[0][1] = 0; - m[0][2] = 0; - m[1][0] = 0; - m[1][1] = 1; - m[1][2] = 0; - m[2][0] = 0; - m[2][1] = 0; - m[2][2] = 1; - } - - void zpl_mat3_mul_vec3(zpl_vec3 *out, zpl_mat3 *m, zpl_vec3 in) { zpl_float33_mul_vec3(out, zpl_float33_m(m), in); } - - zpl_mat3 *zpl_mat3_v(zpl_vec3 m[3]) { return (zpl_mat3 *)m; } - zpl_mat3 *zpl_mat3_f(zpl_f32 m[3][3]) { return (zpl_mat3 *)m; } - - zpl_float3 *zpl_float33_m(zpl_mat3 *m) { return (zpl_float3 *)m; } - zpl_float3 *zpl_float33_v(zpl_vec3 m[3]) { return (zpl_float3 *)m; } - zpl_float3 *zpl_float33_9(zpl_f32 m[9]) { return (zpl_float3 *)m; } - - void zpl_float33_transpose(zpl_f32 (*vec)[3]) { - int i, j; - for (j = 0; j < 3; j++) { - for (i = j + 1; i < 3; i++) { - zpl_f32 t = vec[i][j]; - vec[i][j] = vec[j][i]; - vec[j][i] = t; - } - } - } - - void zpl_float33_mul(zpl_f32 (*out)[3], zpl_f32 (*mat1)[3], zpl_f32 (*mat2)[3]) { - int i, j; - zpl_f32 temp1[3][3], temp2[3][3]; - if (mat1 == out) { - zpl_memcopy(temp1, mat1, sizeof(temp1)); - mat1 = temp1; - } - if (mat2 == out) { - zpl_memcopy(temp2, mat2, sizeof(temp2)); - mat2 = temp2; - } - for (j = 0; j < 3; j++) { - for (i = 0; i < 3; i++) { - out[j][i] = mat1[0][i] * mat2[j][0] + mat1[1][i] * mat2[j][1] + mat1[2][i] * mat2[j][2]; - } - } - } - - void zpl_float33_mul_vec3(zpl_vec3 *out, zpl_f32 m[3][3], zpl_vec3 v) { - out->x = m[0][0] * v.x + m[0][1] * v.y + m[0][2] * v.z; - out->y = m[1][0] * v.x + m[1][1] * v.y + m[1][2] * v.z; - out->z = m[2][0] * v.x + m[2][1] * v.y + m[2][2] * v.z; - } - - zpl_f32 zpl_mat3_determinate(zpl_mat3 *m) { - zpl_float3 *e = zpl_float33_m(m); - zpl_f32 d = - +e[0][0] * (e[1][1] * e[2][2] - e[1][2] * e[2][1]) - -e[0][1] * (e[1][0] * e[2][2] - e[1][2] * e[2][0]) - +e[0][2] * (e[1][0] * e[2][1] - e[1][1] * e[2][0]); - return d; - } - - void zpl_mat3_inverse(zpl_mat3 *out, zpl_mat3 *in) { - zpl_float3 *o = zpl_float33_m(out); - zpl_float3 *i = zpl_float33_m(in); - - zpl_f32 ood = 1.0f / zpl_mat3_determinate(in); - - o[0][0] = +(i[1][1] * i[2][2] - i[2][1] * i[1][2]) * ood; - o[0][1] = -(i[1][0] * i[2][2] - i[2][0] * i[1][2]) * ood; - o[0][2] = +(i[1][0] * i[2][1] - i[2][0] * i[1][1]) * ood; - o[1][0] = -(i[0][1] * i[2][2] - i[2][1] * i[0][2]) * ood; - o[1][1] = +(i[0][0] * i[2][2] - i[2][0] * i[0][2]) * ood; - o[1][2] = -(i[0][0] * i[2][1] - i[2][0] * i[0][1]) * ood; - o[2][0] = +(i[0][1] * i[1][2] - i[1][1] * i[0][2]) * ood; - o[2][1] = -(i[0][0] * i[1][2] - i[1][0] * i[0][2]) * ood; - o[2][2] = +(i[0][0] * i[1][1] - i[1][0] * i[0][1]) * ood; - } - - void zpl_mat4_transpose(zpl_mat4 *m) { zpl_float44_transpose(zpl_float44_m(m)); } - void zpl_mat4_identity(zpl_mat4 *m) { zpl_float44_identity(zpl_float44_m(m)); } - - void zpl_mat4_copy(zpl_mat4* out, zpl_mat4* m) { - zpl_memcopy(out, m, sizeof(zpl_mat4)); - } - - - void zpl_mat4_mul(zpl_mat4 *out, zpl_mat4 *m1, zpl_mat4 *m2) { - zpl_float44_mul(zpl_float44_m(out), zpl_float44_m(m1), zpl_float44_m(m2)); - } - - void zpl_float44_identity(zpl_f32 m[4][4]) { - m[0][0] = 1; - m[0][1] = 0; - m[0][2] = 0; - m[0][3] = 0; - m[1][0] = 0; - m[1][1] = 1; - m[1][2] = 0; - m[1][3] = 0; - m[2][0] = 0; - m[2][1] = 0; - m[2][2] = 1; - m[2][3] = 0; - m[3][0] = 0; - m[3][1] = 0; - m[3][2] = 0; - m[3][3] = 1; - } - - void zpl_mat4_mul_vec4(zpl_vec4 *out, zpl_mat4 *m, zpl_vec4 in) { zpl_float44_mul_vec4(out, zpl_float44_m(m), in); } - - zpl_mat4 *zpl_mat4_v(zpl_vec4 m[4]) { return (zpl_mat4 *)m; } - zpl_mat4 *zpl_mat4_f(zpl_f32 m[4][4]) { return (zpl_mat4 *)m; } - - zpl_float4 *zpl_float44_m(zpl_mat4 *m) { return (zpl_float4 *)m; } - zpl_float4 *zpl_float44_v(zpl_vec4 m[4]) { return (zpl_float4 *)m; } - zpl_float4 *zpl_float44_16(zpl_f32 m[16]) { return (zpl_float4 *)m; } - - void zpl_float44_transpose(zpl_f32 (*vec)[4]) { - zpl_f32 tmp; - tmp = vec[1][0]; - vec[1][0] = vec[0][1]; - vec[0][1] = tmp; - tmp = vec[2][0]; - vec[2][0] = vec[0][2]; - vec[0][2] = tmp; - tmp = vec[3][0]; - vec[3][0] = vec[0][3]; - vec[0][3] = tmp; - tmp = vec[2][1]; - vec[2][1] = vec[1][2]; - vec[1][2] = tmp; - tmp = vec[3][1]; - vec[3][1] = vec[1][3]; - vec[1][3] = tmp; - tmp = vec[3][2]; - vec[3][2] = vec[2][3]; - vec[2][3] = tmp; - } - - void zpl_float44_mul(zpl_f32 (*out)[4], zpl_f32 (*mat1)[4], zpl_f32 (*mat2)[4]) { - int i, j; - zpl_f32 temp1[4][4], temp2[4][4]; - if (mat1 == out) { - zpl_memcopy(temp1, mat1, sizeof(temp1)); - mat1 = temp1; - } - if (mat2 == out) { - zpl_memcopy(temp2, mat2, sizeof(temp2)); - mat2 = temp2; - } - for (j = 0; j < 4; j++) { - for (i = 0; i < 4; i++) { - out[j][i] = - mat1[0][i] * mat2[j][0] + mat1[1][i] * mat2[j][1] - +mat1[2][i] * mat2[j][2] + mat1[3][i] * mat2[j][3]; - } - } - } - - void zpl_float44_mul_vec4(zpl_vec4 *out, zpl_f32 m[4][4], zpl_vec4 v) { - out->x = m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z + m[3][0] * v.w; - out->y = m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z + m[3][1] * v.w; - out->z = m[0][2] * v.x + m[1][2] * v.y + m[2][2] * v.z + m[3][2] * v.w; - out->w = m[0][3] * v.x + m[1][3] * v.y + m[2][3] * v.z + m[3][3] * v.w; - } - - void zpl_mat4_inverse(zpl_mat4 *out, zpl_mat4 *in) { - zpl_float4 *o = zpl_float44_m(out); - zpl_float4 *m = zpl_float44_m(in); - - zpl_f32 ood; - - zpl_f32 sf00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; - zpl_f32 sf01 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; - zpl_f32 sf02 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; - zpl_f32 sf03 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; - zpl_f32 sf04 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; - zpl_f32 sf05 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; - zpl_f32 sf06 = m[1][2] * m[3][3] - m[3][2] * m[1][3]; - zpl_f32 sf07 = m[1][1] * m[3][3] - m[3][1] * m[1][3]; - zpl_f32 sf08 = m[1][1] * m[3][2] - m[3][1] * m[1][2]; - zpl_f32 sf09 = m[1][0] * m[3][3] - m[3][0] * m[1][3]; - zpl_f32 sf10 = m[1][0] * m[3][2] - m[3][0] * m[1][2]; - zpl_f32 sf11 = m[1][1] * m[3][3] - m[3][1] * m[1][3]; - zpl_f32 sf12 = m[1][0] * m[3][1] - m[3][0] * m[1][1]; - zpl_f32 sf13 = m[1][2] * m[2][3] - m[2][2] * m[1][3]; - zpl_f32 sf14 = m[1][1] * m[2][3] - m[2][1] * m[1][3]; - zpl_f32 sf15 = m[1][1] * m[2][2] - m[2][1] * m[1][2]; - zpl_f32 sf16 = m[1][0] * m[2][3] - m[2][0] * m[1][3]; - zpl_f32 sf17 = m[1][0] * m[2][2] - m[2][0] * m[1][2]; - zpl_f32 sf18 = m[1][0] * m[2][1] - m[2][0] * m[1][1]; - - o[0][0] = +(m[1][1] * sf00 - m[1][2] * sf01 + m[1][3] * sf02); - o[1][0] = -(m[1][0] * sf00 - m[1][2] * sf03 + m[1][3] * sf04); - o[2][0] = +(m[1][0] * sf01 - m[1][1] * sf03 + m[1][3] * sf05); - o[3][0] = -(m[1][0] * sf02 - m[1][1] * sf04 + m[1][2] * sf05); - - o[0][1] = -(m[0][1] * sf00 - m[0][2] * sf01 + m[0][3] * sf02); - o[1][1] = +(m[0][0] * sf00 - m[0][2] * sf03 + m[0][3] * sf04); - o[2][1] = -(m[0][0] * sf01 - m[0][1] * sf03 + m[0][3] * sf05); - o[3][1] = +(m[0][0] * sf02 - m[0][1] * sf04 + m[0][2] * sf05); - - o[0][2] = +(m[0][1] * sf06 - m[0][2] * sf07 + m[0][3] * sf08); - o[1][2] = -(m[0][0] * sf06 - m[0][2] * sf09 + m[0][3] * sf10); - o[2][2] = +(m[0][0] * sf11 - m[0][1] * sf09 + m[0][3] * sf12); - o[3][2] = -(m[0][0] * sf08 - m[0][1] * sf10 + m[0][2] * sf12); - - o[0][3] = -(m[0][1] * sf13 - m[0][2] * sf14 + m[0][3] * sf15); - o[1][3] = +(m[0][0] * sf13 - m[0][2] * sf16 + m[0][3] * sf17); - o[2][3] = -(m[0][0] * sf14 - m[0][1] * sf16 + m[0][3] * sf18); - o[3][3] = +(m[0][0] * sf15 - m[0][1] * sf17 + m[0][2] * sf18); - - ood = 1.0f / (m[0][0] * o[0][0] + m[0][1] * o[1][0] + m[0][2] * o[2][0] + m[0][3] * o[3][0]); - - o[0][0] *= ood; o[1][0] *= ood; o[2][0] *= ood; o[3][0] *= ood; - o[0][1] *= ood; o[1][1] *= ood; o[2][1] *= ood; o[3][1] *= ood; - o[0][2] *= ood; o[1][2] *= ood; o[2][2] *= ood; o[3][2] *= ood; - o[0][3] *= ood; o[1][3] *= ood; o[2][3] *= ood; o[3][3] *= ood; - } - - void zpl_mat4_translate(zpl_mat4 *out, zpl_vec3 v) { - zpl_mat4_identity(out); - out->col[3].xyz = v; - out->col[3].w = 1; - } - - void zpl_mat4_rotate(zpl_mat4 *out, zpl_vec3 v, zpl_f32 angle_radians) { - zpl_f32 c, s; - zpl_vec3 axis, t; - zpl_float4 *rot; - - c = zpl_cos(angle_radians); - s = zpl_sin(angle_radians); - - zpl_vec3_norm(&axis, v); - zpl_vec3_mul(&t, axis, 1.0f - c); - - zpl_mat4_identity(out); - rot = zpl_float44_m(out); - - rot[0][0] = c + t.x * axis.x; - rot[0][1] = 0 + t.x * axis.y + s * axis.z; - rot[0][2] = 0 + t.x * axis.z - s * axis.y; - rot[0][3] = 0; - - rot[1][0] = 0 + t.y * axis.x - s * axis.z; - rot[1][1] = c + t.y * axis.y; - rot[1][2] = 0 + t.y * axis.z + s * axis.x; - rot[1][3] = 0; - - rot[2][0] = 0 + t.z * axis.x + s * axis.y; - rot[2][1] = 0 + t.z * axis.y - s * axis.x; - rot[2][2] = c + t.z * axis.z; - rot[2][3] = 0; - } - - void zpl_mat4_scale(zpl_mat4 *out, zpl_vec3 v) { - zpl_mat4_identity(out); - out->e[0] = v.x; - out->e[5] = v.y; - out->e[10] = v.z; - } - - void zpl_mat4_scalef(zpl_mat4 *out, zpl_f32 s) { - zpl_mat4_identity(out); - out->e[0] = s; - out->e[5] = s; - out->e[10] = s; - } - - void zpl_mat4_ortho2d(zpl_mat4 *out, zpl_f32 left, zpl_f32 right, zpl_f32 bottom, zpl_f32 top) { - zpl_float4 *m; - zpl_mat4_identity(out); - m = zpl_float44_m(out); - - m[0][0] = 2.0f / (right - left); - m[1][1] = 2.0f / (top - bottom); - m[2][2] = -1.0f; - m[3][0] = -(right + left) / (right - left); - m[3][1] = -(top + bottom) / (top - bottom); - } - - void zpl_mat4_ortho3d(zpl_mat4 *out, zpl_f32 left, zpl_f32 right, zpl_f32 bottom, zpl_f32 top, zpl_f32 z_near, zpl_f32 z_far) { - zpl_float4 *m; - zpl_mat4_identity(out); - m = zpl_float44_m(out); - - m[0][0] = +2.0f / (right - left); - m[1][1] = +2.0f / (top - bottom); - m[2][2] = -2.0f / (z_far - z_near); - m[3][0] = -(right + left) / (right - left); - m[3][1] = -(top + bottom) / (top - bottom); - m[3][2] = -(z_far + z_near) / (z_far - z_near); - } - - void zpl_mat4_perspective(zpl_mat4 *out, zpl_f32 fovy, zpl_f32 aspect, zpl_f32 z_near, zpl_f32 z_far) { - zpl_f32 tan_half_fovy = zpl_tan(0.5f * fovy); - zpl_mat4 zero_mat = { 0 }; - zpl_float4 *m = zpl_float44_m(out); - *out = zero_mat; - - m[0][0] = 1.0f / (aspect * tan_half_fovy); - m[1][1] = 1.0f / (tan_half_fovy); - m[2][2] = -(z_far + z_near) / (z_far - z_near); - m[2][3] = -1.0f; - m[3][2] = -2.0f * z_far * z_near / (z_far - z_near); - } - - void zpl_mat4_infinite_perspective(zpl_mat4 *out, zpl_f32 fovy, zpl_f32 aspect, zpl_f32 z_near) { - zpl_f32 range = zpl_tan(0.5f * fovy) * z_near; - zpl_f32 left = -range * aspect; - zpl_f32 right = range * aspect; - zpl_f32 bottom = -range; - zpl_f32 top = range; - zpl_mat4 zero_mat = { 0 }; - zpl_float4 *m = zpl_float44_m(out); - *out = zero_mat; - - m[0][0] = (2.0f * z_near) / (right - left); - m[1][1] = (2.0f * z_near) / (top - bottom); - m[2][2] = -1.0f; - m[2][3] = -1.0f; - m[3][2] = -2.0f * z_near; - } - - void zpl_mat4_ortho2d_dx(zpl_mat4 *out, zpl_f32 left, zpl_f32 right, zpl_f32 bottom, zpl_f32 top) { - zpl_float4 *m; - zpl_mat4_identity(out); - m = zpl_float44_m(out); - - m[0][0] = 2.0f / (right - left); - m[1][1] = 2.0f / (top - bottom); - m[2][2] = -1.0f; - m[3][0] = -(right + left) / (right - left); - m[3][1] = -(top + bottom) / (top - bottom); - } - - void zpl_mat4_ortho3d_dx(zpl_mat4 *out, zpl_f32 left, zpl_f32 right, zpl_f32 bottom, zpl_f32 top, zpl_f32 z_near, zpl_f32 z_far) { - zpl_float4 *m; - zpl_mat4_identity(out); - m = zpl_float44_m(out); - - m[0][0] = +2.0f / (right - left); - m[1][1] = +2.0f / (top - bottom); - m[2][2] = -1.0f / (z_far - z_near); - m[3][0] = -(right + left) / (right - left); - m[3][1] = -(top + bottom) / (top - bottom); - m[3][2] = -( z_near) / (z_far - z_near); - } - - void zpl_mat4_perspective_dx(zpl_mat4 *out, zpl_f32 fovy, zpl_f32 aspect, zpl_f32 z_near, zpl_f32 z_far) { - zpl_f32 tan_half_fovy = zpl_tan(0.5f * fovy); - zpl_mat4 zero_mat = { 0 }; - zpl_float4 *m = zpl_float44_m(out); - *out = zero_mat; - - m[0][0] = 1.0f / (aspect * tan_half_fovy); - m[1][1] = 1.0f / (tan_half_fovy); - m[2][2] = -(z_far ) / (z_far - z_near); - m[2][3] = -1.0f; - m[3][2] = - z_near / (z_far - z_near); - } - - void zpl_mat4_infinite_perspective_dx(zpl_mat4 *out, zpl_f32 fovy, zpl_f32 aspect, zpl_f32 z_near) { - zpl_f32 tan_half_fovy = zpl_tan(0.5f * fovy); - zpl_mat4 zero_mat = { 0 }; - zpl_float4 *m = zpl_float44_m(out); - *out = zero_mat; - - m[0][0] = 1.0f / (aspect * tan_half_fovy); - m[1][1] = 1.0f / (tan_half_fovy); - m[2][2] = -1.0f; - m[2][3] = -1.0f; - m[3][2] = - z_near; - } - - - - void zpl_mat4_look_at(zpl_mat4 *out, zpl_vec3 eye, zpl_vec3 centre, zpl_vec3 up) { - zpl_vec3 f, s, u; - zpl_float4 *m; - - zpl_vec3_sub(&f, centre, eye); - zpl_vec3_norm(&f, f); - - zpl_vec3_cross(&s, f, up); - zpl_vec3_norm(&s, s); - - zpl_vec3_cross(&u, s, f); - - zpl_mat4_identity(out); - m = zpl_float44_m(out); - - m[0][0] = +s.x; - m[1][0] = +s.y; - m[2][0] = +s.z; - - m[0][1] = +u.x; - m[1][1] = +u.y; - m[2][1] = +u.z; - - m[0][2] = -f.x; - m[1][2] = -f.y; - m[2][2] = -f.z; - - m[3][0] = -zpl_vec3_dot(s, eye); - m[3][1] = -zpl_vec3_dot(u, eye); - m[3][2] = +zpl_vec3_dot(f, eye); - } - - void zpl_mat4_look_at_lh(zpl_mat4 *out, zpl_vec3 eye, zpl_vec3 centre, zpl_vec3 up) { - zpl_vec3 f, s, u; - zpl_float4 *m; - - zpl_vec3_sub(&f, centre, eye); - zpl_vec3_norm(&f, f); - - zpl_vec3_cross(&s, up, f); - zpl_vec3_norm(&s, s); - - zpl_vec3_cross(&u, f, s); - - zpl_mat4_identity(out); - m = zpl_float44_m(out); - - m[0][0] = +s.x; - m[1][0] = +s.y; - m[2][0] = +s.z; - - m[0][1] = +u.x; - m[1][1] = +u.y; - m[2][1] = +u.z; - - m[0][2] = +f.x; - m[1][2] = +f.y; - m[2][2] = +f.z; - - m[3][0] = -zpl_vec3_dot(s, eye); - m[3][1] = -zpl_vec3_dot(u, eye); - m[3][2] = -zpl_vec3_dot(f, eye); - } - - zpl_quat zpl_quatf(zpl_f32 x, zpl_f32 y, zpl_f32 z, zpl_f32 w) { - zpl_quat q; - q.x = x; - q.y = y; - q.z = z; - q.w = w; - return q; - } - zpl_quat zpl_quatfv(zpl_f32 e[4]) { - zpl_quat q; - q.x = e[0]; - q.y = e[1]; - q.z = e[2]; - q.w = e[3]; - return q; - } - - zpl_quat zpl_quat_axis_angle(zpl_vec3 axis, zpl_f32 angle_radians) { - zpl_quat q; - zpl_vec3_norm(&q.xyz, axis); - zpl_vec3_muleq(&q.xyz, zpl_sin(0.5f * angle_radians)); - q.w = zpl_cos(0.5f * angle_radians); - return q; - } - - zpl_quat zpl_quat_euler_angles(zpl_f32 pitch, zpl_f32 yaw, zpl_f32 roll) { - /* TODO: Do without multiplication, i.e. make it faster */ - zpl_quat q, p, y, r; - p = zpl_quat_axis_angle(zpl_vec3f(1, 0, 0), pitch); - y = zpl_quat_axis_angle(zpl_vec3f(0, 1, 0), yaw); - r = zpl_quat_axis_angle(zpl_vec3f(0, 0, 1), roll); - - zpl_quat_mul(&q, y, p); - zpl_quat_muleq(&q, r); - - return q; - } - - zpl_quat zpl_quat_identity(void) { - zpl_quat q = { 0, 0, 0, 1 }; - return q; - } - - void zpl_quat_add(zpl_quat *d, zpl_quat q0, zpl_quat q1) { zpl_vec4_add(&d->xyzw, q0.xyzw, q1.xyzw); } - void zpl_quat_sub(zpl_quat *d, zpl_quat q0, zpl_quat q1) { zpl_vec4_sub(&d->xyzw, q0.xyzw, q1.xyzw); } - - void zpl_quat_mul(zpl_quat *d, zpl_quat q0, zpl_quat q1) { - d->x = q0.w * q1.x + q0.x * q1.w + q0.y * q1.z - q0.z * q1.y; - d->y = q0.w * q1.y - q0.x * q1.z + q0.y * q1.w + q0.z * q1.x; - d->z = q0.w * q1.z + q0.x * q1.y - q0.y * q1.x + q0.z * q1.w; - d->w = q0.w * q1.w - q0.x * q1.x - q0.y * q1.y - q0.z * q1.z; - } - - void zpl_quat_div(zpl_quat *d, zpl_quat q0, zpl_quat q1) { - zpl_quat iq1; - zpl_quat_inverse(&iq1, q1); - zpl_quat_mul(d, q0, iq1); - } - - void zpl_quat_mulf(zpl_quat *d, zpl_quat q0, zpl_f32 s) { zpl_vec4_mul(&d->xyzw, q0.xyzw, s); } - void zpl_quat_divf(zpl_quat *d, zpl_quat q0, zpl_f32 s) { zpl_vec4_div(&d->xyzw, q0.xyzw, s); } - - void zpl_quat_addeq(zpl_quat *d, zpl_quat q) { zpl_vec4_addeq(&d->xyzw, q.xyzw); } - void zpl_quat_subeq(zpl_quat *d, zpl_quat q) { zpl_vec4_subeq(&d->xyzw, q.xyzw); } - void zpl_quat_muleq(zpl_quat *d, zpl_quat q) { zpl_quat_mul(d, *d, q); } - void zpl_quat_diveq(zpl_quat *d, zpl_quat q) { zpl_quat_div(d, *d, q); } - - void zpl_quat_muleqf(zpl_quat *d, zpl_f32 s) { zpl_vec4_muleq(&d->xyzw, s); } - void zpl_quat_diveqf(zpl_quat *d, zpl_f32 s) { zpl_vec4_diveq(&d->xyzw, s); } - - zpl_f32 zpl_quat_dot(zpl_quat q0, zpl_quat q1) { - zpl_f32 r = zpl_vec3_dot(q0.xyz, q1.xyz) + q0.w * q1.w; - return r; - } - zpl_f32 zpl_quat_mag(zpl_quat q) { - zpl_f32 r = zpl_sqrt(zpl_quat_dot(q, q)); - return r; - } - - void zpl_quat_norm(zpl_quat *d, zpl_quat q) { zpl_quat_divf(d, q, zpl_quat_mag(q)); } - - void zpl_quat_conj(zpl_quat *d, zpl_quat q) { - d->xyz = zpl_vec3f(-q.x, -q.y, -q.z); - d->w = q.w; - } - void zpl_quat_inverse(zpl_quat *d, zpl_quat q) { - zpl_quat_conj(d, q); - zpl_quat_diveqf(d, zpl_quat_dot(q, q)); - } - - void zpl_quat_axis(zpl_vec3 *axis, zpl_quat q) { - zpl_quat n; - zpl_quat_norm(&n, q); - zpl_vec3_div(axis, n.xyz, zpl_sin(zpl_arccos(q.w))); - } - - zpl_f32 zpl_quat_angle(zpl_quat q) { - zpl_f32 mag = zpl_quat_mag(q); - zpl_f32 c = q.w * (1.0f / mag); - zpl_f32 angle = 2.0f * zpl_arccos(c); - return angle; - } - - zpl_f32 zpl_quat_roll(zpl_quat q) { - return zpl_arctan2(2.0f * q.x * q.y + q.z * q.w, q.x * q.x + q.w * q.w - q.y * q.y - q.z * q.z); - } - zpl_f32 zpl_quat_pitch(zpl_quat q) { - return zpl_arctan2(2.0f * q.y * q.z + q.w * q.x, q.w * q.w - q.x * q.x - q.y * q.y + q.z * q.z); - } - zpl_f32 zpl_quat_yaw(zpl_quat q) { return zpl_arcsin(-2.0f * (q.x * q.z - q.w * q.y)); } - - void zpl_quat_rotate_vec3(zpl_vec3 *d, zpl_quat q, zpl_vec3 v) { - /* zpl_vec3 t = 2.0f * cross(q.xyz, v); - * *d = q.w*t + v + cross(q.xyz, t); - */ - zpl_vec3 t, p; - zpl_vec3_cross(&t, q.xyz, v); - zpl_vec3_muleq(&t, 2.0f); - - zpl_vec3_cross(&p, q.xyz, t); - - zpl_vec3_mul(d, t, q.w); - zpl_vec3_addeq(d, v); - zpl_vec3_addeq(d, p); - } - - void zpl_mat4_from_quat(zpl_mat4 *out, zpl_quat q) { - zpl_float4 *m; - zpl_quat a; - zpl_f32 xx, yy, zz, xy, xz, yz, wx, wy, wz; - - zpl_quat_norm(&a, q); - xx = a.x * a.x; - yy = a.y * a.y; - zz = a.z * a.z; - xy = a.x * a.y; - xz = a.x * a.z; - yz = a.y * a.z; - wx = a.w * a.x; - wy = a.w * a.y; - wz = a.w * a.z; - - zpl_mat4_identity(out); - m = zpl_float44_m(out); - - m[0][0] = 1.0f - 2.0f * (yy + zz); - m[0][1] = 2.0f * (xy + wz); - m[0][2] = 2.0f * (xz - wy); - - m[1][0] = 2.0f * (xy - wz); - m[1][1] = 1.0f - 2.0f * (xx + zz); - m[1][2] = 2.0f * (yz + wx); - - m[2][0] = 2.0f * (xz + wy); - m[2][1] = 2.0f * (yz - wx); - m[2][2] = 1.0f - 2.0f * (xx + yy); - } - - void zpl_quat_from_mat4(zpl_quat *out, zpl_mat4 *mat) { - zpl_float4 *m; - zpl_f32 four_x_squared_minus_1, four_y_squared_minus_1, four_z_squared_minus_1, four_w_squared_minus_1, - four_biggest_squared_minus_1; - int biggest_index = 0; - zpl_f32 biggest_value, mult; - - m = zpl_float44_m(mat); - - four_x_squared_minus_1 = m[0][0] - m[1][1] - m[2][2]; - four_y_squared_minus_1 = m[1][1] - m[0][0] - m[2][2]; - four_z_squared_minus_1 = m[2][2] - m[0][0] - m[1][1]; - four_w_squared_minus_1 = m[0][0] + m[1][1] + m[2][2]; - - four_biggest_squared_minus_1 = four_w_squared_minus_1; - if (four_x_squared_minus_1 > four_biggest_squared_minus_1) { - four_biggest_squared_minus_1 = four_x_squared_minus_1; - biggest_index = 1; - } - if (four_y_squared_minus_1 > four_biggest_squared_minus_1) { - four_biggest_squared_minus_1 = four_y_squared_minus_1; - biggest_index = 2; - } - if (four_z_squared_minus_1 > four_biggest_squared_minus_1) { - four_biggest_squared_minus_1 = four_z_squared_minus_1; - biggest_index = 3; - } - - biggest_value = zpl_sqrt(four_biggest_squared_minus_1 + 1.0f) * 0.5f; - mult = 0.25f / biggest_value; - - switch (biggest_index) { - case 0: - out->w = biggest_value; - out->x = (m[1][2] - m[2][1]) * mult; - out->y = (m[2][0] - m[0][2]) * mult; - out->z = (m[0][1] - m[1][0]) * mult; - break; - case 1: - out->w = (m[1][2] - m[2][1]) * mult; - out->x = biggest_value; - out->y = (m[0][1] + m[1][0]) * mult; - out->z = (m[2][0] + m[0][2]) * mult; - break; - case 2: - out->w = (m[2][0] - m[0][2]) * mult; - out->x = (m[0][1] + m[1][0]) * mult; - out->y = biggest_value; - out->z = (m[1][2] + m[2][1]) * mult; - break; - case 3: - out->w = (m[0][1] - m[1][0]) * mult; - out->x = (m[2][0] + m[0][2]) * mult; - out->y = (m[1][2] + m[2][1]) * mult; - out->z = biggest_value; - break; - } - } - - zpl_f32 zpl_plane_distance(zpl_plane* p, zpl_vec3 v) { - return (p->a * v.x + p->b * v.y + p->c * v.z + p->d); - } - - void zpl_frustum_create(zpl_frustum* out, zpl_mat4* camera, zpl_mat4* proj) { - zpl_mat4 pv; - - zpl_mat4_mul(&pv, camera, proj); - - register zpl_plane* fp = 0; - zpl_f32 rmag; - - fp = &out->x1; - fp->a = pv.x.w + pv.x.x; - fp->b = pv.y.w + pv.x.y; - fp->c = pv.z.w + pv.x.z; - fp->d = pv.w.w + pv.x.w; - - rmag = zpl_rsqrt(zpl_square(fp->a) + zpl_square(fp->b) + zpl_square(fp->c)); - - fp->a *= rmag; - fp->b *= rmag; - fp->c *= rmag; - fp->d *= rmag; - - fp = &out->x2; - - fp->a = pv.x.w - pv.x.x; - fp->b = pv.y.w - pv.x.y; - fp->c = pv.z.w - pv.x.z; - fp->d = pv.w.w - pv.x.w; - - rmag = zpl_rsqrt(zpl_square(fp->a) + zpl_square(fp->b) + zpl_square(fp->c)); - - fp->a *= rmag; - fp->b *= rmag; - fp->c *= rmag; - fp->d *= rmag; - - fp = &out->y1; - - fp->a = pv.x.w - pv.y.x; - fp->b = pv.y.w - pv.y.y; - fp->c = pv.z.w - pv.y.w; - fp->d = pv.w.w - pv.y.z; - - rmag = zpl_rsqrt(zpl_square(fp->a) + zpl_square(fp->b) + zpl_square(fp->c)); - - fp->a *= rmag; - fp->b *= rmag; - fp->c *= rmag; - fp->d *= rmag; - - fp = &out->y2; - - fp->a = pv.x.w + pv.y.x; - fp->b = pv.y.w + pv.y.y; - fp->c = pv.z.w + pv.y.z; - fp->d = pv.w.w + pv.y.w; - - rmag = zpl_rsqrt(zpl_square(fp->a) + zpl_square(fp->b) + zpl_square(fp->c)); - - fp->a *= rmag; - fp->b *= rmag; - fp->c *= rmag; - fp->d *= rmag;; - - fp = &out->z1; - - fp->a = pv.x.w + pv.z.x; - fp->b = pv.y.w + pv.z.y; - fp->c = pv.z.w + pv.z.z; - fp->d = pv.w.w + pv.z.w; - - rmag = zpl_rsqrt(zpl_square(fp->a) + zpl_square(fp->b) + zpl_square(fp->c)); - - fp->a *= rmag; - fp->b *= rmag; - fp->c *= rmag; - fp->d *= rmag; - - fp = &out->z2; - - fp->a = pv.x.w - pv.z.x; - fp->b = pv.y.w - pv.z.y; - fp->c = pv.z.w - pv.z.z; - fp->d = pv.w.w - pv.z.w; - - rmag = zpl_rsqrt(zpl_square(fp->a) + zpl_square(fp->b) + zpl_square(fp->c)); - - fp->a *= rmag; - fp->b *= rmag; - fp->c *= rmag; - fp->d *= rmag; - } - - zpl_b8 zpl_frustum_sphere_inside(zpl_frustum* frustum, zpl_vec3 center, zpl_f32 radius) { - if (zpl_plane_distance(&frustum->x1, center) <= -radius) return 0; - if (zpl_plane_distance(&frustum->x2, center) <= -radius) return 0; - if (zpl_plane_distance(&frustum->y1, center) <= -radius) return 0; - if (zpl_plane_distance(&frustum->y2, center) <= -radius) return 0; - if (zpl_plane_distance(&frustum->z1, center) <= -radius) return 0; - if (zpl_plane_distance(&frustum->z2, center) <= -radius) return 0; - - return 1; - } - - zpl_b8 zpl_frustum_point_inside(zpl_frustum* frustum, zpl_vec3 point) { - return zpl_frustum_sphere_inside(frustum, point, 0.0f); - } - - zpl_b8 zpl_frustum_box_inside(zpl_frustum* frustum, zpl_aabb3 aabb) { + + if (e > 30) { + zpl_f32 volatile f = 1e12f; + int j; + for (j = 0; j < 10; j++) f *= f; /* NOTE: Cause overflow */ - zpl_vec3 box = aabb.half_size; - zpl_vec3 v, b; - - b = zpl_vec3f(-box.x, -box.y, -box.z); - zpl_vec3_add(&v, b, aabb.centre); - - if (zpl_frustum_point_inside(frustum, v)) return 1; - - b = zpl_vec3f(+box.x, -box.y, -box.z); - zpl_vec3_add(&v, b, aabb.centre); - - if (zpl_frustum_point_inside(frustum, v)) return 1; - - b = zpl_vec3f(-box.x, +box.y, -box.z); - zpl_vec3_add(&v, b, aabb.centre); - - if (zpl_frustum_point_inside(frustum, v)) return 1; - - b = zpl_vec3f(+box.x, +box.y, -box.z); - zpl_vec3_add(&v, b, aabb.centre); - - if (zpl_frustum_point_inside(frustum, v)) return 1; - - b = zpl_vec3f(+box.x, +box.y, +box.z); - zpl_vec3_add(&v, b, aabb.centre); - - if (zpl_frustum_point_inside(frustum, v)) return 1; - - b = zpl_vec3f(-box.x, +box.y, +box.z); - zpl_vec3_add(&v, b, aabb.centre); - - if (zpl_frustum_point_inside(frustum, v)) return 1; - - b = zpl_vec3f(-box.x, -box.y, +box.z); - zpl_vec3_add(&v, b, aabb.centre); - - if (zpl_frustum_point_inside(frustum, v)) return 1; - - b = zpl_vec3f(+box.x, -box.y, +box.z); - zpl_vec3_add(&v, b, aabb.centre); - - if (zpl_frustum_point_inside(frustum, v)) return 1; - - return 0; + return (zpl_half)(s | 0x7c00); } + + return (zpl_half)(s | (e << 10) | (m >> 13)); + } +} - zpl_f32 zpl_lerp(zpl_f32 a, zpl_f32 b, zpl_f32 t) { return a * (1.0f - t) + b * t; } - zpl_f32 zpl_unlerp(zpl_f32 t, zpl_f32 a, zpl_f32 b) { return (t - a) / (b - a); } - zpl_f32 zpl_smooth_step(zpl_f32 a, zpl_f32 b, zpl_f32 t) { - zpl_f32 x = (t - a) / (b - a); - return x * x * (3.0f - 2.0f * x); +#define ZPL_VEC2_2OP(a, c, post) \ +a->x = c.x post; \ +a->y = c.y post; + +#define ZPL_VEC2_3OP(a, b, op, c, post) \ +a->x = b.x op c.x post; \ +a->y = b.y op c.y post; + +#define ZPL_VEC3_2OP(a, c, post) \ +a->x = c.x post; \ +a->y = c.y post; \ +a->z = c.z post; + +#define ZPL_VEC3_3OP(a, b, op, c, post) \ +a->x = b.x op c.x post; \ +a->y = b.y op c.y post; \ +a->z = b.z op c.z post; + +#define ZPL_VEC4_2OP(a, c, post) \ +a->x = c.x post; \ +a->y = c.y post; \ +a->z = c.z post; \ +a->w = c.w post; + +#define ZPL_VEC4_3OP(a, b, op, c, post) \ +a->x = b.x op c.x post; \ +a->y = b.y op c.y post; \ +a->z = b.z op c.z post; \ +a->w = b.w op c.w post; + +zpl_vec2 zpl_vec2f_zero(void) { + zpl_vec2 v = { 0, 0 }; + return v; +} +zpl_vec2 zpl_vec2f(zpl_f32 x, zpl_f32 y) { + zpl_vec2 v; + v.x = x; + v.y = y; + return v; +} +zpl_vec2 zpl_vec2fv(zpl_f32 x[2]) { + zpl_vec2 v; + v.x = x[0]; + v.y = x[1]; + return v; +} + +zpl_vec3 zpl_vec3f_zero(void) { + zpl_vec3 v = { 0, 0, 0 }; + return v; +} +zpl_vec3 zpl_vec3f(zpl_f32 x, zpl_f32 y, zpl_f32 z) { + zpl_vec3 v; + v.x = x; + v.y = y; + v.z = z; + return v; +} +zpl_vec3 zpl_vec3fv(zpl_f32 x[3]) { + zpl_vec3 v; + v.x = x[0]; + v.y = x[1]; + v.z = x[2]; + return v; +} + +zpl_vec4 zpl_vec4f_zero(void) { + zpl_vec4 v = { 0, 0, 0, 0 }; + return v; +} +zpl_vec4 zpl_vec4f(zpl_f32 x, zpl_f32 y, zpl_f32 z, zpl_f32 w) { + zpl_vec4 v; + v.x = x; + v.y = y; + v.z = z; + v.w = w; + return v; +} +zpl_vec4 zpl_vec4fv(zpl_f32 x[4]) { + zpl_vec4 v; + v.x = x[0]; + v.y = x[1]; + v.z = x[2]; + v.w = x[3]; + return v; +} + +zpl_f32 zpl_vec2_max(zpl_vec2 v) { return zpl_max(v.x, v.y); } +zpl_f32 zpl_vec2_side(zpl_vec2 p, zpl_vec2 q, zpl_vec2 r) { return ((q.x - p.x) * (r.y - p.y) - (r.x - p.x) * (q.y - p.y)); } + +void zpl_vec2_add(zpl_vec2 *d, zpl_vec2 v0, zpl_vec2 v1) { ZPL_VEC2_3OP(d, v0, +, v1, +0); } +void zpl_vec2_sub(zpl_vec2 *d, zpl_vec2 v0, zpl_vec2 v1) { ZPL_VEC2_3OP(d, v0, -, v1, +0); } +void zpl_vec2_mul(zpl_vec2 *d, zpl_vec2 v, zpl_f32 s) { ZPL_VEC2_2OP(d, v, *s); } +void zpl_vec2_div(zpl_vec2 *d, zpl_vec2 v, zpl_f32 s) { ZPL_VEC2_2OP(d, v, / s); } + +zpl_f32 zpl_vec3_max(zpl_vec3 v) { return zpl_max3(v.x, v.y, v.z); } + +void zpl_vec3_add(zpl_vec3 *d, zpl_vec3 v0, zpl_vec3 v1) { ZPL_VEC3_3OP(d, v0, +, v1, +0); } +void zpl_vec3_sub(zpl_vec3 *d, zpl_vec3 v0, zpl_vec3 v1) { ZPL_VEC3_3OP(d, v0, -, v1, +0); } +void zpl_vec3_mul(zpl_vec3 *d, zpl_vec3 v, zpl_f32 s) { ZPL_VEC3_2OP(d, v, *s); } +void zpl_vec3_div(zpl_vec3 *d, zpl_vec3 v, zpl_f32 s) { ZPL_VEC3_2OP(d, v, / s); } + +void zpl_vec4_add(zpl_vec4 *d, zpl_vec4 v0, zpl_vec4 v1) { ZPL_VEC4_3OP(d, v0, +, v1, +0); } +void zpl_vec4_sub(zpl_vec4 *d, zpl_vec4 v0, zpl_vec4 v1) { ZPL_VEC4_3OP(d, v0, -, v1, +0); } +void zpl_vec4_mul(zpl_vec4 *d, zpl_vec4 v, zpl_f32 s) { ZPL_VEC4_2OP(d, v, *s); } +void zpl_vec4_div(zpl_vec4 *d, zpl_vec4 v, zpl_f32 s) { ZPL_VEC4_2OP(d, v, / s); } + +void zpl_vec2_addeq(zpl_vec2 *d, zpl_vec2 v) { ZPL_VEC2_3OP(d, (*d), +, v, +0); } +void zpl_vec2_subeq(zpl_vec2 *d, zpl_vec2 v) { ZPL_VEC2_3OP(d, (*d), -, v, +0); } +void zpl_vec2_muleq(zpl_vec2 *d, zpl_f32 s) { ZPL_VEC2_2OP(d, (*d), *s); } +void zpl_vec2_diveq(zpl_vec2 *d, zpl_f32 s) { ZPL_VEC2_2OP(d, (*d), / s); } + +void zpl_vec3_addeq(zpl_vec3 *d, zpl_vec3 v) { ZPL_VEC3_3OP(d, (*d), +, v, +0); } +void zpl_vec3_subeq(zpl_vec3 *d, zpl_vec3 v) { ZPL_VEC3_3OP(d, (*d), -, v, +0); } +void zpl_vec3_muleq(zpl_vec3 *d, zpl_f32 s) { ZPL_VEC3_2OP(d, (*d), *s); } +void zpl_vec3_diveq(zpl_vec3 *d, zpl_f32 s) { ZPL_VEC3_2OP(d, (*d), / s); } + +void zpl_vec4_addeq(zpl_vec4 *d, zpl_vec4 v) { ZPL_VEC4_3OP(d, (*d), +, v, +0); } +void zpl_vec4_subeq(zpl_vec4 *d, zpl_vec4 v) { ZPL_VEC4_3OP(d, (*d), -, v, +0); } +void zpl_vec4_muleq(zpl_vec4 *d, zpl_f32 s) { ZPL_VEC4_2OP(d, (*d), *s); } +void zpl_vec4_diveq(zpl_vec4 *d, zpl_f32 s) { ZPL_VEC4_2OP(d, (*d), / s); } + +#undef ZPL_VEC2_2OP +#undef ZPL_VEC2_3OP +#undef ZPL_VEC3_3OP +#undef ZPL_VEC3_2OP +#undef ZPL_VEC4_2OP +#undef ZPL_VEC4_3OP + +zpl_f32 zpl_vec2_dot(zpl_vec2 v0, zpl_vec2 v1) { return v0.x * v1.x + v0.y * v1.y; } +zpl_f32 zpl_vec3_dot(zpl_vec3 v0, zpl_vec3 v1) { return v0.x * v1.x + v0.y * v1.y + v0.z * v1.z; } +zpl_f32 zpl_vec4_dot(zpl_vec4 v0, zpl_vec4 v1) { return v0.x * v1.x + v0.y * v1.y + v0.z * v1.z + v0.w * v1.w; } + +void zpl_vec2_cross(zpl_f32 *d, zpl_vec2 v0, zpl_vec2 v1) { *d = v0.x * v1.y - v1.x * v0.y; } +void zpl_vec3_cross(zpl_vec3 *d, zpl_vec3 v0, zpl_vec3 v1) { + d->x = v0.y * v1.z - v0.z * v1.y; + d->y = v0.z * v1.x - v0.x * v1.z; + d->z = v0.x * v1.y - v0.y * v1.x; +} + +zpl_f32 zpl_vec2_mag2(zpl_vec2 v) { return zpl_vec2_dot(v, v); } +zpl_f32 zpl_vec3_mag2(zpl_vec3 v) { return zpl_vec3_dot(v, v); } +zpl_f32 zpl_vec4_mag2(zpl_vec4 v) { return zpl_vec4_dot(v, v); } + +/* TODO: Create custom sqrt function */ +zpl_f32 zpl_vec2_mag(zpl_vec2 v) { return zpl_sqrt(zpl_vec2_dot(v, v)); } +zpl_f32 zpl_vec3_mag(zpl_vec3 v) { return zpl_sqrt(zpl_vec3_dot(v, v)); } +zpl_f32 zpl_vec4_mag(zpl_vec4 v) { return zpl_sqrt(zpl_vec4_dot(v, v)); } + +void zpl_vec2_norm(zpl_vec2 *d, zpl_vec2 v) { + zpl_f32 inv_mag = zpl_rsqrt(zpl_vec2_dot(v, v)); + zpl_vec2_mul(d, v, inv_mag); +} +void zpl_vec3_norm(zpl_vec3 *d, zpl_vec3 v) { + zpl_f32 mag = zpl_vec3_mag(v); + zpl_vec3_div(d, v, mag); +} +void zpl_vec4_norm(zpl_vec4 *d, zpl_vec4 v) { + zpl_f32 mag = zpl_vec4_mag(v); + zpl_vec4_div(d, v, mag); +} + +void zpl_vec2_norm0(zpl_vec2 *d, zpl_vec2 v) { + zpl_f32 mag = zpl_vec2_mag(v); + if (mag > 0) + zpl_vec2_div(d, v, mag); + else + *d = zpl_vec2f_zero( ); +} +void zpl_vec3_norm0(zpl_vec3 *d, zpl_vec3 v) { + zpl_f32 mag = zpl_vec3_mag(v); + if (mag > 0) + zpl_vec3_div(d, v, mag); + else + *d = zpl_vec3f_zero( ); +} +void zpl_vec4_norm0(zpl_vec4 *d, zpl_vec4 v) { + zpl_f32 mag = zpl_vec4_mag(v); + if (mag > 0) + zpl_vec4_div(d, v, mag); + else + *d = zpl_vec4f_zero( ); +} + +void zpl_vec2_reflect(zpl_vec2 *d, zpl_vec2 i, zpl_vec2 n) { + zpl_vec2 b = n; + zpl_vec2_muleq(&b, 2.0f * zpl_vec2_dot(n, i)); + zpl_vec2_sub(d, i, b); +} + +void zpl_vec3_reflect(zpl_vec3 *d, zpl_vec3 i, zpl_vec3 n) { + zpl_vec3 b = n; + zpl_vec3_muleq(&b, 2.0f * zpl_vec3_dot(n, i)); + zpl_vec3_sub(d, i, b); +} + +void zpl_vec2_refract(zpl_vec2 *d, zpl_vec2 i, zpl_vec2 n, zpl_f32 eta) { + zpl_vec2 a, b; + zpl_f32 dv, k; + + dv = zpl_vec2_dot(n, i); + k = 1.0f - eta * eta * (1.0f - dv * dv); + zpl_vec2_mul(&a, i, eta); + zpl_vec2_mul(&b, n, eta * dv * zpl_sqrt(k)); + zpl_vec2_sub(d, a, b); + zpl_vec2_muleq(d, (float)(k >= 0.0f)); +} + +void zpl_vec3_refract(zpl_vec3 *d, zpl_vec3 i, zpl_vec3 n, zpl_f32 eta) { + zpl_vec3 a, b; + zpl_f32 dv, k; + + dv = zpl_vec3_dot(n, i); + k = 1.0f - eta * eta * (1.0f - dv * dv); + zpl_vec3_mul(&a, i, eta); + zpl_vec3_mul(&b, n, eta * dv * zpl_sqrt(k)); + zpl_vec3_sub(d, a, b); + zpl_vec3_muleq(d, (float)(k >= 0.0f)); +} + +zpl_f32 zpl_vec2_aspect_ratio(zpl_vec2 v) { return (v.y < 0.0001f) ? 0.0f : v.x / v.y; } + +void zpl_mat2_transpose(zpl_mat2 *m) { zpl_float22_transpose(zpl_float22_m(m)); } +void zpl_mat2_identity(zpl_mat2 *m) { zpl_float22_identity(zpl_float22_m(m)); } +void zpl_mat2_mul(zpl_mat2 *out, zpl_mat2 *m1, zpl_mat2 *m2) { + zpl_float22_mul(zpl_float22_m(out), zpl_float22_m(m1), zpl_float22_m(m2)); +} + +void zpl_float22_identity(zpl_f32 m[2][2]) { + m[0][0] = 1; + m[0][1] = 0; + m[1][0] = 0; + m[1][1] = 1; +} + +void zpl_mat2_copy(zpl_mat2* out, zpl_mat2* m) { + zpl_memcopy(out, m, sizeof(zpl_mat3)); +} + +void zpl_mat2_mul_vec2(zpl_vec2 *out, zpl_mat2 *m, zpl_vec2 in) { zpl_float22_mul_vec2(out, zpl_float22_m(m), in); } + +zpl_mat2 *zpl_mat2_v(zpl_vec2 m[2]) { return (zpl_mat2 *)m; } +zpl_mat2 *zpl_mat2_f(zpl_f32 m[2][2]) { return (zpl_mat2 *)m; } + +zpl_float2 *zpl_float22_m(zpl_mat2 *m) { return (zpl_float2 *)m; } +zpl_float2 *zpl_float22_v(zpl_vec2 m[2]) { return (zpl_float2 *)m; } +zpl_float2 *zpl_float22_4(zpl_f32 m[4]) { return (zpl_float2 *)m; } + +void zpl_float22_transpose(zpl_f32 (*vec)[2]) { + int i, j; + for (j = 0; j < 2; j++) { + for (i = j + 1; i < 2; i++) { + zpl_f32 t = vec[i][j]; + vec[i][j] = vec[j][i]; + vec[j][i] = t; } - zpl_f32 zpl_smoother_step(zpl_f32 a, zpl_f32 b, zpl_f32 t) { - zpl_f32 x = (t - a) / (b - a); - return x * x * x * (x * (6.0f * x - 15.0f) + 10.0f); + } +} + +void zpl_float22_mul(zpl_f32 (*out)[2], zpl_f32 (*mat1)[2], zpl_f32 (*mat2)[2]) { + int i, j; + zpl_f32 temp1[2][2], temp2[2][2]; + if (mat1 == out) { + zpl_memcopy(temp1, mat1, sizeof(temp1)); + mat1 = temp1; + } + if (mat2 == out) { + zpl_memcopy(temp2, mat2, sizeof(temp2)); + mat2 = temp2; + } + for (j = 0; j < 2; j++) { + for (i = 0; i < 2; i++) { out[j][i] = mat1[0][i] * mat2[j][0] + mat1[1][i] * mat2[j][1]; } + } +} + +void zpl_float22_mul_vec2(zpl_vec2 *out, zpl_f32 m[2][2], zpl_vec2 v) { + out->x = m[0][0] * v.x + m[0][1] * v.y; + out->y = m[1][0] * v.x + m[1][1] * v.y; +} + +zpl_f32 zpl_mat2_determinate(zpl_mat2 *m) { + zpl_float2 *e = zpl_float22_m(m); + return e[0][0] * e[1][1] - e[1][0] * e[0][1]; +} + +void zpl_mat2_inverse(zpl_mat2 *out, zpl_mat2 *in) { + zpl_float2 *o = zpl_float22_m(out); + zpl_float2 *i = zpl_float22_m(in); + + zpl_f32 ood = 1.0f / zpl_mat2_determinate(in); + + o[0][0] = +i[1][1] * ood; + o[0][1] = -i[0][1] * ood; + o[1][0] = -i[1][0] * ood; + o[1][1] = +i[0][0] * ood; +} + +void zpl_mat3_transpose(zpl_mat3 *m) { zpl_float33_transpose(zpl_float33_m(m)); } +void zpl_mat3_identity(zpl_mat3 *m) { zpl_float33_identity(zpl_float33_m(m)); } + +void zpl_mat3_copy(zpl_mat3* out, zpl_mat3* m) { + zpl_memcopy(out, m, sizeof(zpl_mat3)); +} + +void zpl_mat3_mul(zpl_mat3 *out, zpl_mat3 *m1, zpl_mat3 *m2) { + zpl_float33_mul(zpl_float33_m(out), zpl_float33_m(m1), zpl_float33_m(m2)); +} + +void zpl_float33_identity(zpl_f32 m[3][3]) { + m[0][0] = 1; + m[0][1] = 0; + m[0][2] = 0; + m[1][0] = 0; + m[1][1] = 1; + m[1][2] = 0; + m[2][0] = 0; + m[2][1] = 0; + m[2][2] = 1; +} + +void zpl_mat3_mul_vec3(zpl_vec3 *out, zpl_mat3 *m, zpl_vec3 in) { zpl_float33_mul_vec3(out, zpl_float33_m(m), in); } + +zpl_mat3 *zpl_mat3_v(zpl_vec3 m[3]) { return (zpl_mat3 *)m; } +zpl_mat3 *zpl_mat3_f(zpl_f32 m[3][3]) { return (zpl_mat3 *)m; } + +zpl_float3 *zpl_float33_m(zpl_mat3 *m) { return (zpl_float3 *)m; } +zpl_float3 *zpl_float33_v(zpl_vec3 m[3]) { return (zpl_float3 *)m; } +zpl_float3 *zpl_float33_9(zpl_f32 m[9]) { return (zpl_float3 *)m; } + +void zpl_float33_transpose(zpl_f32 (*vec)[3]) { + int i, j; + for (j = 0; j < 3; j++) { + for (i = j + 1; i < 3; i++) { + zpl_f32 t = vec[i][j]; + vec[i][j] = vec[j][i]; + vec[j][i] = t; } + } +} - #define ZPL_VEC_LERPN(N, d, a, b, t) \ - zpl_vec##N db; \ - zpl_vec##N##_sub(&db, b, a); \ - zpl_vec##N##_muleq(&db, t); \ - zpl_vec##N##_add(d, a, db) - - void zpl_vec2_lerp(zpl_vec2 *d, zpl_vec2 a, zpl_vec2 b, zpl_f32 t) { ZPL_VEC_LERPN(2, d, a, b, t); } - void zpl_vec3_lerp(zpl_vec3 *d, zpl_vec3 a, zpl_vec3 b, zpl_f32 t) { ZPL_VEC_LERPN(3, d, a, b, t); } - void zpl_vec4_lerp(zpl_vec4 *d, zpl_vec4 a, zpl_vec4 b, zpl_f32 t) { ZPL_VEC_LERPN(4, d, a, b, t); } - - #undef ZPL_VEC_LERPN - - void zpl_vec2_cslerp(zpl_vec2 *d, zpl_vec2 a, zpl_vec2 v0, zpl_vec2 b, zpl_vec2 v1, zpl_f32 t) { - zpl_f32 t2 = t * t; - zpl_f32 ti = (t - 1); - zpl_f32 ti2 = ti * ti; - - zpl_f32 h00 = (1 + 2 * t) * ti2; - zpl_f32 h10 = t * ti2; - zpl_f32 h01 = t2 * (3 - 2 * t); - zpl_f32 h11 = t2 * ti; - - d->x = h00 * a.x + h10 * v0.x + h01 * b.x + h11 * v1.x; - d->y = h00 * a.y + h10 * v0.y + h01 * b.y + h11 * v1.y; +void zpl_float33_mul(zpl_f32 (*out)[3], zpl_f32 (*mat1)[3], zpl_f32 (*mat2)[3]) { + int i, j; + zpl_f32 temp1[3][3], temp2[3][3]; + if (mat1 == out) { + zpl_memcopy(temp1, mat1, sizeof(temp1)); + mat1 = temp1; + } + if (mat2 == out) { + zpl_memcopy(temp2, mat2, sizeof(temp2)); + mat2 = temp2; + } + for (j = 0; j < 3; j++) { + for (i = 0; i < 3; i++) { + out[j][i] = mat1[0][i] * mat2[j][0] + mat1[1][i] * mat2[j][1] + mat1[2][i] * mat2[j][2]; } + } +} - void zpl_vec3_cslerp(zpl_vec3 *d, zpl_vec3 a, zpl_vec3 v0, zpl_vec3 b, zpl_vec3 v1, zpl_f32 t) { - zpl_f32 t2 = t * t; - zpl_f32 ti = (t - 1); - zpl_f32 ti2 = ti * ti; +void zpl_float33_mul_vec3(zpl_vec3 *out, zpl_f32 m[3][3], zpl_vec3 v) { + out->x = m[0][0] * v.x + m[0][1] * v.y + m[0][2] * v.z; + out->y = m[1][0] * v.x + m[1][1] * v.y + m[1][2] * v.z; + out->z = m[2][0] * v.x + m[2][1] * v.y + m[2][2] * v.z; +} - zpl_f32 h00 = (1 + 2 * t) * ti2; - zpl_f32 h10 = t * ti2; - zpl_f32 h01 = t2 * (3 - 2 * t); - zpl_f32 h11 = t2 * ti; +zpl_f32 zpl_mat3_determinate(zpl_mat3 *m) { + zpl_float3 *e = zpl_float33_m(m); + zpl_f32 d = + +e[0][0] * (e[1][1] * e[2][2] - e[1][2] * e[2][1]) + -e[0][1] * (e[1][0] * e[2][2] - e[1][2] * e[2][0]) + +e[0][2] * (e[1][0] * e[2][1] - e[1][1] * e[2][0]); + return d; +} - d->x = h00 * a.x + h10 * v0.x + h01 * b.x + h11 * v1.x; - d->y = h00 * a.y + h10 * v0.y + h01 * b.y + h11 * v1.y; - d->z = h00 * a.z + h10 * v0.z + h01 * b.z + h11 * v1.z; +void zpl_mat3_inverse(zpl_mat3 *out, zpl_mat3 *in) { + zpl_float3 *o = zpl_float33_m(out); + zpl_float3 *i = zpl_float33_m(in); + + zpl_f32 ood = 1.0f / zpl_mat3_determinate(in); + + o[0][0] = +(i[1][1] * i[2][2] - i[2][1] * i[1][2]) * ood; + o[0][1] = -(i[1][0] * i[2][2] - i[2][0] * i[1][2]) * ood; + o[0][2] = +(i[1][0] * i[2][1] - i[2][0] * i[1][1]) * ood; + o[1][0] = -(i[0][1] * i[2][2] - i[2][1] * i[0][2]) * ood; + o[1][1] = +(i[0][0] * i[2][2] - i[2][0] * i[0][2]) * ood; + o[1][2] = -(i[0][0] * i[2][1] - i[2][0] * i[0][1]) * ood; + o[2][0] = +(i[0][1] * i[1][2] - i[1][1] * i[0][2]) * ood; + o[2][1] = -(i[0][0] * i[1][2] - i[1][0] * i[0][2]) * ood; + o[2][2] = +(i[0][0] * i[1][1] - i[1][0] * i[0][1]) * ood; +} + +void zpl_mat4_transpose(zpl_mat4 *m) { zpl_float44_transpose(zpl_float44_m(m)); } +void zpl_mat4_identity(zpl_mat4 *m) { zpl_float44_identity(zpl_float44_m(m)); } + +void zpl_mat4_copy(zpl_mat4* out, zpl_mat4* m) { + zpl_memcopy(out, m, sizeof(zpl_mat4)); +} + + +void zpl_mat4_mul(zpl_mat4 *out, zpl_mat4 *m1, zpl_mat4 *m2) { + zpl_float44_mul(zpl_float44_m(out), zpl_float44_m(m1), zpl_float44_m(m2)); +} + +void zpl_float44_identity(zpl_f32 m[4][4]) { + m[0][0] = 1; + m[0][1] = 0; + m[0][2] = 0; + m[0][3] = 0; + m[1][0] = 0; + m[1][1] = 1; + m[1][2] = 0; + m[1][3] = 0; + m[2][0] = 0; + m[2][1] = 0; + m[2][2] = 1; + m[2][3] = 0; + m[3][0] = 0; + m[3][1] = 0; + m[3][2] = 0; + m[3][3] = 1; +} + +void zpl_mat4_mul_vec4(zpl_vec4 *out, zpl_mat4 *m, zpl_vec4 in) { zpl_float44_mul_vec4(out, zpl_float44_m(m), in); } + +zpl_mat4 *zpl_mat4_v(zpl_vec4 m[4]) { return (zpl_mat4 *)m; } +zpl_mat4 *zpl_mat4_f(zpl_f32 m[4][4]) { return (zpl_mat4 *)m; } + +zpl_float4 *zpl_float44_m(zpl_mat4 *m) { return (zpl_float4 *)m; } +zpl_float4 *zpl_float44_v(zpl_vec4 m[4]) { return (zpl_float4 *)m; } +zpl_float4 *zpl_float44_16(zpl_f32 m[16]) { return (zpl_float4 *)m; } + +void zpl_float44_transpose(zpl_f32 (*vec)[4]) { + zpl_f32 tmp; + tmp = vec[1][0]; + vec[1][0] = vec[0][1]; + vec[0][1] = tmp; + tmp = vec[2][0]; + vec[2][0] = vec[0][2]; + vec[0][2] = tmp; + tmp = vec[3][0]; + vec[3][0] = vec[0][3]; + vec[0][3] = tmp; + tmp = vec[2][1]; + vec[2][1] = vec[1][2]; + vec[1][2] = tmp; + tmp = vec[3][1]; + vec[3][1] = vec[1][3]; + vec[1][3] = tmp; + tmp = vec[3][2]; + vec[3][2] = vec[2][3]; + vec[2][3] = tmp; +} + +void zpl_float44_mul(zpl_f32 (*out)[4], zpl_f32 (*mat1)[4], zpl_f32 (*mat2)[4]) { + int i, j; + zpl_f32 temp1[4][4], temp2[4][4]; + if (mat1 == out) { + zpl_memcopy(temp1, mat1, sizeof(temp1)); + mat1 = temp1; + } + if (mat2 == out) { + zpl_memcopy(temp2, mat2, sizeof(temp2)); + mat2 = temp2; + } + for (j = 0; j < 4; j++) { + for (i = 0; i < 4; i++) { + out[j][i] = + mat1[0][i] * mat2[j][0] + mat1[1][i] * mat2[j][1] + +mat1[2][i] * mat2[j][2] + mat1[3][i] * mat2[j][3]; } + } +} - void zpl_vec2_dcslerp(zpl_vec2 *d, zpl_vec2 a, zpl_vec2 v0, zpl_vec2 b, zpl_vec2 v1, zpl_f32 t) { - zpl_f32 t2 = t * t; +void zpl_float44_mul_vec4(zpl_vec4 *out, zpl_f32 m[4][4], zpl_vec4 v) { + out->x = m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z + m[3][0] * v.w; + out->y = m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z + m[3][1] * v.w; + out->z = m[0][2] * v.x + m[1][2] * v.y + m[2][2] * v.z + m[3][2] * v.w; + out->w = m[0][3] * v.x + m[1][3] * v.y + m[2][3] * v.z + m[3][3] * v.w; +} - zpl_f32 dh00 = 6 * t2 - 6 * t; - zpl_f32 dh10 = 3 * t2 - 4 * t + 1; - zpl_f32 dh01 = -6 * t2 + 6 * t; - zpl_f32 dh11 = 3 * t2 - 2 * t; +void zpl_mat4_inverse(zpl_mat4 *out, zpl_mat4 *in) { + zpl_float4 *o = zpl_float44_m(out); + zpl_float4 *m = zpl_float44_m(in); + + zpl_f32 ood; + + zpl_f32 sf00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; + zpl_f32 sf01 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; + zpl_f32 sf02 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; + zpl_f32 sf03 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; + zpl_f32 sf04 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; + zpl_f32 sf05 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; + zpl_f32 sf06 = m[1][2] * m[3][3] - m[3][2] * m[1][3]; + zpl_f32 sf07 = m[1][1] * m[3][3] - m[3][1] * m[1][3]; + zpl_f32 sf08 = m[1][1] * m[3][2] - m[3][1] * m[1][2]; + zpl_f32 sf09 = m[1][0] * m[3][3] - m[3][0] * m[1][3]; + zpl_f32 sf10 = m[1][0] * m[3][2] - m[3][0] * m[1][2]; + zpl_f32 sf11 = m[1][1] * m[3][3] - m[3][1] * m[1][3]; + zpl_f32 sf12 = m[1][0] * m[3][1] - m[3][0] * m[1][1]; + zpl_f32 sf13 = m[1][2] * m[2][3] - m[2][2] * m[1][3]; + zpl_f32 sf14 = m[1][1] * m[2][3] - m[2][1] * m[1][3]; + zpl_f32 sf15 = m[1][1] * m[2][2] - m[2][1] * m[1][2]; + zpl_f32 sf16 = m[1][0] * m[2][3] - m[2][0] * m[1][3]; + zpl_f32 sf17 = m[1][0] * m[2][2] - m[2][0] * m[1][2]; + zpl_f32 sf18 = m[1][0] * m[2][1] - m[2][0] * m[1][1]; + + o[0][0] = +(m[1][1] * sf00 - m[1][2] * sf01 + m[1][3] * sf02); + o[1][0] = -(m[1][0] * sf00 - m[1][2] * sf03 + m[1][3] * sf04); + o[2][0] = +(m[1][0] * sf01 - m[1][1] * sf03 + m[1][3] * sf05); + o[3][0] = -(m[1][0] * sf02 - m[1][1] * sf04 + m[1][2] * sf05); + + o[0][1] = -(m[0][1] * sf00 - m[0][2] * sf01 + m[0][3] * sf02); + o[1][1] = +(m[0][0] * sf00 - m[0][2] * sf03 + m[0][3] * sf04); + o[2][1] = -(m[0][0] * sf01 - m[0][1] * sf03 + m[0][3] * sf05); + o[3][1] = +(m[0][0] * sf02 - m[0][1] * sf04 + m[0][2] * sf05); + + o[0][2] = +(m[0][1] * sf06 - m[0][2] * sf07 + m[0][3] * sf08); + o[1][2] = -(m[0][0] * sf06 - m[0][2] * sf09 + m[0][3] * sf10); + o[2][2] = +(m[0][0] * sf11 - m[0][1] * sf09 + m[0][3] * sf12); + o[3][2] = -(m[0][0] * sf08 - m[0][1] * sf10 + m[0][2] * sf12); + + o[0][3] = -(m[0][1] * sf13 - m[0][2] * sf14 + m[0][3] * sf15); + o[1][3] = +(m[0][0] * sf13 - m[0][2] * sf16 + m[0][3] * sf17); + o[2][3] = -(m[0][0] * sf14 - m[0][1] * sf16 + m[0][3] * sf18); + o[3][3] = +(m[0][0] * sf15 - m[0][1] * sf17 + m[0][2] * sf18); + + ood = 1.0f / (m[0][0] * o[0][0] + m[0][1] * o[1][0] + m[0][2] * o[2][0] + m[0][3] * o[3][0]); + + o[0][0] *= ood; o[1][0] *= ood; o[2][0] *= ood; o[3][0] *= ood; + o[0][1] *= ood; o[1][1] *= ood; o[2][1] *= ood; o[3][1] *= ood; + o[0][2] *= ood; o[1][2] *= ood; o[2][2] *= ood; o[3][2] *= ood; + o[0][3] *= ood; o[1][3] *= ood; o[2][3] *= ood; o[3][3] *= ood; +} - d->x = dh00 * a.x + dh10 * v0.x + dh01 * b.x + dh11 * v1.x; - d->y = dh00 * a.y + dh10 * v0.y + dh01 * b.y + dh11 * v1.y; +void zpl_mat4_translate(zpl_mat4 *out, zpl_vec3 v) { + zpl_mat4_identity(out); + out->col[3].xyz = v; + out->col[3].w = 1; +} + +void zpl_mat4_rotate(zpl_mat4 *out, zpl_vec3 v, zpl_f32 angle_radians) { + zpl_f32 c, s; + zpl_vec3 axis, t; + zpl_float4 *rot; + + c = zpl_cos(angle_radians); + s = zpl_sin(angle_radians); + + zpl_vec3_norm(&axis, v); + zpl_vec3_mul(&t, axis, 1.0f - c); + + zpl_mat4_identity(out); + rot = zpl_float44_m(out); + + rot[0][0] = c + t.x * axis.x; + rot[0][1] = 0 + t.x * axis.y + s * axis.z; + rot[0][2] = 0 + t.x * axis.z - s * axis.y; + rot[0][3] = 0; + + rot[1][0] = 0 + t.y * axis.x - s * axis.z; + rot[1][1] = c + t.y * axis.y; + rot[1][2] = 0 + t.y * axis.z + s * axis.x; + rot[1][3] = 0; + + rot[2][0] = 0 + t.z * axis.x + s * axis.y; + rot[2][1] = 0 + t.z * axis.y - s * axis.x; + rot[2][2] = c + t.z * axis.z; + rot[2][3] = 0; +} + +void zpl_mat4_scale(zpl_mat4 *out, zpl_vec3 v) { + zpl_mat4_identity(out); + out->e[0] = v.x; + out->e[5] = v.y; + out->e[10] = v.z; +} + +void zpl_mat4_scalef(zpl_mat4 *out, zpl_f32 s) { + zpl_mat4_identity(out); + out->e[0] = s; + out->e[5] = s; + out->e[10] = s; +} + +void zpl_mat4_ortho2d(zpl_mat4 *out, zpl_f32 left, zpl_f32 right, zpl_f32 bottom, zpl_f32 top) { + zpl_float4 *m; + zpl_mat4_identity(out); + m = zpl_float44_m(out); + + m[0][0] = 2.0f / (right - left); + m[1][1] = 2.0f / (top - bottom); + m[2][2] = -1.0f; + m[3][0] = -(right + left) / (right - left); + m[3][1] = -(top + bottom) / (top - bottom); +} + +void zpl_mat4_ortho3d(zpl_mat4 *out, zpl_f32 left, zpl_f32 right, zpl_f32 bottom, zpl_f32 top, zpl_f32 z_near, zpl_f32 z_far) { + zpl_float4 *m; + zpl_mat4_identity(out); + m = zpl_float44_m(out); + + m[0][0] = +2.0f / (right - left); + m[1][1] = +2.0f / (top - bottom); + m[2][2] = -2.0f / (z_far - z_near); + m[3][0] = -(right + left) / (right - left); + m[3][1] = -(top + bottom) / (top - bottom); + m[3][2] = -(z_far + z_near) / (z_far - z_near); +} + +void zpl_mat4_perspective(zpl_mat4 *out, zpl_f32 fovy, zpl_f32 aspect, zpl_f32 z_near, zpl_f32 z_far) { + zpl_f32 tan_half_fovy = zpl_tan(0.5f * fovy); + zpl_mat4 zero_mat = { 0 }; + zpl_float4 *m = zpl_float44_m(out); + *out = zero_mat; + + m[0][0] = 1.0f / (aspect * tan_half_fovy); + m[1][1] = 1.0f / (tan_half_fovy); + m[2][2] = -(z_far + z_near) / (z_far - z_near); + m[2][3] = -1.0f; + m[3][2] = -2.0f * z_far * z_near / (z_far - z_near); +} + +void zpl_mat4_infinite_perspective(zpl_mat4 *out, zpl_f32 fovy, zpl_f32 aspect, zpl_f32 z_near) { + zpl_f32 range = zpl_tan(0.5f * fovy) * z_near; + zpl_f32 left = -range * aspect; + zpl_f32 right = range * aspect; + zpl_f32 bottom = -range; + zpl_f32 top = range; + zpl_mat4 zero_mat = { 0 }; + zpl_float4 *m = zpl_float44_m(out); + *out = zero_mat; + + m[0][0] = (2.0f * z_near) / (right - left); + m[1][1] = (2.0f * z_near) / (top - bottom); + m[2][2] = -1.0f; + m[2][3] = -1.0f; + m[3][2] = -2.0f * z_near; +} + +void zpl_mat4_ortho2d_dx(zpl_mat4 *out, zpl_f32 left, zpl_f32 right, zpl_f32 bottom, zpl_f32 top) { + zpl_float4 *m; + zpl_mat4_identity(out); + m = zpl_float44_m(out); + + m[0][0] = 2.0f / (right - left); + m[1][1] = 2.0f / (top - bottom); + m[2][2] = -1.0f; + m[3][0] = -(right + left) / (right - left); + m[3][1] = -(top + bottom) / (top - bottom); +} + +void zpl_mat4_ortho3d_dx(zpl_mat4 *out, zpl_f32 left, zpl_f32 right, zpl_f32 bottom, zpl_f32 top, zpl_f32 z_near, zpl_f32 z_far) { + zpl_float4 *m; + zpl_mat4_identity(out); + m = zpl_float44_m(out); + + m[0][0] = +2.0f / (right - left); + m[1][1] = +2.0f / (top - bottom); + m[2][2] = -1.0f / (z_far - z_near); + m[3][0] = -(right + left) / (right - left); + m[3][1] = -(top + bottom) / (top - bottom); + m[3][2] = -( z_near) / (z_far - z_near); +} + +void zpl_mat4_perspective_dx(zpl_mat4 *out, zpl_f32 fovy, zpl_f32 aspect, zpl_f32 z_near, zpl_f32 z_far) { + zpl_f32 tan_half_fovy = zpl_tan(0.5f * fovy); + zpl_mat4 zero_mat = { 0 }; + zpl_float4 *m = zpl_float44_m(out); + *out = zero_mat; + + m[0][0] = 1.0f / (aspect * tan_half_fovy); + m[1][1] = 1.0f / (tan_half_fovy); + m[2][2] = -(z_far ) / (z_far - z_near); + m[2][3] = -1.0f; + m[3][2] = - z_near / (z_far - z_near); +} + +void zpl_mat4_infinite_perspective_dx(zpl_mat4 *out, zpl_f32 fovy, zpl_f32 aspect, zpl_f32 z_near) { + zpl_f32 tan_half_fovy = zpl_tan(0.5f * fovy); + zpl_mat4 zero_mat = { 0 }; + zpl_float4 *m = zpl_float44_m(out); + *out = zero_mat; + + m[0][0] = 1.0f / (aspect * tan_half_fovy); + m[1][1] = 1.0f / (tan_half_fovy); + m[2][2] = -1.0f; + m[2][3] = -1.0f; + m[3][2] = - z_near; +} + + + +void zpl_mat4_look_at(zpl_mat4 *out, zpl_vec3 eye, zpl_vec3 centre, zpl_vec3 up) { + zpl_vec3 f, s, u; + zpl_float4 *m; + + zpl_vec3_sub(&f, centre, eye); + zpl_vec3_norm(&f, f); + + zpl_vec3_cross(&s, f, up); + zpl_vec3_norm(&s, s); + + zpl_vec3_cross(&u, s, f); + + zpl_mat4_identity(out); + m = zpl_float44_m(out); + + m[0][0] = +s.x; + m[1][0] = +s.y; + m[2][0] = +s.z; + + m[0][1] = +u.x; + m[1][1] = +u.y; + m[2][1] = +u.z; + + m[0][2] = -f.x; + m[1][2] = -f.y; + m[2][2] = -f.z; + + m[3][0] = -zpl_vec3_dot(s, eye); + m[3][1] = -zpl_vec3_dot(u, eye); + m[3][2] = +zpl_vec3_dot(f, eye); +} + +void zpl_mat4_look_at_lh(zpl_mat4 *out, zpl_vec3 eye, zpl_vec3 centre, zpl_vec3 up) { + zpl_vec3 f, s, u; + zpl_float4 *m; + + zpl_vec3_sub(&f, centre, eye); + zpl_vec3_norm(&f, f); + + zpl_vec3_cross(&s, up, f); + zpl_vec3_norm(&s, s); + + zpl_vec3_cross(&u, f, s); + + zpl_mat4_identity(out); + m = zpl_float44_m(out); + + m[0][0] = +s.x; + m[1][0] = +s.y; + m[2][0] = +s.z; + + m[0][1] = +u.x; + m[1][1] = +u.y; + m[2][1] = +u.z; + + m[0][2] = +f.x; + m[1][2] = +f.y; + m[2][2] = +f.z; + + m[3][0] = -zpl_vec3_dot(s, eye); + m[3][1] = -zpl_vec3_dot(u, eye); + m[3][2] = -zpl_vec3_dot(f, eye); +} + +zpl_quat zpl_quatf(zpl_f32 x, zpl_f32 y, zpl_f32 z, zpl_f32 w) { + zpl_quat q; + q.x = x; + q.y = y; + q.z = z; + q.w = w; + return q; +} +zpl_quat zpl_quatfv(zpl_f32 e[4]) { + zpl_quat q; + q.x = e[0]; + q.y = e[1]; + q.z = e[2]; + q.w = e[3]; + return q; +} + +zpl_quat zpl_quat_axis_angle(zpl_vec3 axis, zpl_f32 angle_radians) { + zpl_quat q; + zpl_vec3_norm(&q.xyz, axis); + zpl_vec3_muleq(&q.xyz, zpl_sin(0.5f * angle_radians)); + q.w = zpl_cos(0.5f * angle_radians); + return q; +} + +zpl_quat zpl_quat_euler_angles(zpl_f32 pitch, zpl_f32 yaw, zpl_f32 roll) { + /* TODO: Do without multiplication, i.e. make it faster */ + zpl_quat q, p, y, r; + p = zpl_quat_axis_angle(zpl_vec3f(1, 0, 0), pitch); + y = zpl_quat_axis_angle(zpl_vec3f(0, 1, 0), yaw); + r = zpl_quat_axis_angle(zpl_vec3f(0, 0, 1), roll); + + zpl_quat_mul(&q, y, p); + zpl_quat_muleq(&q, r); + + return q; +} + +zpl_quat zpl_quat_identity(void) { + zpl_quat q = { 0, 0, 0, 1 }; + return q; +} + +void zpl_quat_add(zpl_quat *d, zpl_quat q0, zpl_quat q1) { zpl_vec4_add(&d->xyzw, q0.xyzw, q1.xyzw); } +void zpl_quat_sub(zpl_quat *d, zpl_quat q0, zpl_quat q1) { zpl_vec4_sub(&d->xyzw, q0.xyzw, q1.xyzw); } + +void zpl_quat_mul(zpl_quat *d, zpl_quat q0, zpl_quat q1) { + d->x = q0.w * q1.x + q0.x * q1.w + q0.y * q1.z - q0.z * q1.y; + d->y = q0.w * q1.y - q0.x * q1.z + q0.y * q1.w + q0.z * q1.x; + d->z = q0.w * q1.z + q0.x * q1.y - q0.y * q1.x + q0.z * q1.w; + d->w = q0.w * q1.w - q0.x * q1.x - q0.y * q1.y - q0.z * q1.z; +} + +void zpl_quat_div(zpl_quat *d, zpl_quat q0, zpl_quat q1) { + zpl_quat iq1; + zpl_quat_inverse(&iq1, q1); + zpl_quat_mul(d, q0, iq1); +} + +void zpl_quat_mulf(zpl_quat *d, zpl_quat q0, zpl_f32 s) { zpl_vec4_mul(&d->xyzw, q0.xyzw, s); } +void zpl_quat_divf(zpl_quat *d, zpl_quat q0, zpl_f32 s) { zpl_vec4_div(&d->xyzw, q0.xyzw, s); } + +void zpl_quat_addeq(zpl_quat *d, zpl_quat q) { zpl_vec4_addeq(&d->xyzw, q.xyzw); } +void zpl_quat_subeq(zpl_quat *d, zpl_quat q) { zpl_vec4_subeq(&d->xyzw, q.xyzw); } +void zpl_quat_muleq(zpl_quat *d, zpl_quat q) { zpl_quat_mul(d, *d, q); } +void zpl_quat_diveq(zpl_quat *d, zpl_quat q) { zpl_quat_div(d, *d, q); } + +void zpl_quat_muleqf(zpl_quat *d, zpl_f32 s) { zpl_vec4_muleq(&d->xyzw, s); } +void zpl_quat_diveqf(zpl_quat *d, zpl_f32 s) { zpl_vec4_diveq(&d->xyzw, s); } + +zpl_f32 zpl_quat_dot(zpl_quat q0, zpl_quat q1) { + zpl_f32 r = zpl_vec3_dot(q0.xyz, q1.xyz) + q0.w * q1.w; + return r; +} +zpl_f32 zpl_quat_mag(zpl_quat q) { + zpl_f32 r = zpl_sqrt(zpl_quat_dot(q, q)); + return r; +} + +void zpl_quat_norm(zpl_quat *d, zpl_quat q) { zpl_quat_divf(d, q, zpl_quat_mag(q)); } + +void zpl_quat_conj(zpl_quat *d, zpl_quat q) { + d->xyz = zpl_vec3f(-q.x, -q.y, -q.z); + d->w = q.w; +} +void zpl_quat_inverse(zpl_quat *d, zpl_quat q) { + zpl_quat_conj(d, q); + zpl_quat_diveqf(d, zpl_quat_dot(q, q)); +} + +void zpl_quat_axis(zpl_vec3 *axis, zpl_quat q) { + zpl_quat n; + zpl_quat_norm(&n, q); + zpl_vec3_div(axis, n.xyz, zpl_sin(zpl_arccos(q.w))); +} + +zpl_f32 zpl_quat_angle(zpl_quat q) { + zpl_f32 mag = zpl_quat_mag(q); + zpl_f32 c = q.w * (1.0f / mag); + zpl_f32 angle = 2.0f * zpl_arccos(c); + return angle; +} + +zpl_f32 zpl_quat_roll(zpl_quat q) { + return zpl_arctan2(2.0f * q.x * q.y + q.z * q.w, q.x * q.x + q.w * q.w - q.y * q.y - q.z * q.z); +} +zpl_f32 zpl_quat_pitch(zpl_quat q) { + return zpl_arctan2(2.0f * q.y * q.z + q.w * q.x, q.w * q.w - q.x * q.x - q.y * q.y + q.z * q.z); +} +zpl_f32 zpl_quat_yaw(zpl_quat q) { return zpl_arcsin(-2.0f * (q.x * q.z - q.w * q.y)); } + +void zpl_quat_rotate_vec3(zpl_vec3 *d, zpl_quat q, zpl_vec3 v) { + /* zpl_vec3 t = 2.0f * cross(q.xyz, v); + * *d = q.w*t + v + cross(q.xyz, t); + */ + zpl_vec3 t, p; + zpl_vec3_cross(&t, q.xyz, v); + zpl_vec3_muleq(&t, 2.0f); + + zpl_vec3_cross(&p, q.xyz, t); + + zpl_vec3_mul(d, t, q.w); + zpl_vec3_addeq(d, v); + zpl_vec3_addeq(d, p); +} + +void zpl_mat4_from_quat(zpl_mat4 *out, zpl_quat q) { + zpl_float4 *m; + zpl_quat a; + zpl_f32 xx, yy, zz, xy, xz, yz, wx, wy, wz; + + zpl_quat_norm(&a, q); + xx = a.x * a.x; + yy = a.y * a.y; + zz = a.z * a.z; + xy = a.x * a.y; + xz = a.x * a.z; + yz = a.y * a.z; + wx = a.w * a.x; + wy = a.w * a.y; + wz = a.w * a.z; + + zpl_mat4_identity(out); + m = zpl_float44_m(out); + + m[0][0] = 1.0f - 2.0f * (yy + zz); + m[0][1] = 2.0f * (xy + wz); + m[0][2] = 2.0f * (xz - wy); + + m[1][0] = 2.0f * (xy - wz); + m[1][1] = 1.0f - 2.0f * (xx + zz); + m[1][2] = 2.0f * (yz + wx); + + m[2][0] = 2.0f * (xz + wy); + m[2][1] = 2.0f * (yz - wx); + m[2][2] = 1.0f - 2.0f * (xx + yy); +} + +void zpl_quat_from_mat4(zpl_quat *out, zpl_mat4 *mat) { + zpl_float4 *m; + zpl_f32 four_x_squared_minus_1, four_y_squared_minus_1, four_z_squared_minus_1, four_w_squared_minus_1, + four_biggest_squared_minus_1; + int biggest_index = 0; + zpl_f32 biggest_value, mult; + + m = zpl_float44_m(mat); + + four_x_squared_minus_1 = m[0][0] - m[1][1] - m[2][2]; + four_y_squared_minus_1 = m[1][1] - m[0][0] - m[2][2]; + four_z_squared_minus_1 = m[2][2] - m[0][0] - m[1][1]; + four_w_squared_minus_1 = m[0][0] + m[1][1] + m[2][2]; + + four_biggest_squared_minus_1 = four_w_squared_minus_1; + if (four_x_squared_minus_1 > four_biggest_squared_minus_1) { + four_biggest_squared_minus_1 = four_x_squared_minus_1; + biggest_index = 1; + } + if (four_y_squared_minus_1 > four_biggest_squared_minus_1) { + four_biggest_squared_minus_1 = four_y_squared_minus_1; + biggest_index = 2; + } + if (four_z_squared_minus_1 > four_biggest_squared_minus_1) { + four_biggest_squared_minus_1 = four_z_squared_minus_1; + biggest_index = 3; + } + + biggest_value = zpl_sqrt(four_biggest_squared_minus_1 + 1.0f) * 0.5f; + mult = 0.25f / biggest_value; + + switch (biggest_index) { + case 0: + out->w = biggest_value; + out->x = (m[1][2] - m[2][1]) * mult; + out->y = (m[2][0] - m[0][2]) * mult; + out->z = (m[0][1] - m[1][0]) * mult; + break; + case 1: + out->w = (m[1][2] - m[2][1]) * mult; + out->x = biggest_value; + out->y = (m[0][1] + m[1][0]) * mult; + out->z = (m[2][0] + m[0][2]) * mult; + break; + case 2: + out->w = (m[2][0] - m[0][2]) * mult; + out->x = (m[0][1] + m[1][0]) * mult; + out->y = biggest_value; + out->z = (m[1][2] + m[2][1]) * mult; + break; + case 3: + out->w = (m[0][1] - m[1][0]) * mult; + out->x = (m[2][0] + m[0][2]) * mult; + out->y = (m[1][2] + m[2][1]) * mult; + out->z = biggest_value; + break; + } +} + +zpl_f32 zpl_plane_distance(zpl_plane* p, zpl_vec3 v) { + return (p->a * v.x + p->b * v.y + p->c * v.z + p->d); +} + +void zpl_frustum_create(zpl_frustum* out, zpl_mat4* camera, zpl_mat4* proj) { + zpl_mat4 pv; + + zpl_mat4_mul(&pv, camera, proj); + + register zpl_plane* fp = 0; + zpl_f32 rmag; + + fp = &out->x1; + fp->a = pv.x.w + pv.x.x; + fp->b = pv.y.w + pv.x.y; + fp->c = pv.z.w + pv.x.z; + fp->d = pv.w.w + pv.x.w; + + rmag = zpl_rsqrt(zpl_square(fp->a) + zpl_square(fp->b) + zpl_square(fp->c)); + + fp->a *= rmag; + fp->b *= rmag; + fp->c *= rmag; + fp->d *= rmag; + + fp = &out->x2; + + fp->a = pv.x.w - pv.x.x; + fp->b = pv.y.w - pv.x.y; + fp->c = pv.z.w - pv.x.z; + fp->d = pv.w.w - pv.x.w; + + rmag = zpl_rsqrt(zpl_square(fp->a) + zpl_square(fp->b) + zpl_square(fp->c)); + + fp->a *= rmag; + fp->b *= rmag; + fp->c *= rmag; + fp->d *= rmag; + + fp = &out->y1; + + fp->a = pv.x.w - pv.y.x; + fp->b = pv.y.w - pv.y.y; + fp->c = pv.z.w - pv.y.w; + fp->d = pv.w.w - pv.y.z; + + rmag = zpl_rsqrt(zpl_square(fp->a) + zpl_square(fp->b) + zpl_square(fp->c)); + + fp->a *= rmag; + fp->b *= rmag; + fp->c *= rmag; + fp->d *= rmag; + + fp = &out->y2; + + fp->a = pv.x.w + pv.y.x; + fp->b = pv.y.w + pv.y.y; + fp->c = pv.z.w + pv.y.z; + fp->d = pv.w.w + pv.y.w; + + rmag = zpl_rsqrt(zpl_square(fp->a) + zpl_square(fp->b) + zpl_square(fp->c)); + + fp->a *= rmag; + fp->b *= rmag; + fp->c *= rmag; + fp->d *= rmag;; + + fp = &out->z1; + + fp->a = pv.x.w + pv.z.x; + fp->b = pv.y.w + pv.z.y; + fp->c = pv.z.w + pv.z.z; + fp->d = pv.w.w + pv.z.w; + + rmag = zpl_rsqrt(zpl_square(fp->a) + zpl_square(fp->b) + zpl_square(fp->c)); + + fp->a *= rmag; + fp->b *= rmag; + fp->c *= rmag; + fp->d *= rmag; + + fp = &out->z2; + + fp->a = pv.x.w - pv.z.x; + fp->b = pv.y.w - pv.z.y; + fp->c = pv.z.w - pv.z.z; + fp->d = pv.w.w - pv.z.w; + + rmag = zpl_rsqrt(zpl_square(fp->a) + zpl_square(fp->b) + zpl_square(fp->c)); + + fp->a *= rmag; + fp->b *= rmag; + fp->c *= rmag; + fp->d *= rmag; +} + +zpl_b8 zpl_frustum_sphere_inside(zpl_frustum* frustum, zpl_vec3 center, zpl_f32 radius) { + if (zpl_plane_distance(&frustum->x1, center) <= -radius) return 0; + if (zpl_plane_distance(&frustum->x2, center) <= -radius) return 0; + if (zpl_plane_distance(&frustum->y1, center) <= -radius) return 0; + if (zpl_plane_distance(&frustum->y2, center) <= -radius) return 0; + if (zpl_plane_distance(&frustum->z1, center) <= -radius) return 0; + if (zpl_plane_distance(&frustum->z2, center) <= -radius) return 0; + + return 1; +} + +zpl_b8 zpl_frustum_point_inside(zpl_frustum* frustum, zpl_vec3 point) { + return zpl_frustum_sphere_inside(frustum, point, 0.0f); +} + +zpl_b8 zpl_frustum_box_inside(zpl_frustum* frustum, zpl_aabb3 aabb) { + + zpl_vec3 box = aabb.half_size; + zpl_vec3 v, b; + + b = zpl_vec3f(-box.x, -box.y, -box.z); + zpl_vec3_add(&v, b, aabb.centre); + + if (zpl_frustum_point_inside(frustum, v)) return 1; + + b = zpl_vec3f(+box.x, -box.y, -box.z); + zpl_vec3_add(&v, b, aabb.centre); + + if (zpl_frustum_point_inside(frustum, v)) return 1; + + b = zpl_vec3f(-box.x, +box.y, -box.z); + zpl_vec3_add(&v, b, aabb.centre); + + if (zpl_frustum_point_inside(frustum, v)) return 1; + + b = zpl_vec3f(+box.x, +box.y, -box.z); + zpl_vec3_add(&v, b, aabb.centre); + + if (zpl_frustum_point_inside(frustum, v)) return 1; + + b = zpl_vec3f(+box.x, +box.y, +box.z); + zpl_vec3_add(&v, b, aabb.centre); + + if (zpl_frustum_point_inside(frustum, v)) return 1; + + b = zpl_vec3f(-box.x, +box.y, +box.z); + zpl_vec3_add(&v, b, aabb.centre); + + if (zpl_frustum_point_inside(frustum, v)) return 1; + + b = zpl_vec3f(-box.x, -box.y, +box.z); + zpl_vec3_add(&v, b, aabb.centre); + + if (zpl_frustum_point_inside(frustum, v)) return 1; + + b = zpl_vec3f(+box.x, -box.y, +box.z); + zpl_vec3_add(&v, b, aabb.centre); + + if (zpl_frustum_point_inside(frustum, v)) return 1; + + return 0; +} + +zpl_f32 zpl_lerp(zpl_f32 a, zpl_f32 b, zpl_f32 t) { return a * (1.0f - t) + b * t; } +zpl_f32 zpl_unlerp(zpl_f32 t, zpl_f32 a, zpl_f32 b) { return (t - a) / (b - a); } +zpl_f32 zpl_smooth_step(zpl_f32 a, zpl_f32 b, zpl_f32 t) { + zpl_f32 x = (t - a) / (b - a); + return x * x * (3.0f - 2.0f * x); +} +zpl_f32 zpl_smoother_step(zpl_f32 a, zpl_f32 b, zpl_f32 t) { + zpl_f32 x = (t - a) / (b - a); + return x * x * x * (x * (6.0f * x - 15.0f) + 10.0f); +} + +#define ZPL_VEC_LERPN(N, d, a, b, t) \ +zpl_vec##N db; \ +zpl_vec##N##_sub(&db, b, a); \ +zpl_vec##N##_muleq(&db, t); \ +zpl_vec##N##_add(d, a, db) + +void zpl_vec2_lerp(zpl_vec2 *d, zpl_vec2 a, zpl_vec2 b, zpl_f32 t) { ZPL_VEC_LERPN(2, d, a, b, t); } +void zpl_vec3_lerp(zpl_vec3 *d, zpl_vec3 a, zpl_vec3 b, zpl_f32 t) { ZPL_VEC_LERPN(3, d, a, b, t); } +void zpl_vec4_lerp(zpl_vec4 *d, zpl_vec4 a, zpl_vec4 b, zpl_f32 t) { ZPL_VEC_LERPN(4, d, a, b, t); } + +#undef ZPL_VEC_LERPN + +void zpl_vec2_cslerp(zpl_vec2 *d, zpl_vec2 a, zpl_vec2 v0, zpl_vec2 b, zpl_vec2 v1, zpl_f32 t) { + zpl_f32 t2 = t * t; + zpl_f32 ti = (t - 1); + zpl_f32 ti2 = ti * ti; + + zpl_f32 h00 = (1 + 2 * t) * ti2; + zpl_f32 h10 = t * ti2; + zpl_f32 h01 = t2 * (3 - 2 * t); + zpl_f32 h11 = t2 * ti; + + d->x = h00 * a.x + h10 * v0.x + h01 * b.x + h11 * v1.x; + d->y = h00 * a.y + h10 * v0.y + h01 * b.y + h11 * v1.y; +} + +void zpl_vec3_cslerp(zpl_vec3 *d, zpl_vec3 a, zpl_vec3 v0, zpl_vec3 b, zpl_vec3 v1, zpl_f32 t) { + zpl_f32 t2 = t * t; + zpl_f32 ti = (t - 1); + zpl_f32 ti2 = ti * ti; + + zpl_f32 h00 = (1 + 2 * t) * ti2; + zpl_f32 h10 = t * ti2; + zpl_f32 h01 = t2 * (3 - 2 * t); + zpl_f32 h11 = t2 * ti; + + d->x = h00 * a.x + h10 * v0.x + h01 * b.x + h11 * v1.x; + d->y = h00 * a.y + h10 * v0.y + h01 * b.y + h11 * v1.y; + d->z = h00 * a.z + h10 * v0.z + h01 * b.z + h11 * v1.z; +} + +void zpl_vec2_dcslerp(zpl_vec2 *d, zpl_vec2 a, zpl_vec2 v0, zpl_vec2 b, zpl_vec2 v1, zpl_f32 t) { + zpl_f32 t2 = t * t; + + zpl_f32 dh00 = 6 * t2 - 6 * t; + zpl_f32 dh10 = 3 * t2 - 4 * t + 1; + zpl_f32 dh01 = -6 * t2 + 6 * t; + zpl_f32 dh11 = 3 * t2 - 2 * t; + + d->x = dh00 * a.x + dh10 * v0.x + dh01 * b.x + dh11 * v1.x; + d->y = dh00 * a.y + dh10 * v0.y + dh01 * b.y + dh11 * v1.y; +} + +void zpl_vec3_dcslerp(zpl_vec3 *d, zpl_vec3 a, zpl_vec3 v0, zpl_vec3 b, zpl_vec3 v1, zpl_f32 t) { + zpl_f32 t2 = t * t; + + zpl_f32 dh00 = 6 * t2 - 6 * t; + zpl_f32 dh10 = 3 * t2 - 4 * t + 1; + zpl_f32 dh01 = -6 * t2 + 6 * t; + zpl_f32 dh11 = 3 * t2 - 2 * t; + + d->x = dh00 * a.x + dh10 * v0.x + dh01 * b.x + dh11 * v1.x; + d->y = dh00 * a.y + dh10 * v0.y + dh01 * b.y + dh11 * v1.y; + d->z = dh00 * a.z + dh10 * v0.z + dh01 * b.z + dh11 * v1.z; +} + +void zpl_quat_lerp(zpl_quat *d, zpl_quat a, zpl_quat b, zpl_f32 t) { zpl_vec4_lerp(&d->xyzw, a.xyzw, b.xyzw, t); } +void zpl_quat_nlerp(zpl_quat *d, zpl_quat a, zpl_quat b, zpl_f32 t) { + zpl_quat_lerp(d, a, b, t); + zpl_quat_norm(d, *d); +} + +void zpl_quat_slerp(zpl_quat *d, zpl_quat a, zpl_quat b, zpl_f32 t) { + zpl_quat x, y, z; + zpl_f32 cos_theta, angle; + zpl_f32 s1, s0, is; + + z = b; + cos_theta = zpl_quat_dot(a, b); + + if (cos_theta < 0.0f) { + z = zpl_quatf(-b.x, -b.y, -b.z, -b.w); + cos_theta = -cos_theta; + } + + if (cos_theta > 1.0f) { + /* NOTE: Use lerp not nlerp as it's not a real angle or they are not normalized */ + zpl_quat_lerp(d, a, b, t); + } + + angle = zpl_arccos(cos_theta); + + s1 = zpl_sin((1.0f - t) * angle); + s0 = zpl_sin(t * angle); + is = 1.0f / zpl_sin(angle); + zpl_quat_mulf(&x, a, s1); + zpl_quat_mulf(&y, z, s0); + zpl_quat_add(d, x, y); + zpl_quat_muleqf(d, is); +} + +void zpl_quat_slerp_approx(zpl_quat *d, zpl_quat a, zpl_quat b, zpl_f32 t) { + /* NOTE: Derived by taylor expanding the geometric interpolation equation + * Even works okay for nearly anti-parallel versors!!! + */ + /* NOTE: Extra interations cannot be used as they require angle^4 which is not worth it to approximate */ + zpl_f32 tp = t + (1.0f - zpl_quat_dot(a, b)) / 3.0f * t * (-2.0f * t * t + 3.0f * t - 1.0f); + zpl_quat_nlerp(d, a, b, tp); +} + +void zpl_quat_nquad(zpl_quat *d, zpl_quat p, zpl_quat a, zpl_quat b, zpl_quat q, zpl_f32 t) { + zpl_quat x, y; + zpl_quat_nlerp(&x, p, q, t); + zpl_quat_nlerp(&y, a, b, t); + zpl_quat_nlerp(d, x, y, 2.0f * t * (1.0f - t)); +} + +void zpl_quat_squad(zpl_quat *d, zpl_quat p, zpl_quat a, zpl_quat b, zpl_quat q, zpl_f32 t) { + zpl_quat x, y; + zpl_quat_slerp(&x, p, q, t); + zpl_quat_slerp(&y, a, b, t); + zpl_quat_slerp(d, x, y, 2.0f * t * (1.0f - t)); +} + +void zpl_quat_squad_approx(zpl_quat *d, zpl_quat p, zpl_quat a, zpl_quat b, zpl_quat q, zpl_f32 t) { + zpl_quat x, y; + zpl_quat_slerp_approx(&x, p, q, t); + zpl_quat_slerp_approx(&y, a, b, t); + zpl_quat_slerp_approx(d, x, y, 2.0f * t * (1.0f - t)); +} + +zpl_rect2 zpl_rect2f(zpl_vec2 pos, zpl_vec2 dim) { + zpl_rect2 r; + r.pos = pos; + r.dim = dim; + return r; +} + +zpl_rect3 zpl_rect3f(zpl_vec3 pos, zpl_vec3 dim) { + zpl_rect3 r; + r.pos = pos; + r.dim = dim; + return r; +} + +int zpl_rect2_contains(zpl_rect2 a, zpl_f32 x, zpl_f32 y) { + zpl_f32 min_x = zpl_min(a.pos.x, a.pos.x + a.dim.x); + zpl_f32 max_x = zpl_max(a.pos.x, a.pos.x + a.dim.x); + zpl_f32 min_y = zpl_min(a.pos.y, a.pos.y + a.dim.y); + zpl_f32 max_y = zpl_max(a.pos.y, a.pos.y + a.dim.y); + int result = (x >= min_x) & (x < max_x) & (y >= min_y) & (y < max_y); + return result; +} + +int zpl_rect2_contains_vec2(zpl_rect2 a, zpl_vec2 p) { return zpl_rect2_contains(a, p.x, p.y); } + +int zpl_rect2_intersects(zpl_rect2 a, zpl_rect2 b) { + zpl_rect2 r = { 0 }; + return zpl_rect2_intersection_result(a, b, &r); +} + +int zpl_rect2_intersection_result(zpl_rect2 a, zpl_rect2 b, zpl_rect2 *intersection) { + zpl_f32 a_min_x = zpl_min(a.pos.x, a.pos.x + a.dim.x); + zpl_f32 a_max_x = zpl_max(a.pos.x, a.pos.x + a.dim.x); + zpl_f32 a_min_y = zpl_min(a.pos.y, a.pos.y + a.dim.y); + zpl_f32 a_max_y = zpl_max(a.pos.y, a.pos.y + a.dim.y); + + zpl_f32 b_min_x = zpl_min(b.pos.x, b.pos.x + b.dim.x); + zpl_f32 b_max_x = zpl_max(b.pos.x, b.pos.x + b.dim.x); + zpl_f32 b_min_y = zpl_min(b.pos.y, b.pos.y + b.dim.y); + zpl_f32 b_max_y = zpl_max(b.pos.y, b.pos.y + b.dim.y); + + zpl_f32 x0 = zpl_max(a_min_x, b_min_x); + zpl_f32 y0 = zpl_max(a_min_y, b_min_y); + zpl_f32 x1 = zpl_min(a_max_x, b_max_x); + zpl_f32 y1 = zpl_min(a_max_y, b_max_y); + + if ((x0 < x1) && (y0 < y1)) { + zpl_rect2 r = zpl_rect2f(zpl_vec2f(x0, y0), zpl_vec2f(x1 - x0, y1 - y0)); + *intersection = r; + return 1; + } else { + zpl_rect2 r = { 0 }; + *intersection = r; + return 0; + } +} + +ZPL_END_C_DECLS +#endif + +#if defined(ZPL_MODULE_JSON) +// file: source/json.c + +//////////////////////////////////////////////////////////////// +// +// JSON5 Parser +// +// + +#ifdef ZPL_EDITOR +#include +#endif + +#include /* needed for INFINITY and NAN */ + +ZPL_BEGIN_C_DECLS + +static ZPL_ALWAYS_INLINE zpl_b32 zpl__json_is_assign_char(char c) { return !!zpl_strchr(":=|", c); } +static ZPL_ALWAYS_INLINE zpl_b32 zpl__json_is_delim_char(char c) { return !!zpl_strchr(",|\n", c); } + +char *zpl__json_parse_object(zpl_json_object *obj, char *base, zpl_allocator a, zpl_u8 *err_code); +char *zpl__json_parse_array(zpl_json_object *obj, char *base, zpl_allocator a, zpl_u8 *err_code); +char *zpl__json_parse_value(zpl_json_object *obj, char *base, zpl_allocator a, zpl_u8 *err_code); + +#define jx(x) !zpl_char_is_hex_digit(str[x]) +ZPL_ALWAYS_INLINE zpl_b32 zpl__json_validate_name(char *str, char *err) { + while (*str) { + if ((str[0] == '\\' && !zpl_char_is_control(str[1])) && + (str[0] == '\\' && jx(1) && jx(2) && jx(3) && jx(4))) { + *err = *str; + return false; } - - void zpl_vec3_dcslerp(zpl_vec3 *d, zpl_vec3 a, zpl_vec3 v0, zpl_vec3 b, zpl_vec3 v1, zpl_f32 t) { - zpl_f32 t2 = t * t; - - zpl_f32 dh00 = 6 * t2 - 6 * t; - zpl_f32 dh10 = 3 * t2 - 4 * t + 1; - zpl_f32 dh01 = -6 * t2 + 6 * t; - zpl_f32 dh11 = 3 * t2 - 2 * t; - - d->x = dh00 * a.x + dh10 * v0.x + dh01 * b.x + dh11 * v1.x; - d->y = dh00 * a.y + dh10 * v0.y + dh01 * b.y + dh11 * v1.y; - d->z = dh00 * a.z + dh10 * v0.z + dh01 * b.z + dh11 * v1.z; - } - - void zpl_quat_lerp(zpl_quat *d, zpl_quat a, zpl_quat b, zpl_f32 t) { zpl_vec4_lerp(&d->xyzw, a.xyzw, b.xyzw, t); } - void zpl_quat_nlerp(zpl_quat *d, zpl_quat a, zpl_quat b, zpl_f32 t) { - zpl_quat_lerp(d, a, b, t); - zpl_quat_norm(d, *d); - } - - void zpl_quat_slerp(zpl_quat *d, zpl_quat a, zpl_quat b, zpl_f32 t) { - zpl_quat x, y, z; - zpl_f32 cos_theta, angle; - zpl_f32 s1, s0, is; - - z = b; - cos_theta = zpl_quat_dot(a, b); - - if (cos_theta < 0.0f) { - z = zpl_quatf(-b.x, -b.y, -b.z, -b.w); - cos_theta = -cos_theta; - } - - if (cos_theta > 1.0f) { - /* NOTE: Use lerp not nlerp as it's not a real angle or they are not normalized */ - zpl_quat_lerp(d, a, b, t); - } - - angle = zpl_arccos(cos_theta); - - s1 = zpl_sin((1.0f - t) * angle); - s0 = zpl_sin(t * angle); - is = 1.0f / zpl_sin(angle); - zpl_quat_mulf(&x, a, s1); - zpl_quat_mulf(&y, z, s0); - zpl_quat_add(d, x, y); - zpl_quat_muleqf(d, is); - } - - void zpl_quat_slerp_approx(zpl_quat *d, zpl_quat a, zpl_quat b, zpl_f32 t) { - /* NOTE: Derived by taylor expanding the geometric interpolation equation - * Even works okay for nearly anti-parallel versors!!! - */ - /* NOTE: Extra interations cannot be used as they require angle^4 which is not worth it to approximate */ - zpl_f32 tp = t + (1.0f - zpl_quat_dot(a, b)) / 3.0f * t * (-2.0f * t * t + 3.0f * t - 1.0f); - zpl_quat_nlerp(d, a, b, tp); - } - - void zpl_quat_nquad(zpl_quat *d, zpl_quat p, zpl_quat a, zpl_quat b, zpl_quat q, zpl_f32 t) { - zpl_quat x, y; - zpl_quat_nlerp(&x, p, q, t); - zpl_quat_nlerp(&y, a, b, t); - zpl_quat_nlerp(d, x, y, 2.0f * t * (1.0f - t)); - } - - void zpl_quat_squad(zpl_quat *d, zpl_quat p, zpl_quat a, zpl_quat b, zpl_quat q, zpl_f32 t) { - zpl_quat x, y; - zpl_quat_slerp(&x, p, q, t); - zpl_quat_slerp(&y, a, b, t); - zpl_quat_slerp(d, x, y, 2.0f * t * (1.0f - t)); - } - - void zpl_quat_squad_approx(zpl_quat *d, zpl_quat p, zpl_quat a, zpl_quat b, zpl_quat q, zpl_f32 t) { - zpl_quat x, y; - zpl_quat_slerp_approx(&x, p, q, t); - zpl_quat_slerp_approx(&y, a, b, t); - zpl_quat_slerp_approx(d, x, y, 2.0f * t * (1.0f - t)); - } - - zpl_rect2 zpl_rect2f(zpl_vec2 pos, zpl_vec2 dim) { - zpl_rect2 r; - r.pos = pos; - r.dim = dim; - return r; - } - - zpl_rect3 zpl_rect3f(zpl_vec3 pos, zpl_vec3 dim) { - zpl_rect3 r; - r.pos = pos; - r.dim = dim; - return r; - } - - int zpl_rect2_contains(zpl_rect2 a, zpl_f32 x, zpl_f32 y) { - zpl_f32 min_x = zpl_min(a.pos.x, a.pos.x + a.dim.x); - zpl_f32 max_x = zpl_max(a.pos.x, a.pos.x + a.dim.x); - zpl_f32 min_y = zpl_min(a.pos.y, a.pos.y + a.dim.y); - zpl_f32 max_y = zpl_max(a.pos.y, a.pos.y + a.dim.y); - int result = (x >= min_x) & (x < max_x) & (y >= min_y) & (y < max_y); - return result; - } - - int zpl_rect2_contains_vec2(zpl_rect2 a, zpl_vec2 p) { return zpl_rect2_contains(a, p.x, p.y); } - - int zpl_rect2_intersects(zpl_rect2 a, zpl_rect2 b) { - zpl_rect2 r = { 0 }; - return zpl_rect2_intersection_result(a, b, &r); - } - - int zpl_rect2_intersection_result(zpl_rect2 a, zpl_rect2 b, zpl_rect2 *intersection) { - zpl_f32 a_min_x = zpl_min(a.pos.x, a.pos.x + a.dim.x); - zpl_f32 a_max_x = zpl_max(a.pos.x, a.pos.x + a.dim.x); - zpl_f32 a_min_y = zpl_min(a.pos.y, a.pos.y + a.dim.y); - zpl_f32 a_max_y = zpl_max(a.pos.y, a.pos.y + a.dim.y); - - zpl_f32 b_min_x = zpl_min(b.pos.x, b.pos.x + b.dim.x); - zpl_f32 b_max_x = zpl_max(b.pos.x, b.pos.x + b.dim.x); - zpl_f32 b_min_y = zpl_min(b.pos.y, b.pos.y + b.dim.y); - zpl_f32 b_max_y = zpl_max(b.pos.y, b.pos.y + b.dim.y); - - zpl_f32 x0 = zpl_max(a_min_x, b_min_x); - zpl_f32 y0 = zpl_max(a_min_y, b_min_y); - zpl_f32 x1 = zpl_min(a_max_x, b_max_x); - zpl_f32 y1 = zpl_min(a_max_y, b_max_y); - - if ((x0 < x1) && (y0 < y1)) { - zpl_rect2 r = zpl_rect2f(zpl_vec2f(x0, y0), zpl_vec2f(x1 - x0, y1 - y0)); - *intersection = r; - return 1; - } else { - zpl_rect2 r = { 0 }; - *intersection = r; - return 0; - } - } - - ZPL_END_C_DECLS - #endif - - #if defined(ZPL_MODULE_JSON) - // file: source/json.c - - //////////////////////////////////////////////////////////////// - // - // JSON5 Parser - // - // - - #ifdef ZPL_EDITOR - #include - #endif - - #include /* needed for INFINITY and NAN */ - - ZPL_BEGIN_C_DECLS - - static ZPL_ALWAYS_INLINE zpl_b32 zpl__json_is_assign_char(char c) { return !!zpl_strchr(":=|", c); } - static ZPL_ALWAYS_INLINE zpl_b32 zpl__json_is_delim_char(char c) { return !!zpl_strchr(",|\n", c); } - - char *zpl__json_parse_object(zpl_json_object *obj, char *base, zpl_allocator a, zpl_u8 *err_code); - char *zpl__json_parse_array(zpl_json_object *obj, char *base, zpl_allocator a, zpl_u8 *err_code); - char *zpl__json_parse_value(zpl_json_object *obj, char *base, zpl_allocator a, zpl_u8 *err_code); - - #define jx(x) !zpl_char_is_hex_digit(str[x]) - ZPL_ALWAYS_INLINE zpl_b32 zpl__json_validate_name(char *str, char *err) { - while (*str) { - if ((str[0] == '\\' && !zpl_char_is_control(str[1])) && - (str[0] == '\\' && jx(1) && jx(2) && jx(3) && jx(4))) { - *err = *str; - return false; - } - - ++str; - } - - return true; - } - #undef jx - - - void zpl_json_parse(zpl_json_object *root, zpl_usize len, char *source, zpl_allocator a, zpl_b32 handle_comments, - zpl_u8 *err_code) { - - if (!root || !source) - { - ZPL_JSON_ASSERT; - if (err_code) *err_code = ZPL_JSON_ERROR_OBJECT_OR_SOURCE_WAS_NULL; - return; - } - - zpl_unused(len); - - char *dest = (char *)source; - - if (handle_comments) { - zpl_b32 is_lit = false; - char lit_c = '\0'; - char *p = dest; - char *b = dest; - zpl_isize l = 0; - - while (*p) { - if (!is_lit) { - if ((*p == '"' || *p == '\'')) { - lit_c = *p; - is_lit = true; - ++p; - continue; - } - } else { - if (*p == '\\' && *(p + 1) && *(p + 1) == lit_c) { - p += 2; - continue; - } else if (*p == lit_c) { - is_lit = false; - ++p; - continue; - } - } - - if (!is_lit) { - // NOTE(ZaKlaus): block comment - if (p[0] == '/' && p[1] == '*') { - b = p; - l = 2; - p += 2; - - while (p[0] != '*' && p[1] != '/') { - ++p; - ++l; - } - p += 2; - l += 2; - zpl_memset(b, ' ', l); - } - - // NOTE(ZaKlaus): inline comment - if (p[0] == '/' && p[1] == '/') { - b = p; - l = 2; - p += 2; - - while (p[0] != '\n') { - ++p; - ++l; - } - ++l; - zpl_memset(b, ' ', l); - } - } - - ++p; - } - } - - if (err_code) *err_code = ZPL_JSON_ERROR_NONE; - zpl_json_object root_ = { 0 }; - - dest = zpl_str_trim(dest, false); - - zpl_b32 starts_with_bracket = false; - - if (*dest != '{' && *dest != '[') { root_.cfg_mode = true; } - if (*dest == '[') { starts_with_bracket = true; } - - char *endp = NULL; - - if (!starts_with_bracket) - endp = zpl__json_parse_object(&root_, dest, a, err_code); - else - endp = zpl__json_parse_array(&root_, (dest+1), a, err_code); - - if (!root_.cfg_mode && endp == NULL) { - if (err_code) *err_code = ZPL_JSON_ERROR_INVALID_VALUE; - } - - // Replace root node with its child if the JSON document is an array. - if (starts_with_bracket && root_.type != ZPL_JSON_TYPE_ARRAY) { - zpl_json_object *replace = &root_; - *replace = root_.nodes[0]; - } - - *root = root_; - } - - #define zpl___ind(x) \ - for (int i = 0; i < x; ++i) zpl_fprintf(f, " "); - - void zpl__json_write_value(zpl_file *f, zpl_json_object *o, zpl_json_object *t, zpl_isize indent, zpl_b32 is_inline, zpl_b32 is_last); - - void zpl_json_write(zpl_file *f, zpl_json_object *o, zpl_isize indent) { - if (!o) - return; - - zpl___ind(indent - 4); - if (!o->cfg_mode) - zpl_fprintf(f, "{\n"); - else { - indent -= 4; - } - - if (o->nodes) - { - zpl_isize cnt = zpl_array_count(o->nodes); - - for (int i = 0; i < cnt; ++i) { - if (i < cnt - 1) { - zpl__json_write_value(f, o->nodes + i, o, indent, false, false); - } else { - zpl__json_write_value(f, o->nodes + i, o, indent, false, true); - } - } - } - - zpl___ind(indent); - - if (indent > 0) { - zpl_fprintf(f, "}"); - } else { - if (!o->cfg_mode) zpl_fprintf(f, "}\n"); - } - } - - zpl_string zpl_json_write_string(zpl_allocator a, zpl_json_object *obj, zpl_isize indent) { - zpl_file tmp; - zpl_file_stream_new(&tmp, a); - zpl_json_write(&tmp, obj, indent); - zpl_file_seek(&tmp, 0); - zpl_i64 fsize = zpl_file_size(&tmp)-1; - zpl_string output = zpl_string_make_reserve(a, fsize+1); - zpl_file_read(&tmp, output, fsize); - zpl_file_close(&tmp); - return output; - } - - void zpl__json_write_value(zpl_file *f, zpl_json_object *o, zpl_json_object *t, zpl_isize indent, zpl_b32 is_inline, zpl_b32 is_last) { - zpl_json_object *node = o; - indent += 4; - - if (!is_inline) { - zpl___ind(indent); - switch (node->name_style) { - case ZPL_JSON_NAME_STYLE_DOUBLE_QUOTE: { - zpl_fprintf(f, "\"%s\"", node->name); - } break; - - case ZPL_JSON_NAME_STYLE_SINGLE_QUOTE: { - zpl_fprintf(f, "\'%s\'", node->name); - } break; - - case ZPL_JSON_NAME_STYLE_NO_QUOTES: { - zpl_fprintf(f, "%s", node->name); - } break; - } - - if (o->assign_style == ZPL_JSON_ASSIGN_STYLE_COLON) - zpl_fprintf(f, ": "); - else { - if (o->name_style != ZPL_JSON_NAME_STYLE_NO_QUOTES) - zpl___ind(1); - - if (o->assign_style == ZPL_JSON_ASSIGN_STYLE_EQUALS) - zpl_fprintf(f, "= "); - else if (o->assign_style == ZPL_JSON_ASSIGN_STYLE_LINE) - zpl_fprintf(f, "| "); - } - - } - - switch (node->type) { - case ZPL_JSON_TYPE_STRING: { - zpl_fprintf(f, "\"%s\"", node->string); - } break; - - case ZPL_JSON_TYPE_MULTISTRING: { - zpl_fprintf(f, "`%s`", node->string); - } break; - - case ZPL_JSON_TYPE_ARRAY: { - zpl_fprintf(f, "["); - zpl_isize elemn = zpl_array_count(node->nodes); - for (int j = 0; j < elemn; ++j) { - if ((node->nodes + j)->type == ZPL_JSON_TYPE_OBJECT || (node->nodes + j)->type == ZPL_JSON_TYPE_ARRAY) { - zpl__json_write_value(f, node->nodes + j, o, 0, true, true); - } else { - zpl__json_write_value(f, node->nodes + j, o, -4, true, true); - } - - if (j < elemn - 1) { zpl_fprintf(f, ", "); } - } - zpl_fprintf(f, "]"); - } break; - - case ZPL_JSON_TYPE_INTEGER: { - if (node->props == ZPL_JSON_PROPS_IS_HEX) { - zpl_fprintf(f, "0x%llx", (long long)node->integer); - } else { - zpl_fprintf(f, "%lld", (long long)node->integer); - } - } break; - - case ZPL_JSON_TYPE_REAL: { - if (node->props == ZPL_JSON_PROPS_NAN) { - zpl_fprintf(f, "NaN"); - } else if (node->props == ZPL_JSON_PROPS_NAN_NEG) { - zpl_fprintf(f, "-NaN"); - } else if (node->props == ZPL_JSON_PROPS_INFINITY) { - zpl_fprintf(f, "Infinity"); - } else if (node->props == ZPL_JSON_PROPS_INFINITY_NEG) { - zpl_fprintf(f, "-Infinity"); - } else if (node->props == ZPL_JSON_PROPS_IS_EXP) { - zpl_fprintf(f, "%lld.%0*d%llde%c%lld", (long long)node->base, node->base2_offset, 0, (long long)node->base2, node->exp_neg ? '-' : '+', - (long long)node->exp); - } else if (node->props == ZPL_JSON_PROPS_IS_PARSED_REAL) { - if (!node->lead_digit) - zpl_fprintf(f, ".%0*d%lld", node->base2_offset, 0, (long long)node->base2); - else - zpl_fprintf(f, "%lld.%0*d%lld", (long long int)node->base2_offset, 0, (int)node->base, (long long)node->base2); - } else { - zpl_fprintf(f, "%f", node->real); - } - } break; - - case ZPL_JSON_TYPE_OBJECT: { - zpl_json_write(f, node, indent); - } break; - - case ZPL_JSON_TYPE_CONSTANT: { - if (node->constant == ZPL_JSON_CONST_TRUE) { - zpl_fprintf(f, "true"); - } else if (node->constant == ZPL_JSON_CONST_FALSE) { - zpl_fprintf(f, "false"); - } else if (node->constant == ZPL_JSON_CONST_NULL) { - zpl_fprintf(f, "null"); - } - } break; - } - - if (!is_inline) { - - if (o->delim_style != ZPL_JSON_DELIM_STYLE_COMMA) - { - if (o->delim_style == ZPL_JSON_DELIM_STYLE_NEWLINE) - zpl_fprintf(f, "\n"); - else if (o->delim_style == ZPL_JSON_DELIM_STYLE_LINE) - { - zpl___ind(o->delim_line_width); - zpl_fprintf(f, "|\n"); - } - } - else - { - if (!is_last) { - zpl_fprintf(f, ",\n"); - } else { - zpl_fprintf(f, "\n"); - } - } - } - } - #undef zpl___ind - - void zpl_json_free(zpl_json_object *obj) { - if ((obj->type == ZPL_JSON_TYPE_OBJECT || obj->type == ZPL_JSON_TYPE_ARRAY) && obj->nodes) { - for (zpl_isize i = 0; i < zpl_array_count(obj->nodes); ++i) { zpl_json_free(obj->nodes + i); } - - zpl_array_free(obj->nodes); - } - } - - char *zpl__json_parse_array(zpl_json_object *obj, char *base, zpl_allocator a, zpl_u8 *err_code) { - ZPL_ASSERT(obj && base); - char *p = base; - - obj->type = ZPL_JSON_TYPE_ARRAY; - zpl_array_init(obj->nodes, a); - obj->backing = a; - - while (*p) { - p = zpl_str_trim(p, false); - - if (p && *p == ']') { - return p; - } - - zpl_json_object elem = { 0 }; - elem.backing = a; - p = zpl__json_parse_value(&elem, p, a, err_code); - - if (err_code && *err_code != ZPL_JSON_ERROR_NONE) { return NULL; } - - zpl_array_append(obj->nodes, elem); - - p = zpl_str_trim(p, false); - - if (*p == ',') { + + ++str; + } + + return true; +} +#undef jx + + +void zpl_json_parse(zpl_json_object *root, zpl_usize len, char *source, zpl_allocator a, zpl_b32 handle_comments, + zpl_u8 *err_code) { + + if (!root || !source) + { + ZPL_JSON_ASSERT; + if (err_code) *err_code = ZPL_JSON_ERROR_OBJECT_OR_SOURCE_WAS_NULL; + return; + } + + zpl_unused(len); + + char *dest = (char *)source; + + if (handle_comments) { + zpl_b32 is_lit = false; + char lit_c = '\0'; + char *p = dest; + char *b = dest; + zpl_isize l = 0; + + while (*p) { + if (!is_lit) { + if ((*p == '"' || *p == '\'')) { + lit_c = *p; + is_lit = true; + ++p; + continue; + } + } else { + if (*p == '\\' && *(p + 1) && *(p + 1) == lit_c) { + p += 2; + continue; + } else if (*p == lit_c) { + is_lit = false; ++p; continue; - } else { - if (*p != ']') { - if (err_code) { *err_code = ZPL_JSON_ERROR_INVALID_VALUE; } - } - return p; } } + + if (!is_lit) { + // NOTE(ZaKlaus): block comment + if (p[0] == '/' && p[1] == '*') { + b = p; + l = 2; + p += 2; + + while (p[0] != '*' && p[1] != '/') { + ++p; + ++l; + } + p += 2; + l += 2; + zpl_memset(b, ' ', l); + } + + // NOTE(ZaKlaus): inline comment + if (p[0] == '/' && p[1] == '/') { + b = p; + l = 2; + p += 2; + + while (p[0] != '\n') { + ++p; + ++l; + } + ++l; + zpl_memset(b, ' ', l); + } + } + + ++p; + } + } + + if (err_code) *err_code = ZPL_JSON_ERROR_NONE; + zpl_json_object root_ = { 0 }; + + dest = zpl_str_trim(dest, false); + + zpl_b32 starts_with_bracket = false; + + if (*dest != '{' && *dest != '[') { root_.cfg_mode = true; } + if (*dest == '[') { starts_with_bracket = true; } + + char *endp = NULL; + + if (!starts_with_bracket) + endp = zpl__json_parse_object(&root_, dest, a, err_code); + else + endp = zpl__json_parse_array(&root_, (dest+1), a, err_code); + + if (!root_.cfg_mode && endp == NULL) { + if (err_code) *err_code = ZPL_JSON_ERROR_INVALID_VALUE; + } + + // Replace root node with its child if the JSON document is an array. + if (starts_with_bracket && root_.type != ZPL_JSON_TYPE_ARRAY) { + zpl_json_object *replace = &root_; + *replace = root_.nodes[0]; + } + + *root = root_; +} - if (err_code) { *err_code = ZPL_JSON_ERROR_INVALID_VALUE; } +#define zpl___ind(x) \ +for (int i = 0; i < x; ++i) zpl_fprintf(f, " "); + +void zpl__json_write_value(zpl_file *f, zpl_json_object *o, zpl_json_object *t, zpl_isize indent, zpl_b32 is_inline, zpl_b32 is_last); + +void zpl_json_write(zpl_file *f, zpl_json_object *o, zpl_isize indent) { + if (!o) + return; + + zpl___ind(indent - 4); + if (!o->cfg_mode) + zpl_fprintf(f, "{\n"); + else { + indent -= 4; + } + + if (o->nodes) + { + zpl_isize cnt = zpl_array_count(o->nodes); + + for (int i = 0; i < cnt; ++i) { + if (i < cnt - 1) { + zpl__json_write_value(f, o->nodes + i, o, indent, false, false); + } else { + zpl__json_write_value(f, o->nodes + i, o, indent, false, true); + } + } + } + + zpl___ind(indent); + + if (indent > 0) { + zpl_fprintf(f, "}"); + } else { + if (!o->cfg_mode) zpl_fprintf(f, "}\n"); + } +} + +zpl_string zpl_json_write_string(zpl_allocator a, zpl_json_object *obj, zpl_isize indent) { + zpl_file tmp; + zpl_file_stream_new(&tmp, a); + zpl_json_write(&tmp, obj, indent); + zpl_file_seek(&tmp, 0); + zpl_i64 fsize = zpl_file_size(&tmp)-1; + zpl_string output = zpl_string_make_reserve(a, fsize+1); + zpl_file_read(&tmp, output, fsize); + zpl_file_close(&tmp); + return output; +} + +void zpl__json_write_value(zpl_file *f, zpl_json_object *o, zpl_json_object *t, zpl_isize indent, zpl_b32 is_inline, zpl_b32 is_last) { + zpl_json_object *node = o; + indent += 4; + + if (!is_inline) { + zpl___ind(indent); + switch (node->name_style) { + case ZPL_JSON_NAME_STYLE_DOUBLE_QUOTE: { + zpl_fprintf(f, "\"%s\"", node->name); + } break; + + case ZPL_JSON_NAME_STYLE_SINGLE_QUOTE: { + zpl_fprintf(f, "\'%s\'", node->name); + } break; + + case ZPL_JSON_NAME_STYLE_NO_QUOTES: { + zpl_fprintf(f, "%s", node->name); + } break; + } + + if (o->assign_style == ZPL_JSON_ASSIGN_STYLE_COLON) + zpl_fprintf(f, ": "); + else { + if (o->name_style != ZPL_JSON_NAME_STYLE_NO_QUOTES) + zpl___ind(1); + + if (o->assign_style == ZPL_JSON_ASSIGN_STYLE_EQUALS) + zpl_fprintf(f, "= "); + else if (o->assign_style == ZPL_JSON_ASSIGN_STYLE_LINE) + zpl_fprintf(f, "| "); + } + + } + + switch (node->type) { + case ZPL_JSON_TYPE_STRING: { + zpl_fprintf(f, "\"%s\"", node->string); + } break; + + case ZPL_JSON_TYPE_MULTISTRING: { + zpl_fprintf(f, "`%s`", node->string); + } break; + + case ZPL_JSON_TYPE_ARRAY: { + zpl_fprintf(f, "["); + zpl_isize elemn = zpl_array_count(node->nodes); + for (int j = 0; j < elemn; ++j) { + if ((node->nodes + j)->type == ZPL_JSON_TYPE_OBJECT || (node->nodes + j)->type == ZPL_JSON_TYPE_ARRAY) { + zpl__json_write_value(f, node->nodes + j, o, 0, true, true); + } else { + zpl__json_write_value(f, node->nodes + j, o, -4, true, true); + } + + if (j < elemn - 1) { zpl_fprintf(f, ", "); } + } + zpl_fprintf(f, "]"); + } break; + + case ZPL_JSON_TYPE_INTEGER: { + if (node->props == ZPL_JSON_PROPS_IS_HEX) { + zpl_fprintf(f, "0x%llx", (long long)node->integer); + } else { + zpl_fprintf(f, "%lld", (long long)node->integer); + } + } break; + + case ZPL_JSON_TYPE_REAL: { + if (node->props == ZPL_JSON_PROPS_NAN) { + zpl_fprintf(f, "NaN"); + } else if (node->props == ZPL_JSON_PROPS_NAN_NEG) { + zpl_fprintf(f, "-NaN"); + } else if (node->props == ZPL_JSON_PROPS_INFINITY) { + zpl_fprintf(f, "Infinity"); + } else if (node->props == ZPL_JSON_PROPS_INFINITY_NEG) { + zpl_fprintf(f, "-Infinity"); + } else if (node->props == ZPL_JSON_PROPS_IS_EXP) { + zpl_fprintf(f, "%lld.%0*d%llde%c%lld", (long long)node->base, node->base2_offset, 0, (long long)node->base2, node->exp_neg ? '-' : '+', + (long long)node->exp); + } else if (node->props == ZPL_JSON_PROPS_IS_PARSED_REAL) { + if (!node->lead_digit) + zpl_fprintf(f, ".%0*d%lld", node->base2_offset, 0, (long long)node->base2); + else + zpl_fprintf(f, "%lld.%0*d%lld", (long long int)node->base2_offset, 0, (int)node->base, (long long)node->base2); + } else { + zpl_fprintf(f, "%f", node->real); + } + } break; + + case ZPL_JSON_TYPE_OBJECT: { + zpl_json_write(f, node, indent); + } break; + + case ZPL_JSON_TYPE_CONSTANT: { + if (node->constant == ZPL_JSON_CONST_TRUE) { + zpl_fprintf(f, "true"); + } else if (node->constant == ZPL_JSON_CONST_FALSE) { + zpl_fprintf(f, "false"); + } else if (node->constant == ZPL_JSON_CONST_NULL) { + zpl_fprintf(f, "null"); + } + } break; + } + + if (!is_inline) { + + if (o->delim_style != ZPL_JSON_DELIM_STYLE_COMMA) + { + if (o->delim_style == ZPL_JSON_DELIM_STYLE_NEWLINE) + zpl_fprintf(f, "\n"); + else if (o->delim_style == ZPL_JSON_DELIM_STYLE_LINE) + { + zpl___ind(o->delim_line_width); + zpl_fprintf(f, "|\n"); + } + } + else + { + if (!is_last) { + zpl_fprintf(f, ",\n"); + } else { + zpl_fprintf(f, "\n"); + } + } + } +} +#undef zpl___ind + +void zpl_json_free(zpl_json_object *obj) { + if ((obj->type == ZPL_JSON_TYPE_OBJECT || obj->type == ZPL_JSON_TYPE_ARRAY) && obj->nodes) { + for (zpl_isize i = 0; i < zpl_array_count(obj->nodes); ++i) { zpl_json_free(obj->nodes + i); } + + zpl_array_free(obj->nodes); + } +} + +char *zpl__json_parse_array(zpl_json_object *obj, char *base, zpl_allocator a, zpl_u8 *err_code) { + ZPL_ASSERT(obj && base); + char *p = base; + + obj->type = ZPL_JSON_TYPE_ARRAY; + zpl_array_init(obj->nodes, a); + obj->backing = a; + + while (*p) { + p = zpl_str_trim(p, false); + + if (p && *p == ']') { return p; } + + zpl_json_object elem = { 0 }; + elem.backing = a; + p = zpl__json_parse_value(&elem, p, a, err_code); + + if (err_code && *err_code != ZPL_JSON_ERROR_NONE) { return NULL; } + + zpl_array_append(obj->nodes, elem); + + p = zpl_str_trim(p, false); + + if (*p == ',') { + ++p; + continue; + } else { + if (*p != ']') { + if (err_code) { *err_code = ZPL_JSON_ERROR_INVALID_VALUE; } + } + return p; + } + } + + if (err_code) { *err_code = ZPL_JSON_ERROR_INVALID_VALUE; } + return p; +} - char *zpl__json_parse_value(zpl_json_object *obj, char *base, zpl_allocator a, zpl_u8 *err_code) { - ZPL_ASSERT(obj && base); - char *p = base; - char *b = base; - char *e = base; - - if (*p == '"' || *p == '\'') { - char c = *p; - obj->type = ZPL_JSON_TYPE_STRING; - b = p + 1; - e = b; - obj->string = b; - - while (*e) { - if (*e == '\\' && *(e + 1) == c) { - e += 2; - continue; - } else if (*e == '\\' && (*(e + 1) == '\r' || *(e + 1) == '\n')) { - *e = ' '; - e++; - continue; - } else if (*e == c) { - break; - } - ++e; - } - - *e = '\0'; - p = e + 1; - } else if (*p == '`') { - obj->type = ZPL_JSON_TYPE_MULTISTRING; - b = p + 1; - e = b; - obj->string = b; - - while (*e) { - if (*e == '\\' && *(e + 1) == '`') { - e += 2; - continue; - } else if (*e == '`') { - break; - } - ++e; - } - - *e = '\0'; - p = e + 1; - } else if (zpl_char_is_alpha(*p) || (*p == '-' && !zpl_char_is_digit(*(p + 1)))) { - obj->type = ZPL_JSON_TYPE_CONSTANT; - - if (!zpl_strncmp(p, "true", 4)) { - obj->constant = ZPL_JSON_CONST_TRUE; - p += 4; - } else if (!zpl_strncmp(p, "false", 5)) { - obj->constant = ZPL_JSON_CONST_FALSE; - p += 5; - } else if (!zpl_strncmp(p, "null", 4)) { - obj->constant = ZPL_JSON_CONST_NULL; - p += 4; - } else if (!zpl_strncmp(p, "Infinity", 8)) { - obj->type = ZPL_JSON_TYPE_REAL; - obj->real = INFINITY; - obj->props = ZPL_JSON_PROPS_INFINITY; - p += 8; - } else if (!zpl_strncmp(p, "-Infinity", 9)) { - obj->type = ZPL_JSON_TYPE_REAL; - obj->real = -INFINITY; - obj->props = ZPL_JSON_PROPS_INFINITY_NEG; - p += 9; - } else if (!zpl_strncmp(p, "NaN", 3)) { - obj->type = ZPL_JSON_TYPE_REAL; - obj->real = NAN; - obj->props = ZPL_JSON_PROPS_NAN; - p += 3; - } else if (!zpl_strncmp(p, "-NaN", 4)) { - obj->type = ZPL_JSON_TYPE_REAL; - obj->real = -NAN; - obj->props = ZPL_JSON_PROPS_NAN_NEG; - p += 4; - } else { - ZPL_JSON_ASSERT; - if (err_code) *err_code = ZPL_JSON_ERROR_INVALID_VALUE; - return NULL; - } - } else if (zpl_char_is_digit(*p) || *p == '+' || *p == '-' || *p == '.') { - obj->type = ZPL_JSON_TYPE_INTEGER; +char *zpl__json_parse_value(zpl_json_object *obj, char *base, zpl_allocator a, zpl_u8 *err_code) { + ZPL_ASSERT(obj && base); + char *p = base; + char *b = base; + char *e = base; + + if (*p == '"' || *p == '\'') { + char c = *p; + obj->type = ZPL_JSON_TYPE_STRING; + b = p + 1; + e = b; + obj->string = b; + + while (*e) { + if (*e == '\\' && *(e + 1) == c) { + e += 2; + continue; + } else if (*e == '\\' && (*(e + 1) == '\r' || *(e + 1) == '\n')) { + *e = ' '; + e++; + continue; + } else if (*e == c) { + break; + } + ++e; + } + + *e = '\0'; + p = e + 1; + } else if (*p == '`') { + obj->type = ZPL_JSON_TYPE_MULTISTRING; + b = p + 1; + e = b; + obj->string = b; + + while (*e) { + if (*e == '\\' && *(e + 1) == '`') { + e += 2; + continue; + } else if (*e == '`') { + break; + } + ++e; + } + + *e = '\0'; + p = e + 1; + } else if (zpl_char_is_alpha(*p) || (*p == '-' && !zpl_char_is_digit(*(p + 1)))) { + obj->type = ZPL_JSON_TYPE_CONSTANT; + + if (!zpl_strncmp(p, "true", 4)) { + obj->constant = ZPL_JSON_CONST_TRUE; + p += 4; + } else if (!zpl_strncmp(p, "false", 5)) { + obj->constant = ZPL_JSON_CONST_FALSE; + p += 5; + } else if (!zpl_strncmp(p, "null", 4)) { + obj->constant = ZPL_JSON_CONST_NULL; + p += 4; + } else if (!zpl_strncmp(p, "Infinity", 8)) { + obj->type = ZPL_JSON_TYPE_REAL; + obj->real = INFINITY; + obj->props = ZPL_JSON_PROPS_INFINITY; + p += 8; + } else if (!zpl_strncmp(p, "-Infinity", 9)) { + obj->type = ZPL_JSON_TYPE_REAL; + obj->real = -INFINITY; + obj->props = ZPL_JSON_PROPS_INFINITY_NEG; + p += 9; + } else if (!zpl_strncmp(p, "NaN", 3)) { + obj->type = ZPL_JSON_TYPE_REAL; + obj->real = NAN; + obj->props = ZPL_JSON_PROPS_NAN; + p += 3; + } else if (!zpl_strncmp(p, "-NaN", 4)) { + obj->type = ZPL_JSON_TYPE_REAL; + obj->real = -NAN; + obj->props = ZPL_JSON_PROPS_NAN_NEG; + p += 4; + } else { + ZPL_JSON_ASSERT; + if (err_code) *err_code = ZPL_JSON_ERROR_INVALID_VALUE; + return NULL; + } + } else if (zpl_char_is_digit(*p) || *p == '+' || *p == '-' || *p == '.') { + obj->type = ZPL_JSON_TYPE_INTEGER; + + b = p; + e = b; + + zpl_isize ib = 0; + char buf[48] = { 0 }; + + if (*e == '+') + ++e; + else if (*e == '-') { + buf[ib++] = *e++; + } + + if (*e == '.') { + obj->type = ZPL_JSON_TYPE_REAL; + obj->props = ZPL_JSON_PROPS_IS_PARSED_REAL; + buf[ib++] = '0'; + obj->lead_digit = false; + + do { + buf[ib++] = *e; + } while (zpl_char_is_digit(*++e)); + } else { + if (*e == '0' && (*(e + 1) == 'x' || *(e + 1) == 'X')) { obj->props = ZPL_JSON_PROPS_IS_HEX; } + while (zpl_char_is_hex_digit(*e) || *e == 'x' || *e == 'X') { buf[ib++] = *e++; } + + if (*e == '.') { + obj->type = ZPL_JSON_TYPE_REAL; + obj->lead_digit = true; + zpl_u32 step = 0; + + do { + buf[ib++] = *e; + ++step; + } while (zpl_char_is_digit(*++e)); + + if (step < 2) { buf[ib++] = '0'; } + } + } + + zpl_i32 exp = 0; + zpl_f32 eb = 10; + char expbuf[6] = { 0 }; + zpl_isize expi = 0; + + if (*e == 'e' || *e == 'E') { + ++e; + if (*e == '+' || *e == '-' || zpl_char_is_digit(*e)) { + if (*e == '-') { eb = 0.1f; } + + if (!zpl_char_is_digit(*e)) { ++e; } + + while (zpl_char_is_digit(*e)) { expbuf[expi++] = *e++; } + } + + exp = (zpl_i32)zpl_str_to_i64(expbuf, NULL, 10); + } + + if (obj->type == ZPL_JSON_TYPE_INTEGER) { + obj->integer = zpl_str_to_i64(buf, 0, 0); + + while (exp-- > 0) { obj->integer *= (zpl_i64)eb; } + } else { + obj->real = zpl_str_to_f64(buf, 0); + + char *q = buf, *qp = q, *qp2 = q; + while (*qp != '.') ++qp; + *qp = '\0'; + qp2 = qp + 1; + char *qpOff = qp2; + while (*qpOff++ == '0') obj->base2_offset++; + + obj->base = (zpl_i32)zpl_str_to_i64(q, 0, 0); + obj->base2 = (zpl_i32)zpl_str_to_i64(qp2, 0, 0); + + if (exp) { + obj->exp = exp; + obj->exp_neg = !(eb == 10.f); + obj->props = ZPL_JSON_PROPS_IS_EXP; + } + + while (exp-- > 0) { obj->real *= eb; } + } + p = e; + } else if (*p == '[') { + p = zpl_str_trim(p + 1, false); + obj->type = ZPL_JSON_TYPE_ARRAY; + if (*p == ']') return (p+1); + p = zpl__json_parse_array(obj, p, a, err_code); + if (err_code && *err_code != ZPL_JSON_ERROR_NONE) { return NULL; } + + ++p; + } else if (*p == '{') { + p = zpl_str_trim(p + 1, false); + obj->type = ZPL_JSON_TYPE_OBJECT; + if (*p == '}') return (p+1); + p = zpl__json_parse_object(obj, p, a, err_code); + + if (err_code && *err_code != ZPL_JSON_ERROR_NONE) { return NULL; } + + ++p; + } + + return p; +} +char *zpl__json_parse_object(zpl_json_object *obj, char *base, zpl_allocator a, zpl_u8 *err_code) { + ZPL_ASSERT(obj && base); + char *p = base; + char *b = base; + char *e = base; + + zpl_array_init(obj->nodes, a); + obj->backing = a; + + p = zpl_str_trim(p, false); + zpl_b32 starts_with_brace = false; + zpl_b32 starts_with_bracket = false; + /**/ if (*p == '{') { ++p; starts_with_brace = true; obj->type = ZPL_JSON_TYPE_OBJECT; } + else if (*p == '[') { ++p; starts_with_bracket = true; obj->type = ZPL_JSON_TYPE_ARRAY; } + + while (*p) { + zpl_json_object node = { 0 }; + p = zpl_str_trim(p, false); + if (*p == '}' && starts_with_brace) return p; + if (*p == ']' && starts_with_bracket) return p; + + if (*p == ']' && starts_with_brace) { if (err_code) *err_code = ZPL_JSON_ERROR_INVALID_VALUE; return p; } + if (*p == '}' && starts_with_bracket) { if (err_code) *err_code = ZPL_JSON_ERROR_INVALID_VALUE; return p; } + + if (*p == '"' || *p == '\'') { + if (*p == '"') { + node.name_style = ZPL_JSON_NAME_STYLE_DOUBLE_QUOTE; + } else { + node.name_style = ZPL_JSON_NAME_STYLE_SINGLE_QUOTE; + } + + char c = *p; + b = ++p; + e = zpl_str_control_skip(b, c); + node.name = b; + *e = '\0'; + p = ++e; + p = zpl_str_trim(p, false); + if (!zpl__json_is_assign_char(*p)) { + ZPL_JSON_ASSERT; + if (err_code) *err_code = ZPL_JSON_ERROR_INVALID_NAME; + return NULL; + } + } + else { + if (*p == '[') { + starts_with_bracket = true; + if (node.name) *node.name = '\0'; + p = zpl__json_parse_value(&node, p, a, err_code); + goto l_parsed; + } + else if (zpl_char_is_alpha(*p) || *p == '_' || *p == '$') { b = p; e = b; - - zpl_isize ib = 0; - char buf[48] = { 0 }; - - if (*e == '+') + + do { ++e; - else if (*e == '-') { - buf[ib++] = *e++; - } - - if (*e == '.') { - obj->type = ZPL_JSON_TYPE_REAL; - obj->props = ZPL_JSON_PROPS_IS_PARSED_REAL; - buf[ib++] = '0'; - obj->lead_digit = false; - - do { - buf[ib++] = *e; - } while (zpl_char_is_digit(*++e)); - } else { - if (*e == '0' && (*(e + 1) == 'x' || *(e + 1) == 'X')) { obj->props = ZPL_JSON_PROPS_IS_HEX; } - while (zpl_char_is_hex_digit(*e) || *e == 'x' || *e == 'X') { buf[ib++] = *e++; } - - if (*e == '.') { - obj->type = ZPL_JSON_TYPE_REAL; - obj->lead_digit = true; - zpl_u32 step = 0; - - do { - buf[ib++] = *e; - ++step; - } while (zpl_char_is_digit(*++e)); - - if (step < 2) { buf[ib++] = '0'; } - } - } - - zpl_i32 exp = 0; - zpl_f32 eb = 10; - char expbuf[6] = { 0 }; - zpl_isize expi = 0; - - if (*e == 'e' || *e == 'E') { - ++e; - if (*e == '+' || *e == '-' || zpl_char_is_digit(*e)) { - if (*e == '-') { eb = 0.1f; } - - if (!zpl_char_is_digit(*e)) { ++e; } - - while (zpl_char_is_digit(*e)) { expbuf[expi++] = *e++; } - } - - exp = (zpl_i32)zpl_str_to_i64(expbuf, NULL, 10); - } - - if (obj->type == ZPL_JSON_TYPE_INTEGER) { - obj->integer = zpl_str_to_i64(buf, 0, 0); - - while (exp-- > 0) { obj->integer *= (zpl_i64)eb; } - } else { - obj->real = zpl_str_to_f64(buf, 0); - - char *q = buf, *qp = q, *qp2 = q; - while (*qp != '.') ++qp; - *qp = '\0'; - qp2 = qp + 1; - char *qpOff = qp2; - while (*qpOff++ == '0') obj->base2_offset++; - - obj->base = (zpl_i32)zpl_str_to_i64(q, 0, 0); - obj->base2 = (zpl_i32)zpl_str_to_i64(qp2, 0, 0); - - if (exp) { - obj->exp = exp; - obj->exp_neg = !(eb == 10.f); - obj->props = ZPL_JSON_PROPS_IS_EXP; - } - - while (exp-- > 0) { obj->real *= eb; } - } - p = e; - } else if (*p == '[') { - p = zpl_str_trim(p + 1, false); - obj->type = ZPL_JSON_TYPE_ARRAY; - if (*p == ']') return (p+1); - p = zpl__json_parse_array(obj, p, a, err_code); - if (err_code && *err_code != ZPL_JSON_ERROR_NONE) { return NULL; } - - ++p; - } else if (*p == '{') { - p = zpl_str_trim(p + 1, false); - obj->type = ZPL_JSON_TYPE_OBJECT; - if (*p == '}') return (p+1); - p = zpl__json_parse_object(obj, p, a, err_code); - - if (err_code && *err_code != ZPL_JSON_ERROR_NONE) { return NULL; } - - ++p; - } - - return p; - } - - char *zpl__json_parse_object(zpl_json_object *obj, char *base, zpl_allocator a, zpl_u8 *err_code) { - ZPL_ASSERT(obj && base); - char *p = base; - char *b = base; - char *e = base; - - zpl_array_init(obj->nodes, a); - obj->backing = a; - - p = zpl_str_trim(p, false); - zpl_b32 starts_with_brace = false; - zpl_b32 starts_with_bracket = false; - /**/ if (*p == '{') { ++p; starts_with_brace = true; obj->type = ZPL_JSON_TYPE_OBJECT; } - else if (*p == '[') { ++p; starts_with_bracket = true; obj->type = ZPL_JSON_TYPE_ARRAY; } - - while (*p) { - zpl_json_object node = { 0 }; - p = zpl_str_trim(p, false); - if (*p == '}' && starts_with_brace) return p; - if (*p == ']' && starts_with_bracket) return p; - - if (*p == ']' && starts_with_brace) { if (err_code) *err_code = ZPL_JSON_ERROR_INVALID_VALUE; return p; } - if (*p == '}' && starts_with_bracket) { if (err_code) *err_code = ZPL_JSON_ERROR_INVALID_VALUE; return p; } - - if (*p == '"' || *p == '\'') { - if (*p == '"') { - node.name_style = ZPL_JSON_NAME_STYLE_DOUBLE_QUOTE; - } else { - node.name_style = ZPL_JSON_NAME_STYLE_SINGLE_QUOTE; - } - - char c = *p; - b = ++p; - e = zpl_str_control_skip(b, c); - node.name = b; + } while (*e && (zpl_char_is_alphanumeric(*e) || *e == '_') && !zpl_char_is_space(*e) && !zpl__json_is_assign_char(*e)); + + if (zpl_char_is_space(*e)) { + // NOTE(zaklaus): We know this is where the node name ends, cut it here *e = '\0'; - p = ++e; - p = zpl_str_trim(p, false); - if (!zpl__json_is_assign_char(*p)) { - ZPL_JSON_ASSERT; - if (err_code) *err_code = ZPL_JSON_ERROR_INVALID_NAME; - return NULL; - } + ++e; + } + + if (zpl__json_is_assign_char(*e)) { + p = e; + + if (*e == '=') + node.assign_style = ZPL_JSON_ASSIGN_STYLE_EQUALS; + else if (*e == '|') + node.assign_style = ZPL_JSON_ASSIGN_STYLE_LINE; } else { - if (*p == '[') { - starts_with_bracket = true; - if (node.name) *node.name = '\0'; - p = zpl__json_parse_value(&node, p, a, err_code); - goto l_parsed; - } - else if (zpl_char_is_alpha(*p) || *p == '_' || *p == '$') { - b = p; - e = b; - - do { - ++e; - } while (*e && (zpl_char_is_alphanumeric(*e) || *e == '_') && !zpl_char_is_space(*e) && !zpl__json_is_assign_char(*e)); - - if (zpl_char_is_space(*e)) { - // NOTE(zaklaus): We know this is where the node name ends, cut it here - *e = '\0'; - ++e; - } - - if (zpl__json_is_assign_char(*e)) { - p = e; - + while (*e) { + if (*e && (!zpl_char_is_space(*e) || zpl__json_is_assign_char(*e))) + { if (*e == '=') node.assign_style = ZPL_JSON_ASSIGN_STYLE_EQUALS; else if (*e == '|') node.assign_style = ZPL_JSON_ASSIGN_STYLE_LINE; + + break; } - else { - while (*e) { - if (*e && (!zpl_char_is_space(*e) || zpl__json_is_assign_char(*e))) - { - if (*e == '=') - node.assign_style = ZPL_JSON_ASSIGN_STYLE_EQUALS; - else if (*e == '|') - node.assign_style = ZPL_JSON_ASSIGN_STYLE_LINE; - - break; - } - ++e; - } - - e = zpl_str_trim(e, false); - p = e; - - if (*p && !zpl__json_is_assign_char(*p)) { - ZPL_JSON_ASSERT; - if (err_code) *err_code = ZPL_JSON_ERROR_INVALID_NAME; - return NULL; - } - else - { - if (*p == '=') - node.assign_style = ZPL_JSON_ASSIGN_STYLE_EQUALS; - else if (*p == '|') - node.assign_style = ZPL_JSON_ASSIGN_STYLE_LINE; - } - } - - *e = '\0'; - node.name = b; - node.name_style = ZPL_JSON_NAME_STYLE_NO_QUOTES; + ++e; } - } - - char errc; - if (node.name && !zpl__json_validate_name(node.name, &errc)) { - ZPL_JSON_ASSERT; - if (err_code) *err_code = ZPL_JSON_ERROR_INVALID_NAME; - return NULL; - } - - p = zpl_str_trim(p + 1, false); - p = zpl__json_parse_value(&node, p, a, err_code); - node.backing = obj->backing; - - if (err_code && *err_code != ZPL_JSON_ERROR_NONE) { return NULL; } - - l_parsed: - - if (err_code && *err_code != ZPL_JSON_ERROR_NONE) { return NULL; } - - zpl_array_append(obj->nodes, node); - - char *wp = p; - p = zpl_str_trim(p, true); - zpl_u8 wl = cast(zpl_u8)(p-wp); - - if (zpl__json_is_delim_char(*p) || *p == '\0') { - zpl_json_object *n = zpl_array_end(obj->nodes); - - if (*p == '\n') - n->delim_style = ZPL_JSON_DELIM_STYLE_NEWLINE; - else if (*p == '|') { - n->delim_style = ZPL_JSON_DELIM_STYLE_LINE; - n->delim_line_width = wl; + + e = zpl_str_trim(e, false); + p = e; + + if (*p && !zpl__json_is_assign_char(*p)) { + ZPL_JSON_ASSERT; + if (err_code) *err_code = ZPL_JSON_ERROR_INVALID_NAME; + return NULL; } - else if (*p == '\0') { - return p; - } - - p = zpl_str_trim(p + 1, false); - if (*p == '\0' || *p == '}' || *p == ']') - return p; else - continue; - } else if (*p == '\0' || *p == '}' || *p == ']') { - if (starts_with_brace && *p != '}') { - if (err_code) *err_code = ZPL_JSON_ERROR_INVALID_VALUE; - return NULL; + if (*p == '=') + node.assign_style = ZPL_JSON_ASSIGN_STYLE_EQUALS; + else if (*p == '|') + node.assign_style = ZPL_JSON_ASSIGN_STYLE_LINE; } - - if (starts_with_bracket && *p != ']') - { - if (err_code) *err_code = ZPL_JSON_ERROR_INVALID_VALUE; - return NULL; - } - - return p; - } else { - ZPL_JSON_ASSERT; - if (err_code) *err_code = ZPL_JSON_ERROR_INVALID_VALUE; - return NULL; } + + *e = '\0'; + node.name = b; + node.name_style = ZPL_JSON_NAME_STYLE_NO_QUOTES; } - if (err_code) *err_code = ZPL_JSON_ERROR_INVALID_VALUE; - return p; } - - zpl_json_object *zpl_json_find(zpl_json_object *obj, char const *name, zpl_b32 deep_search) - { - if (obj->type != ZPL_JSON_TYPE_OBJECT) - { - return NULL; - } - - for (zpl_isize i = 0; i < zpl_array_count(obj->nodes); i++) - { - if (!zpl_strcmp(obj->nodes[i].name, name)) - { - return (obj->nodes + i); - } - } - - if (deep_search) - { - for (zpl_isize i = 0; i < zpl_array_count(obj->nodes); i++) - { - zpl_json_object *res = zpl_json_find(obj->nodes + i, name, deep_search); - - if (res != NULL) - return res; - } - } - + + char errc; + if (node.name && !zpl__json_validate_name(node.name, &errc)) { + ZPL_JSON_ASSERT; + if (err_code) *err_code = ZPL_JSON_ERROR_INVALID_NAME; return NULL; } - - void zpl_json_init_node(zpl_json_object *obj, zpl_allocator backing, char const *name, zpl_u8 type) - { - obj->name = (char *)name; - obj->type = type; - obj->backing = backing; - - if (type == ZPL_JSON_TYPE_ARRAY || type == ZPL_JSON_TYPE_OBJECT) + + p = zpl_str_trim(p + 1, false); + p = zpl__json_parse_value(&node, p, a, err_code); + node.backing = obj->backing; + + if (err_code && *err_code != ZPL_JSON_ERROR_NONE) { return NULL; } + + l_parsed: + + if (err_code && *err_code != ZPL_JSON_ERROR_NONE) { return NULL; } + + zpl_array_append(obj->nodes, node); + + char *wp = p; + p = zpl_str_trim(p, true); + zpl_u8 wl = cast(zpl_u8)(p-wp); + + if (zpl__json_is_delim_char(*p) || *p == '\0') { + zpl_json_object *n = zpl_array_end(obj->nodes); + + if (*p == '\n') + n->delim_style = ZPL_JSON_DELIM_STYLE_NEWLINE; + else if (*p == '|') { + n->delim_style = ZPL_JSON_DELIM_STYLE_LINE; + n->delim_line_width = wl; + } + else if (*p == '\0') { + return p; + } + + p = zpl_str_trim(p + 1, false); + if (*p == '\0' || *p == '}' || *p == ']') + return p; + else + continue; + } else if (*p == '\0' || *p == '}' || *p == ']') { + if (starts_with_brace && *p != '}') { - zpl_array_init(obj->nodes, backing); + if (err_code) *err_code = ZPL_JSON_ERROR_INVALID_VALUE; + return NULL; } - } - - zpl_json_object *zpl_json_add_at(zpl_json_object *obj, zpl_isize index, char const *name, zpl_u8 type) - { - if (!obj || (obj->type != ZPL_JSON_TYPE_OBJECT && obj->type != ZPL_JSON_TYPE_ARRAY)) + + if (starts_with_bracket && *p != ']') { + if (err_code) *err_code = ZPL_JSON_ERROR_INVALID_VALUE; return NULL; } - - if (!obj->nodes) - return NULL; - - if (index < 0 || index > zpl_array_count(obj->nodes)) - return NULL; - - zpl_json_object o = {0}; - zpl_json_init_node(&o, obj->backing, name, type); - - zpl_array_append_at(obj->nodes, o, index); - - return obj->nodes + index; + + return p; + } else { + ZPL_JSON_ASSERT; + if (err_code) *err_code = ZPL_JSON_ERROR_INVALID_VALUE; + return NULL; } + } + if (err_code) *err_code = ZPL_JSON_ERROR_INVALID_VALUE; + return p; +} - zpl_json_object *zpl_json_add(zpl_json_object *obj, char const *name, zpl_u8 type) +zpl_json_object *zpl_json_find(zpl_json_object *obj, char const *name, zpl_b32 deep_search) +{ + if (obj->type != ZPL_JSON_TYPE_OBJECT) + { + return NULL; + } + + for (zpl_isize i = 0; i < zpl_array_count(obj->nodes); i++) + { + if (!zpl_strcmp(obj->nodes[i].name, name)) { - if (!obj || (obj->type != ZPL_JSON_TYPE_OBJECT && obj->type != ZPL_JSON_TYPE_ARRAY)) - { - return NULL; - } - - if (!obj->nodes) - return NULL; - - return zpl_json_add_at(obj, zpl_array_count(obj->nodes), name, type); + return (obj->nodes + i); } - - ZPL_END_C_DECLS - #endif - - #if defined(ZPL_MODULE_THREADING) - // file: source/threading/fence.c - - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - #if defined(_MSC_VER) - /* Microsoft C/C++-compatible compiler */ - #include - #elif defined(__GNUC__) && (defined(__x86_64__) || defined(__i386__)) - /* GCC-compatible compiler, targeting x86/x86-64 */ - #include - #elif defined(__GNUC__) && defined(__ARM_NEON__) - /* GCC-compatible compiler, targeting ARM with NEON */ - #include - #elif defined(__GNUC__) && defined(__IWMMXT__) - /* GCC-compatible compiler, targeting ARM with WMMX */ - #include - #elif (defined(__GNUC__) || defined(__xlC__)) && (defined(__VEC__) || defined(__ALTIVEC__)) - /* XLC or GCC-compatible compiler, targeting PowerPC with VMX/VSX */ - #include - #elif defined(__GNUC__) && defined(__SPE__) - /* GCC-compatible compiler, targeting PowerPC with SPE */ - #include - #endif - - void zpl_yield_thread(void) { - #if defined(ZPL_SYSTEM_WINDOWS) - _mm_pause(); - #elif defined(ZPL_SYSTEM_OSX) - __asm__ volatile ("" : : : "memory"); - #elif defined(ZPL_CPU_X86) - _mm_pause(); - #endif + } + + if (deep_search) + { + for (zpl_isize i = 0; i < zpl_array_count(obj->nodes); i++) + { + zpl_json_object *res = zpl_json_find(obj->nodes + i, name, deep_search); + + if (res != NULL) + return res; } - - void zpl_mfence(void) { - #if defined(ZPL_SYSTEM_WINDOWS) - _ReadWriteBarrier(); - #elif defined(ZPL_SYSTEM_OSX) - __sync_synchronize(); - #elif defined(ZPL_CPU_X86) - _mm_mfence(); - #endif - } - - void zpl_sfence(void) { - #if defined(ZPL_SYSTEM_WINDOWS) - _WriteBarrier(); - #elif defined(ZPL_SYSTEM_OSX) - __asm__ volatile ("" : : : "memory"); - #elif defined(ZPL_CPU_X86) - _mm_sfence(); - #endif - } - - void zpl_lfence(void) { - #if defined(ZPL_SYSTEM_WINDOWS) - _ReadBarrier(); - #elif defined(ZPL_SYSTEM_OSX) - __asm__ volatile ("" : : : "memory"); - #elif defined(ZPL_CPU_X86) - _mm_lfence(); - #endif - } - - ZPL_END_C_DECLS - // file: source/threading/atomic.c - - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - //////////////////////////////////////////////////////////////// - // - // Concurrency - // - // - // IMPORTANT TODO: Use compiler intrinsics for the atomics - - #if defined(ZPL_COMPILER_MSVC) && !defined(ZPL_COMPILER_CLANG) - zpl_i32 zpl_atomic32_load (zpl_atomic32 const *a) { return a->value; } - void zpl_atomic32_store(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) value) { a->value = value; } - - zpl_i32 zpl_atomic32_compare_exchange(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) expected, zpl_atomicarg(zpl_i32) desired) { - return _InterlockedCompareExchange(cast(long *)a, desired, expected); - } - zpl_i32 zpl_atomic32_exchange(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) desired) { - return _InterlockedExchange(cast(long *)a, desired); - } - zpl_i32 zpl_atomic32_fetch_add(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) operand) { - return _InterlockedExchangeAdd(cast(long *)a, operand); - } - zpl_i32 zpl_atomic32_fetch_and(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) operand) { - return _InterlockedAnd(cast(long *)a, operand); - } - zpl_i32 zpl_atomic32_fetch_or(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) operand) { - return _InterlockedOr(cast(long *)a, operand); - } - - zpl_i64 zpl_atomic64_load(zpl_atomic64 const *a) { - #if defined(ZPL_ARCH_64_BIT) - return a->value; - #elif ZPL_CPU_X86 - // NOTE: The most compatible way to get an atomic 64-bit load on x86 is with cmpxchg8b - zpl_atomicarg(zpl_i64) result; - __asm { - mov esi, a; - mov ebx, eax; - mov ecx, edx; - lock cmpxchg8b [esi]; - mov dword ptr result, eax; - mov dword ptr result[4], edx; - } - return result; - #else - #error TODO: atomics for this CPU - #endif - } - - void zpl_atomic64_store(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) value) { - #if defined(ZPL_ARCH_64_BIT) - a->value = value; - #elif ZPL_CPU_X86 - // NOTE: The most compatible way to get an atomic 64-bit store on x86 is with cmpxchg8b - __asm { - mov esi, a; - mov ebx, dword ptr value; - mov ecx, dword ptr value[4]; - retry: - cmpxchg8b [esi]; - jne retry; - } - #else - #error TODO: atomics for this CPU - #endif - } - - zpl_i64 zpl_atomic64_compare_exchange(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) expected, zpl_atomicarg(zpl_i64) desired) { - return _InterlockedCompareExchange64(cast(zpl_atomicarg(zpl_i64) *)a, desired, expected); - } - - zpl_i64 zpl_atomic64_exchange(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) desired) { - #if defined(ZPL_ARCH_64_BIT) - return _InterlockedExchange64(cast(zpl_atomicarg(zpl_i64) *)a, desired); - #elif ZPL_CPU_X86 - zpl_atomicarg(zpl_i64) expected = a->value; - for (;;) { - zpl_atomicarg(zpl_i64) original = _InterlockedCompareExchange64(cast(zpl_atomicarg(zpl_i64) *)a, desired, expected); - if (original == expected) - return original; - expected = original; - } - #else - #error TODO: atomics for this CPU - #endif - } - - zpl_i64 zpl_atomic64_fetch_add(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) operand) { - #if defined(ZPL_ARCH_64_BIT) - return _InterlockedExchangeAdd64(cast(zpl_atomicarg(zpl_i64) *)a, operand); - #elif ZPL_CPU_X86 - zpl_atomicarg(zpl_i64) expected = a->value; - for (;;) { - zpl_atomicarg(zpl_i64) original = _InterlockedCompareExchange64(cast(zpl_atomicarg(zpl_i64) *)a, expected + operand, expected); - if (original == expected) - return original; - expected = original; - } - #else - #error TODO: atomics for this CPU - #endif - } - - zpl_i64 zpl_atomic64_fetch_and(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) operand) { - #if defined(ZPL_ARCH_64_BIT) - return _InterlockedAnd64(cast(zpl_atomicarg(zpl_i64) *)a, operand); - #elif ZPL_CPU_X86 - zpl_atomicarg(zpl_i64) expected = a->value; - for (;;) { - zpl_atomicarg(zpl_i64) original = _InterlockedCompareExchange64(cast(zpl_atomicarg(zpl_i64) *)a, expected & operand, expected); - if (original == expected) - return original; - expected = original; - } - #else - #error TODO: atomics for this CPU - #endif - } - - zpl_i64 zpl_atomic64_fetch_or(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) operand) { - #if defined(ZPL_ARCH_64_BIT) - return _InterlockedOr64(cast(zpl_atomicarg(zpl_i64) *)a, operand); - #elif ZPL_CPU_X86 - zpl_atomicarg(zpl_i64) expected = a->value; - for (;;) { - zpl_atomicarg(zpl_i64) original = _InterlockedCompareExchange64(cast(zpl_atomicarg(zpl_i64) *)a, expected | operand, expected); - if (original == expected) - return original; - expected = original; - } - #else - #error TODO: atomics for this CPU - #endif - } - - #elif defined(ZPL_CPU_X86) - - zpl_i32 zpl_atomic32_load (zpl_atomic32 const *a) { return a->value; } - void zpl_atomic32_store(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) value) { a->value = value; } - - zpl_i32 zpl_atomic32_compare_exchange(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) expected, zpl_atomicarg(zpl_i32) desired) { - zpl_atomicarg(zpl_i32) original; - __asm__( - "lock; cmpxchgl %2, %1" - : "=a"(original), "+m"(a->value) - : "q"(desired), "0"(expected) - ); - return original; - } - - zpl_i32 zpl_atomic32_exchange(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) desired) { - // NOTE: No lock prefix is necessary for xchgl - zpl_atomicarg(zpl_i32) original; - __asm__( - "xchgl %0, %1" - : "=r"(original), "+m"(a->value) - : "0"(desired) - ); - return original; - } - - zpl_i32 zpl_atomic32_fetch_add(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) operand) { - zpl_atomicarg(zpl_i32) original; - __asm__( - "lock; xaddl %0, %1" - : "=r"(original), "+m"(a->value) - : "0"(operand) - ); - return original; - } - - zpl_i32 zpl_atomic32_fetch_and(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) operand) { - zpl_atomicarg(zpl_i32) original; - zpl_atomicarg(zpl_i32) tmp; - __asm__( - "1: movl %1, %0\n" - " movl %0, %2\n" - " andl %3, %2\n" - " lock; cmpxchgl %2, %1\n" - " jne 1b" - : "=&a"(original), "+m"(a->value), "=&r"(tmp) - : "r"(operand) - ); - return original; - } - - zpl_i32 zpl_atomic32_fetch_or(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) operand) { - zpl_atomicarg(zpl_i32) original; - zpl_atomicarg(zpl_i32) temp; - __asm__( - "1: movl %1, %0\n" - " movl %0, %2\n" - " orl %3, %2\n" - " lock; cmpxchgl %2, %1\n" - " jne 1b" - : "=&a"(original), "+m"(a->value), "=&r"(temp) - : "r"(operand) - ); - return original; - } - - - zpl_i64 zpl_atomic64_load(zpl_atomic64 const *a) { - #if defined(ZPL_ARCH_64_BIT) - return a->value; - #else - zpl_atomicarg(zpl_i64) original; - __asm__( - "movl %%ebx, %%eax\n" - "movl %%ecx, %%edx\n" - "lock; cmpxchg8b %1" - : "=&A"(original) - : "m"(a->value) - ); - return original; - #endif - } - - void zpl_atomic64_store(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) value) { - #if defined(ZPL_ARCH_64_BIT) - a->value = value; - #else - zpl_atomicarg(zpl_i64) expected = a->value; - __asm__( - "1: cmpxchg8b %0\n" - " jne 1b" - : "=m"(a->value) - : "b"((zpl_atomicarg(zpl_i32))value), "c"((zpl_atomicarg(zpl_i32))(value >> 32)), "A"(expected) - ); - #endif - } - - zpl_i64 zpl_atomic64_compare_exchange(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) expected, zpl_atomicarg(zpl_i64) desired) { - #if defined(ZPL_ARCH_64_BIT) - zpl_atomicarg(zpl_i64) original; - __asm__( - "lock; cmpxchgq %2, %1" - : "=a"(original), "+m"(a->value) - : "q"(desired), "0"(expected) - ); - return original; - #else - zpl_atomicarg(zpl_i64) original; - __asm__( - "lock; cmpxchg8b %1" - : "=A"(original), "+m"(a->value) - : "b"((zpl_atomicarg(zpl_i32))desired), "c"((zpl_atomicarg(zpl_i32))(desired >> 32)), "0"(expected) - ); - return original; - #endif - } - - zpl_i64 zpl_atomic64_exchange(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) desired) { - #if defined(ZPL_ARCH_64_BIT) - zpl_atomicarg(zpl_i64) original; - __asm__( - "xchgq %0, %1" - : "=r"(original), "+m"(a->value) - : "0"(desired) - ); - return original; - #else - zpl_atomicarg(zpl_i64) original = a->value; - for (;;) { - zpl_atomicarg(zpl_i64) previous = zpl_atomic64_compare_exchange(a, original, desired); - if (original == previous) - return original; - original = previous; - } - #endif - } - - zpl_i64 zpl_atomic64_fetch_add(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) operand) { - #if defined(ZPL_ARCH_64_BIT) - zpl_atomicarg(zpl_i64) original; - __asm__( - "lock; xaddq %0, %1" - : "=r"(original), "+m"(a->value) - : "0"(operand) - ); - return original; - #else - for (;;) { - zpl_atomicarg(zpl_i64) original = a->value; - if (zpl_atomic64_compare_exchange(a, original, original + operand) == original) - return original; - } - #endif - } - - zpl_i64 zpl_atomic64_fetch_and(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) operand) { - #if defined(ZPL_ARCH_64_BIT) - zpl_atomicarg(zpl_i64) original; - zpl_atomicarg(zpl_i64) tmp; - __asm__( - "1: movq %1, %0\n" - " movq %0, %2\n" - " andq %3, %2\n" - " lock; cmpxchgq %2, %1\n" - " jne 1b" - : "=&a"(original), "+m"(a->value), "=&r"(tmp) - : "r"(operand) - ); - return original; - #else - for (;;) { - zpl_atomicarg(zpl_i64) original = a->value; - if (zpl_atomic64_compare_exchange(a, original, original & operand) == original) - return original; - } - #endif - } - - zpl_i64 zpl_atomic64_fetch_or(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) operand) { - #if defined(ZPL_ARCH_64_BIT) - zpl_atomicarg(zpl_i64) original; - zpl_atomicarg(zpl_i64) temp; - __asm__( - "1: movq %1, %0\n" - " movq %0, %2\n" - " orq %3, %2\n" - " lock; cmpxchgq %2, %1\n" - " jne 1b" - : "=&a"(original), "+m"(a->value), "=&r"(temp) - : "r"(operand) - ); - return original; - #else - for (;;) { - zpl_atomicarg(zpl_i64) original = a->value; - if (zpl_atomic64_compare_exchange(a, original, original | operand) == original) - return original; - } - #endif - } - - #elif !defined(__STDC_NO_ATOMICS__) && !defined(__cplusplus) && !defined(ZPL_COMPILER_MSVC) - zpl_i32 zpl_atomic32_load (zpl_atomic32 const *a) { return a->value; } - void zpl_atomic32_store(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) value) { a->value = value; } - - zpl_i32 zpl_atomic32_compare_exchange(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) expected, zpl_atomicarg(zpl_i32) desired) { - zpl_atomicarg(zpl_i32) original = a->value; - atomic_compare_exchange_strong(&a->value, &expected, desired); - return original; - } - - zpl_i32 zpl_atomic32_exchange(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) desired) { - return atomic_exchange(&a->value, desired); - } - - zpl_i32 zpl_atomic32_fetch_add(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) operand) { - return atomic_fetch_add(&a->value, operand); - } - - zpl_i32 zpl_atomic32_fetch_and(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) operand) { - return atomic_fetch_and(&a->value, operand); - } - - zpl_i32 zpl_atomic32_fetch_or(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) operand) { - return atomic_fetch_or(&a->value, operand); - } - - zpl_i64 zpl_atomic64_load(zpl_atomic64 const *a) { - return a->value; - } - - void zpl_atomic64_store(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) value) { - a->value = value; - } - - zpl_i64 zpl_atomic64_compare_exchange(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) expected, zpl_atomicarg(zpl_i64) desired) { - zpl_atomicarg(zpl_i64) original; - atomic_compare_exchange_strong(&a->value, &expected, desired); - return original; - } - - zpl_i64 zpl_atomic64_exchange(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) desired) { - return atomic_exchange(&a->value, desired); - } - - zpl_i64 zpl_atomic64_fetch_add(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) operand) { - return atomic_fetch_add(&a->value, operand); - } - - zpl_i64 zpl_atomic64_fetch_and(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) operand) { - return atomic_fetch_and(&a->value, operand); - } - - zpl_i64 zpl_atomic64_fetch_or(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) operand) { - return atomic_fetch_or(&a->value, operand); - } - - #else - #error TODO: Implement Atomics for this CPU - #endif - - - - zpl_b32 zpl_atomic32_spin_lock(zpl_atomic32 *a, zpl_isize time_out) { - zpl_atomicarg(zpl_i32) old_value = zpl_atomic32_compare_exchange(a, 1, 0); - zpl_i32 counter = 0; - while (old_value != 0 && (time_out < 0 || counter++ < time_out)) { - zpl_yield_thread(); - old_value = zpl_atomic32_compare_exchange(a, 1, 0); - zpl_mfence(); - } - return old_value == 0; - } - - void zpl_atomic32_spin_unlock(zpl_atomic32 *a) { - zpl_atomic32_store(a, 0); - zpl_mfence(); - } - - zpl_b32 zpl_atomic64_spin_lock(zpl_atomic64 *a, zpl_isize time_out) { - zpl_atomicarg(zpl_i64) old_value = zpl_atomic64_compare_exchange(a, 1, 0); - zpl_atomicarg(zpl_i64) counter = 0; - while (old_value != 0 && (time_out < 0 || counter++ < time_out)) { - zpl_yield_thread(); - old_value = zpl_atomic64_compare_exchange(a, 1, 0); - zpl_mfence(); - } - return old_value == 0; - } - - void zpl_atomic64_spin_unlock(zpl_atomic64 *a) { - zpl_atomic64_store(a, 0); - zpl_mfence(); - } - - zpl_b32 zpl_atomic32_try_acquire_lock(zpl_atomic32 *a) { - zpl_atomicarg(zpl_i32) old_value; - zpl_yield_thread(); - old_value = zpl_atomic32_compare_exchange(a, 1, 0); - zpl_mfence(); - return old_value == 0; - } - - zpl_b32 zpl_atomic64_try_acquire_lock(zpl_atomic64 *a) { - zpl_atomicarg(zpl_i64) old_value; - zpl_yield_thread(); - old_value = zpl_atomic64_compare_exchange(a, 1, 0); - zpl_mfence(); - return old_value == 0; - } - - - - #if defined(ZPL_ARCH_32_BIT) - - void* zpl_atomic_ptr_load(zpl_atomic_ptr const *a) { - return (void *)cast(zpl_intptr)zpl_atomic32_load(cast(zpl_atomic32 const *)a); - } - void zpl_atomic_ptr_store(zpl_atomic_ptr *a, zpl_atomicarg(void *)value) { - zpl_atomic32_store(cast(zpl_atomic32 *)a, cast(zpl_atomicarg(zpl_i32))cast(zpl_intptr)value); - } - void* zpl_atomic_ptr_compare_exchange(zpl_atomic_ptr *a, zpl_atomicarg(void *)expected, zpl_atomicarg(void *)desired) { - return (void *)cast(zpl_intptr)zpl_atomic32_compare_exchange(cast(zpl_atomic32 *)a, cast(zpl_atomicarg(zpl_i32))cast(zpl_intptr)expected, cast(zpl_atomicarg(zpl_i32))cast(zpl_intptr)desired); - } - void* zpl_atomic_ptr_exchange(zpl_atomic_ptr *a, zpl_atomicarg(void *)desired) { - return (void *)cast(zpl_intptr)zpl_atomic32_exchange(cast(zpl_atomic32 *)a, cast(zpl_atomicarg(zpl_i32))cast(zpl_intptr)desired); - } - void* zpl_atomic_ptr_fetch_add(zpl_atomic_ptr *a, zpl_atomicarg(void *)operand) { - return (void *)cast(zpl_intptr)zpl_atomic32_fetch_add(cast(zpl_atomic32 *)a, cast(zpl_atomicarg(zpl_i32))cast(zpl_intptr)operand); - } - void* zpl_atomic_ptr_fetch_and(zpl_atomic_ptr *a, zpl_atomicarg(void *)operand) { - return (void *)cast(zpl_intptr)zpl_atomic32_fetch_and(cast(zpl_atomic32 *)a, cast(zpl_atomicarg(zpl_i32))cast(zpl_intptr)operand); - } - void* zpl_atomic_ptr_fetch_or(zpl_atomic_ptr *a, zpl_atomicarg(void *)operand) { - return (void *)cast(zpl_intptr)zpl_atomic32_fetch_or(cast(zpl_atomic32 *)a, cast(zpl_atomicarg(zpl_i32))cast(zpl_intptr)operand); - } - zpl_b32 zpl_atomic_ptr_spin_lock(zpl_atomic_ptr *a, zpl_isize time_out) { - return zpl_atomic32_spin_lock(cast(zpl_atomic32 *)a, time_out); - } - void zpl_atomic_ptr_spin_unlock(zpl_atomic_ptr *a) { - zpl_atomic32_spin_unlock(cast(zpl_atomic32 *)a); - } - zpl_b32 zpl_atomic_ptr_try_acquire_lock(zpl_atomic_ptr *a) { - return zpl_atomic32_try_acquire_lock(cast(zpl_atomic32 *)a); - } - - #elif defined(ZPL_ARCH_64_BIT) - - void* zpl_atomic_ptr_load(zpl_atomic_ptr const *a) { - return (void *)cast(zpl_intptr)zpl_atomic64_load(cast(zpl_atomic64 const *)a); - } - void zpl_atomic_ptr_store(zpl_atomic_ptr *a, zpl_atomicarg(void *)value) { - zpl_atomic64_store(cast(zpl_atomic64 *)a, cast(zpl_i64)cast(zpl_intptr)value); - } - void* zpl_atomic_ptr_compare_exchange(zpl_atomic_ptr *a, zpl_atomicarg(void *)expected, zpl_atomicarg(void *)desired) { - return (void *)cast(zpl_intptr)zpl_atomic64_compare_exchange(cast(zpl_atomic64 *)a, cast(zpl_i64)cast(zpl_intptr)expected, cast(zpl_i64)cast(zpl_intptr)desired); - } - void* zpl_atomic_ptr_exchange(zpl_atomic_ptr *a, zpl_atomicarg(void *)desired) { - return (void *)cast(zpl_intptr)zpl_atomic64_exchange(cast(zpl_atomic64 *)a, cast(zpl_i64)cast(zpl_intptr)desired); - } - void* zpl_atomic_ptr_fetch_add(zpl_atomic_ptr *a, zpl_atomicarg(void *)operand) { - return (void *)cast(zpl_intptr)zpl_atomic64_fetch_add(cast(zpl_atomic64 *)a, cast(zpl_i64)cast(zpl_intptr)operand); - } - void* zpl_atomic_ptr_fetch_and(zpl_atomic_ptr *a, zpl_atomicarg(void *)operand) { - return (void *)cast(zpl_intptr)zpl_atomic64_fetch_and(cast(zpl_atomic64 *)a, cast(zpl_i64)cast(zpl_intptr)operand); - } - void* zpl_atomic_ptr_fetch_or(zpl_atomic_ptr *a, zpl_atomicarg(void *)operand) { - return (void *)cast(zpl_intptr)zpl_atomic64_fetch_or(cast(zpl_atomic64 *)a, cast(zpl_i64)cast(zpl_intptr)operand); - } - zpl_b32 zpl_atomic_ptr_spin_lock(zpl_atomic_ptr *a, zpl_isize time_out) { - return zpl_atomic64_spin_lock(cast(zpl_atomic64 *)a, time_out); - } - void zpl_atomic_ptr_spin_unlock(zpl_atomic_ptr *a) { - zpl_atomic64_spin_unlock(cast(zpl_atomic64 *)a); - } - zpl_b32 zpl_atomic_ptr_try_acquire_lock(zpl_atomic_ptr *a) { - return zpl_atomic64_try_acquire_lock(cast(zpl_atomic64 *)a); - } - - #endif - - ZPL_END_C_DECLS - // file: source/threading/sem.c - - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - void zpl_semaphore_release(zpl_semaphore *s) { zpl_semaphore_post(s, 1); } - - #if defined(ZPL_SYSTEM_WINDOWS) - - void zpl_semaphore_init (zpl_semaphore *s) { s->win32_handle = CreateSemaphoreA(NULL, 0, ZPL_I32_MAX, NULL); } - void zpl_semaphore_destroy(zpl_semaphore *s) { CloseHandle(s->win32_handle); } - void zpl_semaphore_post (zpl_semaphore *s, zpl_i32 count) { ReleaseSemaphore(s->win32_handle, count, NULL); } - void zpl_semaphore_wait (zpl_semaphore *s) { WaitForSingleObject(s->win32_handle, INFINITE); } - - #elif defined(ZPL_SYSTEM_OSX) - - void zpl_semaphore_init (zpl_semaphore *s) { semaphore_create(mach_task_self(), &s->osx_handle, SYNC_POLICY_FIFO, 0); } - void zpl_semaphore_destroy(zpl_semaphore *s) { semaphore_destroy(mach_task_self(), s->osx_handle); } - void zpl_semaphore_post (zpl_semaphore *s, zpl_i32 count) { while (count --> 0) semaphore_signal(s->osx_handle); } - void zpl_semaphore_wait (zpl_semaphore *s) { semaphore_wait(s->osx_handle); } - - #elif defined(ZPL_SYSTEM_UNIX) - - void zpl_semaphore_init (zpl_semaphore *s) { sem_init(&s->unix_handle, 0, 0); } - void zpl_semaphore_destroy(zpl_semaphore *s) { sem_destroy(&s->unix_handle); } - void zpl_semaphore_post (zpl_semaphore *s, zpl_i32 count) { while (count --> 0) sem_post(&s->unix_handle); } - void zpl_semaphore_wait (zpl_semaphore *s) { int i; do { i = sem_wait(&s->unix_handle); } while (i == -1 && errno == EINTR); } - - #else - #error Semaphores for this OS are not implemented - #endif - - ZPL_END_C_DECLS - // file: source/threading/mutex.c - - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - void zpl_mutex_init(zpl_mutex *m) { - #if defined(ZPL_SYSTEM_WINDOWS) - InitializeCriticalSection(&m->win32_critical_section); - #else - pthread_mutex_init(&m->pthread_mutex, NULL); - #endif - } - - void zpl_mutex_destroy(zpl_mutex *m) { - #if defined(ZPL_SYSTEM_WINDOWS) - DeleteCriticalSection(&m->win32_critical_section); - #else - pthread_mutex_destroy(&m->pthread_mutex); - #endif - } - - void zpl_mutex_lock(zpl_mutex *m) { - #if defined(ZPL_SYSTEM_WINDOWS) - EnterCriticalSection(&m->win32_critical_section); - #else - pthread_mutex_lock(&m->pthread_mutex); - #endif - } - - zpl_b32 zpl_mutex_try_lock(zpl_mutex *m) { - #if defined(ZPL_SYSTEM_WINDOWS) - return TryEnterCriticalSection(&m->win32_critical_section); - #else - return pthread_mutex_trylock(&m->pthread_mutex); - #endif - } - - void zpl_mutex_unlock(zpl_mutex *m) { - #if defined(ZPL_SYSTEM_WINDOWS) - LeaveCriticalSection(&m->win32_critical_section); - #else - pthread_mutex_unlock(&m->pthread_mutex); - #endif - } - - ZPL_END_C_DECLS - // file: source/threading/thread.c - - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - zpl_b32 zpl_thread_is_running(zpl_thread const *t) { return t->is_running != 0; } - - void zpl_thread_init(zpl_thread *t) { - zpl_zero_item(t); - - #if defined(ZPL_SYSTEM_WINDOWS) - t->win32_handle = INVALID_HANDLE_VALUE; - #else - t->posix_handle = 0; - #endif - - zpl_semaphore_init(&t->semaphore); - } - - void zpl_thread_destroy(zpl_thread *t) { - if (t->is_running) zpl_thread_join(t); - zpl_semaphore_destroy(&t->semaphore); - } - - void zpl__thread_run(zpl_thread *t) { - zpl_semaphore_release(&t->semaphore); - t->return_value = t->proc(t); - } - - #if defined(ZPL_SYSTEM_WINDOWS) - DWORD __stdcall zpl__thread_proc(void *arg) { - zpl_thread *t = cast(zpl_thread *)arg; - zpl__thread_run(t); - t->is_running = false; - return 0; - } - #else - void *zpl__thread_proc(void *arg) { - zpl_thread *t = cast(zpl_thread *)arg; - zpl__thread_run(t); - t->is_running = false; - return NULL; - } - #endif - - void zpl_thread_start(zpl_thread *t, zpl_thread_proc proc, void *user_data) { - zpl_thread_start_with_stack(t, proc, user_data, 0); - } - - void zpl_thread_start_with_stack(zpl_thread *t, zpl_thread_proc proc, void *user_data, zpl_isize stack_size) { - ZPL_ASSERT(!t->is_running); - ZPL_ASSERT(proc != NULL); - t->proc = proc; - t->user_data = user_data; - t->stack_size = stack_size; - - #if defined(ZPL_SYSTEM_WINDOWS) - t->win32_handle = CreateThread(NULL, stack_size, zpl__thread_proc, t, 0, NULL); - ZPL_ASSERT_MSG(t->win32_handle != NULL, "CreateThread: GetLastError"); - #else - { - pthread_attr_t attr; - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); - if (stack_size != 0) - pthread_attr_setstacksize(&attr, stack_size); - pthread_create(&t->posix_handle, &attr, zpl__thread_proc, t); - pthread_attr_destroy(&attr); - } - #endif - - t->is_running = true; - zpl_semaphore_wait(&t->semaphore); - } - - void zpl_thread_join(zpl_thread *t) { - if (!t->is_running) return; - - #if defined(ZPL_SYSTEM_WINDOWS) - WaitForSingleObject(t->win32_handle, INFINITE); - CloseHandle(t->win32_handle); - t->win32_handle = INVALID_HANDLE_VALUE; - #else - pthread_join(t->posix_handle, NULL); - t->posix_handle = 0; - #endif - t->is_running = false; - } - - zpl_u32 zpl_thread_current_id(void) { - zpl_u32 thread_id; - #if defined(ZPL_SYSTEM_WINDOWS) - #if defined(ZPL_ARCH_32_BIT) && defined(ZPL_CPU_X86) - thread_id = (cast(zpl_u32 *)__readfsdword(24))[9]; - #elif defined(ZPL_ARCH_64_BIT) && defined(ZPL_CPU_X86) - thread_id = (cast(zpl_u32 *)__readgsqword(48))[18]; - #else - thread_id = GetCurrentThreadId(); - #endif - - #elif defined(ZPL_SYSTEM_OSX) && defined(ZPL_ARCH_64_BIT) - thread_id = pthread_mach_thread_np(pthread_self()); - #elif defined(ZPL_ARCH_32_BIT) && defined(ZPL_CPU_X86) - __asm__("mov %%gs:0x08,%0" : "=r"(thread_id)); - #elif defined(ZPL_ARCH_64_BIT) && defined(ZPL_CPU_X86) - __asm__("mov %%fs:0x10,%0" : "=r"(thread_id)); - #elif defined(__ARM_ARCH) - thread_id = pthread_self(); - #else - #error Unsupported architecture for zpl_thread_current_id() - #endif - - return thread_id; - } - - void zpl_thread_set_name(zpl_thread *t, char const *name) { - #if defined(ZPL_COMPILER_MSVC) - #pragma pack(push, 8) - typedef struct { - DWORD type; - char const *name; - DWORD id; - DWORD flags; - } zplprivThreadName; - #pragma pack(pop) - - zplprivThreadName tn; - tn.type = 0x1000; - tn.name = name; - tn.id = GetThreadId(cast(HANDLE)t->win32_handle); - tn.flags = 0; - - __try { - RaiseException(0x406d1388, 0, zpl_size_of(tn)/4, cast(ULONG_PTR *)&tn); - } __except(1 /*EXCEPTION_EXECUTE_HANDLER*/) { - } - - #elif defined(ZPL_SYSTEM_WINDOWS) && !defined(ZPL_COMPILER_MSVC) - zpl_unused(t); - zpl_unused(name); - // IMPORTANT TODO: Set thread name for GCC/Clang on windows - return; - #elif defined(ZPL_SYSTEM_OSX) - // TODO: Test if this works - pthread_setname_np(name); - #else - zpl_unused(t); - zpl_unused(name); - // TODO: Test if this works - // pthread_set_name_np(t->posix_handle, name); - #endif - } - - ZPL_END_C_DECLS - // file: source/threading/sync.c - - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - void zpl_sync_init(zpl_sync *s) { - zpl_zero_item(s); - zpl_mutex_init(&s->mutex); - zpl_mutex_init(&s->start); - zpl_semaphore_init(&s->release); - } - - void zpl_sync_destroy(zpl_sync *s) { - if (s->waiting) { - ZPL_PANIC("Cannot destroy while threads are waiting!"); - } - - zpl_mutex_destroy(&s->mutex); - zpl_mutex_destroy(&s->start); - zpl_semaphore_destroy(&s->release); - } - - void zpl_sync_set_target(zpl_sync *s, zpl_i32 count) { - zpl_mutex_lock(&s->start); - - zpl_mutex_lock(&s->mutex); - ZPL_ASSERT(s->target == 0); - s->target = count; - s->current = 0; - s->waiting = 0; - zpl_mutex_unlock(&s->mutex); - } - - void zpl_sync_release(zpl_sync *s) { - if (s->waiting) { - zpl_semaphore_release(&s->release); - } else { - s->target = 0; - zpl_mutex_unlock(&s->start); - } - } - - zpl_i32 zpl_sync_reach(zpl_sync *s) { - zpl_i32 n; - zpl_mutex_lock(&s->mutex); - ZPL_ASSERT(s->current < s->target); - n = ++s->current; // NOTE: Record this value to avoid possible race if `return s->current` was done - if (s->current == s->target) - zpl_sync_release(s); - zpl_mutex_unlock(&s->mutex); - return n; - } - - void zpl_sync_reach_and_wait(zpl_sync *s) { - zpl_mutex_lock(&s->mutex); - ZPL_ASSERT(s->current < s->target); - s->current++; - if (s->current == s->target) { - zpl_sync_release(s); - zpl_mutex_unlock(&s->mutex); - } else { - s->waiting++; // NOTE: Waiting, so one more waiter - zpl_mutex_unlock(&s->mutex); // NOTE: Release the mutex to other threads - zpl_semaphore_wait(&s->release); // NOTE: Wait for merge completion - zpl_mutex_lock(&s->mutex); // NOTE: On merge completion, lock mutex - s->waiting--; // NOTE: Done waiting - zpl_sync_release(s); // NOTE: Restart the next waiter - zpl_mutex_unlock(&s->mutex); - } - } - - ZPL_END_C_DECLS - // file: source/threading/affinity.c - - #ifdef ZPL_EDITOR - #include - #endif - - #if defined(ZPL_SYSTEM_MACOS) - #include - #endif - - ZPL_BEGIN_C_DECLS - - #if defined(ZPL_SYSTEM_WINDOWS) || defined(ZPL_SYSTEM_CYGWIN) - - void zpl_affinity_init(zpl_affinity *a) { - SYSTEM_LOGICAL_PROCESSOR_INFORMATION *start_processor_info = NULL; - DWORD length = 0; - zpl_b32 result = GetLogicalProcessorInformation(NULL, &length); - - zpl_zero_item(a); - - if (!result && GetLastError() == 122l /*ERROR_INSUFFICIENT_BUFFER*/ && length > 0) { - start_processor_info = cast(SYSTEM_LOGICAL_PROCESSOR_INFORMATION *)zpl_alloc(zpl_heap_allocator(), length); - result = GetLogicalProcessorInformation(start_processor_info, &length); - if (result) { - SYSTEM_LOGICAL_PROCESSOR_INFORMATION *end_processor_info, *processor_info; - - a->is_accurate = true; - a->core_count = 0; - a->thread_count = 0; - end_processor_info = cast(SYSTEM_LOGICAL_PROCESSOR_INFORMATION *)zpl_pointer_add(start_processor_info, length); - - for (processor_info = start_processor_info; - processor_info < end_processor_info; - processor_info++) { - if (processor_info->Relationship == RelationProcessorCore) { - zpl_isize thread = zpl_count_set_bits(processor_info->ProcessorMask); - if (thread == 0) { - a->is_accurate = false; - } else if (a->thread_count + thread > ZPL_WIN32_MAX_THREADS) { - a->is_accurate = false; - } else { - ZPL_ASSERT(a->core_count <= a->thread_count && - a->thread_count < ZPL_WIN32_MAX_THREADS); - a->core_masks[a->core_count++] = processor_info->ProcessorMask; - a->thread_count += thread; - } - } - } - } - - zpl_free(zpl_heap_allocator(), start_processor_info); - } - - ZPL_ASSERT(a->core_count <= a->thread_count); - if (a->thread_count == 0) { - a->is_accurate = false; - a->core_count = 1; - a->thread_count = 1; - a->core_masks[0] = 1; - } - - } - - void zpl_affinity_destroy(zpl_affinity *a) { - zpl_unused(a); - } - - zpl_b32 zpl_affinity_set(zpl_affinity *a, zpl_isize core, zpl_isize thread) { - zpl_usize available_mask, check_mask = 1; - ZPL_ASSERT(thread < zpl_affinity_thread_count_for_core(a, core)); - - available_mask = a->core_masks[core]; - for (;;) { - if ((available_mask & check_mask) != 0) { - if (thread-- == 0) { - zpl_usize result = SetThreadAffinityMask(GetCurrentThread(), check_mask); - return result != 0; - } - } - check_mask <<= 1; // NOTE: Onto the next bit - } - } - - zpl_isize zpl_affinity_thread_count_for_core(zpl_affinity *a, zpl_isize core) { - ZPL_ASSERT(core >= 0 && core < a->core_count); - return zpl_count_set_bits(a->core_masks[core]); - } - - #elif defined(ZPL_SYSTEM_MACOS) - void zpl_affinity_init(zpl_affinity *a) { - zpl_usize count, count_size = zpl_size_of(count); - - a->is_accurate = false; - a->thread_count = 1; - a->core_count = 1; - a->threads_per_core = 1; - - if (sysctlbyname("hw.logicalcpu", &count, &count_size, NULL, 0) == 0) { - if (count > 0) { - a->thread_count = count; - // Get # of physical cores - if (sysctlbyname("hw.physicalcpu", &count, &count_size, NULL, 0) == 0) { - if (count > 0) { - a->core_count = count; - a->threads_per_core = a->thread_count / count; - if (a->threads_per_core < 1) - a->threads_per_core = 1; - else - a->is_accurate = true; - } - } + } + + return NULL; +} + +void zpl_json_init_node(zpl_json_object *obj, zpl_allocator backing, char const *name, zpl_u8 type) +{ + obj->name = (char *)name; + obj->type = type; + obj->backing = backing; + + if (type == ZPL_JSON_TYPE_ARRAY || type == ZPL_JSON_TYPE_OBJECT) + { + zpl_array_init(obj->nodes, backing); + } +} + +zpl_json_object *zpl_json_add_at(zpl_json_object *obj, zpl_isize index, char const *name, zpl_u8 type) +{ + if (!obj || (obj->type != ZPL_JSON_TYPE_OBJECT && obj->type != ZPL_JSON_TYPE_ARRAY)) + { + return NULL; + } + + if (!obj->nodes) + return NULL; + + if (index < 0 || index > zpl_array_count(obj->nodes)) + return NULL; + + zpl_json_object o = {0}; + zpl_json_init_node(&o, obj->backing, name, type); + + zpl_array_append_at(obj->nodes, o, index); + + return obj->nodes + index; +} + +zpl_json_object *zpl_json_add(zpl_json_object *obj, char const *name, zpl_u8 type) +{ + if (!obj || (obj->type != ZPL_JSON_TYPE_OBJECT && obj->type != ZPL_JSON_TYPE_ARRAY)) + { + return NULL; + } + + if (!obj->nodes) + return NULL; + + return zpl_json_add_at(obj, zpl_array_count(obj->nodes), name, type); +} + +ZPL_END_C_DECLS +#endif + +#if defined(ZPL_MODULE_THREADING) +// file: source/threading/fence.c + +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +#if defined(_MSC_VER) +/* Microsoft C/C++-compatible compiler */ +#include +#elif defined(__GNUC__) && (defined(__x86_64__) || defined(__i386__)) +/* GCC-compatible compiler, targeting x86/x86-64 */ +#include +#elif defined(__GNUC__) && defined(__ARM_NEON__) +/* GCC-compatible compiler, targeting ARM with NEON */ +#include +#elif defined(__GNUC__) && defined(__IWMMXT__) +/* GCC-compatible compiler, targeting ARM with WMMX */ +#include +#elif (defined(__GNUC__) || defined(__xlC__)) && (defined(__VEC__) || defined(__ALTIVEC__)) +/* XLC or GCC-compatible compiler, targeting PowerPC with VMX/VSX */ +#include +#elif defined(__GNUC__) && defined(__SPE__) +/* GCC-compatible compiler, targeting PowerPC with SPE */ +#include +#endif + +void zpl_yield_thread(void) { +#if defined(ZPL_SYSTEM_WINDOWS) + _mm_pause(); +#elif defined(ZPL_SYSTEM_OSX) + __asm__ volatile ("" : : : "memory"); +#elif defined(ZPL_CPU_X86) + _mm_pause(); +#endif +} + +void zpl_mfence(void) { +#if defined(ZPL_SYSTEM_WINDOWS) + _ReadWriteBarrier(); +#elif defined(ZPL_SYSTEM_OSX) + __sync_synchronize(); +#elif defined(ZPL_CPU_X86) + _mm_mfence(); +#endif +} + +void zpl_sfence(void) { +#if defined(ZPL_SYSTEM_WINDOWS) + _WriteBarrier(); +#elif defined(ZPL_SYSTEM_OSX) + __asm__ volatile ("" : : : "memory"); +#elif defined(ZPL_CPU_X86) + _mm_sfence(); +#endif +} + +void zpl_lfence(void) { +#if defined(ZPL_SYSTEM_WINDOWS) + _ReadBarrier(); +#elif defined(ZPL_SYSTEM_OSX) + __asm__ volatile ("" : : : "memory"); +#elif defined(ZPL_CPU_X86) + _mm_lfence(); +#endif +} + +ZPL_END_C_DECLS +// file: source/threading/atomic.c + +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +//////////////////////////////////////////////////////////////// +// +// Concurrency +// +// +// IMPORTANT TODO: Use compiler intrinsics for the atomics + +#if defined(ZPL_COMPILER_MSVC) && !defined(ZPL_COMPILER_CLANG) +zpl_i32 zpl_atomic32_load (zpl_atomic32 const *a) { return a->value; } +void zpl_atomic32_store(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) value) { a->value = value; } + +zpl_i32 zpl_atomic32_compare_exchange(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) expected, zpl_atomicarg(zpl_i32) desired) { + return _InterlockedCompareExchange(cast(long *)a, desired, expected); +} +zpl_i32 zpl_atomic32_exchange(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) desired) { + return _InterlockedExchange(cast(long *)a, desired); +} +zpl_i32 zpl_atomic32_fetch_add(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) operand) { + return _InterlockedExchangeAdd(cast(long *)a, operand); +} +zpl_i32 zpl_atomic32_fetch_and(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) operand) { + return _InterlockedAnd(cast(long *)a, operand); +} +zpl_i32 zpl_atomic32_fetch_or(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) operand) { + return _InterlockedOr(cast(long *)a, operand); +} + +zpl_i64 zpl_atomic64_load(zpl_atomic64 const *a) { +#if defined(ZPL_ARCH_64_BIT) + return a->value; +#elif ZPL_CPU_X86 + // NOTE: The most compatible way to get an atomic 64-bit load on x86 is with cmpxchg8b + zpl_atomicarg(zpl_i64) result; + __asm { + mov esi, a; + mov ebx, eax; + mov ecx, edx; + lock cmpxchg8b [esi]; + mov dword ptr result, eax; + mov dword ptr result[4], edx; + } + return result; +#else +#error TODO: atomics for this CPU +#endif +} + +void zpl_atomic64_store(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) value) { +#if defined(ZPL_ARCH_64_BIT) + a->value = value; +#elif ZPL_CPU_X86 + // NOTE: The most compatible way to get an atomic 64-bit store on x86 is with cmpxchg8b + __asm { + mov esi, a; + mov ebx, dword ptr value; + mov ecx, dword ptr value[4]; + retry: + cmpxchg8b [esi]; + jne retry; + } +#else +#error TODO: atomics for this CPU +#endif +} + +zpl_i64 zpl_atomic64_compare_exchange(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) expected, zpl_atomicarg(zpl_i64) desired) { + return _InterlockedCompareExchange64(cast(zpl_atomicarg(zpl_i64) *)a, desired, expected); +} + +zpl_i64 zpl_atomic64_exchange(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) desired) { +#if defined(ZPL_ARCH_64_BIT) + return _InterlockedExchange64(cast(zpl_atomicarg(zpl_i64) *)a, desired); +#elif ZPL_CPU_X86 + zpl_atomicarg(zpl_i64) expected = a->value; + for (;;) { + zpl_atomicarg(zpl_i64) original = _InterlockedCompareExchange64(cast(zpl_atomicarg(zpl_i64) *)a, desired, expected); + if (original == expected) + return original; + expected = original; + } +#else +#error TODO: atomics for this CPU +#endif +} + +zpl_i64 zpl_atomic64_fetch_add(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) operand) { +#if defined(ZPL_ARCH_64_BIT) + return _InterlockedExchangeAdd64(cast(zpl_atomicarg(zpl_i64) *)a, operand); +#elif ZPL_CPU_X86 + zpl_atomicarg(zpl_i64) expected = a->value; + for (;;) { + zpl_atomicarg(zpl_i64) original = _InterlockedCompareExchange64(cast(zpl_atomicarg(zpl_i64) *)a, expected + operand, expected); + if (original == expected) + return original; + expected = original; + } +#else +#error TODO: atomics for this CPU +#endif +} + +zpl_i64 zpl_atomic64_fetch_and(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) operand) { +#if defined(ZPL_ARCH_64_BIT) + return _InterlockedAnd64(cast(zpl_atomicarg(zpl_i64) *)a, operand); +#elif ZPL_CPU_X86 + zpl_atomicarg(zpl_i64) expected = a->value; + for (;;) { + zpl_atomicarg(zpl_i64) original = _InterlockedCompareExchange64(cast(zpl_atomicarg(zpl_i64) *)a, expected & operand, expected); + if (original == expected) + return original; + expected = original; + } +#else +#error TODO: atomics for this CPU +#endif +} + +zpl_i64 zpl_atomic64_fetch_or(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) operand) { +#if defined(ZPL_ARCH_64_BIT) + return _InterlockedOr64(cast(zpl_atomicarg(zpl_i64) *)a, operand); +#elif ZPL_CPU_X86 + zpl_atomicarg(zpl_i64) expected = a->value; + for (;;) { + zpl_atomicarg(zpl_i64) original = _InterlockedCompareExchange64(cast(zpl_atomicarg(zpl_i64) *)a, expected | operand, expected); + if (original == expected) + return original; + expected = original; + } +#else +#error TODO: atomics for this CPU +#endif +} + +#elif defined(ZPL_CPU_X86) + +zpl_i32 zpl_atomic32_load (zpl_atomic32 const *a) { return a->value; } +void zpl_atomic32_store(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) value) { a->value = value; } + +zpl_i32 zpl_atomic32_compare_exchange(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) expected, zpl_atomicarg(zpl_i32) desired) { + zpl_atomicarg(zpl_i32) original; + __asm__( + "lock; cmpxchgl %2, %1" + : "=a"(original), "+m"(a->value) + : "q"(desired), "0"(expected) + ); + return original; +} + +zpl_i32 zpl_atomic32_exchange(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) desired) { + // NOTE: No lock prefix is necessary for xchgl + zpl_atomicarg(zpl_i32) original; + __asm__( + "xchgl %0, %1" + : "=r"(original), "+m"(a->value) + : "0"(desired) + ); + return original; +} + +zpl_i32 zpl_atomic32_fetch_add(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) operand) { + zpl_atomicarg(zpl_i32) original; + __asm__( + "lock; xaddl %0, %1" + : "=r"(original), "+m"(a->value) + : "0"(operand) + ); + return original; +} + +zpl_i32 zpl_atomic32_fetch_and(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) operand) { + zpl_atomicarg(zpl_i32) original; + zpl_atomicarg(zpl_i32) tmp; + __asm__( + "1: movl %1, %0\n" + " movl %0, %2\n" + " andl %3, %2\n" + " lock; cmpxchgl %2, %1\n" + " jne 1b" + : "=&a"(original), "+m"(a->value), "=&r"(tmp) + : "r"(operand) + ); + return original; +} + +zpl_i32 zpl_atomic32_fetch_or(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) operand) { + zpl_atomicarg(zpl_i32) original; + zpl_atomicarg(zpl_i32) temp; + __asm__( + "1: movl %1, %0\n" + " movl %0, %2\n" + " orl %3, %2\n" + " lock; cmpxchgl %2, %1\n" + " jne 1b" + : "=&a"(original), "+m"(a->value), "=&r"(temp) + : "r"(operand) + ); + return original; +} + + +zpl_i64 zpl_atomic64_load(zpl_atomic64 const *a) { +#if defined(ZPL_ARCH_64_BIT) + return a->value; +#else + zpl_atomicarg(zpl_i64) original; + __asm__( + "movl %%ebx, %%eax\n" + "movl %%ecx, %%edx\n" + "lock; cmpxchg8b %1" + : "=&A"(original) + : "m"(a->value) + ); + return original; +#endif +} + +void zpl_atomic64_store(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) value) { +#if defined(ZPL_ARCH_64_BIT) + a->value = value; +#else + zpl_atomicarg(zpl_i64) expected = a->value; + __asm__( + "1: cmpxchg8b %0\n" + " jne 1b" + : "=m"(a->value) + : "b"((zpl_atomicarg(zpl_i32))value), "c"((zpl_atomicarg(zpl_i32))(value >> 32)), "A"(expected) + ); +#endif +} + +zpl_i64 zpl_atomic64_compare_exchange(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) expected, zpl_atomicarg(zpl_i64) desired) { +#if defined(ZPL_ARCH_64_BIT) + zpl_atomicarg(zpl_i64) original; + __asm__( + "lock; cmpxchgq %2, %1" + : "=a"(original), "+m"(a->value) + : "q"(desired), "0"(expected) + ); + return original; +#else + zpl_atomicarg(zpl_i64) original; + __asm__( + "lock; cmpxchg8b %1" + : "=A"(original), "+m"(a->value) + : "b"((zpl_atomicarg(zpl_i32))desired), "c"((zpl_atomicarg(zpl_i32))(desired >> 32)), "0"(expected) + ); + return original; +#endif +} + +zpl_i64 zpl_atomic64_exchange(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) desired) { +#if defined(ZPL_ARCH_64_BIT) + zpl_atomicarg(zpl_i64) original; + __asm__( + "xchgq %0, %1" + : "=r"(original), "+m"(a->value) + : "0"(desired) + ); + return original; +#else + zpl_atomicarg(zpl_i64) original = a->value; + for (;;) { + zpl_atomicarg(zpl_i64) previous = zpl_atomic64_compare_exchange(a, original, desired); + if (original == previous) + return original; + original = previous; + } +#endif +} + +zpl_i64 zpl_atomic64_fetch_add(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) operand) { +#if defined(ZPL_ARCH_64_BIT) + zpl_atomicarg(zpl_i64) original; + __asm__( + "lock; xaddq %0, %1" + : "=r"(original), "+m"(a->value) + : "0"(operand) + ); + return original; +#else + for (;;) { + zpl_atomicarg(zpl_i64) original = a->value; + if (zpl_atomic64_compare_exchange(a, original, original + operand) == original) + return original; + } +#endif +} + +zpl_i64 zpl_atomic64_fetch_and(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) operand) { +#if defined(ZPL_ARCH_64_BIT) + zpl_atomicarg(zpl_i64) original; + zpl_atomicarg(zpl_i64) tmp; + __asm__( + "1: movq %1, %0\n" + " movq %0, %2\n" + " andq %3, %2\n" + " lock; cmpxchgq %2, %1\n" + " jne 1b" + : "=&a"(original), "+m"(a->value), "=&r"(tmp) + : "r"(operand) + ); + return original; +#else + for (;;) { + zpl_atomicarg(zpl_i64) original = a->value; + if (zpl_atomic64_compare_exchange(a, original, original & operand) == original) + return original; + } +#endif +} + +zpl_i64 zpl_atomic64_fetch_or(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) operand) { +#if defined(ZPL_ARCH_64_BIT) + zpl_atomicarg(zpl_i64) original; + zpl_atomicarg(zpl_i64) temp; + __asm__( + "1: movq %1, %0\n" + " movq %0, %2\n" + " orq %3, %2\n" + " lock; cmpxchgq %2, %1\n" + " jne 1b" + : "=&a"(original), "+m"(a->value), "=&r"(temp) + : "r"(operand) + ); + return original; +#else + for (;;) { + zpl_atomicarg(zpl_i64) original = a->value; + if (zpl_atomic64_compare_exchange(a, original, original | operand) == original) + return original; + } +#endif +} + +#elif !defined(__STDC_NO_ATOMICS__) && !defined(__cplusplus) && !defined(ZPL_COMPILER_MSVC) +zpl_i32 zpl_atomic32_load (zpl_atomic32 const *a) { return a->value; } +void zpl_atomic32_store(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) value) { a->value = value; } + +zpl_i32 zpl_atomic32_compare_exchange(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) expected, zpl_atomicarg(zpl_i32) desired) { + zpl_atomicarg(zpl_i32) original = a->value; + atomic_compare_exchange_strong(&a->value, &expected, desired); + return original; +} + +zpl_i32 zpl_atomic32_exchange(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) desired) { + return atomic_exchange(&a->value, desired); +} + +zpl_i32 zpl_atomic32_fetch_add(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) operand) { + return atomic_fetch_add(&a->value, operand); +} + +zpl_i32 zpl_atomic32_fetch_and(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) operand) { + return atomic_fetch_and(&a->value, operand); +} + +zpl_i32 zpl_atomic32_fetch_or(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) operand) { + return atomic_fetch_or(&a->value, operand); +} + +zpl_i64 zpl_atomic64_load(zpl_atomic64 const *a) { + return a->value; +} + +void zpl_atomic64_store(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) value) { + a->value = value; +} + +zpl_i64 zpl_atomic64_compare_exchange(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) expected, zpl_atomicarg(zpl_i64) desired) { + zpl_atomicarg(zpl_i64) original; + atomic_compare_exchange_strong(&a->value, &expected, desired); + return original; +} + +zpl_i64 zpl_atomic64_exchange(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) desired) { + return atomic_exchange(&a->value, desired); +} + +zpl_i64 zpl_atomic64_fetch_add(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) operand) { + return atomic_fetch_add(&a->value, operand); +} + +zpl_i64 zpl_atomic64_fetch_and(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) operand) { + return atomic_fetch_and(&a->value, operand); +} + +zpl_i64 zpl_atomic64_fetch_or(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) operand) { + return atomic_fetch_or(&a->value, operand); +} + +#else +#error TODO: Implement Atomics for this CPU +#endif + + + +zpl_b32 zpl_atomic32_spin_lock(zpl_atomic32 *a, zpl_isize time_out) { + zpl_atomicarg(zpl_i32) old_value = zpl_atomic32_compare_exchange(a, 1, 0); + zpl_i32 counter = 0; + while (old_value != 0 && (time_out < 0 || counter++ < time_out)) { + zpl_yield_thread(); + old_value = zpl_atomic32_compare_exchange(a, 1, 0); + zpl_mfence(); + } + return old_value == 0; +} + +void zpl_atomic32_spin_unlock(zpl_atomic32 *a) { + zpl_atomic32_store(a, 0); + zpl_mfence(); +} + +zpl_b32 zpl_atomic64_spin_lock(zpl_atomic64 *a, zpl_isize time_out) { + zpl_atomicarg(zpl_i64) old_value = zpl_atomic64_compare_exchange(a, 1, 0); + zpl_atomicarg(zpl_i64) counter = 0; + while (old_value != 0 && (time_out < 0 || counter++ < time_out)) { + zpl_yield_thread(); + old_value = zpl_atomic64_compare_exchange(a, 1, 0); + zpl_mfence(); + } + return old_value == 0; +} + +void zpl_atomic64_spin_unlock(zpl_atomic64 *a) { + zpl_atomic64_store(a, 0); + zpl_mfence(); +} + +zpl_b32 zpl_atomic32_try_acquire_lock(zpl_atomic32 *a) { + zpl_atomicarg(zpl_i32) old_value; + zpl_yield_thread(); + old_value = zpl_atomic32_compare_exchange(a, 1, 0); + zpl_mfence(); + return old_value == 0; +} + +zpl_b32 zpl_atomic64_try_acquire_lock(zpl_atomic64 *a) { + zpl_atomicarg(zpl_i64) old_value; + zpl_yield_thread(); + old_value = zpl_atomic64_compare_exchange(a, 1, 0); + zpl_mfence(); + return old_value == 0; +} + + + +#if defined(ZPL_ARCH_32_BIT) + +void* zpl_atomic_ptr_load(zpl_atomic_ptr const *a) { + return (void *)cast(zpl_intptr)zpl_atomic32_load(cast(zpl_atomic32 const *)a); +} +void zpl_atomic_ptr_store(zpl_atomic_ptr *a, zpl_atomicarg(void *)value) { + zpl_atomic32_store(cast(zpl_atomic32 *)a, cast(zpl_atomicarg(zpl_i32))cast(zpl_intptr)value); +} +void* zpl_atomic_ptr_compare_exchange(zpl_atomic_ptr *a, zpl_atomicarg(void *)expected, zpl_atomicarg(void *)desired) { + return (void *)cast(zpl_intptr)zpl_atomic32_compare_exchange(cast(zpl_atomic32 *)a, cast(zpl_atomicarg(zpl_i32))cast(zpl_intptr)expected, cast(zpl_atomicarg(zpl_i32))cast(zpl_intptr)desired); +} +void* zpl_atomic_ptr_exchange(zpl_atomic_ptr *a, zpl_atomicarg(void *)desired) { + return (void *)cast(zpl_intptr)zpl_atomic32_exchange(cast(zpl_atomic32 *)a, cast(zpl_atomicarg(zpl_i32))cast(zpl_intptr)desired); +} +void* zpl_atomic_ptr_fetch_add(zpl_atomic_ptr *a, zpl_atomicarg(void *)operand) { + return (void *)cast(zpl_intptr)zpl_atomic32_fetch_add(cast(zpl_atomic32 *)a, cast(zpl_atomicarg(zpl_i32))cast(zpl_intptr)operand); +} +void* zpl_atomic_ptr_fetch_and(zpl_atomic_ptr *a, zpl_atomicarg(void *)operand) { + return (void *)cast(zpl_intptr)zpl_atomic32_fetch_and(cast(zpl_atomic32 *)a, cast(zpl_atomicarg(zpl_i32))cast(zpl_intptr)operand); +} +void* zpl_atomic_ptr_fetch_or(zpl_atomic_ptr *a, zpl_atomicarg(void *)operand) { + return (void *)cast(zpl_intptr)zpl_atomic32_fetch_or(cast(zpl_atomic32 *)a, cast(zpl_atomicarg(zpl_i32))cast(zpl_intptr)operand); +} +zpl_b32 zpl_atomic_ptr_spin_lock(zpl_atomic_ptr *a, zpl_isize time_out) { + return zpl_atomic32_spin_lock(cast(zpl_atomic32 *)a, time_out); +} +void zpl_atomic_ptr_spin_unlock(zpl_atomic_ptr *a) { + zpl_atomic32_spin_unlock(cast(zpl_atomic32 *)a); +} +zpl_b32 zpl_atomic_ptr_try_acquire_lock(zpl_atomic_ptr *a) { + return zpl_atomic32_try_acquire_lock(cast(zpl_atomic32 *)a); +} + +#elif defined(ZPL_ARCH_64_BIT) + +void* zpl_atomic_ptr_load(zpl_atomic_ptr const *a) { + return (void *)cast(zpl_intptr)zpl_atomic64_load(cast(zpl_atomic64 const *)a); +} +void zpl_atomic_ptr_store(zpl_atomic_ptr *a, zpl_atomicarg(void *)value) { + zpl_atomic64_store(cast(zpl_atomic64 *)a, cast(zpl_i64)cast(zpl_intptr)value); +} +void* zpl_atomic_ptr_compare_exchange(zpl_atomic_ptr *a, zpl_atomicarg(void *)expected, zpl_atomicarg(void *)desired) { + return (void *)cast(zpl_intptr)zpl_atomic64_compare_exchange(cast(zpl_atomic64 *)a, cast(zpl_i64)cast(zpl_intptr)expected, cast(zpl_i64)cast(zpl_intptr)desired); +} +void* zpl_atomic_ptr_exchange(zpl_atomic_ptr *a, zpl_atomicarg(void *)desired) { + return (void *)cast(zpl_intptr)zpl_atomic64_exchange(cast(zpl_atomic64 *)a, cast(zpl_i64)cast(zpl_intptr)desired); +} +void* zpl_atomic_ptr_fetch_add(zpl_atomic_ptr *a, zpl_atomicarg(void *)operand) { + return (void *)cast(zpl_intptr)zpl_atomic64_fetch_add(cast(zpl_atomic64 *)a, cast(zpl_i64)cast(zpl_intptr)operand); +} +void* zpl_atomic_ptr_fetch_and(zpl_atomic_ptr *a, zpl_atomicarg(void *)operand) { + return (void *)cast(zpl_intptr)zpl_atomic64_fetch_and(cast(zpl_atomic64 *)a, cast(zpl_i64)cast(zpl_intptr)operand); +} +void* zpl_atomic_ptr_fetch_or(zpl_atomic_ptr *a, zpl_atomicarg(void *)operand) { + return (void *)cast(zpl_intptr)zpl_atomic64_fetch_or(cast(zpl_atomic64 *)a, cast(zpl_i64)cast(zpl_intptr)operand); +} +zpl_b32 zpl_atomic_ptr_spin_lock(zpl_atomic_ptr *a, zpl_isize time_out) { + return zpl_atomic64_spin_lock(cast(zpl_atomic64 *)a, time_out); +} +void zpl_atomic_ptr_spin_unlock(zpl_atomic_ptr *a) { + zpl_atomic64_spin_unlock(cast(zpl_atomic64 *)a); +} +zpl_b32 zpl_atomic_ptr_try_acquire_lock(zpl_atomic_ptr *a) { + return zpl_atomic64_try_acquire_lock(cast(zpl_atomic64 *)a); +} + +#endif + +ZPL_END_C_DECLS +// file: source/threading/sem.c + +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +void zpl_semaphore_release(zpl_semaphore *s) { zpl_semaphore_post(s, 1); } + +#if defined(ZPL_SYSTEM_WINDOWS) + +void zpl_semaphore_init (zpl_semaphore *s) { s->win32_handle = CreateSemaphoreA(NULL, 0, ZPL_I32_MAX, NULL); } +void zpl_semaphore_destroy(zpl_semaphore *s) { CloseHandle(s->win32_handle); } +void zpl_semaphore_post (zpl_semaphore *s, zpl_i32 count) { ReleaseSemaphore(s->win32_handle, count, NULL); } +void zpl_semaphore_wait (zpl_semaphore *s) { WaitForSingleObject(s->win32_handle, INFINITE); } + +#elif defined(ZPL_SYSTEM_OSX) + +void zpl_semaphore_init (zpl_semaphore *s) { semaphore_create(mach_task_self(), &s->osx_handle, SYNC_POLICY_FIFO, 0); } +void zpl_semaphore_destroy(zpl_semaphore *s) { semaphore_destroy(mach_task_self(), s->osx_handle); } +void zpl_semaphore_post (zpl_semaphore *s, zpl_i32 count) { while (count --> 0) semaphore_signal(s->osx_handle); } +void zpl_semaphore_wait (zpl_semaphore *s) { semaphore_wait(s->osx_handle); } + +#elif defined(ZPL_SYSTEM_UNIX) + +void zpl_semaphore_init (zpl_semaphore *s) { sem_init(&s->unix_handle, 0, 0); } +void zpl_semaphore_destroy(zpl_semaphore *s) { sem_destroy(&s->unix_handle); } +void zpl_semaphore_post (zpl_semaphore *s, zpl_i32 count) { while (count --> 0) sem_post(&s->unix_handle); } +void zpl_semaphore_wait (zpl_semaphore *s) { int i; do { i = sem_wait(&s->unix_handle); } while (i == -1 && errno == EINTR); } + +#else +#error Semaphores for this OS are not implemented +#endif + +ZPL_END_C_DECLS +// file: source/threading/mutex.c + +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +void zpl_mutex_init(zpl_mutex *m) { +#if defined(ZPL_SYSTEM_WINDOWS) + InitializeCriticalSection(&m->win32_critical_section); +#else + pthread_mutex_init(&m->pthread_mutex, NULL); +#endif +} + +void zpl_mutex_destroy(zpl_mutex *m) { +#if defined(ZPL_SYSTEM_WINDOWS) + DeleteCriticalSection(&m->win32_critical_section); +#else + pthread_mutex_destroy(&m->pthread_mutex); +#endif +} + +void zpl_mutex_lock(zpl_mutex *m) { +#if defined(ZPL_SYSTEM_WINDOWS) + EnterCriticalSection(&m->win32_critical_section); +#else + pthread_mutex_lock(&m->pthread_mutex); +#endif +} + +zpl_b32 zpl_mutex_try_lock(zpl_mutex *m) { +#if defined(ZPL_SYSTEM_WINDOWS) + return TryEnterCriticalSection(&m->win32_critical_section); +#else + return pthread_mutex_trylock(&m->pthread_mutex); +#endif +} + +void zpl_mutex_unlock(zpl_mutex *m) { +#if defined(ZPL_SYSTEM_WINDOWS) + LeaveCriticalSection(&m->win32_critical_section); +#else + pthread_mutex_unlock(&m->pthread_mutex); +#endif +} + +ZPL_END_C_DECLS +// file: source/threading/thread.c + +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +zpl_b32 zpl_thread_is_running(zpl_thread const *t) { return t->is_running != 0; } + +void zpl_thread_init(zpl_thread *t) { + zpl_zero_item(t); + +#if defined(ZPL_SYSTEM_WINDOWS) + t->win32_handle = INVALID_HANDLE_VALUE; +#else + t->posix_handle = 0; +#endif + + zpl_semaphore_init(&t->semaphore); +} + +void zpl_thread_destroy(zpl_thread *t) { + if (t->is_running) zpl_thread_join(t); + zpl_semaphore_destroy(&t->semaphore); +} + +void zpl__thread_run(zpl_thread *t) { + zpl_semaphore_release(&t->semaphore); + t->return_value = t->proc(t); +} + +#if defined(ZPL_SYSTEM_WINDOWS) +DWORD __stdcall zpl__thread_proc(void *arg) { + zpl_thread *t = cast(zpl_thread *)arg; + zpl__thread_run(t); + t->is_running = false; + return 0; +} +#else +void *zpl__thread_proc(void *arg) { + zpl_thread *t = cast(zpl_thread *)arg; + zpl__thread_run(t); + t->is_running = false; + return NULL; +} +#endif + +void zpl_thread_start(zpl_thread *t, zpl_thread_proc proc, void *user_data) { + zpl_thread_start_with_stack(t, proc, user_data, 0); +} + +void zpl_thread_start_with_stack(zpl_thread *t, zpl_thread_proc proc, void *user_data, zpl_isize stack_size) { + ZPL_ASSERT(!t->is_running); + ZPL_ASSERT(proc != NULL); + t->proc = proc; + t->user_data = user_data; + t->stack_size = stack_size; + +#if defined(ZPL_SYSTEM_WINDOWS) + t->win32_handle = CreateThread(NULL, stack_size, zpl__thread_proc, t, 0, NULL); + ZPL_ASSERT_MSG(t->win32_handle != NULL, "CreateThread: GetLastError"); +#else + { + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + if (stack_size != 0) + pthread_attr_setstacksize(&attr, stack_size); + pthread_create(&t->posix_handle, &attr, zpl__thread_proc, t); + pthread_attr_destroy(&attr); + } +#endif + + t->is_running = true; + zpl_semaphore_wait(&t->semaphore); +} + +void zpl_thread_join(zpl_thread *t) { + if (!t->is_running) return; + +#if defined(ZPL_SYSTEM_WINDOWS) + WaitForSingleObject(t->win32_handle, INFINITE); + CloseHandle(t->win32_handle); + t->win32_handle = INVALID_HANDLE_VALUE; +#else + pthread_join(t->posix_handle, NULL); + t->posix_handle = 0; +#endif + t->is_running = false; +} + +zpl_u32 zpl_thread_current_id(void) { + zpl_u32 thread_id; +#if defined(ZPL_SYSTEM_WINDOWS) +#if defined(ZPL_ARCH_32_BIT) && defined(ZPL_CPU_X86) + thread_id = (cast(zpl_u32 *)__readfsdword(24))[9]; +#elif defined(ZPL_ARCH_64_BIT) && defined(ZPL_CPU_X86) + thread_id = (cast(zpl_u32 *)__readgsqword(48))[18]; +#else + thread_id = GetCurrentThreadId(); +#endif + +#elif defined(ZPL_SYSTEM_OSX) && defined(ZPL_ARCH_64_BIT) + thread_id = pthread_mach_thread_np(pthread_self()); +#elif defined(ZPL_ARCH_32_BIT) && defined(ZPL_CPU_X86) + __asm__("mov %%gs:0x08,%0" : "=r"(thread_id)); +#elif defined(ZPL_ARCH_64_BIT) && defined(ZPL_CPU_X86) + __asm__("mov %%fs:0x10,%0" : "=r"(thread_id)); +#elif defined(__ARM_ARCH) + thread_id = pthread_self(); +#else +#error Unsupported architecture for zpl_thread_current_id() +#endif + + return thread_id; +} + +void zpl_thread_set_name(zpl_thread *t, char const *name) { +#if defined(ZPL_COMPILER_MSVC) +#pragma pack(push, 8) + typedef struct { + DWORD type; + char const *name; + DWORD id; + DWORD flags; + } zplprivThreadName; +#pragma pack(pop) + + zplprivThreadName tn; + tn.type = 0x1000; + tn.name = name; + tn.id = GetThreadId(cast(HANDLE)t->win32_handle); + tn.flags = 0; + + __try { + RaiseException(0x406d1388, 0, zpl_size_of(tn)/4, cast(ULONG_PTR *)&tn); + } __except(1 /*EXCEPTION_EXECUTE_HANDLER*/) { + } + +#elif defined(ZPL_SYSTEM_WINDOWS) && !defined(ZPL_COMPILER_MSVC) + zpl_unused(t); + zpl_unused(name); + // IMPORTANT TODO: Set thread name for GCC/Clang on windows + return; +#elif defined(ZPL_SYSTEM_OSX) + // TODO: Test if this works + pthread_setname_np(name); +#else + zpl_unused(t); + zpl_unused(name); + // TODO: Test if this works + // pthread_set_name_np(t->posix_handle, name); +#endif +} + +ZPL_END_C_DECLS +// file: source/threading/sync.c + +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +void zpl_sync_init(zpl_sync *s) { + zpl_zero_item(s); + zpl_mutex_init(&s->mutex); + zpl_mutex_init(&s->start); + zpl_semaphore_init(&s->release); +} + +void zpl_sync_destroy(zpl_sync *s) { + if (s->waiting) { + ZPL_PANIC("Cannot destroy while threads are waiting!"); + } + + zpl_mutex_destroy(&s->mutex); + zpl_mutex_destroy(&s->start); + zpl_semaphore_destroy(&s->release); +} + +void zpl_sync_set_target(zpl_sync *s, zpl_i32 count) { + zpl_mutex_lock(&s->start); + + zpl_mutex_lock(&s->mutex); + ZPL_ASSERT(s->target == 0); + s->target = count; + s->current = 0; + s->waiting = 0; + zpl_mutex_unlock(&s->mutex); +} + +void zpl_sync_release(zpl_sync *s) { + if (s->waiting) { + zpl_semaphore_release(&s->release); + } else { + s->target = 0; + zpl_mutex_unlock(&s->start); + } +} + +zpl_i32 zpl_sync_reach(zpl_sync *s) { + zpl_i32 n; + zpl_mutex_lock(&s->mutex); + ZPL_ASSERT(s->current < s->target); + n = ++s->current; // NOTE: Record this value to avoid possible race if `return s->current` was done + if (s->current == s->target) + zpl_sync_release(s); + zpl_mutex_unlock(&s->mutex); + return n; +} + +void zpl_sync_reach_and_wait(zpl_sync *s) { + zpl_mutex_lock(&s->mutex); + ZPL_ASSERT(s->current < s->target); + s->current++; + if (s->current == s->target) { + zpl_sync_release(s); + zpl_mutex_unlock(&s->mutex); + } else { + s->waiting++; // NOTE: Waiting, so one more waiter + zpl_mutex_unlock(&s->mutex); // NOTE: Release the mutex to other threads + zpl_semaphore_wait(&s->release); // NOTE: Wait for merge completion + zpl_mutex_lock(&s->mutex); // NOTE: On merge completion, lock mutex + s->waiting--; // NOTE: Done waiting + zpl_sync_release(s); // NOTE: Restart the next waiter + zpl_mutex_unlock(&s->mutex); + } +} + +ZPL_END_C_DECLS +// file: source/threading/affinity.c + +#ifdef ZPL_EDITOR +#include +#endif + +#if defined(ZPL_SYSTEM_MACOS) +#include +#endif + +ZPL_BEGIN_C_DECLS + +#if defined(ZPL_SYSTEM_WINDOWS) || defined(ZPL_SYSTEM_CYGWIN) + +void zpl_affinity_init(zpl_affinity *a) { + SYSTEM_LOGICAL_PROCESSOR_INFORMATION *start_processor_info = NULL; + DWORD length = 0; + zpl_b32 result = GetLogicalProcessorInformation(NULL, &length); + + zpl_zero_item(a); + + if (!result && GetLastError() == 122l /*ERROR_INSUFFICIENT_BUFFER*/ && length > 0) { + start_processor_info = cast(SYSTEM_LOGICAL_PROCESSOR_INFORMATION *)zpl_alloc(zpl_heap_allocator(), length); + result = GetLogicalProcessorInformation(start_processor_info, &length); + if (result) { + SYSTEM_LOGICAL_PROCESSOR_INFORMATION *end_processor_info, *processor_info; + + a->is_accurate = true; + a->core_count = 0; + a->thread_count = 0; + end_processor_info = cast(SYSTEM_LOGICAL_PROCESSOR_INFORMATION *)zpl_pointer_add(start_processor_info, length); + + for (processor_info = start_processor_info; + processor_info < end_processor_info; + processor_info++) { + if (processor_info->Relationship == RelationProcessorCore) { + zpl_isize thread = zpl_count_set_bits(processor_info->ProcessorMask); + if (thread == 0) { + a->is_accurate = false; + } else if (a->thread_count + thread > ZPL_WIN32_MAX_THREADS) { + a->is_accurate = false; + } else { + ZPL_ASSERT(a->core_count <= a->thread_count && + a->thread_count < ZPL_WIN32_MAX_THREADS); + a->core_masks[a->core_count++] = processor_info->ProcessorMask; + a->thread_count += thread; } } - } + } + + zpl_free(zpl_heap_allocator(), start_processor_info); + } + + ZPL_ASSERT(a->core_count <= a->thread_count); + if (a->thread_count == 0) { + a->is_accurate = false; + a->core_count = 1; + a->thread_count = 1; + a->core_masks[0] = 1; + } + +} - void zpl_affinity_destroy(zpl_affinity *a) { - zpl_unused(a); +void zpl_affinity_destroy(zpl_affinity *a) { + zpl_unused(a); +} + +zpl_b32 zpl_affinity_set(zpl_affinity *a, zpl_isize core, zpl_isize thread) { + zpl_usize available_mask, check_mask = 1; + ZPL_ASSERT(thread < zpl_affinity_thread_count_for_core(a, core)); + + available_mask = a->core_masks[core]; + for (;;) { + if ((available_mask & check_mask) != 0) { + if (thread-- == 0) { + zpl_usize result = SetThreadAffinityMask(GetCurrentThread(), check_mask); + return result != 0; } + } + check_mask <<= 1; // NOTE: Onto the next bit + } +} - zpl_b32 zpl_affinity_set(zpl_affinity *a, zpl_isize core, zpl_isize thread_index) { - zpl_isize index; - thread_t thread; - thread_affinity_policy_data_t info; - kern_return_t result; +zpl_isize zpl_affinity_thread_count_for_core(zpl_affinity *a, zpl_isize core) { + ZPL_ASSERT(core >= 0 && core < a->core_count); + return zpl_count_set_bits(a->core_masks[core]); +} - ZPL_ASSERT(core < a->core_count); - ZPL_ASSERT(thread_index < a->threads_per_core); - - index = core * a->threads_per_core + thread_index; - thread = mach_thread_self(); - info.affinity_tag = cast(integer_t)index; - result = thread_policy_set(thread, THREAD_AFFINITY_POLICY, cast(thread_policy_t)&info, THREAD_AFFINITY_POLICY_COUNT); - return result == KERN_SUCCESS; - } - - zpl_isize zpl_affinity_thread_count_for_core(zpl_affinity *a, zpl_isize core) { - ZPL_ASSERT(core >= 0 && core < a->core_count); - return a->threads_per_core; - } - - #elif defined(ZPL_SYSTEM_LINUX) || defined(ZPL_SYSTEM_FREEBSD) || defined(ZPL_SYSTEM_OPENBSD) - - // IMPORTANT TODO: This zpl_affinity stuff for linux needs be improved a lot! - // NOTE(zangent): I have to read /proc/cpuinfo to get the number of threads per core. - - void zpl_affinity_init(zpl_affinity *a) { - zpl_b32 accurate = true; - zpl_isize threads = 0; - - a->thread_count = 1; - a->core_count = sysconf(_SC_NPROCESSORS_ONLN); - a->threads_per_core = 1; - - - if(a->core_count <= 0) { - a->core_count = 1; - accurate = false; - } - - // Parsing /proc/cpuinfo to get the number of threads per core. - // NOTE(zangent): This calls the CPU's threads "cores", although the wording - // is kind of weird. This should be right, though. - FILE *cpu_info = fopen("/proc/cpuinfo", "r"); - if (cpu_info != NULL) { - for (;;) { - // The 'temporary char'. Everything goes into this char, - // so that we can check against EOF at the end of this loop. - int c; - - #define AF__CHECK(letter) ((c = getc(cpu_info)) == letter) - if (AF__CHECK('c') && AF__CHECK('p') && AF__CHECK('u') && AF__CHECK(' ') && - AF__CHECK('c') && AF__CHECK('o') && AF__CHECK('r') && AF__CHECK('e') && AF__CHECK('s')) { - // We're on a CPU info line. - while (!AF__CHECK(EOF)) { - if (c == '\n') { - break; - } else if (c < '0' || '9' > c) { - continue; - } - threads = threads * 10 + (c - '0'); - } - break; - } else { - while (!AF__CHECK('\n')) { - if (c==EOF) { - break; - } - } - } - if (c == EOF) { - break; - } - #undef AF__CHECK - } - - fclose(cpu_info); - } - - if (threads == 0) { - threads = 1; - accurate = false; - } - - a->threads_per_core = threads; - a->thread_count = a->threads_per_core * a->core_count; - a->is_accurate = accurate; - - } - - void zpl_affinity_destroy(zpl_affinity *a) { - zpl_unused(a); - } - - zpl_b32 zpl_affinity_set(zpl_affinity * a, zpl_isize core, zpl_isize thread_index) { - zpl_unused(a); - zpl_unused(core); - zpl_unused(thread_index); - return true; - } - - zpl_isize zpl_affinity_thread_count_for_core(zpl_affinity *a, zpl_isize core) { - ZPL_ASSERT(0 <= core && core < a->core_count); - return a->threads_per_core; - } - - #elif defined(ZPL_SYSTEM_EMSCRIPTEN) - #error No affinity implementation for Emscripten - #else - #error TODO: Unknown system - #endif - - ZPL_END_C_DECLS - - #if defined(ZPL_MODULE_JOBS) - // file: source/jobs.c - - /////////////////////////////////////////////////////////////// - // - // Thread Pool - // - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - zpl_isize zpl__jobs_entry(struct zpl_thread *thread) { - zpl_thread_worker *tw = (zpl_thread_worker *)thread->user_data; - zpl_thread_pool *pool = (zpl_thread_pool *)tw->pool; - - for (;;) { - zpl_u32 status = zpl_atomic32_load(&tw->status); - - switch (status) { - case ZPL_JOBS_STATUS_READY: { - zpl_atomic32_store(&tw->status, ZPL_JOBS_STATUS_BUSY); - - zpl_mutex_lock(&pool->access); - zpl_thread_job *job = pool->jobs + tw->jobid; - zpl_mutex_unlock(&pool->access); - - job->proc(job->data); - - zpl_atomic32_store(&tw->status, ZPL_JOBS_STATUS_WAITING); - } break; - - case ZPL_JOBS_STATUS_WAITING: { - zpl_yield( ); - } break; - - case ZPL_JOBS_STATUS_TERM: { - return 0; - } break; - } - } - - return 0; - } - - void zpl_jobs_init(zpl_thread_pool *pool, zpl_allocator a, zpl_u32 max_threads) { - zpl_thread_pool pool_ = { 0 }; - *pool = pool_; - zpl_mutex_init(&pool->access); - - pool->alloc = a; - pool->max_threads = max_threads; - - // NOTE: Spawn a new job slot when number of available slots is below 25% - // compared to the total number of slots. - pool->job_spawn_treshold = 0.25; - - zpl_buffer_init(pool->workers, a, max_threads); - zpl_array_init(pool->jobs, a); - zpl_array_init(pool->queue, a); - zpl_array_init(pool->available, a); - - for (zpl_usize i = 0; i < max_threads; ++i) { - zpl_thread_worker worker_ = { 0 }; - zpl_thread_worker *tw = pool->workers + i; - *tw = worker_; - - zpl_thread_init(&tw->thread); - zpl_atomic32_store(&tw->status, ZPL_JOBS_STATUS_WAITING); - tw->pool = pool; - tw->jobid = ZPL_INVALID_JOB; - zpl_thread_start(&tw->thread, zpl__jobs_entry, (void *)tw); +#elif defined(ZPL_SYSTEM_MACOS) +void zpl_affinity_init(zpl_affinity *a) { + zpl_usize count, count_size = zpl_size_of(count); + + a->is_accurate = false; + a->thread_count = 1; + a->core_count = 1; + a->threads_per_core = 1; + + if (sysctlbyname("hw.logicalcpu", &count, &count_size, NULL, 0) == 0) { + if (count > 0) { + a->thread_count = count; + // Get # of physical cores + if (sysctlbyname("hw.physicalcpu", &count, &count_size, NULL, 0) == 0) { + if (count > 0) { + a->core_count = count; + a->threads_per_core = a->thread_count / count; + if (a->threads_per_core < 1) + a->threads_per_core = 1; + else + a->is_accurate = true; } } + } + } + +} - void zpl_jobs_free(zpl_thread_pool *pool) { - for (zpl_usize i = 0; i < pool->max_threads; ++i) { - zpl_thread_worker *tw = pool->workers + i; +void zpl_affinity_destroy(zpl_affinity *a) { + zpl_unused(a); +} - zpl_atomic32_store(&tw->status, ZPL_JOBS_STATUS_TERM); - zpl_thread_destroy(&tw->thread); - } +zpl_b32 zpl_affinity_set(zpl_affinity *a, zpl_isize core, zpl_isize thread_index) { + zpl_isize index; + thread_t thread; + thread_affinity_policy_data_t info; + kern_return_t result; + + ZPL_ASSERT(core < a->core_count); + ZPL_ASSERT(thread_index < a->threads_per_core); + + index = core * a->threads_per_core + thread_index; + thread = mach_thread_self(); + info.affinity_tag = cast(integer_t)index; + result = thread_policy_set(thread, THREAD_AFFINITY_POLICY, cast(thread_policy_t)&info, THREAD_AFFINITY_POLICY_COUNT); + return result == KERN_SUCCESS; +} - zpl_buffer_free(pool->workers); - zpl_array_free(pool->jobs); - zpl_array_free(pool->queue); - zpl_array_free(pool->available); - } +zpl_isize zpl_affinity_thread_count_for_core(zpl_affinity *a, zpl_isize core) { + ZPL_ASSERT(core >= 0 && core < a->core_count); + return a->threads_per_core; +} - void zpl_jobs_enqueue_with_priority(zpl_thread_pool *pool, zpl_jobs_proc proc, void *data, zpl_f32 priority) { - ZPL_ASSERT_NOT_NULL(proc); - zpl_f32 treshold = 0.0f; +#elif defined(ZPL_SYSTEM_LINUX) || defined(ZPL_SYSTEM_FREEBSD) || defined(ZPL_SYSTEM_OPENBSD) - if (zpl_array_count(pool->queue) > 0) { - treshold = (zpl_array_count(pool->available) / (zpl_f32)zpl_array_count(pool->jobs)); - } +// IMPORTANT TODO: This zpl_affinity stuff for linux needs be improved a lot! +// NOTE(zangent): I have to read /proc/cpuinfo to get the number of threads per core. - if (treshold <= pool->job_spawn_treshold) { - zpl_thread_job job = { 0 }; - job.proc = proc; - job.data = data; - job.priority = priority; - - zpl_array_append(pool->jobs, job); - zpl_u32 jobid = (zpl_u32)zpl_array_count(pool->jobs) - 1; - zpl_array_append(pool->queue, jobid); - } else { - zpl_u32 jobid = zpl_array_back(pool->available); - zpl_thread_job *jp = pool->jobs + jobid; - zpl_array_pop(pool->available); - - jp->proc = proc; - jp->data = data; - jp->priority = priority; - - zpl_array_append(pool->queue, jobid); - } - } - - void zpl_jobs_enqueue(zpl_thread_pool *pool, zpl_jobs_proc proc, void *data) { - ZPL_ASSERT_NOT_NULL(proc); - zpl_jobs_enqueue_with_priority(pool, proc, data, 1.0f); - } - - zpl_thread_local zpl_thread_pool *zpl__thread_pool; - - ZPL_COMPARE_PROC(zpl___jobs_cmp) { - zpl_thread_job *p = (zpl_thread_job *)(zpl__thread_pool->jobs + *(zpl_u32 *)a); - zpl_thread_job *q = (zpl_thread_job *)(zpl__thread_pool->jobs + *(zpl_u32 *)b); - return cast(zpl_i32)(p->priority < q->priority ? 1.0f : p->priority > q->priority); - } - - ZPL_COMPARE_PROC_PTR(zpl__jobs_cmp(zpl_thread_pool *pool)) { - zpl__thread_pool = pool; - return &zpl___jobs_cmp; - } - - zpl_b32 zpl_jobs_process(zpl_thread_pool *pool) { - // NOTE: Sort the queue based on the job priority - if (zpl_array_count(pool->queue)) { - zpl_sort_array(pool->queue, zpl_array_count(pool->queue), zpl__jobs_cmp(pool)); - } - - // NOTE: Process the jobs - for (zpl_usize i = 0; i < pool->max_threads; ++i) { - zpl_thread_worker *tw = pool->workers + i; - if (zpl_array_count(pool->queue) == 0) return false; - - zpl_u32 status = zpl_atomic32_load(&tw->status); - - if (status == ZPL_JOBS_STATUS_WAITING) { - if (tw->jobid != ZPL_INVALID_JOB) { zpl_array_append(pool->available, tw->jobid); } - - zpl_u32 jobid = *pool->queue; - zpl_array_remove_at(pool->queue, 0); - tw->jobid = jobid; - zpl_atomic32_store(&tw->status, ZPL_JOBS_STATUS_READY); - } - } - - return true; - } - - ZPL_END_C_DECLS - #endif - - #if defined(ZPL_MODULE_COROUTINES) - // file: source/coroutines.c - - //////////////////////////////////////////////////////////////// - // - // Coroutines - // - // - #ifdef ZPL_EDITOR - #include - #endif - - ZPL_BEGIN_C_DECLS - - struct { - zpl_b32 is_ready; - zpl_thread_pool coroutines; - zpl_thread runner; - zpl_atomic32 request_term; - zpl_mutex is_processing; - } zpl__co_internals; - - zpl_thread_local zpl_u8 zpl__co_yield_barrier; - - zpl_isize zpl__co_runner(struct zpl_thread *t) { - do { - if (zpl_atomic32_load(&zpl__co_internals.request_term)) +void zpl_affinity_init(zpl_affinity *a) { + zpl_b32 accurate = true; + zpl_isize threads = 0; + + a->thread_count = 1; + a->core_count = sysconf(_SC_NPROCESSORS_ONLN); + a->threads_per_core = 1; + + + if(a->core_count <= 0) { + a->core_count = 1; + accurate = false; + } + + // Parsing /proc/cpuinfo to get the number of threads per core. + // NOTE(zangent): This calls the CPU's threads "cores", although the wording + // is kind of weird. This should be right, though. + FILE *cpu_info = fopen("/proc/cpuinfo", "r"); + if (cpu_info != NULL) { + for (;;) { + // The 'temporary char'. Everything goes into this char, + // so that we can check against EOF at the end of this loop. + int c; + +#define AF__CHECK(letter) ((c = getc(cpu_info)) == letter) + if (AF__CHECK('c') && AF__CHECK('p') && AF__CHECK('u') && AF__CHECK(' ') && + AF__CHECK('c') && AF__CHECK('o') && AF__CHECK('r') && AF__CHECK('e') && AF__CHECK('s')) { + // We're on a CPU info line. + while (!AF__CHECK(EOF)) { + if (c == '\n') { break; - - zpl_b32 lock = zpl_mutex_try_lock(&zpl__co_internals.is_processing); - - while (!lock) { - zpl_yield_thread(); - lock = zpl_mutex_try_lock(&zpl__co_internals.is_processing); - - if (zpl_atomic32_load(&zpl__co_internals.request_term)) - break; - - zpl_mfence(); + } else if (c < '0' || '9' > c) { + continue; } + threads = threads * 10 + (c - '0'); + } + break; + } else { + while (!AF__CHECK('\n')) { + if (c==EOF) { + break; + } + } + } + if (c == EOF) { + break; + } +#undef AF__CHECK + } + + fclose(cpu_info); + } + + if (threads == 0) { + threads = 1; + accurate = false; + } + + a->threads_per_core = threads; + a->thread_count = a->threads_per_core * a->core_count; + a->is_accurate = accurate; + +} - zpl_jobs_process(&zpl__co_internals.coroutines); - zpl_mutex_unlock(&zpl__co_internals.is_processing); - } while (1); +void zpl_affinity_destroy(zpl_affinity *a) { + zpl_unused(a); +} +zpl_b32 zpl_affinity_set(zpl_affinity * a, zpl_isize core, zpl_isize thread_index) { + zpl_unused(a); + zpl_unused(core); + zpl_unused(thread_index); + return true; +} + +zpl_isize zpl_affinity_thread_count_for_core(zpl_affinity *a, zpl_isize core) { + ZPL_ASSERT(0 <= core && core < a->core_count); + return a->threads_per_core; +} + +#elif defined(ZPL_SYSTEM_EMSCRIPTEN) +#error No affinity implementation for Emscripten +#else +#error TODO: Unknown system +#endif + +ZPL_END_C_DECLS + +#if defined(ZPL_MODULE_JOBS) +// file: source/jobs.c + +/////////////////////////////////////////////////////////////// +// +// Thread Pool +// +#ifdef ZPL_EDITOR +#include +#endif + +ZPL_BEGIN_C_DECLS + +zpl_isize zpl__jobs_entry(struct zpl_thread *thread) { + zpl_thread_worker *tw = (zpl_thread_worker *)thread->user_data; + zpl_thread_pool *pool = (zpl_thread_pool *)tw->pool; + + for (;;) { + zpl_u32 status = zpl_atomic32_load(&tw->status); + + switch (status) { + case ZPL_JOBS_STATUS_READY: { + zpl_atomic32_store(&tw->status, ZPL_JOBS_STATUS_BUSY); + + zpl_mutex_lock(&pool->access); + zpl_thread_job *job = pool->jobs + tw->jobid; + zpl_mutex_unlock(&pool->access); + + job->proc(job->data); + + zpl_atomic32_store(&tw->status, ZPL_JOBS_STATUS_WAITING); + } break; + + case ZPL_JOBS_STATUS_WAITING: { + zpl_yield( ); + } break; + + case ZPL_JOBS_STATUS_TERM: { return 0; - } + } break; + } + } + + return 0; +} - void zpl__co_job(void *data) { - zpl_co *co = cast(zpl_co *)data; +void zpl_jobs_init(zpl_thread_pool *pool, zpl_allocator a, zpl_u32 max_threads) { + zpl_thread_pool pool_ = { 0 }; + *pool = pool_; + zpl_mutex_init(&pool->access); + + pool->alloc = a; + pool->max_threads = max_threads; + + // NOTE: Spawn a new job slot when number of available slots is below 25% + // compared to the total number of slots. + pool->job_spawn_treshold = 0.25; + + zpl_buffer_init(pool->workers, a, max_threads); + zpl_array_init(pool->jobs, a); + zpl_array_init(pool->queue, a); + zpl_array_init(pool->available, a); + + for (zpl_usize i = 0; i < max_threads; ++i) { + zpl_thread_worker worker_ = { 0 }; + zpl_thread_worker *tw = pool->workers + i; + *tw = worker_; + + zpl_thread_init(&tw->thread); + zpl_atomic32_store(&tw->status, ZPL_JOBS_STATUS_WAITING); + tw->pool = pool; + tw->jobid = ZPL_INVALID_JOB; + zpl_thread_start(&tw->thread, zpl__jobs_entry, (void *)tw); + } +} - zpl_atomic32_store(&co->status, ZPL_CO_RUNNING); - co->f(co); - zpl_atomic32_store(&co->status, ZPL_CO_DEAD); - } +void zpl_jobs_free(zpl_thread_pool *pool) { + for (zpl_usize i = 0; i < pool->max_threads; ++i) { + zpl_thread_worker *tw = pool->workers + i; + + zpl_atomic32_store(&tw->status, ZPL_JOBS_STATUS_TERM); + zpl_thread_destroy(&tw->thread); + } + + zpl_buffer_free(pool->workers); + zpl_array_free(pool->jobs); + zpl_array_free(pool->queue); + zpl_array_free(pool->available); +} - void zpl_co_init(zpl_allocator a, zpl_u32 max_threads) { - if (!zpl__co_internals.is_ready) { - zpl_zero_item(&zpl__co_internals); - zpl_mutex_init(&zpl__co_internals.is_processing); - zpl_jobs_init(&zpl__co_internals.coroutines, a, max_threads); - zpl_thread_init(&zpl__co_internals.runner); - zpl_thread_start(&zpl__co_internals.runner, zpl__co_runner, NULL); - zpl_atomic32_store(&zpl__co_internals.request_term, 0); - zpl__co_internals.is_ready = 1; +void zpl_jobs_enqueue_with_priority(zpl_thread_pool *pool, zpl_jobs_proc proc, void *data, zpl_f32 priority) { + ZPL_ASSERT_NOT_NULL(proc); + zpl_f32 treshold = 0.0f; + + if (zpl_array_count(pool->queue) > 0) { + treshold = (zpl_array_count(pool->available) / (zpl_f32)zpl_array_count(pool->jobs)); + } + + if (treshold <= pool->job_spawn_treshold) { + zpl_thread_job job = { 0 }; + job.proc = proc; + job.data = data; + job.priority = priority; + + zpl_array_append(pool->jobs, job); + zpl_u32 jobid = (zpl_u32)zpl_array_count(pool->jobs) - 1; + zpl_array_append(pool->queue, jobid); + } else { + zpl_u32 jobid = zpl_array_back(pool->available); + zpl_thread_job *jp = pool->jobs + jobid; + zpl_array_pop(pool->available); + + jp->proc = proc; + jp->data = data; + jp->priority = priority; + + zpl_array_append(pool->queue, jobid); + } +} - // Set up a barrier so that we won't let user call zpl_co_yield in a main thread. - zpl__co_yield_barrier = 1; - } - } +void zpl_jobs_enqueue(zpl_thread_pool *pool, zpl_jobs_proc proc, void *data) { + ZPL_ASSERT_NOT_NULL(proc); + zpl_jobs_enqueue_with_priority(pool, proc, data, 1.0f); +} - void zpl_co_destroy(void) { - zpl_atomic32_exchange(&zpl__co_internals.request_term, 1); - zpl_thread_destroy(&zpl__co_internals.runner); - zpl_mutex_destroy(&zpl__co_internals.is_processing); - zpl_jobs_free(&zpl__co_internals.coroutines); - zpl__co_internals.is_ready = 0; - zpl_mfence(); - } +zpl_thread_local zpl_thread_pool *zpl__thread_pool; - void zpl_co_make(zpl_co *co, zpl_co_proc f) { - ZPL_ASSERT_MSG(zpl__co_internals.is_ready, "Coroutines module is not initialized. Call zpl_co_init first!"); - ZPL_ASSERT_NOT_NULL(co); +ZPL_COMPARE_PROC(zpl___jobs_cmp) { + zpl_thread_job *p = (zpl_thread_job *)(zpl__thread_pool->jobs + *(zpl_u32 *)a); + zpl_thread_job *q = (zpl_thread_job *)(zpl__thread_pool->jobs + *(zpl_u32 *)b); + return cast(zpl_i32)(p->priority < q->priority ? 1.0f : p->priority > q->priority); +} - zpl_zero_item(co); - co->f = f; - zpl_atomic32_store(&co->status, ZPL_CO_READY); - zpl_atomic32_store(&co->resume, 0); - } +ZPL_COMPARE_PROC_PTR(zpl__jobs_cmp(zpl_thread_pool *pool)) { + zpl__thread_pool = pool; + return &zpl___jobs_cmp; +} - void zpl_co_resume(zpl_co *co, void *data) { - ZPL_ASSERT_NOT_NULL(co); +zpl_b32 zpl_jobs_process(zpl_thread_pool *pool) { + // NOTE: Sort the queue based on the job priority + if (zpl_array_count(pool->queue)) { + zpl_sort_array(pool->queue, zpl_array_count(pool->queue), zpl__jobs_cmp(pool)); + } + + // NOTE: Process the jobs + for (zpl_usize i = 0; i < pool->max_threads; ++i) { + zpl_thread_worker *tw = pool->workers + i; + if (zpl_array_count(pool->queue) == 0) return false; + + zpl_u32 status = zpl_atomic32_load(&tw->status); + + if (status == ZPL_JOBS_STATUS_WAITING) { + if (tw->jobid != ZPL_INVALID_JOB) { zpl_array_append(pool->available, tw->jobid); } + + zpl_u32 jobid = *pool->queue; + zpl_array_remove_at(pool->queue, 0); + tw->jobid = jobid; + zpl_atomic32_store(&tw->status, ZPL_JOBS_STATUS_READY); + } + } + + return true; +} - if (data != NULL) { - zpl_atomic32_store(&co->push_arg, 1); - co->data_stack[co->data_write_idx++] = data; - zpl_atomic32_spin_unlock(&co->push_arg); - zpl_mfence(); - } +ZPL_END_C_DECLS +#endif - zpl_i32 status = zpl_atomic32_load(&co->status); +#if defined(ZPL_MODULE_COROUTINES) +// file: source/coroutines.c - // Initialize a job - if (status == ZPL_CO_READY) { +//////////////////////////////////////////////////////////////// +// +// Coroutines +// +// +#ifdef ZPL_EDITOR +#include +#endif - if (data) - co->data = co->data_stack[co->data_read_idx++]; +ZPL_BEGIN_C_DECLS - zpl_atomic32_store(&co->status, ZPL_CO_ENQUEUED); - zpl_mfence(); +struct { + zpl_b32 is_ready; + zpl_thread_pool coroutines; + zpl_thread runner; + zpl_atomic32 request_term; + zpl_mutex is_processing; +} zpl__co_internals; - zpl_mutex_lock(&zpl__co_internals.is_processing); - zpl_jobs_enqueue(&zpl__co_internals.coroutines, zpl__co_job, cast(void *)co); - zpl_mutex_unlock(&zpl__co_internals.is_processing); - } - else { - zpl_atomic32_fetch_add(&co->resume, 1); - zpl_mfence(); - } - } +zpl_thread_local zpl_u8 zpl__co_yield_barrier; - void zpl_co_yield(zpl_co *co) { - zpl_i32 value; - ZPL_ASSERT_NOT_NULL(co); - ZPL_ASSERT_MSG((!zpl__co_yield_barrier), "zpl_co_yield can only be called inside of coroutines!"); +zpl_isize zpl__co_runner(struct zpl_thread *t) { + do { + if (zpl_atomic32_load(&zpl__co_internals.request_term)) + break; + + zpl_b32 lock = zpl_mutex_try_lock(&zpl__co_internals.is_processing); + + while (!lock) { + zpl_yield_thread(); + lock = zpl_mutex_try_lock(&zpl__co_internals.is_processing); + + if (zpl_atomic32_load(&zpl__co_internals.request_term)) + break; + + zpl_mfence(); + } + + zpl_jobs_process(&zpl__co_internals.coroutines); + zpl_mutex_unlock(&zpl__co_internals.is_processing); + } while (1); + + return 0; +} - zpl_atomic32_store(&co->status, ZPL_CO_WAITING); +void zpl__co_job(void *data) { + zpl_co *co = cast(zpl_co *)data; + + zpl_atomic32_store(&co->status, ZPL_CO_RUNNING); + co->f(co); + zpl_atomic32_store(&co->status, ZPL_CO_DEAD); +} - value = zpl_atomic32_load(&co->resume); +void zpl_co_init(zpl_allocator a, zpl_u32 max_threads) { + if (!zpl__co_internals.is_ready) { + zpl_zero_item(&zpl__co_internals); + zpl_mutex_init(&zpl__co_internals.is_processing); + zpl_jobs_init(&zpl__co_internals.coroutines, a, max_threads); + zpl_thread_init(&zpl__co_internals.runner); + zpl_thread_start(&zpl__co_internals.runner, zpl__co_runner, NULL); + zpl_atomic32_store(&zpl__co_internals.request_term, 0); + zpl__co_internals.is_ready = 1; + + // Set up a barrier so that we won't let user call zpl_co_yield in a main thread. + zpl__co_yield_barrier = 1; + } +} - while (value == 0) { - zpl_yield_thread(); - value = zpl_atomic32_load(&co->resume); - zpl_mfence(); - } +void zpl_co_destroy(void) { + zpl_atomic32_exchange(&zpl__co_internals.request_term, 1); + zpl_thread_destroy(&zpl__co_internals.runner); + zpl_mutex_destroy(&zpl__co_internals.is_processing); + zpl_jobs_free(&zpl__co_internals.coroutines); + zpl__co_internals.is_ready = 0; + zpl_mfence(); +} - zpl_atomic32_spin_lock(&co->push_arg, -1); - co->data = co->data_stack[co->data_read_idx++]; +void zpl_co_make(zpl_co *co, zpl_co_proc f) { + ZPL_ASSERT_MSG(zpl__co_internals.is_ready, "Coroutines module is not initialized. Call zpl_co_init first!"); + ZPL_ASSERT_NOT_NULL(co); + + zpl_zero_item(co); + co->f = f; + zpl_atomic32_store(&co->status, ZPL_CO_READY); + zpl_atomic32_store(&co->resume, 0); +} - // null pointer is present, no arg is found, so return back by 1 index - if (co->data == NULL) { - co->data_read_idx--; - } +void zpl_co_resume(zpl_co *co, void *data) { + ZPL_ASSERT_NOT_NULL(co); + + if (data != NULL) { + zpl_atomic32_store(&co->push_arg, 1); + co->data_stack[co->data_write_idx++] = data; + zpl_atomic32_spin_unlock(&co->push_arg); + zpl_mfence(); + } + + zpl_i32 status = zpl_atomic32_load(&co->status); + + // Initialize a job + if (status == ZPL_CO_READY) { + + if (data) + co->data = co->data_stack[co->data_read_idx++]; + + zpl_atomic32_store(&co->status, ZPL_CO_ENQUEUED); + zpl_mfence(); + + zpl_mutex_lock(&zpl__co_internals.is_processing); + zpl_jobs_enqueue(&zpl__co_internals.coroutines, zpl__co_job, cast(void *)co); + zpl_mutex_unlock(&zpl__co_internals.is_processing); + } + else { + zpl_atomic32_fetch_add(&co->resume, 1); + zpl_mfence(); + } +} - zpl_atomic32_spin_unlock(&co->push_arg); +void zpl_co_yield(zpl_co *co) { + zpl_i32 value; + ZPL_ASSERT_NOT_NULL(co); + ZPL_ASSERT_MSG((!zpl__co_yield_barrier), "zpl_co_yield can only be called inside of coroutines!"); + + zpl_atomic32_store(&co->status, ZPL_CO_WAITING); + + value = zpl_atomic32_load(&co->resume); + + while (value == 0) { + zpl_yield_thread(); + value = zpl_atomic32_load(&co->resume); + zpl_mfence(); + } + + zpl_atomic32_spin_lock(&co->push_arg, -1); + co->data = co->data_stack[co->data_read_idx++]; + + // null pointer is present, no arg is found, so return back by 1 index + if (co->data == NULL) { + co->data_read_idx--; + } + + zpl_atomic32_spin_unlock(&co->push_arg); + + zpl_atomic32_store(&co->status, ZPL_CO_RUNNING); + zpl_atomic32_fetch_add(&co->resume, -1); +} - zpl_atomic32_store(&co->status, ZPL_CO_RUNNING); - zpl_atomic32_fetch_add(&co->resume, -1); - } - - ZPL_END_C_DECLS - #endif - #endif +ZPL_END_C_DECLS +#endif +#endif - #if defined(ZPL_COMPILER_MSVC) - #pragma warning(pop) - #endif +#if defined(ZPL_COMPILER_MSVC) +#pragma warning(pop) +#endif - #if defined(__GCC__) || defined(__GNUC__) || defined(__clang__) - #pragma GCC diagnostic pop - #endif +#if defined(__GCC__) || defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic pop +#endif - #endif // ZPL_IMPLEMENTATION +#endif // ZPL_IMPLEMENTATION - #if defined(ZPL_EXPOSE_TYPES) - typedef zpl_u8 u8; - typedef zpl_i8 i8; - typedef zpl_u16 u16; - typedef zpl_i16 i16; - typedef zpl_u32 u32; - typedef zpl_i32 i32; - typedef zpl_u64 u64; - typedef zpl_i64 i64; - typedef zpl_b8 b8; - typedef zpl_b16 b16; - typedef zpl_b32 b32; - typedef zpl_f32 f32; - typedef zpl_f64 f64; - typedef zpl_rune rune; - typedef zpl_usize usize; - typedef zpl_isize isize; - typedef zpl_uintptr uintptr; - typedef zpl_intptr intptr; - #endif // ZPL_EXPOSE_TYPES +#if defined(ZPL_EXPOSE_TYPES) +typedef zpl_u8 u8; +typedef zpl_i8 i8; +typedef zpl_u16 u16; +typedef zpl_i16 i16; +typedef zpl_u32 u32; +typedef zpl_i32 i32; +typedef zpl_u64 u64; +typedef zpl_i64 i64; +typedef zpl_b8 b8; +typedef zpl_b16 b16; +typedef zpl_b32 b32; +typedef zpl_f32 f32; +typedef zpl_f64 f64; +typedef zpl_rune rune; +typedef zpl_usize usize; +typedef zpl_isize isize; +typedef zpl_uintptr uintptr; +typedef zpl_intptr intptr; +#endif // ZPL_EXPOSE_TYPES - #endif // ZPL_H +#endif // ZPL_H - // TOC: - // zpl.h - // zpl_hedley.h - // header/core/system.h - // header/core/types.h - // header/core/helpers.h - // header/core/debug.h - // header/core/memory.h - // header/core/memory_virtual.h - // header/core/memory_custom.h - // header/core/collections/array.h - // header/core/collections/buffer.h - // header/core/collections/list.h - // header/core/collections/ring.h - // header/core/collections/hashtable.h - // header/core/string.h - // header/core/stringlib.h - // header/core/file.h - // header/core/file_stream.h - // header/core/file_misc.h - // header/core/print.h - // header/core/time.h - // header/core/random.h - // header/core/misc.h - // header/core/sort.h - // header/timer.h - // header/hashing.h - // header/regex.h - // header/event.h - // header/dll.h - // header/opts.h - // header/process.h - // header/math.h - // header/json.h - // header/threading/atomic.h - // header/threading/fence.h - // header/threading/sem.h - // header/threading/mutex.h - // header/threading/thread.h - // header/threading/sync.h - // header/threading/affinity.h - // header/jobs.h - // header/coroutines.h - // source/core/debug.c - // source/core/memory.c - // source/core/memory_virtual.c - // source/core/memory_custom.c - // source/core/array.c - // source/core/string.c - // source/core/stringlib.c - // source/core/file.c - // source/core/file_stream.c - // source/core/file_misc.c - // source/core/print.c - // source/core/time.c - // source/core/random.c - // source/core/misc.c - // source/core/sort.c - // source/timer.c - // source/hashing.c - // source/regex.c - // source/event.c - // source/dll.c - // source/opts.c - // source/process.c - // source/math.c - // source/json.c - // source/threading/atomic.c - // source/threading/fence.c - // source/threading/sem.c - // source/threading/mutex.c - // source/threading/thread.c - // source/threading/sync.c - // source/threading/affinity.c - // source/jobs.c - // source/coroutines.c +// TOC: +// zpl.h +// zpl_hedley.h +// header/core/system.h +// header/core/types.h +// header/core/helpers.h +// header/core/debug.h +// header/core/memory.h +// header/core/memory_virtual.h +// header/core/memory_custom.h +// header/core/collections/array.h +// header/core/collections/buffer.h +// header/core/collections/list.h +// header/core/collections/ring.h +// header/core/collections/hashtable.h +// header/core/string.h +// header/core/stringlib.h +// header/core/file.h +// header/core/file_stream.h +// header/core/file_misc.h +// header/core/print.h +// header/core/time.h +// header/core/random.h +// header/core/misc.h +// header/core/sort.h +// header/timer.h +// header/hashing.h +// header/regex.h +// header/event.h +// header/dll.h +// header/opts.h +// header/process.h +// header/math.h +// header/json.h +// header/threading/atomic.h +// header/threading/fence.h +// header/threading/sem.h +// header/threading/mutex.h +// header/threading/thread.h +// header/threading/sync.h +// header/threading/affinity.h +// header/jobs.h +// header/coroutines.h +// source/core/debug.c +// source/core/memory.c +// source/core/memory_virtual.c +// source/core/memory_custom.c +// source/core/array.c +// source/core/string.c +// source/core/stringlib.c +// source/core/file.c +// source/core/file_stream.c +// source/core/file_misc.c +// source/core/print.c +// source/core/time.c +// source/core/random.c +// source/core/misc.c +// source/core/sort.c +// source/timer.c +// source/hashing.c +// source/regex.c +// source/event.c +// source/dll.c +// source/opts.c +// source/process.c +// source/math.c +// source/json.c +// source/threading/atomic.c +// source/threading/fence.c +// source/threading/sem.c +// source/threading/mutex.c +// source/threading/thread.c +// source/threading/sync.c +// source/threading/affinity.c +// source/jobs.c +// source/coroutines.c #endif // file: source/types.c @@ -19660,16 +19660,16 @@ typedef struct librg_entity_t { uint8_t flag_foreign : 1; uint8_t flag_visbility_owner_enabled : 1; uint8_t flag_unused2 : 1; - + int8_t observed_radius; uint16_t ownership_token; - + int32_t dimension; int64_t owner_id; - + librg_chunk chunks[LIBRG_ENTITY_MAXCHUNKS]; librg_table_i8 owner_visibility_map; - + void *userdata; } librg_entity_t; @@ -19688,15 +19688,15 @@ typedef struct librg_world_t { uint8_t valid; zpl_allocator allocator; zpl_random random; - + struct { uint16_t x, y, z; } worldsize; struct { uint16_t x, y, z; } chunksize; struct { int16_t x, y, z; } chunkoffset; - + librg_event_fn handlers[LIBRG_PACKAGING_TOTAL]; librg_table_ent entity_map; librg_table_tbl owner_map; - + void *userdata; } librg_world_t; @@ -19720,18 +19720,18 @@ LIBRG_PRIVATE zpl_allocator librg_alloc_wrap(); ZPL_ALLOCATOR_PROC(librg_allocator_proc) { void *ptr = NULL; - + zpl_unused(allocator_data); zpl_unused(old_size); zpl_unused(flags); - + switch (type) { case ZPL_ALLOCATION_ALLOC: { ptr = LIBRG_MEM_ALLOC(size); } break; case ZPL_ALLOCATION_FREE: { LIBRG_MEM_FREE(old_memory); } break; case ZPL_ALLOCATION_RESIZE: { ptr = zpl_default_resize_align(librg_alloc_wrap(), old_memory, old_size, size, alignment); } break; case ZPL_ALLOCATION_FREE_ALL: break; } - + return ptr; } @@ -19755,51 +19755,51 @@ uint32_t librg_version() { librg_world *librg_world_create() { librg_world_t *wld = LIBRG_MEM_ALLOC(sizeof(librg_world_t)); zpl_memset(wld, 0, sizeof(librg_world_t)); - + /* setup initials */ wld->valid = LIBRG_TRUE; wld->allocator = librg_alloc_wrap(); - + /* setup defaults */ librg_config_chunksize_set((librg_world *)wld, 16, 16, 16); librg_config_chunkamount_set((librg_world *)wld, 256, 256, 256); librg_config_chunkoffset_set((librg_world *)wld, LIBRG_OFFSET_MID, LIBRG_OFFSET_MID, LIBRG_OFFSET_MID); - + /* initialize internal structs */ librg_table_ent_init(&wld->entity_map, wld->allocator); librg_table_tbl_init(&wld->owner_map, wld->allocator); zpl_random_init(&wld->random); - + return (librg_world *)wld; } int8_t librg_world_destroy(librg_world *world) { LIBRG_ASSERT(world); if (!world) return LIBRG_WORLD_INVALID; librg_world_t *wld = (librg_world_t *)world; - + {/* free up entities */ for (int i = 0; i < zpl_array_count(wld->entity_map.entries); ++i) { librg_entity_t *entity = &wld->entity_map.entries[i].value; - + if (entity->flag_visbility_owner_enabled) { entity->flag_visbility_owner_enabled = LIBRG_FALSE; librg_table_i8_destroy(&entity->owner_visibility_map); } } - + librg_table_ent_destroy(&wld->entity_map); } - + {/* free up owners */ for (int i = 0; i < zpl_array_count(wld->owner_map.entries); ++i) librg_table_i64_destroy(&wld->owner_map.entries[i].value); - + librg_table_tbl_destroy(&wld->owner_map); } - + /* mark it invalid */ wld->valid = LIBRG_FALSE; - + LIBRG_MEM_FREE(world); return LIBRG_OK; } @@ -19892,12 +19892,12 @@ int8_t librg_config_chunkoffset_get(librg_world *world, int16_t *x, int16_t *y, int8_t librg_event_set(librg_world *world, librg_event_type id, librg_event_fn handler) { LIBRG_ASSERT(world); if (!world) return LIBRG_WORLD_INVALID; librg_world_t *wld = (librg_world_t *)world; - + if (wld->handlers[id]) { wld->handlers[id] = handler; return LIBRG_HANDLER_REPLACED; } - + wld->handlers[id] = handler; return LIBRG_OK; } @@ -19905,11 +19905,11 @@ int8_t librg_event_set(librg_world *world, librg_event_type id, librg_event_fn h int8_t librg_event_remove(librg_world *world, librg_event_type id) { LIBRG_ASSERT(world); if (!world) return LIBRG_WORLD_INVALID; librg_world_t *wld = (librg_world_t *)world; - + if (!wld->handlers[id]) { return LIBRG_HANDLER_EMPTY; } - + wld->handlers[id] = NULL; return LIBRG_OK; } @@ -19973,29 +19973,29 @@ LIBRG_ALWAYS_INLINE int16_t librg_util_chunkoffset_line(int16_t v, int16_t off, librg_chunk librg_chunk_from_chunkpos(librg_world *world, int16_t chunk_x, int16_t chunk_y, int16_t chunk_z) { LIBRG_ASSERT(world); if (!world) return LIBRG_WORLD_INVALID; librg_world_t *wld = (librg_world_t *)world; - + int16_t chx = librg_util_chunkoffset_line(chunk_x, wld->chunkoffset.x, wld->worldsize.x); int16_t chy = librg_util_chunkoffset_line(chunk_y, wld->chunkoffset.y, wld->worldsize.y); int16_t chz = librg_util_chunkoffset_line(chunk_z, wld->chunkoffset.z, wld->worldsize.z); #define kk(aax,aay) (aax > -aay && aax < aay) #define ll(aax,aay) (aax <= -aay || aax >= aay) - + if (ll(chx, wld->worldsize.x) || ll(chy, wld->worldsize.y) /*|| ll(chz, wld->worldsize.z)*/) return LIBRG_CHUNK_INVALID; - + librg_chunk id = (chz * wld->worldsize.y * wld->worldsize.z) + (chy * wld->worldsize.y) + (chx); - + if (id < 0 || id > (wld->worldsize.x * wld->worldsize.y * wld->worldsize.z)) { return LIBRG_CHUNK_INVALID; } - + return id; } int8_t librg_chunk_to_chunkpos(librg_world *world, librg_chunk id, int16_t *chunk_x, int16_t *chunk_y, int16_t *chunk_z) { LIBRG_ASSERT(world); if (!world) return LIBRG_WORLD_INVALID; librg_world_t *wld = (librg_world_t *)world; - + if (id < 0 || id > (wld->worldsize.x * wld->worldsize.y * wld->worldsize.z)) { return LIBRG_CHUNK_INVALID; } @@ -20007,11 +20007,11 @@ int8_t librg_chunk_to_chunkpos(librg_world *world, librg_chunk id, int16_t *chun int16_t x = r1 % wld->worldsize.y;*/ int16_t y = id / wld->worldsize.x; int16_t x = id % wld->worldsize.x; - + if (chunk_x) *chunk_x = x - librg_util_chunkoffset_line(0, wld->chunkoffset.x, wld->worldsize.x); if (chunk_y) *chunk_y = y - librg_util_chunkoffset_line(0, wld->chunkoffset.y, wld->worldsize.y); //if (chunk_z) *chunk_z = z - librg_util_chunkoffset_line(0, wld->chunkoffset.z, wld->worldsize.z); - + return LIBRG_OK; } @@ -20040,22 +20040,22 @@ LIBRG_BEGIN_C_DECLS int8_t librg_entity_track(librg_world *world, int64_t entity_id) { LIBRG_ASSERT(world); if (!world) return LIBRG_WORLD_INVALID; librg_world_t *wld = (librg_world_t *)world; - + if (librg_entity_tracked(world, entity_id) == LIBRG_TRUE) { return LIBRG_ENTITY_ALREADY_TRACKED; } - + if (entity_id < 0 || entity_id > ZPL_I64_MAX) { return LIBRG_ENTITY_INVALID; } - + librg_entity_t _entity = {0}; librg_table_ent_set(&wld->entity_map, entity_id, _entity); - + /* set defaults */ librg_entity_chunk_set(world, entity_id, LIBRG_CHUNK_INVALID); librg_entity_owner_set(world, entity_id, LIBRG_OWNER_INVALID); - + return LIBRG_OK; } @@ -20063,41 +20063,41 @@ int8_t librg_entity_untrack(librg_world *world, int64_t entity_id) { LIBRG_ASSERT(world); if (!world) return LIBRG_WORLD_INVALID; librg_world_t *wld = (librg_world_t *)world; librg_entity_t *entity = librg_table_ent_get(&wld->entity_map, entity_id); - + if (!entity) { return LIBRG_ENTITY_UNTRACKED; } - + if (entity->flag_foreign == LIBRG_TRUE) { return LIBRG_ENTITY_FOREIGN; } - + /* cleanup owner snapshots */ if (entity->owner_id != LIBRG_OWNER_INVALID) { size_t owned = 0; size_t total = zpl_array_count(wld->entity_map.entries); - + /* count already owned entities by this user */ for (size_t i=0; ientity_map.entries[i].key) == entity->owner_id) owned++; } - + librg_table_i64 *snapshot = librg_table_tbl_get(&wld->owner_map, entity->owner_id); - + /* free up our snapshot storage, if owner does not own other entities (except current one) */ if (snapshot && owned <= 1) { librg_table_i64_destroy(snapshot); librg_table_tbl_remove(&wld->owner_map, entity->owner_id); } } - + /* cleanup owner visibility */ if (entity->flag_visbility_owner_enabled) { entity->flag_visbility_owner_enabled = LIBRG_FALSE; librg_table_i8_destroy(&entity->owner_visibility_map); } - + librg_table_ent_remove(&wld->entity_map, entity_id); return LIBRG_OK; } @@ -20105,7 +20105,7 @@ int8_t librg_entity_untrack(librg_world *world, int64_t entity_id) { int8_t librg_entity_tracked(librg_world *world, int64_t entity_id) { LIBRG_ASSERT(world); if (!world) return LIBRG_FALSE; librg_world_t *wld = (librg_world_t *)world; - + librg_entity_t *entity = librg_table_ent_get(&wld->entity_map, entity_id); return entity == NULL ? LIBRG_FALSE : LIBRG_TRUE; } @@ -20113,17 +20113,17 @@ int8_t librg_entity_tracked(librg_world *world, int64_t entity_id) { int8_t librg_entity_foreign(librg_world *world, int64_t entity_id) { LIBRG_ASSERT(world); if (!world) return LIBRG_FALSE; librg_world_t *wld = (librg_world_t *)world; - + librg_entity_t *entity = librg_table_ent_get(&wld->entity_map, entity_id); if (entity == NULL) return LIBRG_FALSE; - + return entity->flag_foreign == LIBRG_TRUE; } int32_t librg_entity_count(librg_world *world) { LIBRG_ASSERT(world); if (!world) return LIBRG_WORLD_INVALID; librg_world_t *wld = (librg_world_t *)world; - + return (int32_t)zpl_array_count(wld->entity_map.entries); } @@ -20136,50 +20136,50 @@ int32_t librg_entity_count(librg_world *world) { int8_t librg_entity_chunk_set(librg_world *world, int64_t entity_id, librg_chunk chunk) { LIBRG_ASSERT(world); if (!world) return LIBRG_WORLD_INVALID; librg_world_t *wld = (librg_world_t *)world; - + librg_entity_t *entity = librg_table_ent_get(&wld->entity_map, entity_id); if (entity == NULL) return LIBRG_ENTITY_UNTRACKED; - + for (int i = 0; i < LIBRG_ENTITY_MAXCHUNKS; ++i) entity->chunks[i] = LIBRG_CHUNK_INVALID; entity->chunks[0] = chunk; - + return LIBRG_OK; } librg_chunk librg_entity_chunk_get(librg_world *world, int64_t entity_id) { LIBRG_ASSERT(world); if (!world) return LIBRG_WORLD_INVALID; librg_world_t *wld = (librg_world_t *)world; - + librg_entity_t *entity = librg_table_ent_get(&wld->entity_map, entity_id); if (entity == NULL) return LIBRG_ENTITY_UNTRACKED; - + return entity->chunks[0]; } int8_t librg_entity_owner_set(librg_world *world, int64_t entity_id, int64_t owner_id) { LIBRG_ASSERT(world); if (!world) return LIBRG_WORLD_INVALID; librg_world_t *wld = (librg_world_t *)world; - + librg_entity_t *entity = librg_table_ent_get(&wld->entity_map, entity_id); if (entity == NULL) return LIBRG_ENTITY_UNTRACKED; - + if (entity->flag_foreign == LIBRG_TRUE) { return LIBRG_ENTITY_FOREIGN; } - + entity->owner_id = owner_id; entity->flag_owner_updated = LIBRG_TRUE; - + if (entity->owner_id != LIBRG_OWNER_INVALID) { /* set new token, and make sure to prevent collisions */ uint16_t newtoken = 0; do { newtoken = (uint16_t)(zpl_random_gen_u32(&wld->random) % ZPL_U16_MAX); } while (newtoken == 0 || newtoken == entity->ownership_token); entity->ownership_token = newtoken; - + /* fetch or create a new subtable */ librg_table_i64 *snapshot = librg_table_tbl_get(&wld->owner_map, owner_id); - + if (!snapshot) { librg_table_i64 _i64 = {0}; librg_table_tbl_set(&wld->owner_map, owner_id, _i64); @@ -20189,17 +20189,17 @@ int8_t librg_entity_owner_set(librg_world *world, int64_t entity_id, int64_t own } else { entity->ownership_token = 0; } - + return LIBRG_OK; } int64_t librg_entity_owner_get(librg_world *world, int64_t entity_id) { LIBRG_ASSERT(world); if (!world) return LIBRG_WORLD_INVALID; librg_world_t *wld = (librg_world_t *)world; - + librg_entity_t *entity = librg_table_ent_get(&wld->entity_map, entity_id); if (entity == NULL) return LIBRG_ENTITY_UNTRACKED; - + return entity->owner_id; } @@ -20207,10 +20207,10 @@ int64_t librg_entity_owner_get(librg_world *world, int64_t entity_id) { int8_t librg_entity_radius_set(librg_world *world, int64_t entity_id, int8_t observed_chunk_radius) { LIBRG_ASSERT(world); if (!world) return LIBRG_WORLD_INVALID; librg_world_t *wld = (librg_world_t *)world; - + librg_entity_t *entity = librg_table_ent_get(&wld->entity_map, entity_id); if (entity == NULL) return LIBRG_ENTITY_UNTRACKED; - + entity->observed_radius = observed_chunk_radius; return LIBRG_OK; } @@ -20218,20 +20218,20 @@ int8_t librg_entity_radius_set(librg_world *world, int64_t entity_id, int8_t obs int8_t librg_entity_radius_get(librg_world *world, int64_t entity_id) { LIBRG_ASSERT(world); if (!world) return LIBRG_WORLD_INVALID; librg_world_t *wld = (librg_world_t *)world; - + librg_entity_t *entity = librg_table_ent_get(&wld->entity_map, entity_id); if (entity == NULL) return LIBRG_ENTITY_UNTRACKED; - + return entity->observed_radius; } int8_t librg_entity_dimension_set(librg_world *world, int64_t entity_id, int32_t dimension) { LIBRG_ASSERT(world); if (!world) return LIBRG_WORLD_INVALID; librg_world_t *wld = (librg_world_t *)world; - + librg_entity_t *entity = librg_table_ent_get(&wld->entity_map, entity_id); if (entity == NULL) return LIBRG_ENTITY_UNTRACKED; - + entity->dimension = dimension; return LIBRG_OK; } @@ -20239,20 +20239,20 @@ int8_t librg_entity_dimension_set(librg_world *world, int64_t entity_id, int32_t int32_t librg_entity_dimension_get(librg_world *world, int64_t entity_id) { LIBRG_ASSERT(world); if (!world) return LIBRG_WORLD_INVALID; librg_world_t *wld = (librg_world_t *)world; - + librg_entity_t *entity = librg_table_ent_get(&wld->entity_map, entity_id); if (entity == NULL) return LIBRG_ENTITY_UNTRACKED; - + return entity->dimension; } int8_t librg_entity_userdata_set(librg_world *world, int64_t entity_id, void *data) { LIBRG_ASSERT(world); if (!world) return LIBRG_WORLD_INVALID; librg_world_t *wld = (librg_world_t *)world; - + librg_entity_t *entity = librg_table_ent_get(&wld->entity_map, entity_id); if (entity == NULL) return LIBRG_ENTITY_UNTRACKED; - + entity->userdata = data; return LIBRG_OK; } @@ -20260,46 +20260,46 @@ int8_t librg_entity_userdata_set(librg_world *world, int64_t entity_id, void *da void *librg_entity_userdata_get(librg_world *world, int64_t entity_id) { LIBRG_ASSERT(world); if (!world) return NULL; librg_world_t *wld = (librg_world_t *)world; - + librg_entity_t *entity = librg_table_ent_get(&wld->entity_map, entity_id); if (entity == NULL) return NULL; - + return entity->userdata; } int8_t librg_entity_chunkarray_set(librg_world *world, int64_t entity_id, const librg_chunk *values, size_t chunk_amount) { LIBRG_ASSERT(world); if (!world) return LIBRG_WORLD_INVALID; librg_world_t *wld = (librg_world_t *)world; - + librg_entity_t *entity = librg_table_ent_get(&wld->entity_map, entity_id); if (entity == NULL) return LIBRG_ENTITY_UNTRACKED; - + LIBRG_ASSERT(chunk_amount > 0 && chunk_amount < LIBRG_ENTITY_MAXCHUNKS); - + for (int i = 0; i < LIBRG_ENTITY_MAXCHUNKS; ++i) entity->chunks[i] = LIBRG_CHUNK_INVALID; zpl_memcopy(entity->chunks, values, sizeof(librg_chunk) * LIBRG_MIN(chunk_amount, LIBRG_ENTITY_MAXCHUNKS)); - + return LIBRG_OK; - + } int8_t librg_entity_chunkarray_get(librg_world *world, int64_t entity_id, librg_chunk *results, size_t *chunk_amount) { LIBRG_ASSERT(world); if (!world) return LIBRG_WORLD_INVALID; librg_world_t *wld = (librg_world_t *)world; - + librg_entity_t *entity = librg_table_ent_get(&wld->entity_map, entity_id); if (entity == NULL) return LIBRG_ENTITY_UNTRACKED; - + LIBRG_ASSERT(results); size_t count = 0; size_t buffer_limit = *chunk_amount; - + for (size_t i = 0; i < LIBRG_MIN(buffer_limit, LIBRG_ENTITY_MAXCHUNKS); ++i) { if (entity->chunks[i] != LIBRG_CHUNK_INVALID) { results[count++] = entity->chunks[i]; } } - + *chunk_amount = count; return (int8_t)(LIBRG_ENTITY_MAXCHUNKS - buffer_limit); } @@ -20308,57 +20308,57 @@ int8_t librg_entity_chunkarray_get(librg_world *world, int64_t entity_id, librg_ int8_t librg_entity_visibility_global_set(librg_world *world, int64_t entity_id, librg_visibility value) { LIBRG_ASSERT(world); if (!world) return LIBRG_WORLD_INVALID; librg_world_t *wld = (librg_world_t *)world; - + librg_entity_t *entity = librg_table_ent_get(&wld->entity_map, entity_id); if (entity == NULL) return LIBRG_ENTITY_UNTRACKED; - + entity->visibility_global = value; - + return LIBRG_OK; } int8_t librg_entity_visibility_global_get(librg_world *world, int64_t entity_id) { LIBRG_ASSERT(world); if (!world) return LIBRG_WORLD_INVALID; librg_world_t *wld = (librg_world_t *)world; - + librg_entity_t *entity = librg_table_ent_get(&wld->entity_map, entity_id); if (entity == NULL) return LIBRG_ENTITY_UNTRACKED; - + return entity->visibility_global; } int8_t librg_entity_visibility_owner_set(librg_world *world, int64_t entity_id, int64_t owner_id, librg_visibility value) { LIBRG_ASSERT(world); if (!world) return LIBRG_WORLD_INVALID; librg_world_t *wld = (librg_world_t *)world; - + librg_entity_t *entity = librg_table_ent_get(&wld->entity_map, entity_id); if (entity == NULL) return LIBRG_ENTITY_UNTRACKED; - + /* prevent setting visibility, for your own entity, it will be always visible */ if (entity->owner_id == owner_id) { return LIBRG_ENTITY_VISIBILITY_IGNORED; } - + if (!entity->flag_visbility_owner_enabled) { entity->flag_visbility_owner_enabled = LIBRG_TRUE; librg_table_i8_init(&entity->owner_visibility_map, wld->allocator); } - + librg_table_i8_set(&entity->owner_visibility_map, owner_id, value); - + return LIBRG_OK; } int8_t librg_entity_visibility_owner_get(librg_world *world, int64_t entity_id, int64_t owner_id) { LIBRG_ASSERT(world); if (!world) return LIBRG_WORLD_INVALID; librg_world_t *wld = (librg_world_t *)world; - + librg_entity_t *entity = librg_table_ent_get(&wld->entity_map, entity_id); if (entity == NULL) return LIBRG_ENTITY_UNTRACKED; - + if (!entity->flag_visbility_owner_enabled) return LIBRG_VISIBLITY_DEFAULT; - + int8_t *value = librg_table_i8_get(&entity->owner_visibility_map, owner_id); return (value ? *value : LIBRG_VISIBLITY_DEFAULT); } @@ -20383,15 +20383,15 @@ int32_t librg_world_fetch_all(librg_world *world, int64_t *entity_ids, size_t *e LIBRG_ASSERT(world); if (!world) return LIBRG_WORLD_INVALID; LIBRG_ASSERT(entity_amount); if (!entity_amount) return LIBRG_NULL_REFERENCE; librg_world_t *wld = (librg_world_t *)world; - + size_t count = 0; size_t buffer_limit = *entity_amount; size_t total_count = zpl_array_count(wld->entity_map.entries); - + for (size_t i=0; i < LIBRG_MIN(buffer_limit, total_count); ++i) { entity_ids[count++] = wld->entity_map.entries[i].key; } - + *entity_amount = count; return LIBRG_MAX(0, (int32_t)(total_count - buffer_limit)); } @@ -20404,26 +20404,26 @@ int32_t librg_world_fetch_chunkarray(librg_world *world, const librg_chunk *chun LIBRG_ASSERT(world); if (!world) return LIBRG_WORLD_INVALID; LIBRG_ASSERT(entity_amount); if (!entity_amount) return LIBRG_NULL_REFERENCE; librg_world_t *wld = (librg_world_t *)world; - + size_t count = 0; size_t iterated = 0; size_t buffer_limit = *entity_amount; size_t total_count = zpl_array_count(wld->entity_map.entries); - + for (size_t i=0; i < LIBRG_MIN(buffer_limit, total_count); ++i) { uint64_t entity_id = wld->entity_map.entries[i].key; librg_entity_t *entity = &wld->entity_map.entries[i].value; iterated++; - + for (size_t k = 0; k < chunk_amount; ++k) { librg_chunk chunk = chunks[k]; - + for (size_t j=0; j < LIBRG_ENTITY_MAXCHUNKS; ++j) { if (entity->chunks[j] == chunk) { entity_ids[count++] = entity_id; break; } - + /* immidiately exit if chunk is invalid (the rest will also be invalid) */ if (entity->chunks[j] == LIBRG_CHUNK_INVALID) { break; @@ -20431,7 +20431,7 @@ int32_t librg_world_fetch_chunkarray(librg_world *world, const librg_chunk *chun } } } - + *entity_amount = count; return LIBRG_MAX(0, (int32_t)(total_count - iterated)); } @@ -20444,23 +20444,23 @@ int32_t librg_world_fetch_ownerarray(librg_world *world, const int64_t *owner_id LIBRG_ASSERT(world); if (!world) return LIBRG_WORLD_INVALID; LIBRG_ASSERT(entity_amount); if (!entity_amount) return LIBRG_NULL_REFERENCE; librg_world_t *wld = (librg_world_t *)world; - + size_t count = 0; size_t iterated = 0; size_t buffer_limit = *entity_amount; size_t total_count = zpl_array_count(wld->entity_map.entries); - + for (size_t i=0; i < LIBRG_MIN(buffer_limit, total_count); ++i) { uint64_t entity_id = wld->entity_map.entries[i].key; librg_entity_t *entity = &wld->entity_map.entries[i].value; iterated++; - + for (size_t k = 0; k < owner_amount; ++k) { int64_t owner_id = owner_ids[k]; if (entity->owner_id == owner_id) entity_ids[count++] = entity_id; } } - + *entity_amount = count; return LIBRG_MAX(0, (int32_t)(total_count - iterated)); } @@ -20485,7 +20485,7 @@ static LIBRG_ALWAYS_INLINE void librg_util_chunkrange(librg_world_t *w, librg_ta } } } - + return; } @@ -20493,64 +20493,64 @@ int32_t librg_world_query(librg_world *world, int64_t owner_id, int64_t *entity_ LIBRG_ASSERT(world); if (!world) return LIBRG_WORLD_INVALID; LIBRG_ASSERT(entity_amount); if (!entity_amount) return LIBRG_NULL_REFERENCE; librg_world_t *wld = (librg_world_t *)world; - + size_t buffer_limit = *entity_amount; size_t total_count = zpl_array_count(wld->entity_map.entries); - + librg_table_i64 results = {0}; librg_table_tbl dimensions = {0}; - + librg_table_i64_init(&results, wld->allocator); librg_table_tbl_init(&dimensions, wld->allocator); - + /* generate a map of visible chunks (only counting owned entities) */ for (size_t i=0; i < total_count; ++i) { uint64_t entity_id = wld->entity_map.entries[i].key; librg_entity_t *entity = &wld->entity_map.entries[i].value; - + /* allways add self-owned entities */ if (entity->owner_id == owner_id) { librg_table_i64_set(&results, entity_id, 1); } - + /* immidiately skip, if entity was not placed correctly */ if (entity->chunks[0] == LIBRG_CHUNK_INVALID) continue; /* and skip, if used is not an owner of the entity */ if (entity->owner_id != owner_id) continue; /* and skip if entity is not an observer */ if (entity->observed_radius == 0) continue; - + /* fetch, or create chunk set in this dimension if does not exist */ librg_table_i64 *dim_chunks = librg_table_tbl_get(&dimensions, entity->dimension); - + if (!dim_chunks) { librg_table_i64 _chunks = {0}; librg_table_tbl_set(&dimensions, entity->dimension, _chunks); dim_chunks = librg_table_tbl_get(&dimensions, entity->dimension); librg_table_i64_init(dim_chunks, wld->allocator); } - + /* add entity chunks to the total visible chunks */ for (int k = 0; k < LIBRG_ENTITY_MAXCHUNKS; ++k) { if (entity->chunks[k] == LIBRG_CHUNK_INVALID) break; - + int16_t chx=0, chy=0, chz=0; librg_chunk_to_chunkpos(world, entity->chunks[k], &chx, &chy, &chz); librg_util_chunkrange(world, dim_chunks, chx, chy, chz, entity->observed_radius); } } - + /* a slightly increased buffer_limit, that includes own entities */ /* that allows us to prevent edge-cases where the code below will include our entities in the result as well */ size_t owned_entities = zpl_array_count(results.entries); size_t buffer_limit_extended = buffer_limit + owned_entities; - + /* iterate on all entities, and check if they are inside of the interested chunks */ for (size_t i=0; i < LIBRG_MIN(buffer_limit_extended, total_count); ++i) { uint64_t entity_id = wld->entity_map.entries[i].key; librg_entity_t *entity = &wld->entity_map.entries[i].value; librg_table_i64 *chunks = librg_table_tbl_get(&dimensions, entity->dimension); - + /* owner visibility (personal)*/ int8_t vis_owner = librg_entity_visibility_owner_get(world, entity_id, owner_id); if (vis_owner == LIBRG_VISIBLITY_NEVER) { @@ -20560,7 +20560,7 @@ int32_t librg_world_query(librg_world *world, int64_t owner_id, int64_t *entity_ librg_table_i64_set(&results, entity_id, 1); /* always included */ continue; } - + /* global entity visibility */ int8_t vis_global = librg_entity_visibility_global_get(world, entity_id); if (vis_global == LIBRG_VISIBLITY_NEVER) { @@ -20570,18 +20570,18 @@ int32_t librg_world_query(librg_world *world, int64_t owner_id, int64_t *entity_ librg_table_i64_set(&results, entity_id, 1); /* always included */ continue; } - + /* skip if there are no chunks in this dimension */ if (!chunks) continue; size_t chunk_amount = zpl_array_count(chunks->entries); - + for (size_t k = 0; k < chunk_amount; ++k) { librg_chunk chunk = chunks->entries[k].key; - + for (size_t j=0; j < LIBRG_ENTITY_MAXCHUNKS; ++j) { /* immidiately exit if chunk is invalid (the rest will also be invalid) */ if (entity->chunks[j] == LIBRG_CHUNK_INVALID) break; - + /* add entity and continue to the next one */ if (entity->chunks[j] == chunk) { librg_table_i64_set(&results, entity_id, 1); @@ -20590,19 +20590,19 @@ int32_t librg_world_query(librg_world *world, int64_t owner_id, int64_t *entity_ } } } - + /* copy/transform results to a plain array */ size_t count = zpl_array_count(results.entries); for (size_t i = 0; i < LIBRG_MIN(buffer_limit, count); ++i) entity_ids[i] = results.entries[i].key; - + /* free up temp data */ for (int i = 0; i < zpl_array_count(dimensions.entries); ++i) librg_table_i64_destroy(&dimensions.entries[i].value); - + librg_table_tbl_destroy(&dimensions); librg_table_i64_destroy(&results); - + *entity_amount = LIBRG_MIN(buffer_limit, count); return LIBRG_MAX(0, (int32_t)(count - buffer_limit)); } @@ -20651,55 +20651,55 @@ int32_t librg_world_write(librg_world *world, int64_t owner_id, char *buffer, si LIBRG_ASSERT(world); if (!world) return LIBRG_WORLD_INVALID; librg_world_t *wld = (librg_world_t *)world; librg_table_i64 *last_snapshot = librg_table_tbl_get(&wld->owner_map, owner_id); - + /* no snapshot - means we are asking an invalid owner */ if (!last_snapshot) { *size = 0; return LIBRG_OWNER_INVALID; } - + /* get old, and preapre new snapshot handlers */ librg_table_i64 next_snapshot = {0}; librg_table_i64_init(&next_snapshot, wld->allocator); - + int64_t *results = LIBRG_MEM_ALLOC(LIBRG_WORLDWRITE_MAXQUERY * sizeof(int64_t)); size_t total_amount = LIBRG_WORLDWRITE_MAXQUERY; librg_world_query(world, owner_id, results, &total_amount); - + size_t total_written = 0; librg_event_t evt = {0}; - - #define sz_total (total_written + sizeof(librg_segment_t)) - #define sz_value (sz_total + value_written + sizeof(librg_segval_t)) - + +#define sz_total (total_written + sizeof(librg_segment_t)) +#define sz_value (sz_total + value_written + sizeof(librg_segval_t)) + uint8_t action_id = LIBRG_WRITE_CREATE; size_t buffer_limit = *size; size_t insufficient_size = 0; - -librg_lbl_ww: - + + librg_lbl_ww: + /* create and update */ if (sz_total < buffer_limit) { librg_segment_t *seg = (librg_segment_t*)(buffer+total_written); char *segend = (buffer + sz_total); - + uint16_t amount = 0; size_t value_written = 0; size_t iterations = total_amount; - + int64_t entity_id = LIBRG_ENTITY_INVALID; int32_t condition = LIBRG_TRUE; librg_entity_t *entity_blob = NULL; - + /* for deletions we are iterating something else */ if (action_id == LIBRG_WRITE_REMOVE) { iterations = zpl_array_count(last_snapshot->entries); } - + for (size_t i = 0; i < iterations; ++i) { int16_t action_rejected = LIBRG_TRUE; int32_t data_size = 0; - + /* preparation */ if (action_id == LIBRG_WRITE_CREATE) { entity_id = results[i]; /* it did not exist && not foreign */ @@ -20710,7 +20710,7 @@ librg_lbl_ww: entity_id = results[i]; /* it did exist */ entity_blob = librg_table_ent_get(&wld->entity_map, entity_id); condition = librg_table_i64_get(last_snapshot, entity_id) != NULL || librg_entity_foreign(world, entity_id) == LIBRG_TRUE; - + /* mark entity as still alive, to prevent it from being removed */ librg_table_i64_set(last_snapshot, entity_id, 2); } @@ -20727,12 +20727,12 @@ librg_lbl_ww: && entity_blob->flag_owner_updated && librg_table_i64_get(&next_snapshot, entity_id); } - + /* data write */ if (condition && sz_value < buffer_limit) { librg_segval_t *val = (librg_segval_t*)(segend + value_written); char *valend = (segend + value_written + sizeof(librg_segval_t)); - + /* fill in event */ evt.entity_id = entity_id; evt.type = action_id; @@ -20740,18 +20740,18 @@ librg_lbl_ww: evt.buffer = valend; evt.owner_id = owner_id; evt.userdata = userdata; - + /* call event handlers */ if (wld->handlers[action_id]) { data_size = (int32_t)wld->handlers[action_id](world, (librg_event*)&evt); } - + /* if user returned < 0, we consider that event rejected */ if (data_size >= 0) { /* fill in segval */ val->id = entity_id; val->size = data_size; - + if (action_id == LIBRG_WRITE_OWNER) { val->token = entity_blob->ownership_token; } @@ -20760,19 +20760,19 @@ librg_lbl_ww: } else { val->token = 0; } - + /* increase the total size written */ value_written += sizeof(librg_segval_t) + val->size; action_rejected = LIBRG_FALSE; amount++; } } - + /* accumulate insufficient buffer size */ if (condition && sz_value >= buffer_limit) { insufficient_size += (sz_value - buffer_limit); } - + /* finaliztion */ if (action_id == LIBRG_WRITE_CREATE && !action_rejected) { /* mark entity as created, so it can start updating */ @@ -20791,36 +20791,36 @@ librg_lbl_ww: entity_blob->flag_owner_updated = LIBRG_FALSE; } } - + if (amount > 0) { seg->type = action_id; seg->size = (uint32_t)value_written; seg->amount = amount; - + total_written += sizeof(librg_segment_t) + seg->size; } } else { insufficient_size += sz_total - buffer_limit; } - + /* iterate it again till all tasks are finished */ switch (action_id) { case LIBRG_WRITE_CREATE: action_id = LIBRG_WRITE_UPDATE; goto librg_lbl_ww; case LIBRG_WRITE_UPDATE: action_id = LIBRG_WRITE_REMOVE; goto librg_lbl_ww; case LIBRG_WRITE_REMOVE: action_id = LIBRG_WRITE_OWNER; goto librg_lbl_ww; } - + /* swap snapshot tables */ librg_table_i64_destroy(last_snapshot); librg_table_tbl_set(&wld->owner_map, owner_id, next_snapshot); LIBRG_MEM_FREE(results); - + /* write our total size */ *size = total_written; - - #undef sz_total - #undef sz_value - + +#undef sz_total +#undef sz_value + /* if we didnt have enough space, value will be > 0 */ return insufficient_size; } @@ -20834,27 +20834,27 @@ librg_lbl_ww: int32_t librg_world_read(librg_world *world, int64_t owner_id, const char *buffer, size_t size, void *userdata) { LIBRG_ASSERT(world); if (!world) return LIBRG_WORLD_INVALID; librg_world_t *wld = (librg_world_t *)world; - + librg_event_t evt = {0}; size_t total_read = 0; - - #define sz_segment (total_read + sizeof(librg_segment_t)) - #define sz_segval (sz_segment + segment_read + sizeof(librg_segval_t)) - + +#define sz_segment (total_read + sizeof(librg_segment_t)) +#define sz_segval (sz_segment + segment_read + sizeof(librg_segval_t)) + while ((size-total_read) > sizeof(librg_segment_t)) { librg_segment_t *seg = (librg_segment_t*)(buffer+total_read); size_t segment_read = 0; - + /* immidiately exit if we will not be able to read the segment data */ if (sz_segment+seg->size > size || sz_segment + seg->amount * sizeof(librg_segval_t) > size) { break; } - + for (int i = 0; i < seg->amount; ++i) { librg_segval_t *val = (librg_segval_t*)(buffer+sz_segment+segment_read); librg_entity_t *entity_blob = librg_table_ent_get(&wld->entity_map, val->id); int8_t action_id = -1; - + /* do preparation for entity processing */ if (seg->type == LIBRG_WRITE_CREATE) { /* attempt to create an entity */ @@ -20865,39 +20865,39 @@ int32_t librg_world_read(librg_world *world, int64_t owner_id, const char *buffe else if (seg->type == LIBRG_WRITE_UPDATE) { /* try to check if entity exists, and if it is foreign OR owner and token are correct */ action_id = (librg_entity_tracked(world, val->id) == LIBRG_TRUE - && entity_blob - && (entity_blob->flag_foreign || (entity_blob->owner_id == owner_id - && entity_blob->ownership_token == val->token) - )) + && entity_blob + && (entity_blob->flag_foreign || (entity_blob->owner_id == owner_id + && entity_blob->ownership_token == val->token) + )) ? LIBRG_READ_UPDATE : LIBRG_ERROR_UPDATE; } else if (seg->type == LIBRG_WRITE_REMOVE) { /* attempt to check if it does exist and only foreign */ action_id = (librg_entity_tracked(world, val->id) == LIBRG_TRUE - && librg_entity_foreign(world, val->id) == LIBRG_TRUE) + && librg_entity_foreign(world, val->id) == LIBRG_TRUE) ? LIBRG_READ_REMOVE : LIBRG_ERROR_REMOVE; } else if (seg->type == LIBRG_WRITE_OWNER) { /* attempt to check if it does exist and only foreign */ action_id = (librg_entity_tracked(world, val->id) == LIBRG_TRUE - && librg_entity_foreign(world, val->id) == LIBRG_TRUE) + && librg_entity_foreign(world, val->id) == LIBRG_TRUE) ? LIBRG_READ_OWNER : LIBRG_ERROR_OWNER; } - + if (action_id == -1) { return LIBRG_READ_INVALID; } - + /* do the initial entity processing */ if (action_id == LIBRG_READ_CREATE) { /* mark newly created entity as foreign */ librg_entity_t *entity = librg_table_ent_get(&wld->entity_map, val->id); if (!entity) return LIBRG_READ_INVALID; else entity->flag_foreign = LIBRG_TRUE; } - + /* fill in event */ evt.entity_id = val->id; evt.type = action_id; @@ -20905,13 +20905,13 @@ int32_t librg_world_read(librg_world *world, int64_t owner_id, const char *buffe evt.buffer = (char*)(buffer+sz_segval); evt.owner_id = owner_id; evt.userdata = userdata; - + /* call event handlers */ if (wld->handlers[action_id]) { /*ignore response*/ wld->handlers[action_id](world, &evt); } - + /* do the afterwork processing */ if (action_id == LIBRG_READ_REMOVE) { /* remove foreign mark from entity */ @@ -20922,7 +20922,7 @@ int32_t librg_world_read(librg_world *world, int64_t owner_id, const char *buffe else if (action_id == LIBRG_READ_OWNER) { librg_entity_t *entity = librg_table_ent_get(&wld->entity_map, val->id); if (!entity) return LIBRG_READ_INVALID; - + /* immidiately mark entity as owned, set up & override additional info */ entity->flag_foreign = LIBRG_FALSE; /* unmark it temp, while owner is set */ librg_entity_owner_set(world, val->id, owner_id); @@ -20930,25 +20930,25 @@ int32_t librg_world_read(librg_world *world, int64_t owner_id, const char *buffe entity->flag_owner_updated = LIBRG_FALSE; entity->flag_foreign = LIBRG_TRUE; } - + segment_read += sizeof(librg_segval_t) + val->size; } - + /* validate sizes of the data we read */ if (segment_read != seg->size) { return LIBRG_READ_INVALID; } - + total_read += sizeof(librg_segment_t) + segment_read; } - - #undef sz_segment - #undef sz_segval - + +#undef sz_segment +#undef sz_segval + if (total_read != size) { return (int32_t)(size - total_read); } - + return LIBRG_OK; } diff --git a/code/vendors/zpl.h b/code/vendors/zpl.h index aeb31eb..ac60178 100644 --- a/code/vendors/zpl.h +++ b/code/vendors/zpl.h @@ -31,6 +31,7 @@ GitHub: https://github.com/zpl-c/zpl Version History: + 14.1.5 - fix array append_at 14.1.4 - Fix win32 missing CRITICAL_SECTION definition if - ZPL_NO_WINDOWS_H is defined 14.1.0 - add hashtable map_mut method @@ -363,1921 +364,1921 @@ License: #define ZPL_VERSION_MAJOR 14 #define ZPL_VERSION_MINOR 1 -#define ZPL_VERSION_PATCH 4 +#define ZPL_VERSION_PATCH 5 #define ZPL_VERSION_PRE "" - // file: zpl_hedley.h - - /* Hedley - https://nemequ.github.io/hedley - * Created by Evan Nemerson - * - * To the extent possible under law, the author(s) have dedicated all - * copyright and related and neighboring rights to this software to - * the public domain worldwide. This software is distributed without - * any warranty. - * - * For details, see . - * SPDX-License-Identifier: CC0-1.0 - */ - - #if !defined(ZPL_HEDLEY_VERSION) || (ZPL_HEDLEY_VERSION < 12) - #if defined(ZPL_HEDLEY_VERSION) - # undef ZPL_HEDLEY_VERSION - #endif - #define ZPL_HEDLEY_VERSION 12 - - #if defined(ZPL_STRINGIFY_EX) - # undef ZPL_STRINGIFY_EX - #endif - #define ZPL_STRINGIFY_EX(x) #x - - #if defined(ZPL_STRINGIFY) - # undef ZPL_STRINGIFY - #endif - #define ZPL_STRINGIFY(x) ZPL_STRINGIFY_EX(x) - - #if defined(ZPL_CONCAT_EX) - # undef ZPL_CONCAT_EX - #endif - #define ZPL_CONCAT_EX(a,b) a##b - - #if defined(ZPL_CONCAT) - # undef ZPL_CONCAT - #endif - #define ZPL_CONCAT(a,b) ZPL_CONCAT_EX(a,b) - - #if defined(ZPL_VERSION_ENCODE) - # undef ZPL_VERSION_ENCODE - #endif - #define ZPL_VERSION_ENCODE(major,minor,patch) (((major) * 1000000) + ((minor) * 1000) + (patch)) - - #if defined(ZPL_VERSION_DECODE_MAJOR) - # undef ZPL_VERSION_DECODE_MAJOR - #endif - #define ZPL_VERSION_DECODE_MAJOR(version) ((version) / 1000000) - - #if defined(ZPL_VERSION_DECODE_MINOR) - # undef ZPL_VERSION_DECODE_MINOR - #endif - #define ZPL_VERSION_DECODE_MINOR(version) (((version) % 1000000) / 1000) - - #if defined(ZPL_VERSION_DECODE_PATCH) - # undef ZPL_VERSION_DECODE_PATCH - #endif - #define ZPL_VERSION_DECODE_PATCH(version) ((version) % 1000) - - #if defined(ZPL_VERSION_CHECK) - # undef ZPL_VERSION_CHECK - #endif - #define ZPL_VERSION_CHECK(major,minor,patch) (ZPL_VERSION_ENCODE(major,minor,patch) <= ZPL_VERSION) - - #if defined(ZPL_GNUC_VERSION) - # undef ZPL_GNUC_VERSION - #endif - #if defined(__GNUC__) && defined(__GNUC_PATCHLEVEL__) - # define ZPL_GNUC_VERSION ZPL_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) - #elif defined(__GNUC__) - # define ZPL_GNUC_VERSION ZPL_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, 0) - #endif - - #if defined(ZPL_GNUC_VERSION_CHECK) - # undef ZPL_GNUC_VERSION_CHECK - #endif - #if defined(ZPL_GNUC_VERSION) - # define ZPL_GNUC_VERSION_CHECK(major,minor,patch) (ZPL_GNUC_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) - #else - # define ZPL_GNUC_VERSION_CHECK(major,minor,patch) (0) - #endif - - #if defined(ZPL_MSVC_VERSION) - # undef ZPL_MSVC_VERSION - #endif - #if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140000000) - # define ZPL_MSVC_VERSION ZPL_VERSION_ENCODE(_MSC_FULL_VER / 10000000, (_MSC_FULL_VER % 10000000) / 100000, (_MSC_FULL_VER % 100000) / 100) - #elif defined(_MSC_FULL_VER) - # define ZPL_MSVC_VERSION ZPL_VERSION_ENCODE(_MSC_FULL_VER / 1000000, (_MSC_FULL_VER % 1000000) / 10000, (_MSC_FULL_VER % 10000) / 10) - #elif defined(_MSC_VER) - # define ZPL_MSVC_VERSION ZPL_VERSION_ENCODE(_MSC_VER / 100, _MSC_VER % 100, 0) - #endif - - #if defined(ZPL_MSVC_VERSION_CHECK) - # undef ZPL_MSVC_VERSION_CHECK - #endif - #if !defined(_MSC_VER) - # define ZPL_MSVC_VERSION_CHECK(major,minor,patch) (0) - #elif defined(_MSC_VER) && (_MSC_VER >= 1400) - # define ZPL_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch))) - #elif defined(_MSC_VER) && (_MSC_VER >= 1200) - # define ZPL_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 1000000) + (minor * 10000) + (patch))) - #else - # define ZPL_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_VER >= ((major * 100) + (minor))) - #endif - - #if defined(ZPL_INTEL_VERSION) - # undef ZPL_INTEL_VERSION - #endif - #if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) - # define ZPL_INTEL_VERSION ZPL_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, __INTEL_COMPILER_UPDATE) - #elif defined(__INTEL_COMPILER) - # define ZPL_INTEL_VERSION ZPL_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0) - #endif - - #if defined(ZPL_INTEL_VERSION_CHECK) - # undef ZPL_INTEL_VERSION_CHECK - #endif - #if defined(ZPL_INTEL_VERSION) - # define ZPL_INTEL_VERSION_CHECK(major,minor,patch) (ZPL_INTEL_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) - #else - # define ZPL_INTEL_VERSION_CHECK(major,minor,patch) (0) - #endif - - #if defined(ZPL_PGI_VERSION) - # undef ZPL_PGI_VERSION - #endif - #if defined(__PGI) && defined(__PGIC__) && defined(__PGIC_MINOR__) && defined(__PGIC_PATCHLEVEL__) - # define ZPL_PGI_VERSION ZPL_VERSION_ENCODE(__PGIC__, __PGIC_MINOR__, __PGIC_PATCHLEVEL__) - #endif - - #if defined(ZPL_PGI_VERSION_CHECK) - # undef ZPL_PGI_VERSION_CHECK - #endif - #if defined(ZPL_PGI_VERSION) - # define ZPL_PGI_VERSION_CHECK(major,minor,patch) (ZPL_PGI_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) - #else - # define ZPL_PGI_VERSION_CHECK(major,minor,patch) (0) - #endif - - #if defined(ZPL_SUNPRO_VERSION) - # undef ZPL_SUNPRO_VERSION - #endif - #if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000) - # define ZPL_SUNPRO_VERSION ZPL_VERSION_ENCODE((((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), (__SUNPRO_C & 0xf) * 10) - #elif defined(__SUNPRO_C) - # define ZPL_SUNPRO_VERSION ZPL_VERSION_ENCODE((__SUNPRO_C >> 8) & 0xf, (__SUNPRO_C >> 4) & 0xf, (__SUNPRO_C) & 0xf) - #elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000) - # define ZPL_SUNPRO_VERSION ZPL_VERSION_ENCODE((((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), (__SUNPRO_CC & 0xf) * 10) - #elif defined(__SUNPRO_CC) - # define ZPL_SUNPRO_VERSION ZPL_VERSION_ENCODE((__SUNPRO_CC >> 8) & 0xf, (__SUNPRO_CC >> 4) & 0xf, (__SUNPRO_CC) & 0xf) - #endif - - #if defined(ZPL_SUNPRO_VERSION_CHECK) - # undef ZPL_SUNPRO_VERSION_CHECK - #endif - #if defined(ZPL_SUNPRO_VERSION) - # define ZPL_SUNPRO_VERSION_CHECK(major,minor,patch) (ZPL_SUNPRO_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) - #else - # define ZPL_SUNPRO_VERSION_CHECK(major,minor,patch) (0) - #endif - - #if defined(ZPL_EMSCRIPTEN_VERSION) - # undef ZPL_EMSCRIPTEN_VERSION - #endif - #if defined(__EMSCRIPTEN__) - # define ZPL_EMSCRIPTEN_VERSION ZPL_VERSION_ENCODE(__EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__) - #endif - - #if defined(ZPL_EMSCRIPTEN_VERSION_CHECK) - # undef ZPL_EMSCRIPTEN_VERSION_CHECK - #endif - #if defined(ZPL_EMSCRIPTEN_VERSION) - # define ZPL_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (ZPL_EMSCRIPTEN_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) - #else - # define ZPL_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (0) - #endif - - #if defined(ZPL_ARM_VERSION) - # undef ZPL_ARM_VERSION - #endif - #if defined(__CC_ARM) && defined(__ARMCOMPILER_VERSION) - # define ZPL_ARM_VERSION ZPL_VERSION_ENCODE(__ARMCOMPILER_VERSION / 1000000, (__ARMCOMPILER_VERSION % 1000000) / 10000, (__ARMCOMPILER_VERSION % 10000) / 100) - #elif defined(__CC_ARM) && defined(__ARMCC_VERSION) - # define ZPL_ARM_VERSION ZPL_VERSION_ENCODE(__ARMCC_VERSION / 1000000, (__ARMCC_VERSION % 1000000) / 10000, (__ARMCC_VERSION % 10000) / 100) - #endif - - #if defined(ZPL_ARM_VERSION_CHECK) - # undef ZPL_ARM_VERSION_CHECK - #endif - #if defined(ZPL_ARM_VERSION) - # define ZPL_ARM_VERSION_CHECK(major,minor,patch) (ZPL_ARM_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) - #else - # define ZPL_ARM_VERSION_CHECK(major,minor,patch) (0) - #endif - - #if defined(ZPL_IBM_VERSION) - # undef ZPL_IBM_VERSION - #endif - #if defined(__ibmxl__) - # define ZPL_IBM_VERSION ZPL_VERSION_ENCODE(__ibmxl_version__, __ibmxl_release__, __ibmxl_modification__) - #elif defined(__xlC__) && defined(__xlC_ver__) - # define ZPL_IBM_VERSION ZPL_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, (__xlC_ver__ >> 8) & 0xff) - #elif defined(__xlC__) - # define ZPL_IBM_VERSION ZPL_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, 0) - #endif - - #if defined(ZPL_IBM_VERSION_CHECK) - # undef ZPL_IBM_VERSION_CHECK - #endif - #if defined(ZPL_IBM_VERSION) - # define ZPL_IBM_VERSION_CHECK(major,minor,patch) (ZPL_IBM_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) - #else - # define ZPL_IBM_VERSION_CHECK(major,minor,patch) (0) - #endif - - #if defined(ZPL_TI_VERSION) - # undef ZPL_TI_VERSION - #endif - #if \ - defined(__TI_COMPILER_VERSION__) && \ - ( \ - defined(__TMS470__) || defined(__TI_ARM__) || \ - defined(__MSP430__) || \ - defined(__TMS320C2000__) \ - ) - # if (__TI_COMPILER_VERSION__ >= 16000000) - # define ZPL_TI_VERSION ZPL_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) - # endif - #endif - - #if defined(ZPL_TI_VERSION_CHECK) - # undef ZPL_TI_VERSION_CHECK - #endif - #if defined(ZPL_TI_VERSION) - # define ZPL_TI_VERSION_CHECK(major,minor,patch) (ZPL_TI_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) - #else - # define ZPL_TI_VERSION_CHECK(major,minor,patch) (0) - #endif - - #if defined(ZPL_TI_CL2000_VERSION) - # undef ZPL_TI_CL2000_VERSION - #endif - #if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C2000__) - # define ZPL_TI_CL2000_VERSION ZPL_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) - #endif - - #if defined(ZPL_TI_CL2000_VERSION_CHECK) - # undef ZPL_TI_CL2000_VERSION_CHECK - #endif - #if defined(ZPL_TI_CL2000_VERSION) - # define ZPL_TI_CL2000_VERSION_CHECK(major,minor,patch) (ZPL_TI_CL2000_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) - #else - # define ZPL_TI_CL2000_VERSION_CHECK(major,minor,patch) (0) - #endif - - #if defined(ZPL_TI_CL430_VERSION) - # undef ZPL_TI_CL430_VERSION - #endif - #if defined(__TI_COMPILER_VERSION__) && defined(__MSP430__) - # define ZPL_TI_CL430_VERSION ZPL_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) - #endif - - #if defined(ZPL_TI_CL430_VERSION_CHECK) - # undef ZPL_TI_CL430_VERSION_CHECK - #endif - #if defined(ZPL_TI_CL430_VERSION) - # define ZPL_TI_CL430_VERSION_CHECK(major,minor,patch) (ZPL_TI_CL430_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) - #else - # define ZPL_TI_CL430_VERSION_CHECK(major,minor,patch) (0) - #endif - - #if defined(ZPL_TI_ARMCL_VERSION) - # undef ZPL_TI_ARMCL_VERSION - #endif - #if defined(__TI_COMPILER_VERSION__) && (defined(__TMS470__) || defined(__TI_ARM__)) - # define ZPL_TI_ARMCL_VERSION ZPL_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) - #endif - - #if defined(ZPL_TI_ARMCL_VERSION_CHECK) - # undef ZPL_TI_ARMCL_VERSION_CHECK - #endif - #if defined(ZPL_TI_ARMCL_VERSION) - # define ZPL_TI_ARMCL_VERSION_CHECK(major,minor,patch) (ZPL_TI_ARMCL_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) - #else - # define ZPL_TI_ARMCL_VERSION_CHECK(major,minor,patch) (0) - #endif - - #if defined(ZPL_TI_CL6X_VERSION) - # undef ZPL_TI_CL6X_VERSION - #endif - #if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C6X__) - # define ZPL_TI_CL6X_VERSION ZPL_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) - #endif - - #if defined(ZPL_TI_CL6X_VERSION_CHECK) - # undef ZPL_TI_CL6X_VERSION_CHECK - #endif - #if defined(ZPL_TI_CL6X_VERSION) - # define ZPL_TI_CL6X_VERSION_CHECK(major,minor,patch) (ZPL_TI_CL6X_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) - #else - # define ZPL_TI_CL6X_VERSION_CHECK(major,minor,patch) (0) - #endif - - #if defined(ZPL_TI_CL7X_VERSION) - # undef ZPL_TI_CL7X_VERSION - #endif - #if defined(__TI_COMPILER_VERSION__) && defined(__C7000__) - # define ZPL_TI_CL7X_VERSION ZPL_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) - #endif - - #if defined(ZPL_TI_CL7X_VERSION_CHECK) - # undef ZPL_TI_CL7X_VERSION_CHECK - #endif - #if defined(ZPL_TI_CL7X_VERSION) - # define ZPL_TI_CL7X_VERSION_CHECK(major,minor,patch) (ZPL_TI_CL7X_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) - #else - # define ZPL_TI_CL7X_VERSION_CHECK(major,minor,patch) (0) - #endif - - #if defined(ZPL_TI_CLPRU_VERSION) - # undef ZPL_TI_CLPRU_VERSION - #endif - #if defined(__TI_COMPILER_VERSION__) && defined(__PRU__) - # define ZPL_TI_CLPRU_VERSION ZPL_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) - #endif - - #if defined(ZPL_TI_CLPRU_VERSION_CHECK) - # undef ZPL_TI_CLPRU_VERSION_CHECK - #endif - #if defined(ZPL_TI_CLPRU_VERSION) - # define ZPL_TI_CLPRU_VERSION_CHECK(major,minor,patch) (ZPL_TI_CLPRU_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) - #else - # define ZPL_TI_CLPRU_VERSION_CHECK(major,minor,patch) (0) - #endif - - #if defined(ZPL_CRAY_VERSION) - # undef ZPL_CRAY_VERSION - #endif - #if defined(_CRAYC) - # if defined(_RELEASE_PATCHLEVEL) - # define ZPL_CRAY_VERSION ZPL_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, _RELEASE_PATCHLEVEL) - # else - # define ZPL_CRAY_VERSION ZPL_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, 0) - # endif - #endif - - #if defined(ZPL_CRAY_VERSION_CHECK) - # undef ZPL_CRAY_VERSION_CHECK - #endif - #if defined(ZPL_CRAY_VERSION) - # define ZPL_CRAY_VERSION_CHECK(major,minor,patch) (ZPL_CRAY_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) - #else - # define ZPL_CRAY_VERSION_CHECK(major,minor,patch) (0) - #endif - - #if defined(ZPL_IAR_VERSION) - # undef ZPL_IAR_VERSION - #endif - #if defined(__IAR_SYSTEMS_ICC__) - # if __VER__ > 1000 - # define ZPL_IAR_VERSION ZPL_VERSION_ENCODE((__VER__ / 1000000), ((__VER__ / 1000) % 1000), (__VER__ % 1000)) - # else - # define ZPL_IAR_VERSION ZPL_VERSION_ENCODE(VER / 100, __VER__ % 100, 0) - # endif - #endif - - #if defined(ZPL_IAR_VERSION_CHECK) - # undef ZPL_IAR_VERSION_CHECK - #endif - #if defined(ZPL_IAR_VERSION) - # define ZPL_IAR_VERSION_CHECK(major,minor,patch) (ZPL_IAR_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) - #else - # define ZPL_IAR_VERSION_CHECK(major,minor,patch) (0) - #endif - - #if defined(ZPL_TINYC_VERSION) - # undef ZPL_TINYC_VERSION - #endif - #if defined(__TINYC__) - # define ZPL_TINYC_VERSION ZPL_VERSION_ENCODE(__TINYC__ / 1000, (__TINYC__ / 100) % 10, __TINYC__ % 100) - #endif - - #if defined(ZPL_TINYC_VERSION_CHECK) - # undef ZPL_TINYC_VERSION_CHECK - #endif - #if defined(ZPL_TINYC_VERSION) - # define ZPL_TINYC_VERSION_CHECK(major,minor,patch) (ZPL_TINYC_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) - #else - # define ZPL_TINYC_VERSION_CHECK(major,minor,patch) (0) - #endif - - #if defined(ZPL_DMC_VERSION) - # undef ZPL_DMC_VERSION - #endif - #if defined(__DMC__) - # define ZPL_DMC_VERSION ZPL_VERSION_ENCODE(__DMC__ >> 8, (__DMC__ >> 4) & 0xf, __DMC__ & 0xf) - #endif - - #if defined(ZPL_DMC_VERSION_CHECK) - # undef ZPL_DMC_VERSION_CHECK - #endif - #if defined(ZPL_DMC_VERSION) - # define ZPL_DMC_VERSION_CHECK(major,minor,patch) (ZPL_DMC_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) - #else - # define ZPL_DMC_VERSION_CHECK(major,minor,patch) (0) - #endif - - #if defined(ZPL_COMPCERT_VERSION) - # undef ZPL_COMPCERT_VERSION - #endif - #if defined(__COMPCERT_VERSION__) - # define ZPL_COMPCERT_VERSION ZPL_VERSION_ENCODE(__COMPCERT_VERSION__ / 10000, (__COMPCERT_VERSION__ / 100) % 100, __COMPCERT_VERSION__ % 100) - #endif - - #if defined(ZPL_COMPCERT_VERSION_CHECK) - # undef ZPL_COMPCERT_VERSION_CHECK - #endif - #if defined(ZPL_COMPCERT_VERSION) - # define ZPL_COMPCERT_VERSION_CHECK(major,minor,patch) (ZPL_COMPCERT_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) - #else - # define ZPL_COMPCERT_VERSION_CHECK(major,minor,patch) (0) - #endif - - #if defined(ZPL_PELLES_VERSION) - # undef ZPL_PELLES_VERSION - #endif - #if defined(__POCC__) - # define ZPL_PELLES_VERSION ZPL_VERSION_ENCODE(__POCC__ / 100, __POCC__ % 100, 0) - #endif - - #if defined(ZPL_PELLES_VERSION_CHECK) - # undef ZPL_PELLES_VERSION_CHECK - #endif - #if defined(ZPL_PELLES_VERSION) - # define ZPL_PELLES_VERSION_CHECK(major,minor,patch) (ZPL_PELLES_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) - #else - # define ZPL_PELLES_VERSION_CHECK(major,minor,patch) (0) - #endif - - #if defined(ZPL_GCC_VERSION) - # undef ZPL_GCC_VERSION - #endif - #if \ - defined(ZPL_GNUC_VERSION) && \ - !defined(__clang__) && \ - !defined(ZPL_INTEL_VERSION) && \ - !defined(ZPL_PGI_VERSION) && \ - !defined(ZPL_ARM_VERSION) && \ - !defined(ZPL_TI_VERSION) && \ - !defined(ZPL_TI_ARMCL_VERSION) && \ - !defined(ZPL_TI_CL430_VERSION) && \ - !defined(ZPL_TI_CL2000_VERSION) && \ - !defined(ZPL_TI_CL6X_VERSION) && \ - !defined(ZPL_TI_CL7X_VERSION) && \ - !defined(ZPL_TI_CLPRU_VERSION) && \ - !defined(__COMPCERT__) - # define ZPL_GCC_VERSION ZPL_GNUC_VERSION - #endif - - #if defined(ZPL_GCC_VERSION_CHECK) - # undef ZPL_GCC_VERSION_CHECK - #endif - #if defined(ZPL_GCC_VERSION) - # define ZPL_GCC_VERSION_CHECK(major,minor,patch) (ZPL_GCC_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) - #else - # define ZPL_GCC_VERSION_CHECK(major,minor,patch) (0) - #endif - - #if defined(ZPL_HAS_ATTRIBUTE) - # undef ZPL_HAS_ATTRIBUTE - #endif - #if defined(__has_attribute) - # define ZPL_HAS_ATTRIBUTE(attribute) __has_attribute(attribute) - #else - # define ZPL_HAS_ATTRIBUTE(attribute) (0) - #endif - - #if defined(ZPL_GNUC_HAS_ATTRIBUTE) - # undef ZPL_GNUC_HAS_ATTRIBUTE - #endif - #if defined(__has_attribute) - # define ZPL_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) __has_attribute(attribute) - #else - # define ZPL_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) ZPL_GNUC_VERSION_CHECK(major,minor,patch) - #endif - - #if defined(ZPL_GCC_HAS_ATTRIBUTE) - # undef ZPL_GCC_HAS_ATTRIBUTE - #endif - #if defined(__has_attribute) - # define ZPL_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) __has_attribute(attribute) - #else - # define ZPL_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) ZPL_GCC_VERSION_CHECK(major,minor,patch) - #endif - - #if defined(ZPL_HAS_CPP_ATTRIBUTE) - # undef ZPL_HAS_CPP_ATTRIBUTE - #endif - #if \ - defined(__has_cpp_attribute) && \ - defined(__cplusplus) && \ - (!defined(ZPL_SUNPRO_VERSION) || ZPL_SUNPRO_VERSION_CHECK(5,15,0)) - # define ZPL_HAS_CPP_ATTRIBUTE(attribute) __has_cpp_attribute(attribute) - #else - # define ZPL_HAS_CPP_ATTRIBUTE(attribute) (0) - #endif - - #if defined(ZPL_HAS_CPP_ATTRIBUTE_NS) - # undef ZPL_HAS_CPP_ATTRIBUTE_NS - #endif - #if !defined(__cplusplus) || !defined(__has_cpp_attribute) - # define ZPL_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) - #elif \ - !defined(ZPL_PGI_VERSION) && \ - !defined(ZPL_IAR_VERSION) && \ - (!defined(ZPL_SUNPRO_VERSION) || ZPL_SUNPRO_VERSION_CHECK(5,15,0)) && \ - (!defined(ZPL_MSVC_VERSION) || ZPL_MSVC_VERSION_CHECK(19,20,0)) - # define ZPL_HAS_CPP_ATTRIBUTE_NS(ns,attribute) ZPL_HAS_CPP_ATTRIBUTE(ns::attribute) - #else - # define ZPL_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) - #endif - - #if defined(ZPL_GNUC_HAS_CPP_ATTRIBUTE) - # undef ZPL_GNUC_HAS_CPP_ATTRIBUTE - #endif - #if defined(__has_cpp_attribute) && defined(__cplusplus) - # define ZPL_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) - #else - # define ZPL_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) ZPL_GNUC_VERSION_CHECK(major,minor,patch) - #endif - - #if defined(ZPL_GCC_HAS_CPP_ATTRIBUTE) - # undef ZPL_GCC_HAS_CPP_ATTRIBUTE - #endif - #if defined(__has_cpp_attribute) && defined(__cplusplus) - # define ZPL_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) - #else - # define ZPL_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) ZPL_GCC_VERSION_CHECK(major,minor,patch) - #endif - - #if defined(ZPL_HAS_BUILTIN) - # undef ZPL_HAS_BUILTIN - #endif - #if defined(__has_builtin) - # define ZPL_HAS_BUILTIN(builtin) __has_builtin(builtin) - #else - # define ZPL_HAS_BUILTIN(builtin) (0) - #endif - - #if defined(ZPL_GNUC_HAS_BUILTIN) - # undef ZPL_GNUC_HAS_BUILTIN - #endif - #if defined(__has_builtin) - # define ZPL_GNUC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) - #else - # define ZPL_GNUC_HAS_BUILTIN(builtin,major,minor,patch) ZPL_GNUC_VERSION_CHECK(major,minor,patch) - #endif - - #if defined(ZPL_GCC_HAS_BUILTIN) - # undef ZPL_GCC_HAS_BUILTIN - #endif - #if defined(__has_builtin) - # define ZPL_GCC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) - #else - # define ZPL_GCC_HAS_BUILTIN(builtin,major,minor,patch) ZPL_GCC_VERSION_CHECK(major,minor,patch) - #endif - - #if defined(ZPL_HAS_FEATURE) - # undef ZPL_HAS_FEATURE - #endif - #if defined(__has_feature) - # define ZPL_HAS_FEATURE(feature) __has_feature(feature) - #else - # define ZPL_HAS_FEATURE(feature) (0) - #endif - - #if defined(ZPL_GNUC_HAS_FEATURE) - # undef ZPL_GNUC_HAS_FEATURE - #endif - #if defined(__has_feature) - # define ZPL_GNUC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) - #else - # define ZPL_GNUC_HAS_FEATURE(feature,major,minor,patch) ZPL_GNUC_VERSION_CHECK(major,minor,patch) - #endif - - #if defined(ZPL_GCC_HAS_FEATURE) - # undef ZPL_GCC_HAS_FEATURE - #endif - #if defined(__has_feature) - # define ZPL_GCC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) - #else - # define ZPL_GCC_HAS_FEATURE(feature,major,minor,patch) ZPL_GCC_VERSION_CHECK(major,minor,patch) - #endif - - #if defined(ZPL_HAS_EXTENSION) - # undef ZPL_HAS_EXTENSION - #endif - #if defined(__has_extension) - # define ZPL_HAS_EXTENSION(extension) __has_extension(extension) - #else - # define ZPL_HAS_EXTENSION(extension) (0) - #endif - - #if defined(ZPL_GNUC_HAS_EXTENSION) - # undef ZPL_GNUC_HAS_EXTENSION - #endif - #if defined(__has_extension) - # define ZPL_GNUC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) - #else - # define ZPL_GNUC_HAS_EXTENSION(extension,major,minor,patch) ZPL_GNUC_VERSION_CHECK(major,minor,patch) - #endif - - #if defined(ZPL_GCC_HAS_EXTENSION) - # undef ZPL_GCC_HAS_EXTENSION - #endif - #if defined(__has_extension) - # define ZPL_GCC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) - #else - # define ZPL_GCC_HAS_EXTENSION(extension,major,minor,patch) ZPL_GCC_VERSION_CHECK(major,minor,patch) - #endif - - #if defined(ZPL_HAS_DECLSPEC_ATTRIBUTE) - # undef ZPL_HAS_DECLSPEC_ATTRIBUTE - #endif - #if defined(__has_declspec_attribute) - # define ZPL_HAS_DECLSPEC_ATTRIBUTE(attribute) __has_declspec_attribute(attribute) - #else - # define ZPL_HAS_DECLSPEC_ATTRIBUTE(attribute) (0) - #endif - - #if defined(ZPL_GNUC_HAS_DECLSPEC_ATTRIBUTE) - # undef ZPL_GNUC_HAS_DECLSPEC_ATTRIBUTE - #endif - #if defined(__has_declspec_attribute) - # define ZPL_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) - #else - # define ZPL_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) ZPL_GNUC_VERSION_CHECK(major,minor,patch) - #endif - - #if defined(ZPL_GCC_HAS_DECLSPEC_ATTRIBUTE) - # undef ZPL_GCC_HAS_DECLSPEC_ATTRIBUTE - #endif - #if defined(__has_declspec_attribute) - # define ZPL_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) - #else - # define ZPL_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) ZPL_GCC_VERSION_CHECK(major,minor,patch) - #endif - - #if defined(ZPL_HAS_WARNING) - # undef ZPL_HAS_WARNING - #endif - #if defined(__has_warning) - # define ZPL_HAS_WARNING(warning) __has_warning(warning) - #else - # define ZPL_HAS_WARNING(warning) (0) - #endif - - #if defined(ZPL_GNUC_HAS_WARNING) - # undef ZPL_GNUC_HAS_WARNING - #endif - #if defined(__has_warning) - # define ZPL_GNUC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) - #else - # define ZPL_GNUC_HAS_WARNING(warning,major,minor,patch) ZPL_GNUC_VERSION_CHECK(major,minor,patch) - #endif - - #if defined(ZPL_GCC_HAS_WARNING) - # undef ZPL_GCC_HAS_WARNING - #endif - #if defined(__has_warning) - # define ZPL_GCC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) - #else - # define ZPL_GCC_HAS_WARNING(warning,major,minor,patch) ZPL_GCC_VERSION_CHECK(major,minor,patch) - #endif - - /* ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ is for - ZPL INTERNAL USE ONLY. API subject to change without notice. */ - #if defined(ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) - # undef ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ - #endif - #if defined(__cplusplus) - # if ZPL_HAS_WARNING("-Wc++98-compat") - # if ZPL_HAS_WARNING("-Wc++17-extensions") - # define ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ - ZPL_DIAGNOSTIC_PUSH \ - _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ - _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \ - xpr \ - ZPL_DIAGNOSTIC_POP - # else - # define ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ - ZPL_DIAGNOSTIC_PUSH \ - _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ - xpr \ - ZPL_DIAGNOSTIC_POP - # endif - # endif - #endif - #if !defined(ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) - # define ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(x) x - #endif - - #if defined(ZPL_CONST_CAST) - # undef ZPL_CONST_CAST - #endif - #if defined(__cplusplus) - # define ZPL_CONST_CAST(T, expr) (const_cast(expr)) - #elif \ - ZPL_HAS_WARNING("-Wcast-qual") || \ - ZPL_GCC_VERSION_CHECK(4,6,0) || \ - ZPL_INTEL_VERSION_CHECK(13,0,0) - # define ZPL_CONST_CAST(T, expr) (__extension__ ({ \ - ZPL_DIAGNOSTIC_PUSH \ - ZPL_DIAGNOSTIC_DISABLE_CAST_QUAL \ - ((T) (expr)); \ - ZPL_DIAGNOSTIC_POP \ - })) - #else - # define ZPL_CONST_CAST(T, expr) ((T) (expr)) - #endif - - #if defined(ZPL_REINTERPRET_CAST) - # undef ZPL_REINTERPRET_CAST - #endif - #if defined(__cplusplus) - # define ZPL_REINTERPRET_CAST(T, expr) (reinterpret_cast(expr)) - #else - # define ZPL_REINTERPRET_CAST(T, expr) ((T) (expr)) - #endif - - #if defined(ZPL_STATIC_CAST) - # undef ZPL_STATIC_CAST - #endif - #if defined(__cplusplus) - # define ZPL_STATIC_CAST(T, expr) (static_cast(expr)) - #else - # define ZPL_STATIC_CAST(T, expr) ((T) (expr)) - #endif - - #if defined(ZPL_CPP_CAST) - # undef ZPL_CPP_CAST - #endif - #if defined(__cplusplus) - # if ZPL_HAS_WARNING("-Wold-style-cast") - # define ZPL_CPP_CAST(T, expr) \ - ZPL_DIAGNOSTIC_PUSH \ - _Pragma("clang diagnostic ignored \"-Wold-style-cast\"") \ - ((T) (expr)) \ - ZPL_DIAGNOSTIC_POP - # elif ZPL_IAR_VERSION_CHECK(8,3,0) - # define ZPL_CPP_CAST(T, expr) \ - ZPL_DIAGNOSTIC_PUSH \ - _Pragma("diag_suppress=Pe137") \ - ZPL_DIAGNOSTIC_POP \ - # else - # define ZPL_CPP_CAST(T, expr) ((T) (expr)) - # endif - #else - # define ZPL_CPP_CAST(T, expr) (expr) - #endif - - #if \ - (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ - defined(__clang__) || \ - ZPL_GCC_VERSION_CHECK(3,0,0) || \ - ZPL_INTEL_VERSION_CHECK(13,0,0) || \ - ZPL_IAR_VERSION_CHECK(8,0,0) || \ - ZPL_PGI_VERSION_CHECK(18,4,0) || \ - ZPL_ARM_VERSION_CHECK(4,1,0) || \ - ZPL_TI_VERSION_CHECK(15,12,0) || \ - ZPL_TI_ARMCL_VERSION_CHECK(4,7,0) || \ - ZPL_TI_CL430_VERSION_CHECK(2,0,1) || \ - ZPL_TI_CL2000_VERSION_CHECK(6,1,0) || \ - ZPL_TI_CL6X_VERSION_CHECK(7,0,0) || \ - ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ - ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - ZPL_CRAY_VERSION_CHECK(5,0,0) || \ - ZPL_TINYC_VERSION_CHECK(0,9,17) || \ - ZPL_SUNPRO_VERSION_CHECK(8,0,0) || \ - (ZPL_IBM_VERSION_CHECK(10,1,0) && defined(__C99_PRAGMA_OPERATOR)) - # define ZPL_PRAGMA(value) _Pragma(#value) - #elif ZPL_MSVC_VERSION_CHECK(15,0,0) - # define ZPL_PRAGMA(value) __pragma(value) - #else - # define ZPL_PRAGMA(value) - #endif - - #if defined(ZPL_DIAGNOSTIC_PUSH) - # undef ZPL_DIAGNOSTIC_PUSH - #endif - #if defined(ZPL_DIAGNOSTIC_POP) - # undef ZPL_DIAGNOSTIC_POP - #endif - #if defined(__clang__) - # define ZPL_DIAGNOSTIC_PUSH _Pragma("clang diagnostic push") - # define ZPL_DIAGNOSTIC_POP _Pragma("clang diagnostic pop") - #elif ZPL_INTEL_VERSION_CHECK(13,0,0) - # define ZPL_DIAGNOSTIC_PUSH _Pragma("warning(push)") - # define ZPL_DIAGNOSTIC_POP _Pragma("warning(pop)") - #elif ZPL_GCC_VERSION_CHECK(4,6,0) - # define ZPL_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push") - # define ZPL_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop") - #elif ZPL_MSVC_VERSION_CHECK(15,0,0) - # define ZPL_DIAGNOSTIC_PUSH __pragma(warning(push)) - # define ZPL_DIAGNOSTIC_POP __pragma(warning(pop)) - #elif ZPL_ARM_VERSION_CHECK(5,6,0) - # define ZPL_DIAGNOSTIC_PUSH _Pragma("push") - # define ZPL_DIAGNOSTIC_POP _Pragma("pop") - #elif \ - ZPL_TI_VERSION_CHECK(15,12,0) || \ - ZPL_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - ZPL_TI_CL430_VERSION_CHECK(4,4,0) || \ - ZPL_TI_CL6X_VERSION_CHECK(8,1,0) || \ - ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ - ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) - # define ZPL_DIAGNOSTIC_PUSH _Pragma("diag_push") - # define ZPL_DIAGNOSTIC_POP _Pragma("diag_pop") - #elif ZPL_PELLES_VERSION_CHECK(2,90,0) - # define ZPL_DIAGNOSTIC_PUSH _Pragma("warning(push)") - # define ZPL_DIAGNOSTIC_POP _Pragma("warning(pop)") - #else - # define ZPL_DIAGNOSTIC_PUSH - # define ZPL_DIAGNOSTIC_POP - #endif - - #if defined(ZPL_DIAGNOSTIC_DISABLE_DEPRECATED) - # undef ZPL_DIAGNOSTIC_DISABLE_DEPRECATED - #endif - #if ZPL_HAS_WARNING("-Wdeprecated-declarations") - # define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") - #elif ZPL_INTEL_VERSION_CHECK(13,0,0) - # define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warning(disable:1478 1786)") - #elif ZPL_PGI_VERSION_CHECK(17,10,0) - # define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") - #elif ZPL_GCC_VERSION_CHECK(4,3,0) - # define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") - #elif ZPL_MSVC_VERSION_CHECK(15,0,0) - # define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:4996)) - #elif \ - ZPL_TI_VERSION_CHECK(15,12,0) || \ - (ZPL_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (ZPL_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (ZPL_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL430_VERSION_CHECK(4,3,0) || \ - (ZPL_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL6X_VERSION_CHECK(7,5,0) || \ - ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ - ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) - # define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1291,1718") - #elif ZPL_SUNPRO_VERSION_CHECK(5,13,0) && !defined(__cplusplus) - # define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)") - #elif ZPL_SUNPRO_VERSION_CHECK(5,13,0) && defined(__cplusplus) - # define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,symdeprecated,symdeprecated2)") - #elif ZPL_IAR_VERSION_CHECK(8,0,0) - # define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress=Pe1444,Pe1215") - #elif ZPL_PELLES_VERSION_CHECK(2,90,0) - # define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warn(disable:2241)") - #else - # define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED - #endif - - #if defined(ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS) - # undef ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS - #endif - #if ZPL_HAS_WARNING("-Wunknown-pragmas") - # define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"") - #elif ZPL_INTEL_VERSION_CHECK(13,0,0) - # define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("warning(disable:161)") - #elif ZPL_PGI_VERSION_CHECK(17,10,0) - # define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 1675") - #elif ZPL_GCC_VERSION_CHECK(4,3,0) - # define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("GCC diagnostic ignored \"-Wunknown-pragmas\"") - #elif ZPL_MSVC_VERSION_CHECK(15,0,0) - # define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:4068)) - #elif \ - ZPL_TI_VERSION_CHECK(16,9,0) || \ - ZPL_TI_CL6X_VERSION_CHECK(8,0,0) || \ - ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ - ZPL_TI_CLPRU_VERSION_CHECK(2,3,0) - # define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") - #elif ZPL_TI_CL6X_VERSION_CHECK(8,0,0) - # define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") - #elif ZPL_IAR_VERSION_CHECK(8,0,0) - # define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress=Pe161") - #else - # define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS - #endif - - #if defined(ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES) - # undef ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES - #endif - #if ZPL_HAS_WARNING("-Wunknown-attributes") - # define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("clang diagnostic ignored \"-Wunknown-attributes\"") - #elif ZPL_GCC_VERSION_CHECK(4,6,0) - # define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") - #elif ZPL_INTEL_VERSION_CHECK(17,0,0) - # define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("warning(disable:1292)") - #elif ZPL_MSVC_VERSION_CHECK(19,0,0) - # define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:5030)) - #elif ZPL_PGI_VERSION_CHECK(17,10,0) - # define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097") - #elif ZPL_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus) - # define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("error_messages(off,attrskipunsup)") - #elif \ - ZPL_TI_VERSION_CHECK(18,1,0) || \ - ZPL_TI_CL6X_VERSION_CHECK(8,3,0) || \ - ZPL_TI_CL7X_VERSION_CHECK(1,2,0) - # define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1173") - #elif ZPL_IAR_VERSION_CHECK(8,0,0) - # define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress=Pe1097") - #else - # define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES - #endif - - #if defined(ZPL_DIAGNOSTIC_DISABLE_CAST_QUAL) - # undef ZPL_DIAGNOSTIC_DISABLE_CAST_QUAL - #endif - #if ZPL_HAS_WARNING("-Wcast-qual") - # define ZPL_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("clang diagnostic ignored \"-Wcast-qual\"") - #elif ZPL_INTEL_VERSION_CHECK(13,0,0) - # define ZPL_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("warning(disable:2203 2331)") - #elif ZPL_GCC_VERSION_CHECK(3,0,0) - # define ZPL_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") - #else - # define ZPL_DIAGNOSTIC_DISABLE_CAST_QUAL - #endif - - #if defined(ZPL_DEPRECATED) - # undef ZPL_DEPRECATED - #endif - #if defined(ZPL_DEPRECATED_FOR) - # undef ZPL_DEPRECATED_FOR - #endif - #if defined(__cplusplus) && (__cplusplus >= 201402L) - # define ZPL_DEPRECATED(since) ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since)]]) - # define ZPL_DEPRECATED_FOR(since, replacement) ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since "; use " #replacement)]]) - #elif \ - ZPL_HAS_EXTENSION(attribute_deprecated_with_message) || \ - ZPL_GCC_VERSION_CHECK(4,5,0) || \ - ZPL_INTEL_VERSION_CHECK(13,0,0) || \ - ZPL_ARM_VERSION_CHECK(5,6,0) || \ - ZPL_SUNPRO_VERSION_CHECK(5,13,0) || \ - ZPL_PGI_VERSION_CHECK(17,10,0) || \ - ZPL_TI_VERSION_CHECK(18,1,0) || \ - ZPL_TI_ARMCL_VERSION_CHECK(18,1,0) || \ - ZPL_TI_CL6X_VERSION_CHECK(8,3,0) || \ - ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ - ZPL_TI_CLPRU_VERSION_CHECK(2,3,0) - # define ZPL_DEPRECATED(since) __attribute__((__deprecated__("Since " #since))) - # define ZPL_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__("Since " #since "; use " #replacement))) - #elif \ - ZPL_HAS_ATTRIBUTE(deprecated) || \ - ZPL_GCC_VERSION_CHECK(3,1,0) || \ - ZPL_ARM_VERSION_CHECK(4,1,0) || \ - ZPL_TI_VERSION_CHECK(15,12,0) || \ - (ZPL_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (ZPL_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (ZPL_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL430_VERSION_CHECK(4,3,0) || \ - (ZPL_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL6X_VERSION_CHECK(7,5,0) || \ - ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ - ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) - # define ZPL_DEPRECATED(since) __attribute__((__deprecated__)) - # define ZPL_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__)) - #elif ZPL_MSVC_VERSION_CHECK(14,0,0) - # define ZPL_DEPRECATED(since) __declspec(deprecated("Since " # since)) - # define ZPL_DEPRECATED_FOR(since, replacement) __declspec(deprecated("Since " #since "; use " #replacement)) - #elif \ - ZPL_MSVC_VERSION_CHECK(13,10,0) || \ - ZPL_PELLES_VERSION_CHECK(6,50,0) - # define ZPL_DEPRECATED(since) __declspec(deprecated) - # define ZPL_DEPRECATED_FOR(since, replacement) __declspec(deprecated) - #elif ZPL_IAR_VERSION_CHECK(8,0,0) - # define ZPL_DEPRECATED(since) _Pragma("deprecated") - # define ZPL_DEPRECATED_FOR(since, replacement) _Pragma("deprecated") - #else - # define ZPL_DEPRECATED(since) - # define ZPL_DEPRECATED_FOR(since, replacement) - #endif - - #if defined(ZPL_UNAVAILABLE) - # undef ZPL_UNAVAILABLE - #endif - #if \ - ZPL_HAS_ATTRIBUTE(warning) || \ - ZPL_GCC_VERSION_CHECK(4,3,0) || \ - ZPL_INTEL_VERSION_CHECK(13,0,0) - # define ZPL_UNAVAILABLE(available_since) __attribute__((__warning__("Not available until " #available_since))) - #else - # define ZPL_UNAVAILABLE(available_since) - #endif - - #if defined(ZPL_WARN_UNUSED_RESULT) - # undef ZPL_WARN_UNUSED_RESULT - #endif - #if defined(ZPL_WARN_UNUSED_RESULT_MSG) - # undef ZPL_WARN_UNUSED_RESULT_MSG - #endif - #if (ZPL_HAS_CPP_ATTRIBUTE(nodiscard) >= 201907L) - # define ZPL_WARN_UNUSED_RESULT ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) - # define ZPL_WARN_UNUSED_RESULT_MSG(msg) ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard(msg)]]) - #elif ZPL_HAS_CPP_ATTRIBUTE(nodiscard) - # define ZPL_WARN_UNUSED_RESULT ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) - # define ZPL_WARN_UNUSED_RESULT_MSG(msg) ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) - #elif \ - ZPL_HAS_ATTRIBUTE(warn_unused_result) || \ - ZPL_GCC_VERSION_CHECK(3,4,0) || \ - ZPL_INTEL_VERSION_CHECK(13,0,0) || \ - ZPL_TI_VERSION_CHECK(15,12,0) || \ - (ZPL_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (ZPL_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (ZPL_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL430_VERSION_CHECK(4,3,0) || \ - (ZPL_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL6X_VERSION_CHECK(7,5,0) || \ - ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ - ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - (ZPL_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ - ZPL_PGI_VERSION_CHECK(17,10,0) - # define ZPL_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__)) - # define ZPL_WARN_UNUSED_RESULT_MSG(msg) __attribute__((__warn_unused_result__)) - #elif defined(_Check_return_) /* SAL */ - # define ZPL_WARN_UNUSED_RESULT _Check_return_ - # define ZPL_WARN_UNUSED_RESULT_MSG(msg) _Check_return_ - #else - # define ZPL_WARN_UNUSED_RESULT - # define ZPL_WARN_UNUSED_RESULT_MSG(msg) - #endif - - #if defined(ZPL_SENTINEL) - # undef ZPL_SENTINEL - #endif - #if \ - ZPL_HAS_ATTRIBUTE(sentinel) || \ - ZPL_GCC_VERSION_CHECK(4,0,0) || \ - ZPL_INTEL_VERSION_CHECK(13,0,0) || \ - ZPL_ARM_VERSION_CHECK(5,4,0) - # define ZPL_SENTINEL(position) __attribute__((__sentinel__(position))) - #else - # define ZPL_SENTINEL(position) - #endif - - #if defined(ZPL_NO_RETURN) - # undef ZPL_NO_RETURN - #endif - #if ZPL_IAR_VERSION_CHECK(8,0,0) - # define ZPL_NO_RETURN __noreturn - #elif ZPL_INTEL_VERSION_CHECK(13,0,0) - # define ZPL_NO_RETURN __attribute__((__noreturn__)) - #elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L - # define ZPL_NO_RETURN _Noreturn - #elif defined(__cplusplus) && (__cplusplus >= 201103L) - # define ZPL_NO_RETURN ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[noreturn]]) - #elif \ - ZPL_HAS_ATTRIBUTE(noreturn) || \ - ZPL_GCC_VERSION_CHECK(3,2,0) || \ - ZPL_SUNPRO_VERSION_CHECK(5,11,0) || \ - ZPL_ARM_VERSION_CHECK(4,1,0) || \ - ZPL_IBM_VERSION_CHECK(10,1,0) || \ - ZPL_TI_VERSION_CHECK(15,12,0) || \ - (ZPL_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (ZPL_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (ZPL_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL430_VERSION_CHECK(4,3,0) || \ - (ZPL_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL6X_VERSION_CHECK(7,5,0) || \ - ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ - ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) - # define ZPL_NO_RETURN __attribute__((__noreturn__)) - #elif ZPL_SUNPRO_VERSION_CHECK(5,10,0) - # define ZPL_NO_RETURN _Pragma("does_not_return") - #elif ZPL_MSVC_VERSION_CHECK(13,10,0) - # define ZPL_NO_RETURN __declspec(noreturn) - #elif ZPL_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus) - # define ZPL_NO_RETURN _Pragma("FUNC_NEVER_RETURNS;") - #elif ZPL_COMPCERT_VERSION_CHECK(3,2,0) - # define ZPL_NO_RETURN __attribute((noreturn)) - #elif ZPL_PELLES_VERSION_CHECK(9,0,0) - # define ZPL_NO_RETURN __declspec(noreturn) - #else - # define ZPL_NO_RETURN - #endif - - #if defined(ZPL_NO_ESCAPE) - # undef ZPL_NO_ESCAPE - #endif - #if ZPL_HAS_ATTRIBUTE(noescape) - # define ZPL_NO_ESCAPE __attribute__((__noescape__)) - #else - # define ZPL_NO_ESCAPE - #endif - - #if defined(ZPL_UNREACHABLE) - # undef ZPL_UNREACHABLE - #endif - #if defined(ZPL_UNREACHABLE_RETURN) - # undef ZPL_UNREACHABLE_RETURN - #endif - #if defined(ZPL_ASSUME) - # undef ZPL_ASSUME - #endif - #if \ - ZPL_MSVC_VERSION_CHECK(13,10,0) || \ - ZPL_INTEL_VERSION_CHECK(13,0,0) - # define ZPL_ASSUME(expr) __assume(expr) - #elif ZPL_HAS_BUILTIN(__builtin_assume) - # define ZPL_ASSUME(expr) __builtin_assume(expr) - #elif \ - ZPL_TI_CL2000_VERSION_CHECK(6,2,0) || \ - ZPL_TI_CL6X_VERSION_CHECK(4,0,0) - # if defined(__cplusplus) - # define ZPL_ASSUME(expr) std::_nassert(expr) - # else - # define ZPL_ASSUME(expr) _nassert(expr) - # endif - #endif - #if \ - (ZPL_HAS_BUILTIN(__builtin_unreachable) && (!defined(ZPL_ARM_VERSION))) || \ - ZPL_GCC_VERSION_CHECK(4,5,0) || \ - ZPL_PGI_VERSION_CHECK(18,10,0) || \ - ZPL_INTEL_VERSION_CHECK(13,0,0) || \ - ZPL_IBM_VERSION_CHECK(13,1,5) - # define ZPL_UNREACHABLE() __builtin_unreachable() - #elif defined(ZPL_ASSUME) - # define ZPL_UNREACHABLE() ZPL_ASSUME(0) - #endif - #if !defined(ZPL_ASSUME) - # if defined(ZPL_UNREACHABLE) - # define ZPL_ASSUME(expr) ZPL_STATIC_CAST(void, ((expr) ? 1 : (ZPL_UNREACHABLE(), 1))) - # else - # define ZPL_ASSUME(expr) ZPL_STATIC_CAST(void, expr) - # endif - #endif - #if defined(ZPL_UNREACHABLE) - # if \ - ZPL_TI_CL2000_VERSION_CHECK(6,2,0) || \ - ZPL_TI_CL6X_VERSION_CHECK(4,0,0) - # define ZPL_UNREACHABLE_RETURN(value) return (ZPL_STATIC_CAST(void, ZPL_ASSUME(0)), (value)) - # else - # define ZPL_UNREACHABLE_RETURN(value) ZPL_UNREACHABLE() - # endif - #else - # define ZPL_UNREACHABLE_RETURN(value) return (value) - #endif - #if !defined(ZPL_UNREACHABLE) - # define ZPL_UNREACHABLE() ZPL_ASSUME(0) - #endif - - ZPL_DIAGNOSTIC_PUSH - #if ZPL_HAS_WARNING("-Wpedantic") - # pragma clang diagnostic ignored "-Wpedantic" - #endif - #if ZPL_HAS_WARNING("-Wc++98-compat-pedantic") && defined(__cplusplus) - # pragma clang diagnostic ignored "-Wc++98-compat-pedantic" - #endif - #if ZPL_GCC_HAS_WARNING("-Wvariadic-macros",4,0,0) - # if defined(__clang__) - # pragma clang diagnostic ignored "-Wvariadic-macros" - # elif defined(ZPL_GCC_VERSION) - # pragma GCC diagnostic ignored "-Wvariadic-macros" - # endif - #endif - #if defined(ZPL_NON_NULL) - # undef ZPL_NON_NULL - #endif - #if \ - ZPL_HAS_ATTRIBUTE(nonnull) || \ - ZPL_GCC_VERSION_CHECK(3,3,0) || \ - ZPL_INTEL_VERSION_CHECK(13,0,0) || \ - ZPL_ARM_VERSION_CHECK(4,1,0) - # define ZPL_NON_NULL(...) __attribute__((__nonnull__(__VA_ARGS__))) - #else - # define ZPL_NON_NULL(...) - #endif - ZPL_DIAGNOSTIC_POP - - #if defined(ZPL_PRINTF_FORMAT) - # undef ZPL_PRINTF_FORMAT - #endif - #if defined(__MINGW32__) && ZPL_GCC_HAS_ATTRIBUTE(format,4,4,0) && !defined(__USE_MINGW_ANSI_STDIO) - # define ZPL_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(ms_printf, string_idx, first_to_check))) - #elif defined(__MINGW32__) && ZPL_GCC_HAS_ATTRIBUTE(format,4,4,0) && defined(__USE_MINGW_ANSI_STDIO) - # define ZPL_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(gnu_printf, string_idx, first_to_check))) - #elif \ - ZPL_HAS_ATTRIBUTE(format) || \ - ZPL_GCC_VERSION_CHECK(3,1,0) || \ - ZPL_INTEL_VERSION_CHECK(13,0,0) || \ - ZPL_ARM_VERSION_CHECK(5,6,0) || \ - ZPL_IBM_VERSION_CHECK(10,1,0) || \ - ZPL_TI_VERSION_CHECK(15,12,0) || \ - (ZPL_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (ZPL_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (ZPL_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL430_VERSION_CHECK(4,3,0) || \ - (ZPL_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL6X_VERSION_CHECK(7,5,0) || \ - ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ - ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) - # define ZPL_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(__printf__, string_idx, first_to_check))) - #elif ZPL_PELLES_VERSION_CHECK(6,0,0) - # define ZPL_PRINTF_FORMAT(string_idx,first_to_check) __declspec(vaformat(printf,string_idx,first_to_check)) - #else - # define ZPL_PRINTF_FORMAT(string_idx,first_to_check) - #endif - - #if defined(ZPL_CONSTEXPR) - # undef ZPL_CONSTEXPR - #endif - #if defined(__cplusplus) - # if __cplusplus >= 201103L - # define ZPL_CONSTEXPR ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(constexpr) - # endif - #endif - #if !defined(ZPL_CONSTEXPR) - # define ZPL_CONSTEXPR - #endif - - #if defined(ZPL_PREDICT) - # undef ZPL_PREDICT - #endif - #if defined(ZPL_LIKELY) - # undef ZPL_LIKELY - #endif - #if defined(ZPL_UNLIKELY) - # undef ZPL_UNLIKELY - #endif - #if defined(ZPL_UNPREDICTABLE) - # undef ZPL_UNPREDICTABLE - #endif - #if ZPL_HAS_BUILTIN(__builtin_unpredictable) - # define ZPL_UNPREDICTABLE(expr) __builtin_unpredictable((expr)) - #endif - #if \ - ZPL_HAS_BUILTIN(__builtin_expect_with_probability) || \ - ZPL_GCC_VERSION_CHECK(9,0,0) - # define ZPL_PREDICT(expr, value, probability) __builtin_expect_with_probability( (expr), (value), (probability)) - # define ZPL_PREDICT_TRUE(expr, probability) __builtin_expect_with_probability(!!(expr), 1 , (probability)) - # define ZPL_PREDICT_FALSE(expr, probability) __builtin_expect_with_probability(!!(expr), 0 , (probability)) - # define ZPL_LIKELY(expr) __builtin_expect (!!(expr), 1 ) - # define ZPL_UNLIKELY(expr) __builtin_expect (!!(expr), 0 ) - #elif \ - ZPL_HAS_BUILTIN(__builtin_expect) || \ - ZPL_GCC_VERSION_CHECK(3,0,0) || \ - ZPL_INTEL_VERSION_CHECK(13,0,0) || \ - (ZPL_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ - ZPL_ARM_VERSION_CHECK(4,1,0) || \ - ZPL_IBM_VERSION_CHECK(10,1,0) || \ - ZPL_TI_VERSION_CHECK(15,12,0) || \ - ZPL_TI_ARMCL_VERSION_CHECK(4,7,0) || \ - ZPL_TI_CL430_VERSION_CHECK(3,1,0) || \ - ZPL_TI_CL2000_VERSION_CHECK(6,1,0) || \ - ZPL_TI_CL6X_VERSION_CHECK(6,1,0) || \ - ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ - ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - ZPL_TINYC_VERSION_CHECK(0,9,27) || \ - ZPL_CRAY_VERSION_CHECK(8,1,0) - # define ZPL_PREDICT(expr, expected, probability) \ - (((probability) >= 0.9) ? __builtin_expect((expr), (expected)) : (ZPL_STATIC_CAST(void, expected), (expr))) - # define ZPL_PREDICT_TRUE(expr, probability) \ - (__extension__ ({ \ - double zpl_probability_ = (probability); \ - ((zpl_probability_ >= 0.9) ? __builtin_expect(!!(expr), 1) : ((zpl_probability_ <= 0.1) ? __builtin_expect(!!(expr), 0) : !!(expr))); \ - })) - # define ZPL_PREDICT_FALSE(expr, probability) \ - (__extension__ ({ \ - double zpl_probability_ = (probability); \ - ((zpl_probability_ >= 0.9) ? __builtin_expect(!!(expr), 0) : ((zpl_probability_ <= 0.1) ? __builtin_expect(!!(expr), 1) : !!(expr))); \ - })) - # define ZPL_LIKELY(expr) __builtin_expect(!!(expr), 1) - # define ZPL_UNLIKELY(expr) __builtin_expect(!!(expr), 0) - #else - # define ZPL_PREDICT(expr, expected, probability) (ZPL_STATIC_CAST(void, expected), (expr)) - # define ZPL_PREDICT_TRUE(expr, probability) (!!(expr)) - # define ZPL_PREDICT_FALSE(expr, probability) (!!(expr)) - # define ZPL_LIKELY(expr) (!!(expr)) - # define ZPL_UNLIKELY(expr) (!!(expr)) - #endif - #if !defined(ZPL_UNPREDICTABLE) - # define ZPL_UNPREDICTABLE(expr) ZPL_PREDICT(expr, 1, 0.5) - #endif - - #if defined(ZPL_MALLOC) - # undef ZPL_MALLOC - #endif - #if \ - ZPL_HAS_ATTRIBUTE(malloc) || \ - ZPL_GCC_VERSION_CHECK(3,1,0) || \ - ZPL_INTEL_VERSION_CHECK(13,0,0) || \ - ZPL_SUNPRO_VERSION_CHECK(5,11,0) || \ - ZPL_ARM_VERSION_CHECK(4,1,0) || \ - ZPL_IBM_VERSION_CHECK(12,1,0) || \ - ZPL_TI_VERSION_CHECK(15,12,0) || \ - (ZPL_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (ZPL_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (ZPL_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL430_VERSION_CHECK(4,3,0) || \ - (ZPL_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL6X_VERSION_CHECK(7,5,0) || \ - ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ - ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) - # define ZPL_MALLOC __attribute__((__malloc__)) - #elif ZPL_SUNPRO_VERSION_CHECK(5,10,0) - # define ZPL_MALLOC _Pragma("returns_new_memory") - #elif ZPL_MSVC_VERSION_CHECK(14, 0, 0) - # define ZPL_MALLOC __declspec(restrict) - #else - # define ZPL_MALLOC - #endif - - #if defined(ZPL_PURE) - # undef ZPL_PURE - #endif - #if \ - ZPL_HAS_ATTRIBUTE(pure) || \ - ZPL_GCC_VERSION_CHECK(2,96,0) || \ - ZPL_INTEL_VERSION_CHECK(13,0,0) || \ - ZPL_SUNPRO_VERSION_CHECK(5,11,0) || \ - ZPL_ARM_VERSION_CHECK(4,1,0) || \ - ZPL_IBM_VERSION_CHECK(10,1,0) || \ - ZPL_TI_VERSION_CHECK(15,12,0) || \ - (ZPL_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (ZPL_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (ZPL_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL430_VERSION_CHECK(4,3,0) || \ - (ZPL_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL6X_VERSION_CHECK(7,5,0) || \ - ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ - ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - ZPL_PGI_VERSION_CHECK(17,10,0) - # define ZPL_PURE __attribute__((__pure__)) - #elif ZPL_SUNPRO_VERSION_CHECK(5,10,0) - # define ZPL_PURE _Pragma("does_not_write_global_data") - #elif defined(__cplusplus) && \ - ( \ - ZPL_TI_CL430_VERSION_CHECK(2,0,1) || \ - ZPL_TI_CL6X_VERSION_CHECK(4,0,0) || \ - ZPL_TI_CL7X_VERSION_CHECK(1,2,0) \ - ) - # define ZPL_PURE _Pragma("FUNC_IS_PURE;") - #else - # define ZPL_PURE - #endif - - #if defined(ZPL_CONST) - # undef ZPL_CONST - #endif - #if \ - ZPL_HAS_ATTRIBUTE(const) || \ - ZPL_GCC_VERSION_CHECK(2,5,0) || \ - ZPL_INTEL_VERSION_CHECK(13,0,0) || \ - ZPL_SUNPRO_VERSION_CHECK(5,11,0) || \ - ZPL_ARM_VERSION_CHECK(4,1,0) || \ - ZPL_IBM_VERSION_CHECK(10,1,0) || \ - ZPL_TI_VERSION_CHECK(15,12,0) || \ - (ZPL_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (ZPL_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (ZPL_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL430_VERSION_CHECK(4,3,0) || \ - (ZPL_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL6X_VERSION_CHECK(7,5,0) || \ - ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ - ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - ZPL_PGI_VERSION_CHECK(17,10,0) - # define ZPL_CONST __attribute__((__const__)) - #elif \ - ZPL_SUNPRO_VERSION_CHECK(5,10,0) - # define ZPL_CONST _Pragma("no_side_effect") - #else - # define ZPL_CONST ZPL_PURE - #endif - - #if defined(ZPL_RESTRICT) - # undef ZPL_RESTRICT - #endif - #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && !defined(__cplusplus) - # define ZPL_RESTRICT restrict - #elif \ - ZPL_GCC_VERSION_CHECK(3,1,0) || \ - ZPL_MSVC_VERSION_CHECK(14,0,0) || \ - ZPL_INTEL_VERSION_CHECK(13,0,0) || \ - ZPL_ARM_VERSION_CHECK(4,1,0) || \ - ZPL_IBM_VERSION_CHECK(10,1,0) || \ - ZPL_PGI_VERSION_CHECK(17,10,0) || \ - ZPL_TI_CL430_VERSION_CHECK(4,3,0) || \ - ZPL_TI_CL2000_VERSION_CHECK(6,2,4) || \ - ZPL_TI_CL6X_VERSION_CHECK(8,1,0) || \ - ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ - (ZPL_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)) || \ - ZPL_IAR_VERSION_CHECK(8,0,0) || \ - defined(__clang__) - # define ZPL_RESTRICT __restrict - #elif ZPL_SUNPRO_VERSION_CHECK(5,3,0) && !defined(__cplusplus) - # define ZPL_RESTRICT _Restrict - #else - # define ZPL_RESTRICT - #endif - - #if defined(ZPL_INLINE) - # undef ZPL_INLINE - #endif - #if \ - (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ - (defined(__cplusplus) && (__cplusplus >= 199711L)) - # define ZPL_INLINE inline - #elif \ - defined(ZPL_GCC_VERSION) || \ - ZPL_ARM_VERSION_CHECK(6,2,0) - # define ZPL_INLINE __inline__ - #elif \ - ZPL_MSVC_VERSION_CHECK(12,0,0) || \ - ZPL_ARM_VERSION_CHECK(4,1,0) || \ - ZPL_TI_ARMCL_VERSION_CHECK(5,1,0) || \ - ZPL_TI_CL430_VERSION_CHECK(3,1,0) || \ - ZPL_TI_CL2000_VERSION_CHECK(6,2,0) || \ - ZPL_TI_CL6X_VERSION_CHECK(8,0,0) || \ - ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ - ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) - # define ZPL_INLINE __inline - #else - # define ZPL_INLINE - #endif - - #if defined(ZPL_ALWAYS_INLINE) - # undef ZPL_ALWAYS_INLINE - #endif - #if \ - ZPL_HAS_ATTRIBUTE(always_inline) || \ - ZPL_GCC_VERSION_CHECK(4,0,0) || \ - ZPL_INTEL_VERSION_CHECK(13,0,0) || \ - ZPL_SUNPRO_VERSION_CHECK(5,11,0) || \ - ZPL_ARM_VERSION_CHECK(4,1,0) || \ - ZPL_IBM_VERSION_CHECK(10,1,0) || \ - ZPL_TI_VERSION_CHECK(15,12,0) || \ - (ZPL_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (ZPL_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (ZPL_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL430_VERSION_CHECK(4,3,0) || \ - (ZPL_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL6X_VERSION_CHECK(7,5,0) || \ - ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ - ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) - # define ZPL_ALWAYS_INLINE __attribute__((__always_inline__)) ZPL_INLINE - #elif ZPL_MSVC_VERSION_CHECK(12,0,0) - # define ZPL_ALWAYS_INLINE __forceinline - #elif defined(__cplusplus) && \ - ( \ - ZPL_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - ZPL_TI_CL430_VERSION_CHECK(4,3,0) || \ - ZPL_TI_CL2000_VERSION_CHECK(6,4,0) || \ - ZPL_TI_CL6X_VERSION_CHECK(6,1,0) || \ - ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ - ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) \ - ) - # define ZPL_ALWAYS_INLINE _Pragma("FUNC_ALWAYS_INLINE;") - #elif ZPL_IAR_VERSION_CHECK(8,0,0) - # define ZPL_ALWAYS_INLINE _Pragma("inline=forced") - #else - # define ZPL_ALWAYS_INLINE ZPL_INLINE - #endif - - #undef ZPL_ALWAYS_INLINE - #define ZPL_ALWAYS_INLINE ZPL_INLINE - - #if defined(ZPL_NEVER_INLINE) - # undef ZPL_NEVER_INLINE - #endif - #if \ - ZPL_HAS_ATTRIBUTE(noinline) || \ - ZPL_GCC_VERSION_CHECK(4,0,0) || \ - ZPL_INTEL_VERSION_CHECK(13,0,0) || \ - ZPL_SUNPRO_VERSION_CHECK(5,11,0) || \ - ZPL_ARM_VERSION_CHECK(4,1,0) || \ - ZPL_IBM_VERSION_CHECK(10,1,0) || \ - ZPL_TI_VERSION_CHECK(15,12,0) || \ - (ZPL_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (ZPL_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (ZPL_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL430_VERSION_CHECK(4,3,0) || \ - (ZPL_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL6X_VERSION_CHECK(7,5,0) || \ - ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ - ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) - # define ZPL_NEVER_INLINE __attribute__((__noinline__)) - #elif ZPL_MSVC_VERSION_CHECK(13,10,0) - # define ZPL_NEVER_INLINE __declspec(noinline) - #elif ZPL_PGI_VERSION_CHECK(10,2,0) - # define ZPL_NEVER_INLINE _Pragma("noinline") - #elif ZPL_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus) - # define ZPL_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;") - #elif ZPL_IAR_VERSION_CHECK(8,0,0) - # define ZPL_NEVER_INLINE _Pragma("inline=never") - #elif ZPL_COMPCERT_VERSION_CHECK(3,2,0) - # define ZPL_NEVER_INLINE __attribute((noinline)) - #elif ZPL_PELLES_VERSION_CHECK(9,0,0) - # define ZPL_NEVER_INLINE __declspec(noinline) - #else - # define ZPL_NEVER_INLINE - #endif - - #if defined(ZPL_PRIVATE) - # undef ZPL_PRIVATE - #endif - #if defined(ZPL_PUBLIC) - # undef ZPL_PUBLIC - #endif - #if defined(ZPL_IMPORT) - # undef ZPL_IMPORT - #endif - #if defined(_WIN32) || defined(__CYGWIN__) - # define ZPL_PRIVATE - # define ZPL_PUBLIC __declspec(dllexport) - # define ZPL_IMPORT __declspec(dllimport) - #else - # if \ - ZPL_HAS_ATTRIBUTE(visibility) || \ - ZPL_GCC_VERSION_CHECK(3,3,0) || \ - ZPL_SUNPRO_VERSION_CHECK(5,11,0) || \ - ZPL_INTEL_VERSION_CHECK(13,0,0) || \ - ZPL_ARM_VERSION_CHECK(4,1,0) || \ - ZPL_IBM_VERSION_CHECK(13,1,0) || \ - ( \ - defined(__TI_EABI__) && \ - ( \ - (ZPL_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - ZPL_TI_CL6X_VERSION_CHECK(7,5,0) \ - ) \ - ) - # define ZPL_PRIVATE __attribute__((__visibility__("hidden"))) - # define ZPL_PUBLIC __attribute__((__visibility__("default"))) - # else - # define ZPL_PRIVATE - # define ZPL_PUBLIC - # endif - # define ZPL_IMPORT extern - #endif - - #if defined(ZPL_NO_THROW) - # undef ZPL_NO_THROW - #endif - #if \ - ZPL_HAS_ATTRIBUTE(nothrow) || \ - ZPL_GCC_VERSION_CHECK(3,3,0) || \ - ZPL_INTEL_VERSION_CHECK(13,0,0) - # define ZPL_NO_THROW __attribute__((__nothrow__)) - #elif \ - ZPL_MSVC_VERSION_CHECK(13,1,0) || \ - ZPL_ARM_VERSION_CHECK(4,1,0) - # define ZPL_NO_THROW __declspec(nothrow) - #else - # define ZPL_NO_THROW - #endif - - #if defined(ZPL_FALL_THROUGH) - # undef ZPL_FALL_THROUGH - #endif - #if ZPL_GNUC_HAS_ATTRIBUTE(fallthrough,7,0,0) && !defined(ZPL_PGI_VERSION) - # define ZPL_FALL_THROUGH __attribute__((__fallthrough__)) - #elif ZPL_HAS_CPP_ATTRIBUTE_NS(clang,fallthrough) - # define ZPL_FALL_THROUGH ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[clang::fallthrough]]) - #elif ZPL_HAS_CPP_ATTRIBUTE(fallthrough) - # define ZPL_FALL_THROUGH ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[fallthrough]]) - #elif defined(__fallthrough) /* SAL */ - # define ZPL_FALL_THROUGH __fallthrough - #else - # define ZPL_FALL_THROUGH - #endif - - #if defined(ZPL_RETURNS_NON_NULL) - # undef ZPL_RETURNS_NON_NULL - #endif - #if \ - ZPL_HAS_ATTRIBUTE(returns_nonnull) || \ - ZPL_GCC_VERSION_CHECK(4,9,0) - # define ZPL_RETURNS_NON_NULL __attribute__((__returns_nonnull__)) - #elif defined(_Ret_notnull_) /* SAL */ - # define ZPL_RETURNS_NON_NULL _Ret_notnull_ - #else - # define ZPL_RETURNS_NON_NULL - #endif - - #if defined(ZPL_ARRAY_PARAM) - # undef ZPL_ARRAY_PARAM - #endif - #if \ - defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ - !defined(__STDC_NO_VLA__) && \ - !defined(__cplusplus) && \ - !defined(ZPL_PGI_VERSION) && \ - !defined(ZPL_TINYC_VERSION) - # define ZPL_ARRAY_PARAM(name) (name) - #else - # define ZPL_ARRAY_PARAM(name) - #endif - - #if defined(ZPL_IS_CONSTANT) - # undef ZPL_IS_CONSTANT - #endif - #if defined(ZPL_REQUIRE_CONSTEXPR) - # undef ZPL_REQUIRE_CONSTEXPR - #endif - /* ZPL_IS_CONSTEXPR_ is for - ZPL INTERNAL USE ONLY. API subject to change without notice. */ - #if defined(ZPL_IS_CONSTEXPR_) - # undef ZPL_IS_CONSTEXPR_ - #endif - #if \ - ZPL_HAS_BUILTIN(__builtin_constant_p) || \ - ZPL_GCC_VERSION_CHECK(3,4,0) || \ - ZPL_INTEL_VERSION_CHECK(13,0,0) || \ - ZPL_TINYC_VERSION_CHECK(0,9,19) || \ - ZPL_ARM_VERSION_CHECK(4,1,0) || \ - ZPL_IBM_VERSION_CHECK(13,1,0) || \ - ZPL_TI_CL6X_VERSION_CHECK(6,1,0) || \ - (ZPL_SUNPRO_VERSION_CHECK(5,10,0) && !defined(__cplusplus)) || \ - ZPL_CRAY_VERSION_CHECK(8,1,0) - # define ZPL_IS_CONSTANT(expr) __builtin_constant_p(expr) - #endif - #if !defined(__cplusplus) - # if \ - ZPL_HAS_BUILTIN(__builtin_types_compatible_p) || \ - ZPL_GCC_VERSION_CHECK(3,4,0) || \ - ZPL_INTEL_VERSION_CHECK(13,0,0) || \ - ZPL_IBM_VERSION_CHECK(13,1,0) || \ - ZPL_CRAY_VERSION_CHECK(8,1,0) || \ - ZPL_ARM_VERSION_CHECK(5,4,0) || \ - ZPL_TINYC_VERSION_CHECK(0,9,24) - # if defined(__INTPTR_TYPE__) - # define ZPL_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0)), int*) - # else - # include - # define ZPL_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((intptr_t) ((expr) * 0)) : (int*) 0)), int*) - # endif - # elif \ - ( \ - defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && \ - !defined(ZPL_SUNPRO_VERSION) && \ - !defined(ZPL_PGI_VERSION) && \ - !defined(ZPL_IAR_VERSION)) || \ - ZPL_HAS_EXTENSION(c_generic_selections) || \ - ZPL_GCC_VERSION_CHECK(4,9,0) || \ - ZPL_INTEL_VERSION_CHECK(17,0,0) || \ - ZPL_IBM_VERSION_CHECK(12,1,0) || \ - ZPL_ARM_VERSION_CHECK(5,3,0) - # if defined(__INTPTR_TYPE__) - # define ZPL_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0), int*: 1, void*: 0) - # else - # include - # define ZPL_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((intptr_t) * 0) : (int*) 0), int*: 1, void*: 0) - # endif - # elif \ - defined(ZPL_GCC_VERSION) || \ - defined(ZPL_INTEL_VERSION) || \ - defined(ZPL_TINYC_VERSION) || \ - defined(ZPL_TI_ARMCL_VERSION) || \ - ZPL_TI_CL430_VERSION_CHECK(18,12,0) || \ - defined(ZPL_TI_CL2000_VERSION) || \ - defined(ZPL_TI_CL6X_VERSION) || \ - defined(ZPL_TI_CL7X_VERSION) || \ - defined(ZPL_TI_CLPRU_VERSION) || \ - defined(__clang__) - # define ZPL_IS_CONSTEXPR_(expr) ( \ - sizeof(void) != \ - sizeof(*( \ - 1 ? \ - ((void*) ((expr) * 0L) ) : \ - ((struct { char v[sizeof(void) * 2]; } *) 1) \ - ) \ - ) \ - ) - # endif - #endif - #if defined(ZPL_IS_CONSTEXPR_) - # if !defined(ZPL_IS_CONSTANT) - # define ZPL_IS_CONSTANT(expr) ZPL_IS_CONSTEXPR_(expr) - # endif - # define ZPL_REQUIRE_CONSTEXPR(expr) (ZPL_IS_CONSTEXPR_(expr) ? (expr) : (-1)) - #else - # if !defined(ZPL_IS_CONSTANT) - # define ZPL_IS_CONSTANT(expr) (0) - # endif - # define ZPL_REQUIRE_CONSTEXPR(expr) (expr) - #endif - - #if defined(ZPL_BEGIN_C_DECLS) - # undef ZPL_BEGIN_C_DECLS - #endif - #if defined(ZPL_END_C_DECLS) - # undef ZPL_END_C_DECLS - #endif - #if defined(ZPL_C_DECL) - # undef ZPL_C_DECL - #endif - #if defined(__cplusplus) - # define ZPL_BEGIN_C_DECLS extern "C" { - # define ZPL_END_C_DECLS } - # define ZPL_C_DECL extern "C" - #else - # define ZPL_BEGIN_C_DECLS - # define ZPL_END_C_DECLS - # define ZPL_C_DECL - #endif - - #if defined(ZPL_STATIC_ASSERT) - # undef ZPL_STATIC_ASSERT - #endif - #if \ - !defined(__cplusplus) && ( \ - (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || \ - ZPL_HAS_FEATURE(c_static_assert) || \ - ZPL_GCC_VERSION_CHECK(6,0,0) || \ - ZPL_INTEL_VERSION_CHECK(13,0,0) || \ - defined(_Static_assert) \ - ) - # define ZPL_STATIC_ASSERT(expr, message) _Static_assert(expr, message) - #elif \ - (defined(__cplusplus) && (__cplusplus >= 201103L)) || \ - ZPL_MSVC_VERSION_CHECK(16,0,0) - # define ZPL_STATIC_ASSERT(expr, message) ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(static_assert(expr, message)) - #else - # define ZPL_STATIC_ASSERT3(cond, msg) typedef char static_assertion_##msg[(!!(cond)) * 2 - 1] - # define ZPL_STATIC_ASSERT2(cond, line) ZPL_STATIC_ASSERT3(cond, static_assertion_at_line_##line) - # define ZPL_STATIC_ASSERT1(cond, line) ZPL_STATIC_ASSERT2(cond, line) - # define ZPL_STATIC_ASSERT(cond, unused) ZPL_STATIC_ASSERT1(cond, __LINE__) - #endif - - #if defined(ZPL_NULL) - # undef ZPL_NULL - #endif - #if defined(__cplusplus) - # if __cplusplus >= 201103L - # define ZPL_NULL ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(nullptr) - # elif defined(NULL) - # define ZPL_NULL NULL - # else - # define ZPL_NULL ZPL_STATIC_CAST(void*, 0) - # endif - #elif defined(NULL) - # define ZPL_NULL NULL - #else - # define ZPL_NULL ((void*) 0) - #endif - - #if defined(ZPL_MESSAGE) - # undef ZPL_MESSAGE - #endif - #if ZPL_HAS_WARNING("-Wunknown-pragmas") - # define ZPL_MESSAGE(msg) \ - ZPL_DIAGNOSTIC_PUSH \ - ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ - ZPL_PRAGMA(message msg) \ - ZPL_DIAGNOSTIC_POP - #elif \ - ZPL_GCC_VERSION_CHECK(4,4,0) || \ - ZPL_INTEL_VERSION_CHECK(13,0,0) - # define ZPL_MESSAGE(msg) ZPL_PRAGMA(message msg) - #elif ZPL_CRAY_VERSION_CHECK(5,0,0) - # define ZPL_MESSAGE(msg) ZPL_PRAGMA(_CRI message msg) - #elif ZPL_IAR_VERSION_CHECK(8,0,0) - # define ZPL_MESSAGE(msg) ZPL_PRAGMA(message(msg)) - #elif ZPL_PELLES_VERSION_CHECK(2,0,0) - # define ZPL_MESSAGE(msg) ZPL_PRAGMA(message(msg)) - #else - # define ZPL_MESSAGE(msg) - #endif - - #if defined(ZPL_WARNING) - # undef ZPL_WARNING - #endif - #if ZPL_HAS_WARNING("-Wunknown-pragmas") - # define ZPL_WARNING(msg) \ - ZPL_DIAGNOSTIC_PUSH \ - ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ - ZPL_PRAGMA(clang warning msg) \ - ZPL_DIAGNOSTIC_POP - #elif \ - ZPL_GCC_VERSION_CHECK(4,8,0) || \ - ZPL_PGI_VERSION_CHECK(18,4,0) || \ - ZPL_INTEL_VERSION_CHECK(13,0,0) - # define ZPL_WARNING(msg) ZPL_PRAGMA(GCC warning msg) - #elif ZPL_MSVC_VERSION_CHECK(15,0,0) - # define ZPL_WARNING(msg) ZPL_PRAGMA(message(msg)) - #else - # define ZPL_WARNING(msg) ZPL_MESSAGE(msg) - #endif - - #if defined(ZPL_REQUIRE) - # undef ZPL_REQUIRE - #endif - #if defined(ZPL_REQUIRE_MSG) - # undef ZPL_REQUIRE_MSG - #endif - #if ZPL_HAS_ATTRIBUTE(diagnose_if) - # if ZPL_HAS_WARNING("-Wgcc-compat") - # define ZPL_REQUIRE(expr) \ - ZPL_DIAGNOSTIC_PUSH \ - _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ - __attribute__((diagnose_if(!(expr), #expr, "error"))) \ - ZPL_DIAGNOSTIC_POP - # define ZPL_REQUIRE_MSG(expr,msg) \ - ZPL_DIAGNOSTIC_PUSH \ - _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ - __attribute__((diagnose_if(!(expr), msg, "error"))) \ - ZPL_DIAGNOSTIC_POP - # else - # define ZPL_REQUIRE(expr) __attribute__((diagnose_if(!(expr), #expr, "error"))) - # define ZPL_REQUIRE_MSG(expr,msg) __attribute__((diagnose_if(!(expr), msg, "error"))) - # endif - #else - # define ZPL_REQUIRE(expr) - # define ZPL_REQUIRE_MSG(expr,msg) - #endif - - #if defined(ZPL_FLAGS) - # undef ZPL_FLAGS - #endif - #if ZPL_HAS_ATTRIBUTE(flag_enum) - # define ZPL_FLAGS __attribute__((__flag_enum__)) - #endif - - #if defined(ZPL_FLAGS_CAST) - # undef ZPL_FLAGS_CAST - #endif - #if ZPL_INTEL_VERSION_CHECK(19,0,0) - # define ZPL_FLAGS_CAST(T, expr) (__extension__ ({ \ - ZPL_DIAGNOSTIC_PUSH \ - _Pragma("warning(disable:188)") \ - ((T) (expr)); \ - ZPL_DIAGNOSTIC_POP \ - })) - #else - # define ZPL_FLAGS_CAST(T, expr) ZPL_STATIC_CAST(T, expr) - #endif - - #if defined(ZPL_EMPTY_BASES) - # undef ZPL_EMPTY_BASES - #endif - #if ZPL_MSVC_VERSION_CHECK(19,0,23918) && !ZPL_MSVC_VERSION_CHECK(20,0,0) - # define ZPL_EMPTY_BASES __declspec(empty_bases) - #else - # define ZPL_EMPTY_BASES - #endif - - /* Remaining macros are deprecated. */ - - #if defined(ZPL_GCC_NOT_CLANG_VERSION_CHECK) - # undef ZPL_GCC_NOT_CLANG_VERSION_CHECK - #endif - #if defined(__clang__) - # define ZPL_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) (0) - #else - # define ZPL_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) ZPL_GCC_VERSION_CHECK(major,minor,patch) - #endif - - #if defined(ZPL_CLANG_HAS_ATTRIBUTE) - # undef ZPL_CLANG_HAS_ATTRIBUTE - #endif - #define ZPL_CLANG_HAS_ATTRIBUTE(attribute) ZPL_HAS_ATTRIBUTE(attribute) - - #if defined(ZPL_CLANG_HAS_CPP_ATTRIBUTE) - # undef ZPL_CLANG_HAS_CPP_ATTRIBUTE - #endif - #define ZPL_CLANG_HAS_CPP_ATTRIBUTE(attribute) ZPL_HAS_CPP_ATTRIBUTE(attribute) - - #if defined(ZPL_CLANG_HAS_BUILTIN) - # undef ZPL_CLANG_HAS_BUILTIN - #endif - #define ZPL_CLANG_HAS_BUILTIN(builtin) ZPL_HAS_BUILTIN(builtin) - - #if defined(ZPL_CLANG_HAS_FEATURE) - # undef ZPL_CLANG_HAS_FEATURE - #endif - #define ZPL_CLANG_HAS_FEATURE(feature) ZPL_HAS_FEATURE(feature) - - #if defined(ZPL_CLANG_HAS_EXTENSION) - # undef ZPL_CLANG_HAS_EXTENSION - #endif - #define ZPL_CLANG_HAS_EXTENSION(extension) ZPL_HAS_EXTENSION(extension) - - #if defined(ZPL_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE) - # undef ZPL_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE - #endif - #define ZPL_CLANG_HAS_DECLSPEC_ATTRIBUTE(attribute) ZPL_HAS_DECLSPEC_ATTRIBUTE(attribute) - - #if defined(ZPL_CLANG_HAS_WARNING) - # undef ZPL_CLANG_HAS_WARNING - #endif - #define ZPL_CLANG_HAS_WARNING(warning) ZPL_HAS_WARNING(warning) - - #endif /* !defined(ZPL_HEDLEY_VERSION) || (ZPL_HEDLEY_VERSION < X) */ +// file: zpl_hedley.h + +/* Hedley - https://nemequ.github.io/hedley + * Created by Evan Nemerson + * + * To the extent possible under law, the author(s) have dedicated all + * copyright and related and neighboring rights to this software to + * the public domain worldwide. This software is distributed without + * any warranty. + * + * For details, see . + * SPDX-License-Identifier: CC0-1.0 + */ + +#if !defined(ZPL_HEDLEY_VERSION) || (ZPL_HEDLEY_VERSION < 12) +#if defined(ZPL_HEDLEY_VERSION) +# undef ZPL_HEDLEY_VERSION +#endif +#define ZPL_HEDLEY_VERSION 12 + +#if defined(ZPL_STRINGIFY_EX) +# undef ZPL_STRINGIFY_EX +#endif +#define ZPL_STRINGIFY_EX(x) #x + +#if defined(ZPL_STRINGIFY) +# undef ZPL_STRINGIFY +#endif +#define ZPL_STRINGIFY(x) ZPL_STRINGIFY_EX(x) + +#if defined(ZPL_CONCAT_EX) +# undef ZPL_CONCAT_EX +#endif +#define ZPL_CONCAT_EX(a,b) a##b + +#if defined(ZPL_CONCAT) +# undef ZPL_CONCAT +#endif +#define ZPL_CONCAT(a,b) ZPL_CONCAT_EX(a,b) + +#if defined(ZPL_VERSION_ENCODE) +# undef ZPL_VERSION_ENCODE +#endif +#define ZPL_VERSION_ENCODE(major,minor,patch) (((major) * 1000000) + ((minor) * 1000) + (patch)) + +#if defined(ZPL_VERSION_DECODE_MAJOR) +# undef ZPL_VERSION_DECODE_MAJOR +#endif +#define ZPL_VERSION_DECODE_MAJOR(version) ((version) / 1000000) + +#if defined(ZPL_VERSION_DECODE_MINOR) +# undef ZPL_VERSION_DECODE_MINOR +#endif +#define ZPL_VERSION_DECODE_MINOR(version) (((version) % 1000000) / 1000) + +#if defined(ZPL_VERSION_DECODE_PATCH) +# undef ZPL_VERSION_DECODE_PATCH +#endif +#define ZPL_VERSION_DECODE_PATCH(version) ((version) % 1000) + +#if defined(ZPL_VERSION_CHECK) +# undef ZPL_VERSION_CHECK +#endif +#define ZPL_VERSION_CHECK(major,minor,patch) (ZPL_VERSION_ENCODE(major,minor,patch) <= ZPL_VERSION) + +#if defined(ZPL_GNUC_VERSION) +# undef ZPL_GNUC_VERSION +#endif +#if defined(__GNUC__) && defined(__GNUC_PATCHLEVEL__) +# define ZPL_GNUC_VERSION ZPL_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) +#elif defined(__GNUC__) +# define ZPL_GNUC_VERSION ZPL_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, 0) +#endif + +#if defined(ZPL_GNUC_VERSION_CHECK) +# undef ZPL_GNUC_VERSION_CHECK +#endif +#if defined(ZPL_GNUC_VERSION) +# define ZPL_GNUC_VERSION_CHECK(major,minor,patch) (ZPL_GNUC_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) +#else +# define ZPL_GNUC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(ZPL_MSVC_VERSION) +# undef ZPL_MSVC_VERSION +#endif +#if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140000000) +# define ZPL_MSVC_VERSION ZPL_VERSION_ENCODE(_MSC_FULL_VER / 10000000, (_MSC_FULL_VER % 10000000) / 100000, (_MSC_FULL_VER % 100000) / 100) +#elif defined(_MSC_FULL_VER) +# define ZPL_MSVC_VERSION ZPL_VERSION_ENCODE(_MSC_FULL_VER / 1000000, (_MSC_FULL_VER % 1000000) / 10000, (_MSC_FULL_VER % 10000) / 10) +#elif defined(_MSC_VER) +# define ZPL_MSVC_VERSION ZPL_VERSION_ENCODE(_MSC_VER / 100, _MSC_VER % 100, 0) +#endif + +#if defined(ZPL_MSVC_VERSION_CHECK) +# undef ZPL_MSVC_VERSION_CHECK +#endif +#if !defined(_MSC_VER) +# define ZPL_MSVC_VERSION_CHECK(major,minor,patch) (0) +#elif defined(_MSC_VER) && (_MSC_VER >= 1400) +# define ZPL_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch))) +#elif defined(_MSC_VER) && (_MSC_VER >= 1200) +# define ZPL_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 1000000) + (minor * 10000) + (patch))) +#else +# define ZPL_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_VER >= ((major * 100) + (minor))) +#endif + +#if defined(ZPL_INTEL_VERSION) +# undef ZPL_INTEL_VERSION +#endif +#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) +# define ZPL_INTEL_VERSION ZPL_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, __INTEL_COMPILER_UPDATE) +#elif defined(__INTEL_COMPILER) +# define ZPL_INTEL_VERSION ZPL_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0) +#endif + +#if defined(ZPL_INTEL_VERSION_CHECK) +# undef ZPL_INTEL_VERSION_CHECK +#endif +#if defined(ZPL_INTEL_VERSION) +# define ZPL_INTEL_VERSION_CHECK(major,minor,patch) (ZPL_INTEL_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) +#else +# define ZPL_INTEL_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(ZPL_PGI_VERSION) +# undef ZPL_PGI_VERSION +#endif +#if defined(__PGI) && defined(__PGIC__) && defined(__PGIC_MINOR__) && defined(__PGIC_PATCHLEVEL__) +# define ZPL_PGI_VERSION ZPL_VERSION_ENCODE(__PGIC__, __PGIC_MINOR__, __PGIC_PATCHLEVEL__) +#endif + +#if defined(ZPL_PGI_VERSION_CHECK) +# undef ZPL_PGI_VERSION_CHECK +#endif +#if defined(ZPL_PGI_VERSION) +# define ZPL_PGI_VERSION_CHECK(major,minor,patch) (ZPL_PGI_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) +#else +# define ZPL_PGI_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(ZPL_SUNPRO_VERSION) +# undef ZPL_SUNPRO_VERSION +#endif +#if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000) +# define ZPL_SUNPRO_VERSION ZPL_VERSION_ENCODE((((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), (__SUNPRO_C & 0xf) * 10) +#elif defined(__SUNPRO_C) +# define ZPL_SUNPRO_VERSION ZPL_VERSION_ENCODE((__SUNPRO_C >> 8) & 0xf, (__SUNPRO_C >> 4) & 0xf, (__SUNPRO_C) & 0xf) +#elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000) +# define ZPL_SUNPRO_VERSION ZPL_VERSION_ENCODE((((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), (__SUNPRO_CC & 0xf) * 10) +#elif defined(__SUNPRO_CC) +# define ZPL_SUNPRO_VERSION ZPL_VERSION_ENCODE((__SUNPRO_CC >> 8) & 0xf, (__SUNPRO_CC >> 4) & 0xf, (__SUNPRO_CC) & 0xf) +#endif + +#if defined(ZPL_SUNPRO_VERSION_CHECK) +# undef ZPL_SUNPRO_VERSION_CHECK +#endif +#if defined(ZPL_SUNPRO_VERSION) +# define ZPL_SUNPRO_VERSION_CHECK(major,minor,patch) (ZPL_SUNPRO_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) +#else +# define ZPL_SUNPRO_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(ZPL_EMSCRIPTEN_VERSION) +# undef ZPL_EMSCRIPTEN_VERSION +#endif +#if defined(__EMSCRIPTEN__) +# define ZPL_EMSCRIPTEN_VERSION ZPL_VERSION_ENCODE(__EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__) +#endif + +#if defined(ZPL_EMSCRIPTEN_VERSION_CHECK) +# undef ZPL_EMSCRIPTEN_VERSION_CHECK +#endif +#if defined(ZPL_EMSCRIPTEN_VERSION) +# define ZPL_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (ZPL_EMSCRIPTEN_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) +#else +# define ZPL_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(ZPL_ARM_VERSION) +# undef ZPL_ARM_VERSION +#endif +#if defined(__CC_ARM) && defined(__ARMCOMPILER_VERSION) +# define ZPL_ARM_VERSION ZPL_VERSION_ENCODE(__ARMCOMPILER_VERSION / 1000000, (__ARMCOMPILER_VERSION % 1000000) / 10000, (__ARMCOMPILER_VERSION % 10000) / 100) +#elif defined(__CC_ARM) && defined(__ARMCC_VERSION) +# define ZPL_ARM_VERSION ZPL_VERSION_ENCODE(__ARMCC_VERSION / 1000000, (__ARMCC_VERSION % 1000000) / 10000, (__ARMCC_VERSION % 10000) / 100) +#endif + +#if defined(ZPL_ARM_VERSION_CHECK) +# undef ZPL_ARM_VERSION_CHECK +#endif +#if defined(ZPL_ARM_VERSION) +# define ZPL_ARM_VERSION_CHECK(major,minor,patch) (ZPL_ARM_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) +#else +# define ZPL_ARM_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(ZPL_IBM_VERSION) +# undef ZPL_IBM_VERSION +#endif +#if defined(__ibmxl__) +# define ZPL_IBM_VERSION ZPL_VERSION_ENCODE(__ibmxl_version__, __ibmxl_release__, __ibmxl_modification__) +#elif defined(__xlC__) && defined(__xlC_ver__) +# define ZPL_IBM_VERSION ZPL_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, (__xlC_ver__ >> 8) & 0xff) +#elif defined(__xlC__) +# define ZPL_IBM_VERSION ZPL_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, 0) +#endif + +#if defined(ZPL_IBM_VERSION_CHECK) +# undef ZPL_IBM_VERSION_CHECK +#endif +#if defined(ZPL_IBM_VERSION) +# define ZPL_IBM_VERSION_CHECK(major,minor,patch) (ZPL_IBM_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) +#else +# define ZPL_IBM_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(ZPL_TI_VERSION) +# undef ZPL_TI_VERSION +#endif +#if \ +defined(__TI_COMPILER_VERSION__) && \ +( \ +defined(__TMS470__) || defined(__TI_ARM__) || \ +defined(__MSP430__) || \ +defined(__TMS320C2000__) \ +) +# if (__TI_COMPILER_VERSION__ >= 16000000) +# define ZPL_TI_VERSION ZPL_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +# endif +#endif + +#if defined(ZPL_TI_VERSION_CHECK) +# undef ZPL_TI_VERSION_CHECK +#endif +#if defined(ZPL_TI_VERSION) +# define ZPL_TI_VERSION_CHECK(major,minor,patch) (ZPL_TI_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) +#else +# define ZPL_TI_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(ZPL_TI_CL2000_VERSION) +# undef ZPL_TI_CL2000_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C2000__) +# define ZPL_TI_CL2000_VERSION ZPL_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(ZPL_TI_CL2000_VERSION_CHECK) +# undef ZPL_TI_CL2000_VERSION_CHECK +#endif +#if defined(ZPL_TI_CL2000_VERSION) +# define ZPL_TI_CL2000_VERSION_CHECK(major,minor,patch) (ZPL_TI_CL2000_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) +#else +# define ZPL_TI_CL2000_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(ZPL_TI_CL430_VERSION) +# undef ZPL_TI_CL430_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__MSP430__) +# define ZPL_TI_CL430_VERSION ZPL_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(ZPL_TI_CL430_VERSION_CHECK) +# undef ZPL_TI_CL430_VERSION_CHECK +#endif +#if defined(ZPL_TI_CL430_VERSION) +# define ZPL_TI_CL430_VERSION_CHECK(major,minor,patch) (ZPL_TI_CL430_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) +#else +# define ZPL_TI_CL430_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(ZPL_TI_ARMCL_VERSION) +# undef ZPL_TI_ARMCL_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && (defined(__TMS470__) || defined(__TI_ARM__)) +# define ZPL_TI_ARMCL_VERSION ZPL_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(ZPL_TI_ARMCL_VERSION_CHECK) +# undef ZPL_TI_ARMCL_VERSION_CHECK +#endif +#if defined(ZPL_TI_ARMCL_VERSION) +# define ZPL_TI_ARMCL_VERSION_CHECK(major,minor,patch) (ZPL_TI_ARMCL_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) +#else +# define ZPL_TI_ARMCL_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(ZPL_TI_CL6X_VERSION) +# undef ZPL_TI_CL6X_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C6X__) +# define ZPL_TI_CL6X_VERSION ZPL_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(ZPL_TI_CL6X_VERSION_CHECK) +# undef ZPL_TI_CL6X_VERSION_CHECK +#endif +#if defined(ZPL_TI_CL6X_VERSION) +# define ZPL_TI_CL6X_VERSION_CHECK(major,minor,patch) (ZPL_TI_CL6X_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) +#else +# define ZPL_TI_CL6X_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(ZPL_TI_CL7X_VERSION) +# undef ZPL_TI_CL7X_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__C7000__) +# define ZPL_TI_CL7X_VERSION ZPL_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(ZPL_TI_CL7X_VERSION_CHECK) +# undef ZPL_TI_CL7X_VERSION_CHECK +#endif +#if defined(ZPL_TI_CL7X_VERSION) +# define ZPL_TI_CL7X_VERSION_CHECK(major,minor,patch) (ZPL_TI_CL7X_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) +#else +# define ZPL_TI_CL7X_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(ZPL_TI_CLPRU_VERSION) +# undef ZPL_TI_CLPRU_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__PRU__) +# define ZPL_TI_CLPRU_VERSION ZPL_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(ZPL_TI_CLPRU_VERSION_CHECK) +# undef ZPL_TI_CLPRU_VERSION_CHECK +#endif +#if defined(ZPL_TI_CLPRU_VERSION) +# define ZPL_TI_CLPRU_VERSION_CHECK(major,minor,patch) (ZPL_TI_CLPRU_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) +#else +# define ZPL_TI_CLPRU_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(ZPL_CRAY_VERSION) +# undef ZPL_CRAY_VERSION +#endif +#if defined(_CRAYC) +# if defined(_RELEASE_PATCHLEVEL) +# define ZPL_CRAY_VERSION ZPL_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, _RELEASE_PATCHLEVEL) +# else +# define ZPL_CRAY_VERSION ZPL_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, 0) +# endif +#endif + +#if defined(ZPL_CRAY_VERSION_CHECK) +# undef ZPL_CRAY_VERSION_CHECK +#endif +#if defined(ZPL_CRAY_VERSION) +# define ZPL_CRAY_VERSION_CHECK(major,minor,patch) (ZPL_CRAY_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) +#else +# define ZPL_CRAY_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(ZPL_IAR_VERSION) +# undef ZPL_IAR_VERSION +#endif +#if defined(__IAR_SYSTEMS_ICC__) +# if __VER__ > 1000 +# define ZPL_IAR_VERSION ZPL_VERSION_ENCODE((__VER__ / 1000000), ((__VER__ / 1000) % 1000), (__VER__ % 1000)) +# else +# define ZPL_IAR_VERSION ZPL_VERSION_ENCODE(VER / 100, __VER__ % 100, 0) +# endif +#endif + +#if defined(ZPL_IAR_VERSION_CHECK) +# undef ZPL_IAR_VERSION_CHECK +#endif +#if defined(ZPL_IAR_VERSION) +# define ZPL_IAR_VERSION_CHECK(major,minor,patch) (ZPL_IAR_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) +#else +# define ZPL_IAR_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(ZPL_TINYC_VERSION) +# undef ZPL_TINYC_VERSION +#endif +#if defined(__TINYC__) +# define ZPL_TINYC_VERSION ZPL_VERSION_ENCODE(__TINYC__ / 1000, (__TINYC__ / 100) % 10, __TINYC__ % 100) +#endif + +#if defined(ZPL_TINYC_VERSION_CHECK) +# undef ZPL_TINYC_VERSION_CHECK +#endif +#if defined(ZPL_TINYC_VERSION) +# define ZPL_TINYC_VERSION_CHECK(major,minor,patch) (ZPL_TINYC_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) +#else +# define ZPL_TINYC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(ZPL_DMC_VERSION) +# undef ZPL_DMC_VERSION +#endif +#if defined(__DMC__) +# define ZPL_DMC_VERSION ZPL_VERSION_ENCODE(__DMC__ >> 8, (__DMC__ >> 4) & 0xf, __DMC__ & 0xf) +#endif + +#if defined(ZPL_DMC_VERSION_CHECK) +# undef ZPL_DMC_VERSION_CHECK +#endif +#if defined(ZPL_DMC_VERSION) +# define ZPL_DMC_VERSION_CHECK(major,minor,patch) (ZPL_DMC_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) +#else +# define ZPL_DMC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(ZPL_COMPCERT_VERSION) +# undef ZPL_COMPCERT_VERSION +#endif +#if defined(__COMPCERT_VERSION__) +# define ZPL_COMPCERT_VERSION ZPL_VERSION_ENCODE(__COMPCERT_VERSION__ / 10000, (__COMPCERT_VERSION__ / 100) % 100, __COMPCERT_VERSION__ % 100) +#endif + +#if defined(ZPL_COMPCERT_VERSION_CHECK) +# undef ZPL_COMPCERT_VERSION_CHECK +#endif +#if defined(ZPL_COMPCERT_VERSION) +# define ZPL_COMPCERT_VERSION_CHECK(major,minor,patch) (ZPL_COMPCERT_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) +#else +# define ZPL_COMPCERT_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(ZPL_PELLES_VERSION) +# undef ZPL_PELLES_VERSION +#endif +#if defined(__POCC__) +# define ZPL_PELLES_VERSION ZPL_VERSION_ENCODE(__POCC__ / 100, __POCC__ % 100, 0) +#endif + +#if defined(ZPL_PELLES_VERSION_CHECK) +# undef ZPL_PELLES_VERSION_CHECK +#endif +#if defined(ZPL_PELLES_VERSION) +# define ZPL_PELLES_VERSION_CHECK(major,minor,patch) (ZPL_PELLES_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) +#else +# define ZPL_PELLES_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(ZPL_GCC_VERSION) +# undef ZPL_GCC_VERSION +#endif +#if \ +defined(ZPL_GNUC_VERSION) && \ +!defined(__clang__) && \ +!defined(ZPL_INTEL_VERSION) && \ +!defined(ZPL_PGI_VERSION) && \ +!defined(ZPL_ARM_VERSION) && \ +!defined(ZPL_TI_VERSION) && \ +!defined(ZPL_TI_ARMCL_VERSION) && \ +!defined(ZPL_TI_CL430_VERSION) && \ +!defined(ZPL_TI_CL2000_VERSION) && \ +!defined(ZPL_TI_CL6X_VERSION) && \ +!defined(ZPL_TI_CL7X_VERSION) && \ +!defined(ZPL_TI_CLPRU_VERSION) && \ +!defined(__COMPCERT__) +# define ZPL_GCC_VERSION ZPL_GNUC_VERSION +#endif + +#if defined(ZPL_GCC_VERSION_CHECK) +# undef ZPL_GCC_VERSION_CHECK +#endif +#if defined(ZPL_GCC_VERSION) +# define ZPL_GCC_VERSION_CHECK(major,minor,patch) (ZPL_GCC_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch)) +#else +# define ZPL_GCC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(ZPL_HAS_ATTRIBUTE) +# undef ZPL_HAS_ATTRIBUTE +#endif +#if defined(__has_attribute) +# define ZPL_HAS_ATTRIBUTE(attribute) __has_attribute(attribute) +#else +# define ZPL_HAS_ATTRIBUTE(attribute) (0) +#endif + +#if defined(ZPL_GNUC_HAS_ATTRIBUTE) +# undef ZPL_GNUC_HAS_ATTRIBUTE +#endif +#if defined(__has_attribute) +# define ZPL_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) __has_attribute(attribute) +#else +# define ZPL_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) ZPL_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(ZPL_GCC_HAS_ATTRIBUTE) +# undef ZPL_GCC_HAS_ATTRIBUTE +#endif +#if defined(__has_attribute) +# define ZPL_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) __has_attribute(attribute) +#else +# define ZPL_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) ZPL_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(ZPL_HAS_CPP_ATTRIBUTE) +# undef ZPL_HAS_CPP_ATTRIBUTE +#endif +#if \ +defined(__has_cpp_attribute) && \ +defined(__cplusplus) && \ +(!defined(ZPL_SUNPRO_VERSION) || ZPL_SUNPRO_VERSION_CHECK(5,15,0)) +# define ZPL_HAS_CPP_ATTRIBUTE(attribute) __has_cpp_attribute(attribute) +#else +# define ZPL_HAS_CPP_ATTRIBUTE(attribute) (0) +#endif + +#if defined(ZPL_HAS_CPP_ATTRIBUTE_NS) +# undef ZPL_HAS_CPP_ATTRIBUTE_NS +#endif +#if !defined(__cplusplus) || !defined(__has_cpp_attribute) +# define ZPL_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) +#elif \ +!defined(ZPL_PGI_VERSION) && \ +!defined(ZPL_IAR_VERSION) && \ +(!defined(ZPL_SUNPRO_VERSION) || ZPL_SUNPRO_VERSION_CHECK(5,15,0)) && \ +(!defined(ZPL_MSVC_VERSION) || ZPL_MSVC_VERSION_CHECK(19,20,0)) +# define ZPL_HAS_CPP_ATTRIBUTE_NS(ns,attribute) ZPL_HAS_CPP_ATTRIBUTE(ns::attribute) +#else +# define ZPL_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) +#endif + +#if defined(ZPL_GNUC_HAS_CPP_ATTRIBUTE) +# undef ZPL_GNUC_HAS_CPP_ATTRIBUTE +#endif +#if defined(__has_cpp_attribute) && defined(__cplusplus) +# define ZPL_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) +#else +# define ZPL_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) ZPL_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(ZPL_GCC_HAS_CPP_ATTRIBUTE) +# undef ZPL_GCC_HAS_CPP_ATTRIBUTE +#endif +#if defined(__has_cpp_attribute) && defined(__cplusplus) +# define ZPL_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) +#else +# define ZPL_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) ZPL_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(ZPL_HAS_BUILTIN) +# undef ZPL_HAS_BUILTIN +#endif +#if defined(__has_builtin) +# define ZPL_HAS_BUILTIN(builtin) __has_builtin(builtin) +#else +# define ZPL_HAS_BUILTIN(builtin) (0) +#endif + +#if defined(ZPL_GNUC_HAS_BUILTIN) +# undef ZPL_GNUC_HAS_BUILTIN +#endif +#if defined(__has_builtin) +# define ZPL_GNUC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) +#else +# define ZPL_GNUC_HAS_BUILTIN(builtin,major,minor,patch) ZPL_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(ZPL_GCC_HAS_BUILTIN) +# undef ZPL_GCC_HAS_BUILTIN +#endif +#if defined(__has_builtin) +# define ZPL_GCC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) +#else +# define ZPL_GCC_HAS_BUILTIN(builtin,major,minor,patch) ZPL_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(ZPL_HAS_FEATURE) +# undef ZPL_HAS_FEATURE +#endif +#if defined(__has_feature) +# define ZPL_HAS_FEATURE(feature) __has_feature(feature) +#else +# define ZPL_HAS_FEATURE(feature) (0) +#endif + +#if defined(ZPL_GNUC_HAS_FEATURE) +# undef ZPL_GNUC_HAS_FEATURE +#endif +#if defined(__has_feature) +# define ZPL_GNUC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) +#else +# define ZPL_GNUC_HAS_FEATURE(feature,major,minor,patch) ZPL_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(ZPL_GCC_HAS_FEATURE) +# undef ZPL_GCC_HAS_FEATURE +#endif +#if defined(__has_feature) +# define ZPL_GCC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) +#else +# define ZPL_GCC_HAS_FEATURE(feature,major,minor,patch) ZPL_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(ZPL_HAS_EXTENSION) +# undef ZPL_HAS_EXTENSION +#endif +#if defined(__has_extension) +# define ZPL_HAS_EXTENSION(extension) __has_extension(extension) +#else +# define ZPL_HAS_EXTENSION(extension) (0) +#endif + +#if defined(ZPL_GNUC_HAS_EXTENSION) +# undef ZPL_GNUC_HAS_EXTENSION +#endif +#if defined(__has_extension) +# define ZPL_GNUC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) +#else +# define ZPL_GNUC_HAS_EXTENSION(extension,major,minor,patch) ZPL_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(ZPL_GCC_HAS_EXTENSION) +# undef ZPL_GCC_HAS_EXTENSION +#endif +#if defined(__has_extension) +# define ZPL_GCC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) +#else +# define ZPL_GCC_HAS_EXTENSION(extension,major,minor,patch) ZPL_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(ZPL_HAS_DECLSPEC_ATTRIBUTE) +# undef ZPL_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) +# define ZPL_HAS_DECLSPEC_ATTRIBUTE(attribute) __has_declspec_attribute(attribute) +#else +# define ZPL_HAS_DECLSPEC_ATTRIBUTE(attribute) (0) +#endif + +#if defined(ZPL_GNUC_HAS_DECLSPEC_ATTRIBUTE) +# undef ZPL_GNUC_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) +# define ZPL_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) +#else +# define ZPL_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) ZPL_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(ZPL_GCC_HAS_DECLSPEC_ATTRIBUTE) +# undef ZPL_GCC_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) +# define ZPL_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) +#else +# define ZPL_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) ZPL_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(ZPL_HAS_WARNING) +# undef ZPL_HAS_WARNING +#endif +#if defined(__has_warning) +# define ZPL_HAS_WARNING(warning) __has_warning(warning) +#else +# define ZPL_HAS_WARNING(warning) (0) +#endif + +#if defined(ZPL_GNUC_HAS_WARNING) +# undef ZPL_GNUC_HAS_WARNING +#endif +#if defined(__has_warning) +# define ZPL_GNUC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) +#else +# define ZPL_GNUC_HAS_WARNING(warning,major,minor,patch) ZPL_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(ZPL_GCC_HAS_WARNING) +# undef ZPL_GCC_HAS_WARNING +#endif +#if defined(__has_warning) +# define ZPL_GCC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) +#else +# define ZPL_GCC_HAS_WARNING(warning,major,minor,patch) ZPL_GCC_VERSION_CHECK(major,minor,patch) +#endif + +/* ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ is for + ZPL INTERNAL USE ONLY. API subject to change without notice. */ +#if defined(ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) +# undef ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ +#endif +#if defined(__cplusplus) +# if ZPL_HAS_WARNING("-Wc++98-compat") +# if ZPL_HAS_WARNING("-Wc++17-extensions") +# define ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ +ZPL_DIAGNOSTIC_PUSH \ +_Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ +_Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \ +xpr \ +ZPL_DIAGNOSTIC_POP +# else +# define ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ +ZPL_DIAGNOSTIC_PUSH \ +_Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ +xpr \ +ZPL_DIAGNOSTIC_POP +# endif +# endif +#endif +#if !defined(ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) +# define ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(x) x +#endif + +#if defined(ZPL_CONST_CAST) +# undef ZPL_CONST_CAST +#endif +#if defined(__cplusplus) +# define ZPL_CONST_CAST(T, expr) (const_cast(expr)) +#elif \ +ZPL_HAS_WARNING("-Wcast-qual") || \ +ZPL_GCC_VERSION_CHECK(4,6,0) || \ +ZPL_INTEL_VERSION_CHECK(13,0,0) +# define ZPL_CONST_CAST(T, expr) (__extension__ ({ \ +ZPL_DIAGNOSTIC_PUSH \ +ZPL_DIAGNOSTIC_DISABLE_CAST_QUAL \ +((T) (expr)); \ +ZPL_DIAGNOSTIC_POP \ +})) +#else +# define ZPL_CONST_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(ZPL_REINTERPRET_CAST) +# undef ZPL_REINTERPRET_CAST +#endif +#if defined(__cplusplus) +# define ZPL_REINTERPRET_CAST(T, expr) (reinterpret_cast(expr)) +#else +# define ZPL_REINTERPRET_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(ZPL_STATIC_CAST) +# undef ZPL_STATIC_CAST +#endif +#if defined(__cplusplus) +# define ZPL_STATIC_CAST(T, expr) (static_cast(expr)) +#else +# define ZPL_STATIC_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(ZPL_CPP_CAST) +# undef ZPL_CPP_CAST +#endif +#if defined(__cplusplus) +# if ZPL_HAS_WARNING("-Wold-style-cast") +# define ZPL_CPP_CAST(T, expr) \ +ZPL_DIAGNOSTIC_PUSH \ +_Pragma("clang diagnostic ignored \"-Wold-style-cast\"") \ +((T) (expr)) \ +ZPL_DIAGNOSTIC_POP +# elif ZPL_IAR_VERSION_CHECK(8,3,0) +# define ZPL_CPP_CAST(T, expr) \ +ZPL_DIAGNOSTIC_PUSH \ +_Pragma("diag_suppress=Pe137") \ +ZPL_DIAGNOSTIC_POP \ +# else +# define ZPL_CPP_CAST(T, expr) ((T) (expr)) +# endif +#else +# define ZPL_CPP_CAST(T, expr) (expr) +#endif + +#if \ +(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ +defined(__clang__) || \ +ZPL_GCC_VERSION_CHECK(3,0,0) || \ +ZPL_INTEL_VERSION_CHECK(13,0,0) || \ +ZPL_IAR_VERSION_CHECK(8,0,0) || \ +ZPL_PGI_VERSION_CHECK(18,4,0) || \ +ZPL_ARM_VERSION_CHECK(4,1,0) || \ +ZPL_TI_VERSION_CHECK(15,12,0) || \ +ZPL_TI_ARMCL_VERSION_CHECK(4,7,0) || \ +ZPL_TI_CL430_VERSION_CHECK(2,0,1) || \ +ZPL_TI_CL2000_VERSION_CHECK(6,1,0) || \ +ZPL_TI_CL6X_VERSION_CHECK(7,0,0) || \ +ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ +ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) || \ +ZPL_CRAY_VERSION_CHECK(5,0,0) || \ +ZPL_TINYC_VERSION_CHECK(0,9,17) || \ +ZPL_SUNPRO_VERSION_CHECK(8,0,0) || \ +(ZPL_IBM_VERSION_CHECK(10,1,0) && defined(__C99_PRAGMA_OPERATOR)) +# define ZPL_PRAGMA(value) _Pragma(#value) +#elif ZPL_MSVC_VERSION_CHECK(15,0,0) +# define ZPL_PRAGMA(value) __pragma(value) +#else +# define ZPL_PRAGMA(value) +#endif + +#if defined(ZPL_DIAGNOSTIC_PUSH) +# undef ZPL_DIAGNOSTIC_PUSH +#endif +#if defined(ZPL_DIAGNOSTIC_POP) +# undef ZPL_DIAGNOSTIC_POP +#endif +#if defined(__clang__) +# define ZPL_DIAGNOSTIC_PUSH _Pragma("clang diagnostic push") +# define ZPL_DIAGNOSTIC_POP _Pragma("clang diagnostic pop") +#elif ZPL_INTEL_VERSION_CHECK(13,0,0) +# define ZPL_DIAGNOSTIC_PUSH _Pragma("warning(push)") +# define ZPL_DIAGNOSTIC_POP _Pragma("warning(pop)") +#elif ZPL_GCC_VERSION_CHECK(4,6,0) +# define ZPL_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push") +# define ZPL_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop") +#elif ZPL_MSVC_VERSION_CHECK(15,0,0) +# define ZPL_DIAGNOSTIC_PUSH __pragma(warning(push)) +# define ZPL_DIAGNOSTIC_POP __pragma(warning(pop)) +#elif ZPL_ARM_VERSION_CHECK(5,6,0) +# define ZPL_DIAGNOSTIC_PUSH _Pragma("push") +# define ZPL_DIAGNOSTIC_POP _Pragma("pop") +#elif \ +ZPL_TI_VERSION_CHECK(15,12,0) || \ +ZPL_TI_ARMCL_VERSION_CHECK(5,2,0) || \ +ZPL_TI_CL430_VERSION_CHECK(4,4,0) || \ +ZPL_TI_CL6X_VERSION_CHECK(8,1,0) || \ +ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ +ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) +# define ZPL_DIAGNOSTIC_PUSH _Pragma("diag_push") +# define ZPL_DIAGNOSTIC_POP _Pragma("diag_pop") +#elif ZPL_PELLES_VERSION_CHECK(2,90,0) +# define ZPL_DIAGNOSTIC_PUSH _Pragma("warning(push)") +# define ZPL_DIAGNOSTIC_POP _Pragma("warning(pop)") +#else +# define ZPL_DIAGNOSTIC_PUSH +# define ZPL_DIAGNOSTIC_POP +#endif + +#if defined(ZPL_DIAGNOSTIC_DISABLE_DEPRECATED) +# undef ZPL_DIAGNOSTIC_DISABLE_DEPRECATED +#endif +#if ZPL_HAS_WARNING("-Wdeprecated-declarations") +# define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") +#elif ZPL_INTEL_VERSION_CHECK(13,0,0) +# define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warning(disable:1478 1786)") +#elif ZPL_PGI_VERSION_CHECK(17,10,0) +# define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") +#elif ZPL_GCC_VERSION_CHECK(4,3,0) +# define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +#elif ZPL_MSVC_VERSION_CHECK(15,0,0) +# define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:4996)) +#elif \ +ZPL_TI_VERSION_CHECK(15,12,0) || \ +(ZPL_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_ARMCL_VERSION_CHECK(5,2,0) || \ +(ZPL_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL2000_VERSION_CHECK(6,4,0) || \ +(ZPL_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL430_VERSION_CHECK(4,3,0) || \ +(ZPL_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL6X_VERSION_CHECK(7,5,0) || \ +ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ +ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) +# define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1291,1718") +#elif ZPL_SUNPRO_VERSION_CHECK(5,13,0) && !defined(__cplusplus) +# define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)") +#elif ZPL_SUNPRO_VERSION_CHECK(5,13,0) && defined(__cplusplus) +# define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,symdeprecated,symdeprecated2)") +#elif ZPL_IAR_VERSION_CHECK(8,0,0) +# define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress=Pe1444,Pe1215") +#elif ZPL_PELLES_VERSION_CHECK(2,90,0) +# define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warn(disable:2241)") +#else +# define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED +#endif + +#if defined(ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS) +# undef ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS +#endif +#if ZPL_HAS_WARNING("-Wunknown-pragmas") +# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"") +#elif ZPL_INTEL_VERSION_CHECK(13,0,0) +# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("warning(disable:161)") +#elif ZPL_PGI_VERSION_CHECK(17,10,0) +# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 1675") +#elif ZPL_GCC_VERSION_CHECK(4,3,0) +# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("GCC diagnostic ignored \"-Wunknown-pragmas\"") +#elif ZPL_MSVC_VERSION_CHECK(15,0,0) +# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:4068)) +#elif \ +ZPL_TI_VERSION_CHECK(16,9,0) || \ +ZPL_TI_CL6X_VERSION_CHECK(8,0,0) || \ +ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ +ZPL_TI_CLPRU_VERSION_CHECK(2,3,0) +# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") +#elif ZPL_TI_CL6X_VERSION_CHECK(8,0,0) +# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") +#elif ZPL_IAR_VERSION_CHECK(8,0,0) +# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress=Pe161") +#else +# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS +#endif + +#if defined(ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES) +# undef ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES +#endif +#if ZPL_HAS_WARNING("-Wunknown-attributes") +# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("clang diagnostic ignored \"-Wunknown-attributes\"") +#elif ZPL_GCC_VERSION_CHECK(4,6,0) +# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +#elif ZPL_INTEL_VERSION_CHECK(17,0,0) +# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("warning(disable:1292)") +#elif ZPL_MSVC_VERSION_CHECK(19,0,0) +# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:5030)) +#elif ZPL_PGI_VERSION_CHECK(17,10,0) +# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097") +#elif ZPL_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus) +# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("error_messages(off,attrskipunsup)") +#elif \ +ZPL_TI_VERSION_CHECK(18,1,0) || \ +ZPL_TI_CL6X_VERSION_CHECK(8,3,0) || \ +ZPL_TI_CL7X_VERSION_CHECK(1,2,0) +# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1173") +#elif ZPL_IAR_VERSION_CHECK(8,0,0) +# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress=Pe1097") +#else +# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES +#endif + +#if defined(ZPL_DIAGNOSTIC_DISABLE_CAST_QUAL) +# undef ZPL_DIAGNOSTIC_DISABLE_CAST_QUAL +#endif +#if ZPL_HAS_WARNING("-Wcast-qual") +# define ZPL_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("clang diagnostic ignored \"-Wcast-qual\"") +#elif ZPL_INTEL_VERSION_CHECK(13,0,0) +# define ZPL_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("warning(disable:2203 2331)") +#elif ZPL_GCC_VERSION_CHECK(3,0,0) +# define ZPL_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") +#else +# define ZPL_DIAGNOSTIC_DISABLE_CAST_QUAL +#endif + +#if defined(ZPL_DEPRECATED) +# undef ZPL_DEPRECATED +#endif +#if defined(ZPL_DEPRECATED_FOR) +# undef ZPL_DEPRECATED_FOR +#endif +#if defined(__cplusplus) && (__cplusplus >= 201402L) +# define ZPL_DEPRECATED(since) ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since)]]) +# define ZPL_DEPRECATED_FOR(since, replacement) ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since "; use " #replacement)]]) +#elif \ +ZPL_HAS_EXTENSION(attribute_deprecated_with_message) || \ +ZPL_GCC_VERSION_CHECK(4,5,0) || \ +ZPL_INTEL_VERSION_CHECK(13,0,0) || \ +ZPL_ARM_VERSION_CHECK(5,6,0) || \ +ZPL_SUNPRO_VERSION_CHECK(5,13,0) || \ +ZPL_PGI_VERSION_CHECK(17,10,0) || \ +ZPL_TI_VERSION_CHECK(18,1,0) || \ +ZPL_TI_ARMCL_VERSION_CHECK(18,1,0) || \ +ZPL_TI_CL6X_VERSION_CHECK(8,3,0) || \ +ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ +ZPL_TI_CLPRU_VERSION_CHECK(2,3,0) +# define ZPL_DEPRECATED(since) __attribute__((__deprecated__("Since " #since))) +# define ZPL_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__("Since " #since "; use " #replacement))) +#elif \ +ZPL_HAS_ATTRIBUTE(deprecated) || \ +ZPL_GCC_VERSION_CHECK(3,1,0) || \ +ZPL_ARM_VERSION_CHECK(4,1,0) || \ +ZPL_TI_VERSION_CHECK(15,12,0) || \ +(ZPL_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_ARMCL_VERSION_CHECK(5,2,0) || \ +(ZPL_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL2000_VERSION_CHECK(6,4,0) || \ +(ZPL_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL430_VERSION_CHECK(4,3,0) || \ +(ZPL_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL6X_VERSION_CHECK(7,5,0) || \ +ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ +ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) +# define ZPL_DEPRECATED(since) __attribute__((__deprecated__)) +# define ZPL_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__)) +#elif ZPL_MSVC_VERSION_CHECK(14,0,0) +# define ZPL_DEPRECATED(since) __declspec(deprecated("Since " # since)) +# define ZPL_DEPRECATED_FOR(since, replacement) __declspec(deprecated("Since " #since "; use " #replacement)) +#elif \ +ZPL_MSVC_VERSION_CHECK(13,10,0) || \ +ZPL_PELLES_VERSION_CHECK(6,50,0) +# define ZPL_DEPRECATED(since) __declspec(deprecated) +# define ZPL_DEPRECATED_FOR(since, replacement) __declspec(deprecated) +#elif ZPL_IAR_VERSION_CHECK(8,0,0) +# define ZPL_DEPRECATED(since) _Pragma("deprecated") +# define ZPL_DEPRECATED_FOR(since, replacement) _Pragma("deprecated") +#else +# define ZPL_DEPRECATED(since) +# define ZPL_DEPRECATED_FOR(since, replacement) +#endif + +#if defined(ZPL_UNAVAILABLE) +# undef ZPL_UNAVAILABLE +#endif +#if \ +ZPL_HAS_ATTRIBUTE(warning) || \ +ZPL_GCC_VERSION_CHECK(4,3,0) || \ +ZPL_INTEL_VERSION_CHECK(13,0,0) +# define ZPL_UNAVAILABLE(available_since) __attribute__((__warning__("Not available until " #available_since))) +#else +# define ZPL_UNAVAILABLE(available_since) +#endif + +#if defined(ZPL_WARN_UNUSED_RESULT) +# undef ZPL_WARN_UNUSED_RESULT +#endif +#if defined(ZPL_WARN_UNUSED_RESULT_MSG) +# undef ZPL_WARN_UNUSED_RESULT_MSG +#endif +#if (ZPL_HAS_CPP_ATTRIBUTE(nodiscard) >= 201907L) +# define ZPL_WARN_UNUSED_RESULT ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) +# define ZPL_WARN_UNUSED_RESULT_MSG(msg) ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard(msg)]]) +#elif ZPL_HAS_CPP_ATTRIBUTE(nodiscard) +# define ZPL_WARN_UNUSED_RESULT ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) +# define ZPL_WARN_UNUSED_RESULT_MSG(msg) ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) +#elif \ +ZPL_HAS_ATTRIBUTE(warn_unused_result) || \ +ZPL_GCC_VERSION_CHECK(3,4,0) || \ +ZPL_INTEL_VERSION_CHECK(13,0,0) || \ +ZPL_TI_VERSION_CHECK(15,12,0) || \ +(ZPL_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_ARMCL_VERSION_CHECK(5,2,0) || \ +(ZPL_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL2000_VERSION_CHECK(6,4,0) || \ +(ZPL_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL430_VERSION_CHECK(4,3,0) || \ +(ZPL_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL6X_VERSION_CHECK(7,5,0) || \ +ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ +ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) || \ +(ZPL_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ +ZPL_PGI_VERSION_CHECK(17,10,0) +# define ZPL_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__)) +# define ZPL_WARN_UNUSED_RESULT_MSG(msg) __attribute__((__warn_unused_result__)) +#elif defined(_Check_return_) /* SAL */ +# define ZPL_WARN_UNUSED_RESULT _Check_return_ +# define ZPL_WARN_UNUSED_RESULT_MSG(msg) _Check_return_ +#else +# define ZPL_WARN_UNUSED_RESULT +# define ZPL_WARN_UNUSED_RESULT_MSG(msg) +#endif + +#if defined(ZPL_SENTINEL) +# undef ZPL_SENTINEL +#endif +#if \ +ZPL_HAS_ATTRIBUTE(sentinel) || \ +ZPL_GCC_VERSION_CHECK(4,0,0) || \ +ZPL_INTEL_VERSION_CHECK(13,0,0) || \ +ZPL_ARM_VERSION_CHECK(5,4,0) +# define ZPL_SENTINEL(position) __attribute__((__sentinel__(position))) +#else +# define ZPL_SENTINEL(position) +#endif + +#if defined(ZPL_NO_RETURN) +# undef ZPL_NO_RETURN +#endif +#if ZPL_IAR_VERSION_CHECK(8,0,0) +# define ZPL_NO_RETURN __noreturn +#elif ZPL_INTEL_VERSION_CHECK(13,0,0) +# define ZPL_NO_RETURN __attribute__((__noreturn__)) +#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L +# define ZPL_NO_RETURN _Noreturn +#elif defined(__cplusplus) && (__cplusplus >= 201103L) +# define ZPL_NO_RETURN ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[noreturn]]) +#elif \ +ZPL_HAS_ATTRIBUTE(noreturn) || \ +ZPL_GCC_VERSION_CHECK(3,2,0) || \ +ZPL_SUNPRO_VERSION_CHECK(5,11,0) || \ +ZPL_ARM_VERSION_CHECK(4,1,0) || \ +ZPL_IBM_VERSION_CHECK(10,1,0) || \ +ZPL_TI_VERSION_CHECK(15,12,0) || \ +(ZPL_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_ARMCL_VERSION_CHECK(5,2,0) || \ +(ZPL_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL2000_VERSION_CHECK(6,4,0) || \ +(ZPL_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL430_VERSION_CHECK(4,3,0) || \ +(ZPL_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL6X_VERSION_CHECK(7,5,0) || \ +ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ +ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) +# define ZPL_NO_RETURN __attribute__((__noreturn__)) +#elif ZPL_SUNPRO_VERSION_CHECK(5,10,0) +# define ZPL_NO_RETURN _Pragma("does_not_return") +#elif ZPL_MSVC_VERSION_CHECK(13,10,0) +# define ZPL_NO_RETURN __declspec(noreturn) +#elif ZPL_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus) +# define ZPL_NO_RETURN _Pragma("FUNC_NEVER_RETURNS;") +#elif ZPL_COMPCERT_VERSION_CHECK(3,2,0) +# define ZPL_NO_RETURN __attribute((noreturn)) +#elif ZPL_PELLES_VERSION_CHECK(9,0,0) +# define ZPL_NO_RETURN __declspec(noreturn) +#else +# define ZPL_NO_RETURN +#endif + +#if defined(ZPL_NO_ESCAPE) +# undef ZPL_NO_ESCAPE +#endif +#if ZPL_HAS_ATTRIBUTE(noescape) +# define ZPL_NO_ESCAPE __attribute__((__noescape__)) +#else +# define ZPL_NO_ESCAPE +#endif + +#if defined(ZPL_UNREACHABLE) +# undef ZPL_UNREACHABLE +#endif +#if defined(ZPL_UNREACHABLE_RETURN) +# undef ZPL_UNREACHABLE_RETURN +#endif +#if defined(ZPL_ASSUME) +# undef ZPL_ASSUME +#endif +#if \ +ZPL_MSVC_VERSION_CHECK(13,10,0) || \ +ZPL_INTEL_VERSION_CHECK(13,0,0) +# define ZPL_ASSUME(expr) __assume(expr) +#elif ZPL_HAS_BUILTIN(__builtin_assume) +# define ZPL_ASSUME(expr) __builtin_assume(expr) +#elif \ +ZPL_TI_CL2000_VERSION_CHECK(6,2,0) || \ +ZPL_TI_CL6X_VERSION_CHECK(4,0,0) +# if defined(__cplusplus) +# define ZPL_ASSUME(expr) std::_nassert(expr) +# else +# define ZPL_ASSUME(expr) _nassert(expr) +# endif +#endif +#if \ +(ZPL_HAS_BUILTIN(__builtin_unreachable) && (!defined(ZPL_ARM_VERSION))) || \ +ZPL_GCC_VERSION_CHECK(4,5,0) || \ +ZPL_PGI_VERSION_CHECK(18,10,0) || \ +ZPL_INTEL_VERSION_CHECK(13,0,0) || \ +ZPL_IBM_VERSION_CHECK(13,1,5) +# define ZPL_UNREACHABLE() __builtin_unreachable() +#elif defined(ZPL_ASSUME) +# define ZPL_UNREACHABLE() ZPL_ASSUME(0) +#endif +#if !defined(ZPL_ASSUME) +# if defined(ZPL_UNREACHABLE) +# define ZPL_ASSUME(expr) ZPL_STATIC_CAST(void, ((expr) ? 1 : (ZPL_UNREACHABLE(), 1))) +# else +# define ZPL_ASSUME(expr) ZPL_STATIC_CAST(void, expr) +# endif +#endif +#if defined(ZPL_UNREACHABLE) +# if \ +ZPL_TI_CL2000_VERSION_CHECK(6,2,0) || \ +ZPL_TI_CL6X_VERSION_CHECK(4,0,0) +# define ZPL_UNREACHABLE_RETURN(value) return (ZPL_STATIC_CAST(void, ZPL_ASSUME(0)), (value)) +# else +# define ZPL_UNREACHABLE_RETURN(value) ZPL_UNREACHABLE() +# endif +#else +# define ZPL_UNREACHABLE_RETURN(value) return (value) +#endif +#if !defined(ZPL_UNREACHABLE) +# define ZPL_UNREACHABLE() ZPL_ASSUME(0) +#endif + +ZPL_DIAGNOSTIC_PUSH +#if ZPL_HAS_WARNING("-Wpedantic") +# pragma clang diagnostic ignored "-Wpedantic" +#endif +#if ZPL_HAS_WARNING("-Wc++98-compat-pedantic") && defined(__cplusplus) +# pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +#endif +#if ZPL_GCC_HAS_WARNING("-Wvariadic-macros",4,0,0) +# if defined(__clang__) +# pragma clang diagnostic ignored "-Wvariadic-macros" +# elif defined(ZPL_GCC_VERSION) +# pragma GCC diagnostic ignored "-Wvariadic-macros" +# endif +#endif +#if defined(ZPL_NON_NULL) +# undef ZPL_NON_NULL +#endif +#if \ +ZPL_HAS_ATTRIBUTE(nonnull) || \ +ZPL_GCC_VERSION_CHECK(3,3,0) || \ +ZPL_INTEL_VERSION_CHECK(13,0,0) || \ +ZPL_ARM_VERSION_CHECK(4,1,0) +# define ZPL_NON_NULL(...) __attribute__((__nonnull__(__VA_ARGS__))) +#else +# define ZPL_NON_NULL(...) +#endif +ZPL_DIAGNOSTIC_POP + +#if defined(ZPL_PRINTF_FORMAT) +# undef ZPL_PRINTF_FORMAT +#endif +#if defined(__MINGW32__) && ZPL_GCC_HAS_ATTRIBUTE(format,4,4,0) && !defined(__USE_MINGW_ANSI_STDIO) +# define ZPL_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(ms_printf, string_idx, first_to_check))) +#elif defined(__MINGW32__) && ZPL_GCC_HAS_ATTRIBUTE(format,4,4,0) && defined(__USE_MINGW_ANSI_STDIO) +# define ZPL_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(gnu_printf, string_idx, first_to_check))) +#elif \ +ZPL_HAS_ATTRIBUTE(format) || \ +ZPL_GCC_VERSION_CHECK(3,1,0) || \ +ZPL_INTEL_VERSION_CHECK(13,0,0) || \ +ZPL_ARM_VERSION_CHECK(5,6,0) || \ +ZPL_IBM_VERSION_CHECK(10,1,0) || \ +ZPL_TI_VERSION_CHECK(15,12,0) || \ +(ZPL_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_ARMCL_VERSION_CHECK(5,2,0) || \ +(ZPL_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL2000_VERSION_CHECK(6,4,0) || \ +(ZPL_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL430_VERSION_CHECK(4,3,0) || \ +(ZPL_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL6X_VERSION_CHECK(7,5,0) || \ +ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ +ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) +# define ZPL_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(__printf__, string_idx, first_to_check))) +#elif ZPL_PELLES_VERSION_CHECK(6,0,0) +# define ZPL_PRINTF_FORMAT(string_idx,first_to_check) __declspec(vaformat(printf,string_idx,first_to_check)) +#else +# define ZPL_PRINTF_FORMAT(string_idx,first_to_check) +#endif + +#if defined(ZPL_CONSTEXPR) +# undef ZPL_CONSTEXPR +#endif +#if defined(__cplusplus) +# if __cplusplus >= 201103L +# define ZPL_CONSTEXPR ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(constexpr) +# endif +#endif +#if !defined(ZPL_CONSTEXPR) +# define ZPL_CONSTEXPR +#endif + +#if defined(ZPL_PREDICT) +# undef ZPL_PREDICT +#endif +#if defined(ZPL_LIKELY) +# undef ZPL_LIKELY +#endif +#if defined(ZPL_UNLIKELY) +# undef ZPL_UNLIKELY +#endif +#if defined(ZPL_UNPREDICTABLE) +# undef ZPL_UNPREDICTABLE +#endif +#if ZPL_HAS_BUILTIN(__builtin_unpredictable) +# define ZPL_UNPREDICTABLE(expr) __builtin_unpredictable((expr)) +#endif +#if \ +ZPL_HAS_BUILTIN(__builtin_expect_with_probability) || \ +ZPL_GCC_VERSION_CHECK(9,0,0) +# define ZPL_PREDICT(expr, value, probability) __builtin_expect_with_probability( (expr), (value), (probability)) +# define ZPL_PREDICT_TRUE(expr, probability) __builtin_expect_with_probability(!!(expr), 1 , (probability)) +# define ZPL_PREDICT_FALSE(expr, probability) __builtin_expect_with_probability(!!(expr), 0 , (probability)) +# define ZPL_LIKELY(expr) __builtin_expect (!!(expr), 1 ) +# define ZPL_UNLIKELY(expr) __builtin_expect (!!(expr), 0 ) +#elif \ +ZPL_HAS_BUILTIN(__builtin_expect) || \ +ZPL_GCC_VERSION_CHECK(3,0,0) || \ +ZPL_INTEL_VERSION_CHECK(13,0,0) || \ +(ZPL_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ +ZPL_ARM_VERSION_CHECK(4,1,0) || \ +ZPL_IBM_VERSION_CHECK(10,1,0) || \ +ZPL_TI_VERSION_CHECK(15,12,0) || \ +ZPL_TI_ARMCL_VERSION_CHECK(4,7,0) || \ +ZPL_TI_CL430_VERSION_CHECK(3,1,0) || \ +ZPL_TI_CL2000_VERSION_CHECK(6,1,0) || \ +ZPL_TI_CL6X_VERSION_CHECK(6,1,0) || \ +ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ +ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) || \ +ZPL_TINYC_VERSION_CHECK(0,9,27) || \ +ZPL_CRAY_VERSION_CHECK(8,1,0) +# define ZPL_PREDICT(expr, expected, probability) \ +(((probability) >= 0.9) ? __builtin_expect((expr), (expected)) : (ZPL_STATIC_CAST(void, expected), (expr))) +# define ZPL_PREDICT_TRUE(expr, probability) \ +(__extension__ ({ \ +double zpl_probability_ = (probability); \ +((zpl_probability_ >= 0.9) ? __builtin_expect(!!(expr), 1) : ((zpl_probability_ <= 0.1) ? __builtin_expect(!!(expr), 0) : !!(expr))); \ +})) +# define ZPL_PREDICT_FALSE(expr, probability) \ +(__extension__ ({ \ +double zpl_probability_ = (probability); \ +((zpl_probability_ >= 0.9) ? __builtin_expect(!!(expr), 0) : ((zpl_probability_ <= 0.1) ? __builtin_expect(!!(expr), 1) : !!(expr))); \ +})) +# define ZPL_LIKELY(expr) __builtin_expect(!!(expr), 1) +# define ZPL_UNLIKELY(expr) __builtin_expect(!!(expr), 0) +#else +# define ZPL_PREDICT(expr, expected, probability) (ZPL_STATIC_CAST(void, expected), (expr)) +# define ZPL_PREDICT_TRUE(expr, probability) (!!(expr)) +# define ZPL_PREDICT_FALSE(expr, probability) (!!(expr)) +# define ZPL_LIKELY(expr) (!!(expr)) +# define ZPL_UNLIKELY(expr) (!!(expr)) +#endif +#if !defined(ZPL_UNPREDICTABLE) +# define ZPL_UNPREDICTABLE(expr) ZPL_PREDICT(expr, 1, 0.5) +#endif + +#if defined(ZPL_MALLOC) +# undef ZPL_MALLOC +#endif +#if \ +ZPL_HAS_ATTRIBUTE(malloc) || \ +ZPL_GCC_VERSION_CHECK(3,1,0) || \ +ZPL_INTEL_VERSION_CHECK(13,0,0) || \ +ZPL_SUNPRO_VERSION_CHECK(5,11,0) || \ +ZPL_ARM_VERSION_CHECK(4,1,0) || \ +ZPL_IBM_VERSION_CHECK(12,1,0) || \ +ZPL_TI_VERSION_CHECK(15,12,0) || \ +(ZPL_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_ARMCL_VERSION_CHECK(5,2,0) || \ +(ZPL_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL2000_VERSION_CHECK(6,4,0) || \ +(ZPL_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL430_VERSION_CHECK(4,3,0) || \ +(ZPL_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL6X_VERSION_CHECK(7,5,0) || \ +ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ +ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) +# define ZPL_MALLOC __attribute__((__malloc__)) +#elif ZPL_SUNPRO_VERSION_CHECK(5,10,0) +# define ZPL_MALLOC _Pragma("returns_new_memory") +#elif ZPL_MSVC_VERSION_CHECK(14, 0, 0) +# define ZPL_MALLOC __declspec(restrict) +#else +# define ZPL_MALLOC +#endif + +#if defined(ZPL_PURE) +# undef ZPL_PURE +#endif +#if \ +ZPL_HAS_ATTRIBUTE(pure) || \ +ZPL_GCC_VERSION_CHECK(2,96,0) || \ +ZPL_INTEL_VERSION_CHECK(13,0,0) || \ +ZPL_SUNPRO_VERSION_CHECK(5,11,0) || \ +ZPL_ARM_VERSION_CHECK(4,1,0) || \ +ZPL_IBM_VERSION_CHECK(10,1,0) || \ +ZPL_TI_VERSION_CHECK(15,12,0) || \ +(ZPL_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_ARMCL_VERSION_CHECK(5,2,0) || \ +(ZPL_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL2000_VERSION_CHECK(6,4,0) || \ +(ZPL_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL430_VERSION_CHECK(4,3,0) || \ +(ZPL_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL6X_VERSION_CHECK(7,5,0) || \ +ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ +ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) || \ +ZPL_PGI_VERSION_CHECK(17,10,0) +# define ZPL_PURE __attribute__((__pure__)) +#elif ZPL_SUNPRO_VERSION_CHECK(5,10,0) +# define ZPL_PURE _Pragma("does_not_write_global_data") +#elif defined(__cplusplus) && \ +( \ +ZPL_TI_CL430_VERSION_CHECK(2,0,1) || \ +ZPL_TI_CL6X_VERSION_CHECK(4,0,0) || \ +ZPL_TI_CL7X_VERSION_CHECK(1,2,0) \ +) +# define ZPL_PURE _Pragma("FUNC_IS_PURE;") +#else +# define ZPL_PURE +#endif + +#if defined(ZPL_CONST) +# undef ZPL_CONST +#endif +#if \ +ZPL_HAS_ATTRIBUTE(const) || \ +ZPL_GCC_VERSION_CHECK(2,5,0) || \ +ZPL_INTEL_VERSION_CHECK(13,0,0) || \ +ZPL_SUNPRO_VERSION_CHECK(5,11,0) || \ +ZPL_ARM_VERSION_CHECK(4,1,0) || \ +ZPL_IBM_VERSION_CHECK(10,1,0) || \ +ZPL_TI_VERSION_CHECK(15,12,0) || \ +(ZPL_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_ARMCL_VERSION_CHECK(5,2,0) || \ +(ZPL_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL2000_VERSION_CHECK(6,4,0) || \ +(ZPL_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL430_VERSION_CHECK(4,3,0) || \ +(ZPL_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL6X_VERSION_CHECK(7,5,0) || \ +ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ +ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) || \ +ZPL_PGI_VERSION_CHECK(17,10,0) +# define ZPL_CONST __attribute__((__const__)) +#elif \ +ZPL_SUNPRO_VERSION_CHECK(5,10,0) +# define ZPL_CONST _Pragma("no_side_effect") +#else +# define ZPL_CONST ZPL_PURE +#endif + +#if defined(ZPL_RESTRICT) +# undef ZPL_RESTRICT +#endif +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && !defined(__cplusplus) +# define ZPL_RESTRICT restrict +#elif \ +ZPL_GCC_VERSION_CHECK(3,1,0) || \ +ZPL_MSVC_VERSION_CHECK(14,0,0) || \ +ZPL_INTEL_VERSION_CHECK(13,0,0) || \ +ZPL_ARM_VERSION_CHECK(4,1,0) || \ +ZPL_IBM_VERSION_CHECK(10,1,0) || \ +ZPL_PGI_VERSION_CHECK(17,10,0) || \ +ZPL_TI_CL430_VERSION_CHECK(4,3,0) || \ +ZPL_TI_CL2000_VERSION_CHECK(6,2,4) || \ +ZPL_TI_CL6X_VERSION_CHECK(8,1,0) || \ +ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ +(ZPL_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)) || \ +ZPL_IAR_VERSION_CHECK(8,0,0) || \ +defined(__clang__) +# define ZPL_RESTRICT __restrict +#elif ZPL_SUNPRO_VERSION_CHECK(5,3,0) && !defined(__cplusplus) +# define ZPL_RESTRICT _Restrict +#else +# define ZPL_RESTRICT +#endif + +#if defined(ZPL_INLINE) +# undef ZPL_INLINE +#endif +#if \ +(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ +(defined(__cplusplus) && (__cplusplus >= 199711L)) +# define ZPL_INLINE inline +#elif \ +defined(ZPL_GCC_VERSION) || \ +ZPL_ARM_VERSION_CHECK(6,2,0) +# define ZPL_INLINE __inline__ +#elif \ +ZPL_MSVC_VERSION_CHECK(12,0,0) || \ +ZPL_ARM_VERSION_CHECK(4,1,0) || \ +ZPL_TI_ARMCL_VERSION_CHECK(5,1,0) || \ +ZPL_TI_CL430_VERSION_CHECK(3,1,0) || \ +ZPL_TI_CL2000_VERSION_CHECK(6,2,0) || \ +ZPL_TI_CL6X_VERSION_CHECK(8,0,0) || \ +ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ +ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) +# define ZPL_INLINE __inline +#else +# define ZPL_INLINE +#endif + +#if defined(ZPL_ALWAYS_INLINE) +# undef ZPL_ALWAYS_INLINE +#endif +#if \ +ZPL_HAS_ATTRIBUTE(always_inline) || \ +ZPL_GCC_VERSION_CHECK(4,0,0) || \ +ZPL_INTEL_VERSION_CHECK(13,0,0) || \ +ZPL_SUNPRO_VERSION_CHECK(5,11,0) || \ +ZPL_ARM_VERSION_CHECK(4,1,0) || \ +ZPL_IBM_VERSION_CHECK(10,1,0) || \ +ZPL_TI_VERSION_CHECK(15,12,0) || \ +(ZPL_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_ARMCL_VERSION_CHECK(5,2,0) || \ +(ZPL_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL2000_VERSION_CHECK(6,4,0) || \ +(ZPL_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL430_VERSION_CHECK(4,3,0) || \ +(ZPL_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL6X_VERSION_CHECK(7,5,0) || \ +ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ +ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) +# define ZPL_ALWAYS_INLINE __attribute__((__always_inline__)) ZPL_INLINE +#elif ZPL_MSVC_VERSION_CHECK(12,0,0) +# define ZPL_ALWAYS_INLINE __forceinline +#elif defined(__cplusplus) && \ +( \ +ZPL_TI_ARMCL_VERSION_CHECK(5,2,0) || \ +ZPL_TI_CL430_VERSION_CHECK(4,3,0) || \ +ZPL_TI_CL2000_VERSION_CHECK(6,4,0) || \ +ZPL_TI_CL6X_VERSION_CHECK(6,1,0) || \ +ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ +ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) \ +) +# define ZPL_ALWAYS_INLINE _Pragma("FUNC_ALWAYS_INLINE;") +#elif ZPL_IAR_VERSION_CHECK(8,0,0) +# define ZPL_ALWAYS_INLINE _Pragma("inline=forced") +#else +# define ZPL_ALWAYS_INLINE ZPL_INLINE +#endif + +#undef ZPL_ALWAYS_INLINE +#define ZPL_ALWAYS_INLINE ZPL_INLINE + +#if defined(ZPL_NEVER_INLINE) +# undef ZPL_NEVER_INLINE +#endif +#if \ +ZPL_HAS_ATTRIBUTE(noinline) || \ +ZPL_GCC_VERSION_CHECK(4,0,0) || \ +ZPL_INTEL_VERSION_CHECK(13,0,0) || \ +ZPL_SUNPRO_VERSION_CHECK(5,11,0) || \ +ZPL_ARM_VERSION_CHECK(4,1,0) || \ +ZPL_IBM_VERSION_CHECK(10,1,0) || \ +ZPL_TI_VERSION_CHECK(15,12,0) || \ +(ZPL_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_ARMCL_VERSION_CHECK(5,2,0) || \ +(ZPL_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL2000_VERSION_CHECK(6,4,0) || \ +(ZPL_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL430_VERSION_CHECK(4,3,0) || \ +(ZPL_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL6X_VERSION_CHECK(7,5,0) || \ +ZPL_TI_CL7X_VERSION_CHECK(1,2,0) || \ +ZPL_TI_CLPRU_VERSION_CHECK(2,1,0) +# define ZPL_NEVER_INLINE __attribute__((__noinline__)) +#elif ZPL_MSVC_VERSION_CHECK(13,10,0) +# define ZPL_NEVER_INLINE __declspec(noinline) +#elif ZPL_PGI_VERSION_CHECK(10,2,0) +# define ZPL_NEVER_INLINE _Pragma("noinline") +#elif ZPL_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus) +# define ZPL_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;") +#elif ZPL_IAR_VERSION_CHECK(8,0,0) +# define ZPL_NEVER_INLINE _Pragma("inline=never") +#elif ZPL_COMPCERT_VERSION_CHECK(3,2,0) +# define ZPL_NEVER_INLINE __attribute((noinline)) +#elif ZPL_PELLES_VERSION_CHECK(9,0,0) +# define ZPL_NEVER_INLINE __declspec(noinline) +#else +# define ZPL_NEVER_INLINE +#endif + +#if defined(ZPL_PRIVATE) +# undef ZPL_PRIVATE +#endif +#if defined(ZPL_PUBLIC) +# undef ZPL_PUBLIC +#endif +#if defined(ZPL_IMPORT) +# undef ZPL_IMPORT +#endif +#if defined(_WIN32) || defined(__CYGWIN__) +# define ZPL_PRIVATE +# define ZPL_PUBLIC __declspec(dllexport) +# define ZPL_IMPORT __declspec(dllimport) +#else +# if \ +ZPL_HAS_ATTRIBUTE(visibility) || \ +ZPL_GCC_VERSION_CHECK(3,3,0) || \ +ZPL_SUNPRO_VERSION_CHECK(5,11,0) || \ +ZPL_INTEL_VERSION_CHECK(13,0,0) || \ +ZPL_ARM_VERSION_CHECK(4,1,0) || \ +ZPL_IBM_VERSION_CHECK(13,1,0) || \ +( \ +defined(__TI_EABI__) && \ +( \ +(ZPL_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +ZPL_TI_CL6X_VERSION_CHECK(7,5,0) \ +) \ +) +# define ZPL_PRIVATE __attribute__((__visibility__("hidden"))) +# define ZPL_PUBLIC __attribute__((__visibility__("default"))) +# else +# define ZPL_PRIVATE +# define ZPL_PUBLIC +# endif +# define ZPL_IMPORT extern +#endif + +#if defined(ZPL_NO_THROW) +# undef ZPL_NO_THROW +#endif +#if \ +ZPL_HAS_ATTRIBUTE(nothrow) || \ +ZPL_GCC_VERSION_CHECK(3,3,0) || \ +ZPL_INTEL_VERSION_CHECK(13,0,0) +# define ZPL_NO_THROW __attribute__((__nothrow__)) +#elif \ +ZPL_MSVC_VERSION_CHECK(13,1,0) || \ +ZPL_ARM_VERSION_CHECK(4,1,0) +# define ZPL_NO_THROW __declspec(nothrow) +#else +# define ZPL_NO_THROW +#endif + +#if defined(ZPL_FALL_THROUGH) +# undef ZPL_FALL_THROUGH +#endif +#if ZPL_GNUC_HAS_ATTRIBUTE(fallthrough,7,0,0) && !defined(ZPL_PGI_VERSION) +# define ZPL_FALL_THROUGH __attribute__((__fallthrough__)) +#elif ZPL_HAS_CPP_ATTRIBUTE_NS(clang,fallthrough) +# define ZPL_FALL_THROUGH ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[clang::fallthrough]]) +#elif ZPL_HAS_CPP_ATTRIBUTE(fallthrough) +# define ZPL_FALL_THROUGH ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[fallthrough]]) +#elif defined(__fallthrough) /* SAL */ +# define ZPL_FALL_THROUGH __fallthrough +#else +# define ZPL_FALL_THROUGH +#endif + +#if defined(ZPL_RETURNS_NON_NULL) +# undef ZPL_RETURNS_NON_NULL +#endif +#if \ +ZPL_HAS_ATTRIBUTE(returns_nonnull) || \ +ZPL_GCC_VERSION_CHECK(4,9,0) +# define ZPL_RETURNS_NON_NULL __attribute__((__returns_nonnull__)) +#elif defined(_Ret_notnull_) /* SAL */ +# define ZPL_RETURNS_NON_NULL _Ret_notnull_ +#else +# define ZPL_RETURNS_NON_NULL +#endif + +#if defined(ZPL_ARRAY_PARAM) +# undef ZPL_ARRAY_PARAM +#endif +#if \ +defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ +!defined(__STDC_NO_VLA__) && \ +!defined(__cplusplus) && \ +!defined(ZPL_PGI_VERSION) && \ +!defined(ZPL_TINYC_VERSION) +# define ZPL_ARRAY_PARAM(name) (name) +#else +# define ZPL_ARRAY_PARAM(name) +#endif + +#if defined(ZPL_IS_CONSTANT) +# undef ZPL_IS_CONSTANT +#endif +#if defined(ZPL_REQUIRE_CONSTEXPR) +# undef ZPL_REQUIRE_CONSTEXPR +#endif +/* ZPL_IS_CONSTEXPR_ is for + ZPL INTERNAL USE ONLY. API subject to change without notice. */ +#if defined(ZPL_IS_CONSTEXPR_) +# undef ZPL_IS_CONSTEXPR_ +#endif +#if \ +ZPL_HAS_BUILTIN(__builtin_constant_p) || \ +ZPL_GCC_VERSION_CHECK(3,4,0) || \ +ZPL_INTEL_VERSION_CHECK(13,0,0) || \ +ZPL_TINYC_VERSION_CHECK(0,9,19) || \ +ZPL_ARM_VERSION_CHECK(4,1,0) || \ +ZPL_IBM_VERSION_CHECK(13,1,0) || \ +ZPL_TI_CL6X_VERSION_CHECK(6,1,0) || \ +(ZPL_SUNPRO_VERSION_CHECK(5,10,0) && !defined(__cplusplus)) || \ +ZPL_CRAY_VERSION_CHECK(8,1,0) +# define ZPL_IS_CONSTANT(expr) __builtin_constant_p(expr) +#endif +#if !defined(__cplusplus) +# if \ +ZPL_HAS_BUILTIN(__builtin_types_compatible_p) || \ +ZPL_GCC_VERSION_CHECK(3,4,0) || \ +ZPL_INTEL_VERSION_CHECK(13,0,0) || \ +ZPL_IBM_VERSION_CHECK(13,1,0) || \ +ZPL_CRAY_VERSION_CHECK(8,1,0) || \ +ZPL_ARM_VERSION_CHECK(5,4,0) || \ +ZPL_TINYC_VERSION_CHECK(0,9,24) +# if defined(__INTPTR_TYPE__) +# define ZPL_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0)), int*) +# else +# include +# define ZPL_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((intptr_t) ((expr) * 0)) : (int*) 0)), int*) +# endif +# elif \ +( \ +defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && \ +!defined(ZPL_SUNPRO_VERSION) && \ +!defined(ZPL_PGI_VERSION) && \ +!defined(ZPL_IAR_VERSION)) || \ +ZPL_HAS_EXTENSION(c_generic_selections) || \ +ZPL_GCC_VERSION_CHECK(4,9,0) || \ +ZPL_INTEL_VERSION_CHECK(17,0,0) || \ +ZPL_IBM_VERSION_CHECK(12,1,0) || \ +ZPL_ARM_VERSION_CHECK(5,3,0) +# if defined(__INTPTR_TYPE__) +# define ZPL_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0), int*: 1, void*: 0) +# else +# include +# define ZPL_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((intptr_t) * 0) : (int*) 0), int*: 1, void*: 0) +# endif +# elif \ +defined(ZPL_GCC_VERSION) || \ +defined(ZPL_INTEL_VERSION) || \ +defined(ZPL_TINYC_VERSION) || \ +defined(ZPL_TI_ARMCL_VERSION) || \ +ZPL_TI_CL430_VERSION_CHECK(18,12,0) || \ +defined(ZPL_TI_CL2000_VERSION) || \ +defined(ZPL_TI_CL6X_VERSION) || \ +defined(ZPL_TI_CL7X_VERSION) || \ +defined(ZPL_TI_CLPRU_VERSION) || \ +defined(__clang__) +# define ZPL_IS_CONSTEXPR_(expr) ( \ +sizeof(void) != \ +sizeof(*( \ +1 ? \ +((void*) ((expr) * 0L) ) : \ +((struct { char v[sizeof(void) * 2]; } *) 1) \ +) \ +) \ +) +# endif +#endif +#if defined(ZPL_IS_CONSTEXPR_) +# if !defined(ZPL_IS_CONSTANT) +# define ZPL_IS_CONSTANT(expr) ZPL_IS_CONSTEXPR_(expr) +# endif +# define ZPL_REQUIRE_CONSTEXPR(expr) (ZPL_IS_CONSTEXPR_(expr) ? (expr) : (-1)) +#else +# if !defined(ZPL_IS_CONSTANT) +# define ZPL_IS_CONSTANT(expr) (0) +# endif +# define ZPL_REQUIRE_CONSTEXPR(expr) (expr) +#endif + +#if defined(ZPL_BEGIN_C_DECLS) +# undef ZPL_BEGIN_C_DECLS +#endif +#if defined(ZPL_END_C_DECLS) +# undef ZPL_END_C_DECLS +#endif +#if defined(ZPL_C_DECL) +# undef ZPL_C_DECL +#endif +#if defined(__cplusplus) +# define ZPL_BEGIN_C_DECLS extern "C" { +# define ZPL_END_C_DECLS } +# define ZPL_C_DECL extern "C" +#else +# define ZPL_BEGIN_C_DECLS +# define ZPL_END_C_DECLS +# define ZPL_C_DECL +#endif + +#if defined(ZPL_STATIC_ASSERT) +# undef ZPL_STATIC_ASSERT +#endif +#if \ +!defined(__cplusplus) && ( \ +(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || \ +ZPL_HAS_FEATURE(c_static_assert) || \ +ZPL_GCC_VERSION_CHECK(6,0,0) || \ +ZPL_INTEL_VERSION_CHECK(13,0,0) || \ +defined(_Static_assert) \ +) +# define ZPL_STATIC_ASSERT(expr, message) _Static_assert(expr, message) +#elif \ +(defined(__cplusplus) && (__cplusplus >= 201103L)) || \ +ZPL_MSVC_VERSION_CHECK(16,0,0) +# define ZPL_STATIC_ASSERT(expr, message) ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(static_assert(expr, message)) +#else +# define ZPL_STATIC_ASSERT3(cond, msg) typedef char static_assertion_##msg[(!!(cond)) * 2 - 1] +# define ZPL_STATIC_ASSERT2(cond, line) ZPL_STATIC_ASSERT3(cond, static_assertion_at_line_##line) +# define ZPL_STATIC_ASSERT1(cond, line) ZPL_STATIC_ASSERT2(cond, line) +# define ZPL_STATIC_ASSERT(cond, unused) ZPL_STATIC_ASSERT1(cond, __LINE__) +#endif + +#if defined(ZPL_NULL) +# undef ZPL_NULL +#endif +#if defined(__cplusplus) +# if __cplusplus >= 201103L +# define ZPL_NULL ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(nullptr) +# elif defined(NULL) +# define ZPL_NULL NULL +# else +# define ZPL_NULL ZPL_STATIC_CAST(void*, 0) +# endif +#elif defined(NULL) +# define ZPL_NULL NULL +#else +# define ZPL_NULL ((void*) 0) +#endif + +#if defined(ZPL_MESSAGE) +# undef ZPL_MESSAGE +#endif +#if ZPL_HAS_WARNING("-Wunknown-pragmas") +# define ZPL_MESSAGE(msg) \ +ZPL_DIAGNOSTIC_PUSH \ +ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ +ZPL_PRAGMA(message msg) \ +ZPL_DIAGNOSTIC_POP +#elif \ +ZPL_GCC_VERSION_CHECK(4,4,0) || \ +ZPL_INTEL_VERSION_CHECK(13,0,0) +# define ZPL_MESSAGE(msg) ZPL_PRAGMA(message msg) +#elif ZPL_CRAY_VERSION_CHECK(5,0,0) +# define ZPL_MESSAGE(msg) ZPL_PRAGMA(_CRI message msg) +#elif ZPL_IAR_VERSION_CHECK(8,0,0) +# define ZPL_MESSAGE(msg) ZPL_PRAGMA(message(msg)) +#elif ZPL_PELLES_VERSION_CHECK(2,0,0) +# define ZPL_MESSAGE(msg) ZPL_PRAGMA(message(msg)) +#else +# define ZPL_MESSAGE(msg) +#endif + +#if defined(ZPL_WARNING) +# undef ZPL_WARNING +#endif +#if ZPL_HAS_WARNING("-Wunknown-pragmas") +# define ZPL_WARNING(msg) \ +ZPL_DIAGNOSTIC_PUSH \ +ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ +ZPL_PRAGMA(clang warning msg) \ +ZPL_DIAGNOSTIC_POP +#elif \ +ZPL_GCC_VERSION_CHECK(4,8,0) || \ +ZPL_PGI_VERSION_CHECK(18,4,0) || \ +ZPL_INTEL_VERSION_CHECK(13,0,0) +# define ZPL_WARNING(msg) ZPL_PRAGMA(GCC warning msg) +#elif ZPL_MSVC_VERSION_CHECK(15,0,0) +# define ZPL_WARNING(msg) ZPL_PRAGMA(message(msg)) +#else +# define ZPL_WARNING(msg) ZPL_MESSAGE(msg) +#endif + +#if defined(ZPL_REQUIRE) +# undef ZPL_REQUIRE +#endif +#if defined(ZPL_REQUIRE_MSG) +# undef ZPL_REQUIRE_MSG +#endif +#if ZPL_HAS_ATTRIBUTE(diagnose_if) +# if ZPL_HAS_WARNING("-Wgcc-compat") +# define ZPL_REQUIRE(expr) \ +ZPL_DIAGNOSTIC_PUSH \ +_Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ +__attribute__((diagnose_if(!(expr), #expr, "error"))) \ +ZPL_DIAGNOSTIC_POP +# define ZPL_REQUIRE_MSG(expr,msg) \ +ZPL_DIAGNOSTIC_PUSH \ +_Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ +__attribute__((diagnose_if(!(expr), msg, "error"))) \ +ZPL_DIAGNOSTIC_POP +# else +# define ZPL_REQUIRE(expr) __attribute__((diagnose_if(!(expr), #expr, "error"))) +# define ZPL_REQUIRE_MSG(expr,msg) __attribute__((diagnose_if(!(expr), msg, "error"))) +# endif +#else +# define ZPL_REQUIRE(expr) +# define ZPL_REQUIRE_MSG(expr,msg) +#endif + +#if defined(ZPL_FLAGS) +# undef ZPL_FLAGS +#endif +#if ZPL_HAS_ATTRIBUTE(flag_enum) +# define ZPL_FLAGS __attribute__((__flag_enum__)) +#endif + +#if defined(ZPL_FLAGS_CAST) +# undef ZPL_FLAGS_CAST +#endif +#if ZPL_INTEL_VERSION_CHECK(19,0,0) +# define ZPL_FLAGS_CAST(T, expr) (__extension__ ({ \ +ZPL_DIAGNOSTIC_PUSH \ +_Pragma("warning(disable:188)") \ +((T) (expr)); \ +ZPL_DIAGNOSTIC_POP \ +})) +#else +# define ZPL_FLAGS_CAST(T, expr) ZPL_STATIC_CAST(T, expr) +#endif + +#if defined(ZPL_EMPTY_BASES) +# undef ZPL_EMPTY_BASES +#endif +#if ZPL_MSVC_VERSION_CHECK(19,0,23918) && !ZPL_MSVC_VERSION_CHECK(20,0,0) +# define ZPL_EMPTY_BASES __declspec(empty_bases) +#else +# define ZPL_EMPTY_BASES +#endif + +/* Remaining macros are deprecated. */ + +#if defined(ZPL_GCC_NOT_CLANG_VERSION_CHECK) +# undef ZPL_GCC_NOT_CLANG_VERSION_CHECK +#endif +#if defined(__clang__) +# define ZPL_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) (0) +#else +# define ZPL_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) ZPL_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(ZPL_CLANG_HAS_ATTRIBUTE) +# undef ZPL_CLANG_HAS_ATTRIBUTE +#endif +#define ZPL_CLANG_HAS_ATTRIBUTE(attribute) ZPL_HAS_ATTRIBUTE(attribute) + +#if defined(ZPL_CLANG_HAS_CPP_ATTRIBUTE) +# undef ZPL_CLANG_HAS_CPP_ATTRIBUTE +#endif +#define ZPL_CLANG_HAS_CPP_ATTRIBUTE(attribute) ZPL_HAS_CPP_ATTRIBUTE(attribute) + +#if defined(ZPL_CLANG_HAS_BUILTIN) +# undef ZPL_CLANG_HAS_BUILTIN +#endif +#define ZPL_CLANG_HAS_BUILTIN(builtin) ZPL_HAS_BUILTIN(builtin) + +#if defined(ZPL_CLANG_HAS_FEATURE) +# undef ZPL_CLANG_HAS_FEATURE +#endif +#define ZPL_CLANG_HAS_FEATURE(feature) ZPL_HAS_FEATURE(feature) + +#if defined(ZPL_CLANG_HAS_EXTENSION) +# undef ZPL_CLANG_HAS_EXTENSION +#endif +#define ZPL_CLANG_HAS_EXTENSION(extension) ZPL_HAS_EXTENSION(extension) + +#if defined(ZPL_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE) +# undef ZPL_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE +#endif +#define ZPL_CLANG_HAS_DECLSPEC_ATTRIBUTE(attribute) ZPL_HAS_DECLSPEC_ATTRIBUTE(attribute) + +#if defined(ZPL_CLANG_HAS_WARNING) +# undef ZPL_CLANG_HAS_WARNING +#endif +#define ZPL_CLANG_HAS_WARNING(warning) ZPL_HAS_WARNING(warning) + +#endif /* !defined(ZPL_HEDLEY_VERSION) || (ZPL_HEDLEY_VERSION < X) */ #define ZPL_VERSION ZPL_VERSION_ENCODE(ZPL_VERSION_MAJOR, ZPL_VERSION_MINOR, ZPL_VERSION_PATCH) @@ -2334,7 +2335,7 @@ License: /* Distributions */ #ifndef ZPL_CUSTOM_MODULES - /* default distribution */ +/* default distribution */ # define ZPL_MODULE_ESSENTIALS # define ZPL_MODULE_CORE # define ZPL_MODULE_TIMER @@ -2350,7 +2351,7 @@ License: # define ZPL_MODULE_COROUTINES # define ZPL_MODULE_PARSER - /* zpl nano distribution */ +/* zpl nano distribution */ # if defined(ZPL_NANO) || defined(ZPL_PICO) # undef ZPL_MODULE_TIMER # undef ZPL_MODULE_HASHING @@ -2370,7 +2371,7 @@ License: # undef ZPL_MODULE_CORE # endif - /* module enabling overrides */ +/* module enabling overrides */ # if defined(ZPL_ENABLE_CORE) && !defined(ZPL_MODULE_CORE) # define ZPL_MODULE_CORE # endif @@ -2419,7 +2420,7 @@ License: # define ZPL_MODULE_PARSER # endif - /* module disabling overrides */ +/* module disabling overrides */ # if defined(ZPL_DISABLE_CORE) && defined(ZPL_MODULE_CORE) # undef ZPL_MODULE_CORE # endif @@ -2485,182 +2486,182 @@ License: /* general purpose includes */ - // file: header/core/system.h +// file: header/core/system.h - ZPL_BEGIN_C_DECLS +ZPL_BEGIN_C_DECLS - /* Platform architecture */ +/* Platform architecture */ - #if defined(_WIN64) || defined(__x86_64__) || defined(_M_X64) || defined(__64BIT__) || defined(__powerpc64__) || \ - defined(__ppc64__) || defined(__aarch64__) - # ifndef ZPL_ARCH_64_BIT - # define ZPL_ARCH_64_BIT 1 - # endif - #else - # ifndef ZPL_ARCH_32_BIT - # define ZPL_ARCH_32_BIT 1 - # endif - #endif +#if defined(_WIN64) || defined(__x86_64__) || defined(_M_X64) || defined(__64BIT__) || defined(__powerpc64__) || \ +defined(__ppc64__) || defined(__aarch64__) +# ifndef ZPL_ARCH_64_BIT +# define ZPL_ARCH_64_BIT 1 +# endif +#else +# ifndef ZPL_ARCH_32_BIT +# define ZPL_ARCH_32_BIT 1 +# endif +#endif - /* Platform endiannes */ +/* Platform endiannes */ - #ifndef ZPL_ENDIAN_ORDER - # define ZPL_ENDIAN_ORDER - # define ZPL_IS_BIG_ENDIAN (!*(zpl_u8 *)&(zpl_u16){ 1 }) - # define ZPL_IS_LITTLE_ENDIAN (!ZPL_IS_BIG_ENDIAN) - #endif +#ifndef ZPL_ENDIAN_ORDER +# define ZPL_ENDIAN_ORDER +# define ZPL_IS_BIG_ENDIAN (!*(zpl_u8 *)&(zpl_u16){ 1 }) +# define ZPL_IS_LITTLE_ENDIAN (!ZPL_IS_BIG_ENDIAN) +#endif - /* Platform OS */ +/* Platform OS */ - #if defined(_WIN32) || defined(_WIN64) - # ifndef ZPL_SYSTEM_WINDOWS - # define ZPL_SYSTEM_WINDOWS 1 - # endif - #elif defined(__APPLE__) && defined(__MACH__) - # ifndef ZPL_SYSTEM_OSX - # define ZPL_SYSTEM_OSX 1 - # endif - # ifndef ZPL_SYSTEM_MACOS - # define ZPL_SYSTEM_MACOS 1 - # endif - # include - # if TARGET_IPHONE_SIMULATOR == 1 || TARGET_OS_IPHONE == 1 - # ifndef ZPL_SYSTEM_IOS - # define ZPL_SYSTEM_IOS 1 - # endif - # endif - #elif defined(__unix__) - # ifndef ZPL_SYSTEM_UNIX - # define ZPL_SYSTEM_UNIX 1 - # endif - # if defined(ANDROID) || defined(__ANDROID__) - # ifndef ZPL_SYSTEM_ANDROID - # define ZPL_SYSTEM_ANDROID 1 - # endif - # ifndef ZPL_SYSTEM_LINUX - # define ZPL_SYSTEM_LINUX 1 - # endif - # elif defined(__linux__) - # ifndef ZPL_SYSTEM_LINUX - # define ZPL_SYSTEM_LINUX 1 - # endif - # elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) - # ifndef ZPL_SYSTEM_FREEBSD - # define ZPL_SYSTEM_FREEBSD 1 - # endif - # elif defined(__OpenBSD__) - # ifndef ZPL_SYSTEM_OPENBSD - # define ZPL_SYSTEM_OPENBSD 1 - # endif - # elif defined(__EMSCRIPTEN__) - # ifndef ZPL_SYSTEM_EMSCRIPTEN - # define ZPL_SYSTEM_EMSCRIPTEN 1 - # endif - # elif defined(__CYGWIN__) - # ifndef ZPL_SYSTEM_CYGWIN - # define ZPL_SYSTEM_CYGWIN 1 - # endif - # else - # error This UNIX operating system is not supported - # endif - #else - # error This operating system is not supported - #endif +#if defined(_WIN32) || defined(_WIN64) +# ifndef ZPL_SYSTEM_WINDOWS +# define ZPL_SYSTEM_WINDOWS 1 +# endif +#elif defined(__APPLE__) && defined(__MACH__) +# ifndef ZPL_SYSTEM_OSX +# define ZPL_SYSTEM_OSX 1 +# endif +# ifndef ZPL_SYSTEM_MACOS +# define ZPL_SYSTEM_MACOS 1 +# endif +# include +# if TARGET_IPHONE_SIMULATOR == 1 || TARGET_OS_IPHONE == 1 +# ifndef ZPL_SYSTEM_IOS +# define ZPL_SYSTEM_IOS 1 +# endif +# endif +#elif defined(__unix__) +# ifndef ZPL_SYSTEM_UNIX +# define ZPL_SYSTEM_UNIX 1 +# endif +# if defined(ANDROID) || defined(__ANDROID__) +# ifndef ZPL_SYSTEM_ANDROID +# define ZPL_SYSTEM_ANDROID 1 +# endif +# ifndef ZPL_SYSTEM_LINUX +# define ZPL_SYSTEM_LINUX 1 +# endif +# elif defined(__linux__) +# ifndef ZPL_SYSTEM_LINUX +# define ZPL_SYSTEM_LINUX 1 +# endif +# elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) +# ifndef ZPL_SYSTEM_FREEBSD +# define ZPL_SYSTEM_FREEBSD 1 +# endif +# elif defined(__OpenBSD__) +# ifndef ZPL_SYSTEM_OPENBSD +# define ZPL_SYSTEM_OPENBSD 1 +# endif +# elif defined(__EMSCRIPTEN__) +# ifndef ZPL_SYSTEM_EMSCRIPTEN +# define ZPL_SYSTEM_EMSCRIPTEN 1 +# endif +# elif defined(__CYGWIN__) +# ifndef ZPL_SYSTEM_CYGWIN +# define ZPL_SYSTEM_CYGWIN 1 +# endif +# else +# error This UNIX operating system is not supported +# endif +#else +# error This operating system is not supported +#endif - /* Platform compiler */ +/* Platform compiler */ - #if defined(_MSC_VER) - # define ZPL_COMPILER_MSVC 1 - #elif defined(__GNUC__) - # define ZPL_COMPILER_GCC 1 - #elif defined(__clang__) - # define ZPL_COMPILER_CLANG 1 - #elif defined(__MINGW32__) - # define ZPL_COMPILER_MINGW 1 - #elif defined(__TINYC__) - # define ZPL_COMPILER_TINYC 1 - #else - # error Unknown compiler - #endif +#if defined(_MSC_VER) +# define ZPL_COMPILER_MSVC 1 +#elif defined(__GNUC__) +# define ZPL_COMPILER_GCC 1 +#elif defined(__clang__) +# define ZPL_COMPILER_CLANG 1 +#elif defined(__MINGW32__) +# define ZPL_COMPILER_MINGW 1 +#elif defined(__TINYC__) +# define ZPL_COMPILER_TINYC 1 +#else +# error Unknown compiler +#endif - /* Platform CPU */ +/* Platform CPU */ - #if defined(__arm__) || defined(__aarch64__) || defined(__ARM_ARCH) - # ifndef ZPL_CPU_ARM - # define ZPL_CPU_ARM 1 - # endif - # ifndef ZPL_CACHE_LINE_SIZE - # define ZPL_CACHE_LINE_SIZE 64 - # endif - #elif defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__x86_64__) || defined(ZPL_SYSTEM_EMSCRIPTEN) - # ifndef ZPL_CPU_X86 - # define ZPL_CPU_X86 1 - # endif - # ifndef ZPL_CACHE_LINE_SIZE - # define ZPL_CACHE_LINE_SIZE 64 - # endif - #elif defined(_M_PPC) || defined(__powerpc__) || defined(__powerpc64__) - # ifndef ZPL_CPU_PPC - # define ZPL_CPU_PPC 1 - # endif - # ifndef ZPL_CACHE_LINE_SIZE - # define ZPL_CACHE_LINE_SIZE 128 - # endif - #elif defined(__MIPSEL__) || defined(__mips_isa_rev) - # ifndef ZPL_CPU_MIPS - # define ZPL_CPU_MIPS 1 - # endif - # ifndef ZPL_CACHE_LINE_SIZE - # define ZPL_CACHE_LINE_SIZE 64 - # endif - #else - # error Unknown CPU Type - #endif +#if defined(__arm__) || defined(__aarch64__) || defined(__ARM_ARCH) +# ifndef ZPL_CPU_ARM +# define ZPL_CPU_ARM 1 +# endif +# ifndef ZPL_CACHE_LINE_SIZE +# define ZPL_CACHE_LINE_SIZE 64 +# endif +#elif defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__x86_64__) || defined(ZPL_SYSTEM_EMSCRIPTEN) +# ifndef ZPL_CPU_X86 +# define ZPL_CPU_X86 1 +# endif +# ifndef ZPL_CACHE_LINE_SIZE +# define ZPL_CACHE_LINE_SIZE 64 +# endif +#elif defined(_M_PPC) || defined(__powerpc__) || defined(__powerpc64__) +# ifndef ZPL_CPU_PPC +# define ZPL_CPU_PPC 1 +# endif +# ifndef ZPL_CACHE_LINE_SIZE +# define ZPL_CACHE_LINE_SIZE 128 +# endif +#elif defined(__MIPSEL__) || defined(__mips_isa_rev) +# ifndef ZPL_CPU_MIPS +# define ZPL_CPU_MIPS 1 +# endif +# ifndef ZPL_CACHE_LINE_SIZE +# define ZPL_CACHE_LINE_SIZE 64 +# endif +#else +# error Unknown CPU Type +#endif - // TODO(ZaKlaus): Find a better way to get this flag in MinGW. - #if (defined(ZPL_COMPILER_GCC) && !defined(WC_ERR_INVALID_CHARS)) || defined(ZPL_COMPILER_TINYC) - # define WC_ERR_INVALID_CHARS 0x0080 - #endif +// TODO(ZaKlaus): Find a better way to get this flag in MinGW. +#if (defined(ZPL_COMPILER_GCC) && !defined(WC_ERR_INVALID_CHARS)) || defined(ZPL_COMPILER_TINYC) +# define WC_ERR_INVALID_CHARS 0x0080 +#endif - #if defined(ZPL_COMPILER_GCC) && defined(ZPL_SYSTEM_WINDOWS) - # ifndef ZPL_COMPILER_MINGW - # define ZPL_COMPILER_MINGW // assume we use mingw as a compiler - # endif - #endif +#if defined(ZPL_COMPILER_GCC) && defined(ZPL_SYSTEM_WINDOWS) +# ifndef ZPL_COMPILER_MINGW +# define ZPL_COMPILER_MINGW // assume we use mingw as a compiler +# endif +#endif - #if defined(ZPL_SYSTEM_UNIX) - # ifndef _GNU_SOURCE - # define _GNU_SOURCE - # endif +#if defined(ZPL_SYSTEM_UNIX) +# ifndef _GNU_SOURCE +# define _GNU_SOURCE +# endif - # ifndef _LARGEFILE64_SOURCE - # define _LARGEFILE64_SOURCE - # endif - #endif +# ifndef _LARGEFILE64_SOURCE +# define _LARGEFILE64_SOURCE +# endif +#endif - #if ZPL_GNUC_VERSION_CHECK(3, 3, 0) - # define ZPL_INFINITY (__builtin_inff()) - # define ZPL_NAN (__builtin_nanf("")) - #elif defined(ZPL_COMPILER_MSVC) +#if ZPL_GNUC_VERSION_CHECK(3, 3, 0) +# define ZPL_INFINITY (__builtin_inff()) +# define ZPL_NAN (__builtin_nanf("")) +#elif defined(ZPL_COMPILER_MSVC) - # if !defined(ZPL__HACK_INFINITY) - typedef union zpl__msvc_inf_hack { - unsigned __int8 bytes[4]; - float value; - } zpl__msvc_inf_hack; - static union zpl__msvc_inf_hack ZPL__INFINITY_HACK = {{0x00, 0x00, 0x80, 0x7F}}; - # define ZPL__HACK_INFINITY (ZPL__INFINITY_HACK.value) - # endif +# if !defined(ZPL__HACK_INFINITY) +typedef union zpl__msvc_inf_hack { + unsigned __int8 bytes[4]; + float value; +} zpl__msvc_inf_hack; +static union zpl__msvc_inf_hack ZPL__INFINITY_HACK = {{0x00, 0x00, 0x80, 0x7F}}; +# define ZPL__HACK_INFINITY (ZPL__INFINITY_HACK.value) +# endif - # define ZPL_INFINITY (ZPL__HACK_INFINITY) - # define ZPL_NAN (0) - #else - # define ZPL_INFINITY (1e10000f) - # define ZPL_NAN (0.0f / 0.0f) - #endif +# define ZPL_INFINITY (ZPL__HACK_INFINITY) +# define ZPL_NAN (0) +#else +# define ZPL_INFINITY (1e10000f) +# define ZPL_NAN (0.0f / 0.0f) +#endif - ZPL_END_C_DECLS +ZPL_END_C_DECLS #include #include @@ -2669,4641 +2670,4638 @@ License: # include #endif - // file: header/essentials/types.h +// file: header/essentials/types.h - ZPL_BEGIN_C_DECLS +ZPL_BEGIN_C_DECLS - /* Basic types */ +/* Basic types */ - #if defined(ZPL_COMPILER_MSVC) - # if _MSC_VER < 1300 - typedef unsigned char zpl_u8; - typedef signed char zpl_i8; - typedef unsigned short zpl_u16; - typedef signed short zpl_i16; - typedef unsigned int zpl_u32; - typedef signed int zpl_i32; - # else - typedef unsigned __int8 zpl_u8; - typedef signed __int8 zpl_i8; - typedef unsigned __int16 zpl_u16; - typedef signed __int16 zpl_i16; - typedef unsigned __int32 zpl_u32; - typedef signed __int32 zpl_i32; - # endif - typedef unsigned __int64 zpl_u64; - typedef signed __int64 zpl_i64; - #else - # include +#if defined(ZPL_COMPILER_MSVC) +# if _MSC_VER < 1300 +typedef unsigned char zpl_u8; +typedef signed char zpl_i8; +typedef unsigned short zpl_u16; +typedef signed short zpl_i16; +typedef unsigned int zpl_u32; +typedef signed int zpl_i32; +# else +typedef unsigned __int8 zpl_u8; +typedef signed __int8 zpl_i8; +typedef unsigned __int16 zpl_u16; +typedef signed __int16 zpl_i16; +typedef unsigned __int32 zpl_u32; +typedef signed __int32 zpl_i32; +# endif +typedef unsigned __int64 zpl_u64; +typedef signed __int64 zpl_i64; +#else +# include - typedef uint8_t zpl_u8; - typedef int8_t zpl_i8; - typedef uint16_t zpl_u16; - typedef int16_t zpl_i16; - typedef uint32_t zpl_u32; - typedef int32_t zpl_i32; - typedef uint64_t zpl_u64; - typedef int64_t zpl_i64; - #endif +typedef uint8_t zpl_u8; +typedef int8_t zpl_i8; +typedef uint16_t zpl_u16; +typedef int16_t zpl_i16; +typedef uint32_t zpl_u32; +typedef int32_t zpl_i32; +typedef uint64_t zpl_u64; +typedef int64_t zpl_i64; +#endif - ZPL_STATIC_ASSERT(sizeof(zpl_u8) == sizeof(zpl_i8), "sizeof(zpl_u8) != sizeof(zpl_i8)"); - ZPL_STATIC_ASSERT(sizeof(zpl_u16) == sizeof(zpl_i16), "sizeof(zpl_u16) != sizeof(zpl_i16)"); - ZPL_STATIC_ASSERT(sizeof(zpl_u32) == sizeof(zpl_i32), "sizeof(zpl_u32) != sizeof(zpl_i32)"); - ZPL_STATIC_ASSERT(sizeof(zpl_u64) == sizeof(zpl_i64), "sizeof(zpl_u64) != sizeof(zpl_i64)"); +ZPL_STATIC_ASSERT(sizeof(zpl_u8) == sizeof(zpl_i8), "sizeof(zpl_u8) != sizeof(zpl_i8)"); +ZPL_STATIC_ASSERT(sizeof(zpl_u16) == sizeof(zpl_i16), "sizeof(zpl_u16) != sizeof(zpl_i16)"); +ZPL_STATIC_ASSERT(sizeof(zpl_u32) == sizeof(zpl_i32), "sizeof(zpl_u32) != sizeof(zpl_i32)"); +ZPL_STATIC_ASSERT(sizeof(zpl_u64) == sizeof(zpl_i64), "sizeof(zpl_u64) != sizeof(zpl_i64)"); - ZPL_STATIC_ASSERT(sizeof(zpl_u8) == 1, "sizeof(zpl_u8) != 1"); - ZPL_STATIC_ASSERT(sizeof(zpl_u16) == 2, "sizeof(zpl_u16) != 2"); - ZPL_STATIC_ASSERT(sizeof(zpl_u32) == 4, "sizeof(zpl_u32) != 4"); - ZPL_STATIC_ASSERT(sizeof(zpl_u64) == 8, "sizeof(zpl_u64) != 8"); +ZPL_STATIC_ASSERT(sizeof(zpl_u8) == 1, "sizeof(zpl_u8) != 1"); +ZPL_STATIC_ASSERT(sizeof(zpl_u16) == 2, "sizeof(zpl_u16) != 2"); +ZPL_STATIC_ASSERT(sizeof(zpl_u32) == 4, "sizeof(zpl_u32) != 4"); +ZPL_STATIC_ASSERT(sizeof(zpl_u64) == 8, "sizeof(zpl_u64) != 8"); - typedef size_t zpl_usize; - typedef ptrdiff_t zpl_isize; +typedef size_t zpl_usize; +typedef ptrdiff_t zpl_isize; - ZPL_STATIC_ASSERT(sizeof(zpl_usize) == sizeof(zpl_isize), "sizeof(zpl_usize) != sizeof(zpl_isize)"); +ZPL_STATIC_ASSERT(sizeof(zpl_usize) == sizeof(zpl_isize), "sizeof(zpl_usize) != sizeof(zpl_isize)"); - // NOTE: (u)zpl_intptr is only here for semantic reasons really as this library will only support 32/64 bit OSes. - #if defined(_WIN64) - typedef signed __int64 zpl_intptr; - typedef unsigned __int64 zpl_uintptr; - #elif defined(_WIN32) - // NOTE; To mark types changing their size, e.g. zpl_intptr - # ifndef _W64 - # if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 - # define _W64 __w64 - # else - # define _W64 - # endif - # endif - typedef _W64 signed int zpl_intptr; - typedef _W64 unsigned int zpl_uintptr; - #else - typedef uintptr_t zpl_uintptr; - typedef intptr_t zpl_intptr; - #endif +// NOTE: (u)zpl_intptr is only here for semantic reasons really as this library will only support 32/64 bit OSes. +#if defined(_WIN64) +typedef signed __int64 zpl_intptr; +typedef unsigned __int64 zpl_uintptr; +#elif defined(_WIN32) +// NOTE; To mark types changing their size, e.g. zpl_intptr +# ifndef _W64 +# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 +# define _W64 __w64 +# else +# define _W64 +# endif +# endif +typedef _W64 signed int zpl_intptr; +typedef _W64 unsigned int zpl_uintptr; +#else +typedef uintptr_t zpl_uintptr; +typedef intptr_t zpl_intptr; +#endif - ZPL_STATIC_ASSERT(sizeof(zpl_uintptr) == sizeof(zpl_intptr), "sizeof(zpl_uintptr) != sizeof(zpl_intptr)"); +ZPL_STATIC_ASSERT(sizeof(zpl_uintptr) == sizeof(zpl_intptr), "sizeof(zpl_uintptr) != sizeof(zpl_intptr)"); - typedef float zpl_f32; - typedef double zpl_f64; +typedef float zpl_f32; +typedef double zpl_f64; - ZPL_STATIC_ASSERT(sizeof(zpl_f32) == 4, "sizeof(zpl_f32) != 4"); - ZPL_STATIC_ASSERT(sizeof(zpl_f64) == 8, "sizeof(zpl_f64) != 8"); +ZPL_STATIC_ASSERT(sizeof(zpl_f32) == 4, "sizeof(zpl_f32) != 4"); +ZPL_STATIC_ASSERT(sizeof(zpl_f64) == 8, "sizeof(zpl_f64) != 8"); - typedef zpl_i32 zpl_rune; // NOTE: Unicode codepoint - typedef zpl_i32 zpl_char32; - #define ZPL_RUNE_INVALID cast(zpl_rune)(0xfffd) - #define ZPL_RUNE_MAX cast(zpl_rune)(0x0010ffff) - #define ZPL_RUNE_BOM cast(zpl_rune)(0xfeff) - #define ZPL_RUNE_EOF cast(zpl_rune)(-1) +typedef zpl_i32 zpl_rune; // NOTE: Unicode codepoint +typedef zpl_i32 zpl_char32; +#define ZPL_RUNE_INVALID cast(zpl_rune)(0xfffd) +#define ZPL_RUNE_MAX cast(zpl_rune)(0x0010ffff) +#define ZPL_RUNE_BOM cast(zpl_rune)(0xfeff) +#define ZPL_RUNE_EOF cast(zpl_rune)(-1) - typedef zpl_i8 zpl_b8; - typedef zpl_i16 zpl_b16; - typedef zpl_i32 zpl_b32; +typedef zpl_i8 zpl_b8; +typedef zpl_i16 zpl_b16; +typedef zpl_i32 zpl_b32; - #if !defined(__cplusplus) - # if (defined(_MSC_VER) && _MSC_VER < 1800) || (!defined(_MSC_VER) && !defined(__STDC_VERSION__)) - # ifndef true - # define true(0 == 0) - # endif - # ifndef false - # define false(0 != 0) - # endif +#if !defined(__cplusplus) +# if (defined(_MSC_VER) && _MSC_VER < 1800) || (!defined(_MSC_VER) && !defined(__STDC_VERSION__)) +# ifndef true +# define true(0 == 0) +# endif +# ifndef false +# define false(0 != 0) +# endif - typedef zpl_b8 bool; - # else - # include - # endif - #endif +typedef zpl_b8 bool; +# else +# include +# endif +#endif - #ifndef ZPL_U8_MIN - # define ZPL_U8_MIN 0u - # define ZPL_U8_MAX 0xffu - # define ZPL_I8_MIN (-0x7f - 1) - # define ZPL_I8_MAX 0x7f +#ifndef ZPL_U8_MIN +# define ZPL_U8_MIN 0u +# define ZPL_U8_MAX 0xffu +# define ZPL_I8_MIN (-0x7f - 1) +# define ZPL_I8_MAX 0x7f - # define ZPL_U16_MIN 0u - # define ZPL_U16_MAX 0xffffu - # define ZPL_I16_MIN (-0x7fff - 1) - # define ZPL_I16_MAX 0x7fff +# define ZPL_U16_MIN 0u +# define ZPL_U16_MAX 0xffffu +# define ZPL_I16_MIN (-0x7fff - 1) +# define ZPL_I16_MAX 0x7fff - # define ZPL_U32_MIN 0u - # define ZPL_U32_MAX 0xffffffffu - # define ZPL_I32_MIN (-0x7fffffff - 1) - # define ZPL_I32_MAX 0x7fffffff +# define ZPL_U32_MIN 0u +# define ZPL_U32_MAX 0xffffffffu +# define ZPL_I32_MIN (-0x7fffffff - 1) +# define ZPL_I32_MAX 0x7fffffff - # define ZPL_U64_MIN 0ull - # define ZPL_U64_MAX 0xffffffffffffffffull - # define ZPL_I64_MIN (-0x7fffffffffffffffll - 1) - # define ZPL_I64_MAX 0x7fffffffffffffffll +# define ZPL_U64_MIN 0ull +# define ZPL_U64_MAX 0xffffffffffffffffull +# define ZPL_I64_MIN (-0x7fffffffffffffffll - 1) +# define ZPL_I64_MAX 0x7fffffffffffffffll - # if defined(ZPL_ARCH_32_BIT) - # define ZPL_USIZE_MIN ZPL_U32_MIN - # define ZPL_USIZE_MAX ZPL_U32_MAX - # define ZPL_ISIZE_MIN ZPL_S32_MIN - # define ZPL_ISIZE_MAX ZPL_S32_MAX - # elif defined(ZPL_ARCH_64_BIT) - # define ZPL_USIZE_MIN ZPL_U64_MIN - # define ZPL_USIZE_MAX ZPL_U64_MAX - # define ZPL_ISIZE_MIN ZPL_I64_MIN - # define ZPL_ISIZE_MAX ZPL_I64_MAX - # else - # error Unknown architecture size. This library only supports 32 bit and 64 bit architectures. - # endif +# if defined(ZPL_ARCH_32_BIT) +# define ZPL_USIZE_MIN ZPL_U32_MIN +# define ZPL_USIZE_MAX ZPL_U32_MAX +# define ZPL_ISIZE_MIN ZPL_S32_MIN +# define ZPL_ISIZE_MAX ZPL_S32_MAX +# elif defined(ZPL_ARCH_64_BIT) +# define ZPL_USIZE_MIN ZPL_U64_MIN +# define ZPL_USIZE_MAX ZPL_U64_MAX +# define ZPL_ISIZE_MIN ZPL_I64_MIN +# define ZPL_ISIZE_MAX ZPL_I64_MAX +# else +# error Unknown architecture size. This library only supports 32 bit and 64 bit architectures. +# endif - # define ZPL_F32_MIN 1.17549435e-38f - # define ZPL_F32_MAX 3.40282347e+38f +# define ZPL_F32_MIN 1.17549435e-38f +# define ZPL_F32_MAX 3.40282347e+38f - # define ZPL_F64_MIN 2.2250738585072014e-308 - # define ZPL_F64_MAX 1.7976931348623157e+308 - #endif +# define ZPL_F64_MIN 2.2250738585072014e-308 +# define ZPL_F64_MAX 1.7976931348623157e+308 +#endif - #ifdef ZPL_DEFINE_NULL_MACRO - # ifndef NULL - # define NULL ZPL_NULL - # endif - #endif +#ifdef ZPL_DEFINE_NULL_MACRO +# ifndef NULL +# define NULL ZPL_NULL +# endif +#endif - ZPL_END_C_DECLS - // file: header/essentials/helpers.h +ZPL_END_C_DECLS +// file: header/essentials/helpers.h - /* Various macro based helpers */ +/* Various macro based helpers */ - ZPL_BEGIN_C_DECLS +ZPL_BEGIN_C_DECLS - #ifndef cast - # define cast(Type) (Type) - #endif +#ifndef cast +# define cast(Type) (Type) +#endif - #ifndef zpl_size_of - # define zpl_size_of(x) (zpl_isize)(sizeof(x)) - #endif +#ifndef zpl_size_of +# define zpl_size_of(x) (zpl_isize)(sizeof(x)) +#endif - #ifndef zpl_count_of - # define zpl_count_of(x) ((zpl_size_of(x) / zpl_size_of(0 [x])) / ((zpl_isize)(!(zpl_size_of(x) % zpl_size_of(0 [x]))))) - #endif +#ifndef zpl_count_of +# define zpl_count_of(x) ((zpl_size_of(x) / zpl_size_of(0 [x])) / ((zpl_isize)(!(zpl_size_of(x) % zpl_size_of(0 [x]))))) +#endif - #ifndef zpl_offset_of - #if defined(_MSC_VER) || defined(ZPL_COMPILER_TINYC) - # define zpl_offset_of(Type, element) ((zpl_isize) & (((Type *)0)->element)) - #else - # define zpl_offset_of(Type, element) __builtin_offsetof(Type, element) - #endif - #endif +#ifndef zpl_offset_of +#if defined(_MSC_VER) || defined(ZPL_COMPILER_TINYC) +# define zpl_offset_of(Type, element) ((zpl_isize) & (((Type *)0)->element)) +#else +# define zpl_offset_of(Type, element) __builtin_offsetof(Type, element) +#endif +#endif - #if defined(__cplusplus) - # ifndef zpl_align_of - # if __cplusplus >= 201103L - # define zpl_align_of(Type) (zpl_isize)alignof(Type) - # else - extern "C++" { - template struct zpl_alignment_trick { - char c; - T member; - }; - } - # define zpl_align_of(Type) zpl_offset_of(zpl_alignment_trick, member) - # endif - # endif - #else - # ifndef zpl_align_of - # define zpl_align_of(Type) \ - zpl_offset_of( \ - struct { \ - char c; \ - Type member; \ - }, \ - member) - # endif - #endif +#if defined(__cplusplus) +# ifndef zpl_align_of +# if __cplusplus >= 201103L +# define zpl_align_of(Type) (zpl_isize)alignof(Type) +# else +extern "C++" { + template struct zpl_alignment_trick { + char c; + T member; + }; +} +# define zpl_align_of(Type) zpl_offset_of(zpl_alignment_trick, member) +# endif +# endif +#else +# ifndef zpl_align_of +# define zpl_align_of(Type) \ +zpl_offset_of( \ +struct { \ +char c; \ +Type member; \ +}, \ +member) +# endif +#endif - #ifndef zpl_swap - # define zpl_swap(Type, a, b) \ - do { \ - Type tmp = (a); \ - (a) = (b); \ - (b) = tmp; \ - } while (0) - #endif +#ifndef zpl_swap +# define zpl_swap(Type, a, b) \ +do { \ +Type tmp = (a); \ +(a) = (b); \ +(b) = tmp; \ +} while (0) +#endif - #ifndef zpl_global - # define zpl_global static // Global variables - #endif +#ifndef zpl_global +# define zpl_global static // Global variables +#endif - #ifndef zpl_internal - # define zpl_internal static // Internal linkage - #endif +#ifndef zpl_internal +# define zpl_internal static // Internal linkage +#endif - #ifndef zpl_local_persist - # define zpl_local_persist static // Local Persisting variables - #endif +#ifndef zpl_local_persist +# define zpl_local_persist static // Local Persisting variables +#endif - #ifndef zpl_unused - # if defined(_MSC_VER) - # define zpl_unused(x) (__pragma(warning(suppress : 4100))(x)) - # elif defined(__GCC__) - # define zpl_unused(x) __attribute__((__unused__))(x) - # else - # define zpl_unused(x) ((void)(zpl_size_of(x))) - # endif - #endif +#ifndef zpl_unused +# if defined(_MSC_VER) +# define zpl_unused(x) (__pragma(warning(suppress : 4100))(x)) +# elif defined(__GCC__) +# define zpl_unused(x) __attribute__((__unused__))(x) +# else +# define zpl_unused(x) ((void)(zpl_size_of(x))) +# endif +#endif - #ifndef ZPL_JOIN_MACROS - # define ZPL_JOIN_MACROS +#ifndef ZPL_JOIN_MACROS +# define ZPL_JOIN_MACROS - # define ZPL_JOIN2 ZPL_CONCAT - # define ZPL_JOIN3(a, b, c) ZPL_JOIN2(ZPL_JOIN2(a, b), c) - # define ZPL_JOIN4(a, b, c, d) ZPL_JOIN2(ZPL_JOIN2(ZPL_JOIN2(a, b), c), d) - #endif +# define ZPL_JOIN2 ZPL_CONCAT +# define ZPL_JOIN3(a, b, c) ZPL_JOIN2(ZPL_JOIN2(a, b), c) +# define ZPL_JOIN4(a, b, c, d) ZPL_JOIN2(ZPL_JOIN2(ZPL_JOIN2(a, b), c), d) +#endif - #ifndef ZPL_BIT - # define ZPL_BIT(x) (1 << (x)) - #endif +#ifndef ZPL_BIT +# define ZPL_BIT(x) (1 << (x)) +#endif - #ifndef zpl_min - # define zpl_min(a, b) ((a) < (b) ? (a) : (b)) - #endif +#ifndef zpl_min +# define zpl_min(a, b) ((a) < (b) ? (a) : (b)) +#endif - #ifndef zpl_max - # define zpl_max(a, b) ((a) > (b) ? (a) : (b)) - #endif +#ifndef zpl_max +# define zpl_max(a, b) ((a) > (b) ? (a) : (b)) +#endif - #ifndef zpl_min3 - # define zpl_min3(a, b, c) zpl_min(zpl_min(a, b), c) - #endif +#ifndef zpl_min3 +# define zpl_min3(a, b, c) zpl_min(zpl_min(a, b), c) +#endif - #ifndef zpl_max3 - # define zpl_max3(a, b, c) zpl_max(zpl_max(a, b), c) - #endif +#ifndef zpl_max3 +# define zpl_max3(a, b, c) zpl_max(zpl_max(a, b), c) +#endif - #ifndef zpl_clamp - # define zpl_clamp(x, lower, upper) zpl_min(zpl_max((x), (lower)), (upper)) - #endif +#ifndef zpl_clamp +# define zpl_clamp(x, lower, upper) zpl_min(zpl_max((x), (lower)), (upper)) +#endif - #ifndef zpl_clamp01 - # define zpl_clamp01(x) zpl_clamp((x), 0, 1) - #endif +#ifndef zpl_clamp01 +# define zpl_clamp01(x) zpl_clamp((x), 0, 1) +#endif - #ifndef zpl_is_between - # define zpl_is_between(x, lower, upper) (((lower) <= (x)) && ((x) <= (upper))) - #endif +#ifndef zpl_is_between +# define zpl_is_between(x, lower, upper) (((lower) <= (x)) && ((x) <= (upper))) +#endif - #ifndef zpl_is_between_limit - # define zpl_is_between_limit(x, lower, upper) (((lower) <= (x)) && ((x) < (upper))) - #endif +#ifndef zpl_is_between_limit +# define zpl_is_between_limit(x, lower, upper) (((lower) <= (x)) && ((x) < (upper))) +#endif - #ifndef zpl_step - #define zpl_step(x,y) (((x)/(y))*(y)) - #endif +#ifndef zpl_step +#define zpl_step(x,y) (((x)/(y))*(y)) +#endif - #ifndef zpl_abs - # define zpl_abs(x) ((x) < 0 ? -(x) : (x)) - #endif +#ifndef zpl_abs +# define zpl_abs(x) ((x) < 0 ? -(x) : (x)) +#endif - #ifndef hard_cast - # define hard_cast(type) *cast(type) & - #endif +#ifndef hard_cast +# define hard_cast(type) *cast(type) & +#endif - // WARN(ZaKlaus): Supported only on GCC via GNU extensions!!! - #ifndef zpl_lambda - # define zpl_lambda(b_) ({ b_ _; }) - #endif +// WARN(ZaKlaus): Supported only on GCC via GNU extensions!!! +#ifndef zpl_lambda +# define zpl_lambda(b_) ({ b_ _; }) +#endif - #ifndef zpl_when - # define zpl_when(init, type, name) \ - type name = init; \ - if (name) - #endif +#ifndef zpl_when +# define zpl_when(init, type, name) \ +type name = init; \ +if (name) +#endif - /* NOTE: Very useful bit setting */ - #ifndef ZPL_MASK_SET - # define ZPL_MASK_SET(var, set, mask) \ - do { \ - if (set) \ - (var) |= (mask); \ - else \ - (var) &= ~(mask); \ - } while (0) - #endif +/* NOTE: Very useful bit setting */ +#ifndef ZPL_MASK_SET +# define ZPL_MASK_SET(var, set, mask) \ +do { \ +if (set) \ +(var) |= (mask); \ +else \ +(var) &= ~(mask); \ +} while (0) +#endif - // Multiline string literals in C99! - #ifndef ZPL_MULTILINE - # define ZPL_MULTILINE(...) #__VA_ARGS__ - #endif +// Multiline string literals in C99! +#ifndef ZPL_MULTILINE +# define ZPL_MULTILINE(...) #__VA_ARGS__ +#endif - ZPL_END_C_DECLS +ZPL_END_C_DECLS #if defined(ZPL_MODULE_ESSENTIALS) - // file: header/essentials/debug.h +// file: header/essentials/debug.h - /* Debugging stuff */ +/* Debugging stuff */ - ZPL_BEGIN_C_DECLS +ZPL_BEGIN_C_DECLS - #ifndef ZPL_DEBUG_TRAP - # if defined(_MSC_VER) - # if _MSC_VER < 1300 - # define ZPL_DEBUG_TRAP( ) __asm int 3 /* Trap to debugger! */ - # else - # define ZPL_DEBUG_TRAP( ) __debugbreak( ) - # endif - # elif defined(ZPL_COMPILER_TINYC) - # define ZPL_DEBUG_TRAP( ) zpl_exit(1) - # else - # define ZPL_DEBUG_TRAP( ) __builtin_trap( ) - # endif - #endif +#ifndef ZPL_DEBUG_TRAP +# if defined(_MSC_VER) +# if _MSC_VER < 1300 +# define ZPL_DEBUG_TRAP( ) __asm int 3 /* Trap to debugger! */ +# else +# define ZPL_DEBUG_TRAP( ) __debugbreak( ) +# endif +# elif defined(ZPL_COMPILER_TINYC) +# define ZPL_DEBUG_TRAP( ) zpl_exit(1) +# else +# define ZPL_DEBUG_TRAP( ) __builtin_trap( ) +# endif +#endif - #ifndef ZPL_ASSERT_MSG - # define ZPL_ASSERT_MSG(cond, msg, ...) \ - do { \ - if (!(cond)) { \ - zpl_assert_handler(#cond, __FILE__, cast(zpl_i64) __LINE__, msg, ##__VA_ARGS__); \ - ZPL_DEBUG_TRAP( ); \ - } \ - } while (0) - #endif +#ifndef ZPL_ASSERT_MSG +# define ZPL_ASSERT_MSG(cond, msg, ...) \ +do { \ +if (!(cond)) { \ +zpl_assert_handler(#cond, __FILE__, cast(zpl_i64) __LINE__, msg, ##__VA_ARGS__); \ +ZPL_DEBUG_TRAP( ); \ +} \ +} while (0) +#endif - #ifndef ZPL_ASSERT - # define ZPL_ASSERT(cond) ZPL_ASSERT_MSG(cond, NULL) - #endif +#ifndef ZPL_ASSERT +# define ZPL_ASSERT(cond) ZPL_ASSERT_MSG(cond, NULL) +#endif - #ifndef ZPL_ASSERT_NOT_NULL - # define ZPL_ASSERT_NOT_NULL(ptr) ZPL_ASSERT_MSG((ptr) != NULL, #ptr " must not be NULL") - #endif +#ifndef ZPL_ASSERT_NOT_NULL +# define ZPL_ASSERT_NOT_NULL(ptr) ZPL_ASSERT_MSG((ptr) != NULL, #ptr " must not be NULL") +#endif - // NOTE: Things that shouldn't happen with a message! - #ifndef ZPL_PANIC - # define ZPL_PANIC(msg, ...) ZPL_ASSERT_MSG(0, msg, ##__VA_ARGS__) - #endif +// NOTE: Things that shouldn't happen with a message! +#ifndef ZPL_PANIC +# define ZPL_PANIC(msg, ...) ZPL_ASSERT_MSG(0, msg, ##__VA_ARGS__) +#endif - #ifndef ZPL_NOT_IMPLEMENTED - # define ZPL_NOT_IMPLEMENTED ZPL_PANIC("not implemented") - #endif +#ifndef ZPL_NOT_IMPLEMENTED +# define ZPL_NOT_IMPLEMENTED ZPL_PANIC("not implemented") +#endif - /* Functions */ +/* Functions */ - ZPL_DEF void zpl_assert_handler(char const *condition, char const *file, zpl_i32 line, char const *msg, ...); - ZPL_DEF zpl_i32 zpl_assert_crash(char const *condition); - ZPL_DEF void zpl_exit(zpl_u32 code); +ZPL_DEF void zpl_assert_handler(char const *condition, char const *file, zpl_i32 line, char const *msg, ...); +ZPL_DEF zpl_i32 zpl_assert_crash(char const *condition); +ZPL_DEF void zpl_exit(zpl_u32 code); - ZPL_END_C_DECLS - // file: header/essentials/memory.h +ZPL_END_C_DECLS +// file: header/essentials/memory.h - /** @file mem.c - @brief Memory manipulation and helpers. - @defgroup memman Memory management +/** @file mem.c +@brief Memory manipulation and helpers. +@defgroup memman Memory management - Consists of pointer arithmetic methods, virtual memory management and custom memory allocators. + Consists of pointer arithmetic methods, virtual memory management and custom memory allocators. - @{ - */ + @{ + */ - ZPL_BEGIN_C_DECLS +ZPL_BEGIN_C_DECLS - //! Checks if value is power of 2. - ZPL_DEF_INLINE zpl_b32 zpl_is_power_of_two(zpl_isize x); +//! Checks if value is power of 2. +ZPL_DEF_INLINE zpl_b32 zpl_is_power_of_two(zpl_isize x); - //! Aligns address to specified alignment. - ZPL_DEF_INLINE void *zpl_align_forward(void *ptr, zpl_isize alignment); +//! Aligns address to specified alignment. +ZPL_DEF_INLINE void *zpl_align_forward(void *ptr, zpl_isize alignment); - //! Aligns value to a specified alignment. - ZPL_DEF_INLINE zpl_i64 zpl_align_forward_i64(zpl_i64 value, zpl_isize alignment); +//! Aligns value to a specified alignment. +ZPL_DEF_INLINE zpl_i64 zpl_align_forward_i64(zpl_i64 value, zpl_isize alignment); - //! Aligns value to a specified alignment. - ZPL_DEF_INLINE zpl_u64 zpl_align_forward_u64(zpl_u64 value, zpl_usize alignment); +//! Aligns value to a specified alignment. +ZPL_DEF_INLINE zpl_u64 zpl_align_forward_u64(zpl_u64 value, zpl_usize alignment); - //! Moves pointer forward by bytes. - ZPL_DEF_INLINE void *zpl_pointer_add(void *ptr, zpl_isize bytes); +//! Moves pointer forward by bytes. +ZPL_DEF_INLINE void *zpl_pointer_add(void *ptr, zpl_isize bytes); - //! Moves pointer backward by bytes. - ZPL_DEF_INLINE void *zpl_pointer_sub(void *ptr, zpl_isize bytes); +//! Moves pointer backward by bytes. +ZPL_DEF_INLINE void *zpl_pointer_sub(void *ptr, zpl_isize bytes); - //! Moves pointer forward by bytes. - ZPL_DEF_INLINE void const *zpl_pointer_add_const(void const *ptr, zpl_isize bytes); +//! Moves pointer forward by bytes. +ZPL_DEF_INLINE void const *zpl_pointer_add_const(void const *ptr, zpl_isize bytes); - //! Moves pointer backward by bytes. - ZPL_DEF_INLINE void const *zpl_pointer_sub_const(void const *ptr, zpl_isize bytes); +//! Moves pointer backward by bytes. +ZPL_DEF_INLINE void const *zpl_pointer_sub_const(void const *ptr, zpl_isize bytes); - //! Calculates difference between two addresses. - ZPL_DEF_INLINE zpl_isize zpl_pointer_diff(void const *begin, void const *end); +//! Calculates difference between two addresses. +ZPL_DEF_INLINE zpl_isize zpl_pointer_diff(void const *begin, void const *end); - #define zpl_ptr_add zpl_pointer_add - #define zpl_ptr_sub zpl_pointer_sub - #define zpl_ptr_add_const zpl_pointer_add_const - #define zpl_ptr_sub_const zpl_pointer_sub_const - #define zpl_ptr_diff zpl_pointer_diff +#define zpl_ptr_add zpl_pointer_add +#define zpl_ptr_sub zpl_pointer_sub +#define zpl_ptr_add_const zpl_pointer_add_const +#define zpl_ptr_sub_const zpl_pointer_sub_const +#define zpl_ptr_diff zpl_pointer_diff - //! Clears up memory at location by specified size. +//! Clears up memory at location by specified size. - //! @param ptr Memory location to clear up. - //! @param size The size to clear up with. - ZPL_DEF_INLINE void zpl_zero_size(void *ptr, zpl_isize size); +//! @param ptr Memory location to clear up. +//! @param size The size to clear up with. +ZPL_DEF_INLINE void zpl_zero_size(void *ptr, zpl_isize size); + +#ifndef zpl_zero_item +//! Clears up an item. +#define zpl_zero_item(t) zpl_zero_size((t), zpl_size_of(*(t))) // NOTE: Pass pointer of struct + +//! Clears up an array. +#define zpl_zero_array(a, count) zpl_zero_size((a), zpl_size_of(*(a)) * count) +#endif + +//! Copy memory from source to destination. +ZPL_DEF_INLINE void *zpl_memmove(void *dest, void const *source, zpl_isize size); + +//! Set constant value at memory location with specified size. +ZPL_DEF_INLINE void *zpl_memset(void *data, zpl_u8 byte_value, zpl_isize size); + +//! Compare two memory locations with specified size. +ZPL_DEF_INLINE zpl_i32 zpl_memcompare(void const *s1, void const *s2, zpl_isize size); + +//! Swap memory contents between 2 locations with size. +ZPL_DEF void zpl_memswap(void *i, void *j, zpl_isize size); + +//! Search for a constant value within the size limit at memory location. +ZPL_DEF void const *zpl_memchr(void const *data, zpl_u8 byte_value, zpl_isize size); + +//! Search for a constant value within the size limit at memory location in backwards. +ZPL_DEF void const *zpl_memrchr(void const *data, zpl_u8 byte_value, zpl_isize size); + +//! Copy non-overlapping memory from source to destination. +ZPL_DEF void *zpl_memcopy(void *dest, void const *source, zpl_isize size); + +#ifndef zpl_memcopy_array + +//! Copy non-overlapping array. +#define zpl_memcopy_array(dst, src, count) zpl_memcopy((dst), (src), zpl_size_of(*(dst)) * (count)) +#endif + +//! Copy an array. +#ifndef zpl_memmove_array +#define zpl_memmove_array(dst, src, count) zpl_memmove((dst), (src), zpl_size_of(*(dst)) * (count)) +#endif + +#ifndef ZPL_BIT_CAST +#define ZPL_BIT_CAST(dest, source) \ +do { \ +ZPL_STATIC_ASSERT(zpl_size_of(*(dest)) <= zpl_size_of(source), "zpl_size_of(*(dest)) !<= zpl_size_of(source)");\ +zpl_memcopy((dest), &(source), zpl_size_of(*dest)); \ +} while (0) +#endif + +#ifndef zpl_kilobytes +#define zpl_kilobytes(x) ((x) * (zpl_i64)(1024)) +#define zpl_megabytes(x) (zpl_kilobytes(x) * (zpl_i64)(1024)) +#define zpl_gigabytes(x) (zpl_megabytes(x) * (zpl_i64)(1024)) +#define zpl_terabytes(x) (zpl_gigabytes(x) * (zpl_i64)(1024)) +#endif + + +/* inlines */ + +#define ZPL__ONES (cast(zpl_usize) - 1 / ZPL_U8_MAX) +#define ZPL__HIGHS (ZPL__ONES * (ZPL_U8_MAX / 2 + 1)) +#define ZPL__HAS_ZERO(x) (((x)-ZPL__ONES) & ~(x)&ZPL__HIGHS) + +ZPL_IMPL_INLINE void *zpl_align_forward(void *ptr, zpl_isize alignment) { + zpl_uintptr p; + + ZPL_ASSERT(zpl_is_power_of_two(alignment)); + + p = cast(zpl_uintptr) ptr; + return cast(void *)((p + (alignment - 1)) & ~(alignment - 1)); +} + +ZPL_IMPL_INLINE zpl_i64 zpl_align_forward_i64(zpl_i64 value, zpl_isize alignment) { + return value + (alignment - value % alignment) % alignment; +} + +ZPL_IMPL_INLINE zpl_u64 zpl_align_forward_u64(zpl_u64 value, zpl_usize alignment) { + return value + (alignment - value % alignment) % alignment; +} + +ZPL_IMPL_INLINE void *zpl_pointer_add(void *ptr, zpl_isize bytes) { return cast(void *)(cast(zpl_u8 *) ptr + bytes); } +ZPL_IMPL_INLINE void *zpl_pointer_sub(void *ptr, zpl_isize bytes) { return cast(void *)(cast(zpl_u8 *) ptr - bytes); } +ZPL_IMPL_INLINE void const *zpl_pointer_add_const(void const *ptr, zpl_isize bytes) { + return cast(void const *)(cast(zpl_u8 const *) ptr + bytes); +} +ZPL_IMPL_INLINE void const *zpl_pointer_sub_const(void const *ptr, zpl_isize bytes) { + return cast(void const *)(cast(zpl_u8 const *) ptr - bytes); +} +ZPL_IMPL_INLINE zpl_isize zpl_pointer_diff(void const *begin, void const *end) { + return cast(zpl_isize)(cast(zpl_u8 const *) end - cast(zpl_u8 const *) begin); +} + +ZPL_IMPL_INLINE void zpl_zero_size(void *ptr, zpl_isize size) { zpl_memset(ptr, 0, size); } + +#if defined(_MSC_VER) && !defined(__clang__) +#pragma intrinsic(__movsb) +#endif + +ZPL_IMPL_INLINE void *zpl_memmove(void *dest, void const *source, zpl_isize n) { + if (dest == NULL) { return NULL; } + + zpl_u8 *d = cast(zpl_u8 *) dest; + zpl_u8 const *s = cast(zpl_u8 const *) source; + + if (d == s) return d; + if (s + n <= d || d + n <= s) // NOTE: Non-overlapping + return zpl_memcopy(d, s, n); + + if (d < s) { + if (cast(zpl_uintptr) s % zpl_size_of(zpl_isize) == cast(zpl_uintptr) d % zpl_size_of(zpl_isize)) { + while (cast(zpl_uintptr) d % zpl_size_of(zpl_isize)) { + if (!n--) return dest; + *d++ = *s++; + } + while (n >= zpl_size_of(zpl_isize)) { + *cast(zpl_isize *) d = *cast(zpl_isize *) s; + n -= zpl_size_of(zpl_isize); + d += zpl_size_of(zpl_isize); + s += zpl_size_of(zpl_isize); + } + } + for (; n; n--) *d++ = *s++; + } else { + if ((cast(zpl_uintptr) s % zpl_size_of(zpl_isize)) == (cast(zpl_uintptr) d % zpl_size_of(zpl_isize))) { + while (cast(zpl_uintptr)(d + n) % zpl_size_of(zpl_isize)) { + if (!n--) return dest; + d[n] = s[n]; + } + while (n >= zpl_size_of(zpl_isize)) { + n -= zpl_size_of(zpl_isize); + *cast(zpl_isize *)(d + n) = *cast(zpl_isize *)(s + n); + } + } + while (n) n--, d[n] = s[n]; + } + + return dest; +} + +ZPL_IMPL_INLINE void *zpl_memset(void *dest, zpl_u8 c, zpl_isize n) { + if (dest == NULL) { return NULL; } + + zpl_u8 *s = cast(zpl_u8 *) dest; + zpl_isize k; + zpl_u32 c32 = ((zpl_u32)-1) / 255 * c; + + if (n == 0) return dest; + s[0] = s[n - 1] = c; + if (n < 3) return dest; + s[1] = s[n - 2] = c; + s[2] = s[n - 3] = c; + if (n < 7) return dest; + s[3] = s[n - 4] = c; + if (n < 9) return dest; + + k = -cast(zpl_intptr) s & 3; + s += k; + n -= k; + n &= -4; + + *cast(zpl_u32 *)(s + 0) = c32; + *cast(zpl_u32 *)(s + n - 4) = c32; + if (n < 9) return dest; + *cast(zpl_u32 *)(s + 4) = c32; + *cast(zpl_u32 *)(s + 8) = c32; + *cast(zpl_u32 *)(s + n - 12) = c32; + *cast(zpl_u32 *)(s + n - 8) = c32; + if (n < 25) return dest; + *cast(zpl_u32 *)(s + 12) = c32; + *cast(zpl_u32 *)(s + 16) = c32; + *cast(zpl_u32 *)(s + 20) = c32; + *cast(zpl_u32 *)(s + 24) = c32; + *cast(zpl_u32 *)(s + n - 28) = c32; + *cast(zpl_u32 *)(s + n - 24) = c32; + *cast(zpl_u32 *)(s + n - 20) = c32; + *cast(zpl_u32 *)(s + n - 16) = c32; + + k = 24 + (cast(zpl_uintptr) s & 4); + s += k; + n -= k; + + { + zpl_u64 c64 = (cast(zpl_u64) c32 << 32) | c32; + while (n > 31) { + *cast(zpl_u64 *)(s + 0) = c64; + *cast(zpl_u64 *)(s + 8) = c64; + *cast(zpl_u64 *)(s + 16) = c64; + *cast(zpl_u64 *)(s + 24) = c64; + + n -= 32; + s += 32; + } + } + + return dest; +} + +ZPL_IMPL_INLINE zpl_i32 zpl_memcompare(void const *s1, void const *s2, zpl_isize size) { + zpl_u8 const *s1p8 = cast(zpl_u8 const *) s1; + zpl_u8 const *s2p8 = cast(zpl_u8 const *) s2; + + if (s1 == NULL || s2 == NULL) { return 0; } + + while (size--) { + zpl_isize d; + if ((d = (*s1p8++ - *s2p8++)) != 0) return cast(zpl_i32) d; + } + return 0; +} + +ZPL_IMPL_INLINE zpl_b32 zpl_is_power_of_two(zpl_isize x) { + if (x <= 0) return false; + return !(x & (x - 1)); +} + +ZPL_END_C_DECLS +// file: header/essentials/memory_custom.h + +//////////////////////////////////////////////////////////////// +// +// Custom Allocation +// +// + +ZPL_BEGIN_C_DECLS + +typedef enum zpl_alloc_type { + ZPL_ALLOCATION_ALLOC, + ZPL_ALLOCATION_FREE, + ZPL_ALLOCATION_FREE_ALL, + ZPL_ALLOCATION_RESIZE, +} zpl_alloc_type; + +// NOTE: This is useful so you can define an allocator of the same type and parameters +#define ZPL_ALLOCATOR_PROC(name) \ +void *name(void *allocator_data, zpl_alloc_type type, zpl_isize size, zpl_isize alignment, void *old_memory, \ +zpl_isize old_size, zpl_u64 flags) +typedef ZPL_ALLOCATOR_PROC(zpl_allocator_proc); + + +typedef struct zpl_allocator { + zpl_allocator_proc *proc; + void *data; +} zpl_allocator; + +typedef enum zpl_alloc_flag { + ZPL_ALLOCATOR_FLAG_CLEAR_TO_ZERO = ZPL_BIT(0), +} zpl_alloc_flag; + +#ifndef ZPL_DEFAULT_MEMORY_ALIGNMENT +#define ZPL_DEFAULT_MEMORY_ALIGNMENT (2 * zpl_size_of(void *)) +#endif + +#ifndef ZPL_DEFAULT_ALLOCATOR_FLAGS +#define ZPL_DEFAULT_ALLOCATOR_FLAGS (ZPL_ALLOCATOR_FLAG_CLEAR_TO_ZERO) +#endif + +//! Allocate memory with specified alignment. +ZPL_DEF_INLINE void *zpl_alloc_align(zpl_allocator a, zpl_isize size, zpl_isize alignment); + +//! Allocate memory with default alignment. +ZPL_DEF_INLINE void *zpl_alloc(zpl_allocator a, zpl_isize size); + +//! Free allocated memory. +ZPL_DEF_INLINE void zpl_free(zpl_allocator a, void *ptr); + +//! Free all memory allocated by an allocator. +ZPL_DEF_INLINE void zpl_free_all(zpl_allocator a); + +//! Resize an allocated memory. +ZPL_DEF_INLINE void *zpl_resize(zpl_allocator a, void *ptr, zpl_isize old_size, zpl_isize new_size); + +//! Resize an allocated memory with specified alignment. +ZPL_DEF_INLINE void *zpl_resize_align(zpl_allocator a, void *ptr, zpl_isize old_size, zpl_isize new_size, zpl_isize alignment); + +//! Allocate memory and copy data into it. +ZPL_DEF_INLINE void *zpl_alloc_copy(zpl_allocator a, void const *src, zpl_isize size); + +//! Allocate memory with specified alignment and copy data into it. +ZPL_DEF_INLINE void *zpl_alloc_copy_align(zpl_allocator a, void const *src, zpl_isize size, zpl_isize alignment); - #ifndef zpl_zero_item - //! Clears up an item. - #define zpl_zero_item(t) zpl_zero_size((t), zpl_size_of(*(t))) // NOTE: Pass pointer of struct +//! Allocate memory for null-terminated C-String. +ZPL_DEF char *zpl_alloc_str(zpl_allocator a, char const *str); - //! Clears up an array. - #define zpl_zero_array(a, count) zpl_zero_size((a), zpl_size_of(*(a)) * count) - #endif +//! Allocate memory for C-String with specified size. +ZPL_DEF_INLINE char *zpl_alloc_str_len(zpl_allocator a, char const *str, zpl_isize len); - //! Copy memory from source to destination. - ZPL_DEF_INLINE void *zpl_memmove(void *dest, void const *source, zpl_isize size); +#ifndef zpl_alloc_item - //! Set constant value at memory location with specified size. - ZPL_DEF_INLINE void *zpl_memset(void *data, zpl_u8 byte_value, zpl_isize size); +//! Allocate memory for an item. +#define zpl_alloc_item(allocator_, Type) (Type *)zpl_alloc(allocator_, zpl_size_of(Type)) - //! Compare two memory locations with specified size. - ZPL_DEF_INLINE zpl_i32 zpl_memcompare(void const *s1, void const *s2, zpl_isize size); +//! Allocate memory for an array of items. +#define zpl_alloc_array(allocator_, Type, count) (Type *)zpl_alloc(allocator_, zpl_size_of(Type) * (count)) +#endif - //! Swap memory contents between 2 locations with size. - ZPL_DEF void zpl_memswap(void *i, void *j, zpl_isize size); +/* heap memory analysis tools */ +/* define ZPL_HEAP_ANALYSIS to enable this feature */ +/* call zpl_heap_stats_init at the beginning of the entry point */ +/* you can call zpl_heap_stats_check near the end of the execution to validate any possible leaks */ +ZPL_DEF void zpl_heap_stats_init(void); +ZPL_DEF zpl_isize zpl_heap_stats_used_memory(void); +ZPL_DEF zpl_isize zpl_heap_stats_alloc_count(void); +ZPL_DEF void zpl_heap_stats_check(void); - //! Search for a constant value within the size limit at memory location. - ZPL_DEF void const *zpl_memchr(void const *data, zpl_u8 byte_value, zpl_isize size); +//! Allocate/Resize memory using default options. - //! Search for a constant value within the size limit at memory location in backwards. - ZPL_DEF void const *zpl_memrchr(void const *data, zpl_u8 byte_value, zpl_isize size); +//! Use this if you don't need a "fancy" resize allocation +ZPL_DEF_INLINE void *zpl_default_resize_align(zpl_allocator a, void *ptr, zpl_isize old_size, zpl_isize new_size, zpl_isize alignment); - //! Copy non-overlapping memory from source to destination. - ZPL_DEF void *zpl_memcopy(void *dest, void const *source, zpl_isize size); +//! The heap allocator backed by operating system's memory manager. +ZPL_DEF_INLINE zpl_allocator zpl_heap_allocator(void); +ZPL_DEF ZPL_ALLOCATOR_PROC(zpl_heap_allocator_proc); - #ifndef zpl_memcopy_array +#ifndef zpl_malloc - //! Copy non-overlapping array. - #define zpl_memcopy_array(dst, src, count) zpl_memcopy((dst), (src), zpl_size_of(*(dst)) * (count)) - #endif +//! Helper to allocate memory using heap allocator. +#define zpl_malloc(sz) zpl_alloc(zpl_heap_allocator( ), sz) - //! Copy an array. - #ifndef zpl_memmove_array - #define zpl_memmove_array(dst, src, count) zpl_memmove((dst), (src), zpl_size_of(*(dst)) * (count)) - #endif +//! Helper to free memory allocated by heap allocator. +#define zpl_mfree(ptr) zpl_free(zpl_heap_allocator( ), ptr) - #ifndef ZPL_BIT_CAST - #define ZPL_BIT_CAST(dest, source) \ - do { \ - ZPL_STATIC_ASSERT(zpl_size_of(*(dest)) <= zpl_size_of(source), "zpl_size_of(*(dest)) !<= zpl_size_of(source)");\ - zpl_memcopy((dest), &(source), zpl_size_of(*dest)); \ - } while (0) - #endif - - #ifndef zpl_kilobytes - #define zpl_kilobytes(x) ((x) * (zpl_i64)(1024)) - #define zpl_megabytes(x) (zpl_kilobytes(x) * (zpl_i64)(1024)) - #define zpl_gigabytes(x) (zpl_megabytes(x) * (zpl_i64)(1024)) - #define zpl_terabytes(x) (zpl_gigabytes(x) * (zpl_i64)(1024)) - #endif - - - /* inlines */ - - #define ZPL__ONES (cast(zpl_usize) - 1 / ZPL_U8_MAX) - #define ZPL__HIGHS (ZPL__ONES * (ZPL_U8_MAX / 2 + 1)) - #define ZPL__HAS_ZERO(x) (((x)-ZPL__ONES) & ~(x)&ZPL__HIGHS) - - ZPL_IMPL_INLINE void *zpl_align_forward(void *ptr, zpl_isize alignment) { - zpl_uintptr p; - - ZPL_ASSERT(zpl_is_power_of_two(alignment)); - - p = cast(zpl_uintptr) ptr; - return cast(void *)((p + (alignment - 1)) & ~(alignment - 1)); - } - - ZPL_IMPL_INLINE zpl_i64 zpl_align_forward_i64(zpl_i64 value, zpl_isize alignment) { - return value + (alignment - value % alignment) % alignment; - } - - ZPL_IMPL_INLINE zpl_u64 zpl_align_forward_u64(zpl_u64 value, zpl_usize alignment) { - return value + (alignment - value % alignment) % alignment; - } - - ZPL_IMPL_INLINE void *zpl_pointer_add(void *ptr, zpl_isize bytes) { return cast(void *)(cast(zpl_u8 *) ptr + bytes); } - ZPL_IMPL_INLINE void *zpl_pointer_sub(void *ptr, zpl_isize bytes) { return cast(void *)(cast(zpl_u8 *) ptr - bytes); } - ZPL_IMPL_INLINE void const *zpl_pointer_add_const(void const *ptr, zpl_isize bytes) { - return cast(void const *)(cast(zpl_u8 const *) ptr + bytes); - } - ZPL_IMPL_INLINE void const *zpl_pointer_sub_const(void const *ptr, zpl_isize bytes) { - return cast(void const *)(cast(zpl_u8 const *) ptr - bytes); - } - ZPL_IMPL_INLINE zpl_isize zpl_pointer_diff(void const *begin, void const *end) { - return cast(zpl_isize)(cast(zpl_u8 const *) end - cast(zpl_u8 const *) begin); - } - - ZPL_IMPL_INLINE void zpl_zero_size(void *ptr, zpl_isize size) { zpl_memset(ptr, 0, size); } - - #if defined(_MSC_VER) && !defined(__clang__) - #pragma intrinsic(__movsb) - #endif - - ZPL_IMPL_INLINE void *zpl_memmove(void *dest, void const *source, zpl_isize n) { - if (dest == NULL) { return NULL; } - - zpl_u8 *d = cast(zpl_u8 *) dest; - zpl_u8 const *s = cast(zpl_u8 const *) source; - - if (d == s) return d; - if (s + n <= d || d + n <= s) // NOTE: Non-overlapping - return zpl_memcopy(d, s, n); - - if (d < s) { - if (cast(zpl_uintptr) s % zpl_size_of(zpl_isize) == cast(zpl_uintptr) d % zpl_size_of(zpl_isize)) { - while (cast(zpl_uintptr) d % zpl_size_of(zpl_isize)) { - if (!n--) return dest; - *d++ = *s++; - } - while (n >= zpl_size_of(zpl_isize)) { - *cast(zpl_isize *) d = *cast(zpl_isize *) s; - n -= zpl_size_of(zpl_isize); - d += zpl_size_of(zpl_isize); - s += zpl_size_of(zpl_isize); - } - } - for (; n; n--) *d++ = *s++; - } else { - if ((cast(zpl_uintptr) s % zpl_size_of(zpl_isize)) == (cast(zpl_uintptr) d % zpl_size_of(zpl_isize))) { - while (cast(zpl_uintptr)(d + n) % zpl_size_of(zpl_isize)) { - if (!n--) return dest; - d[n] = s[n]; - } - while (n >= zpl_size_of(zpl_isize)) { - n -= zpl_size_of(zpl_isize); - *cast(zpl_isize *)(d + n) = *cast(zpl_isize *)(s + n); - } - } - while (n) n--, d[n] = s[n]; - } - - return dest; - } - - ZPL_IMPL_INLINE void *zpl_memset(void *dest, zpl_u8 c, zpl_isize n) { - if (dest == NULL) { return NULL; } - - zpl_u8 *s = cast(zpl_u8 *) dest; - zpl_isize k; - zpl_u32 c32 = ((zpl_u32)-1) / 255 * c; - - if (n == 0) return dest; - s[0] = s[n - 1] = c; - if (n < 3) return dest; - s[1] = s[n - 2] = c; - s[2] = s[n - 3] = c; - if (n < 7) return dest; - s[3] = s[n - 4] = c; - if (n < 9) return dest; - - k = -cast(zpl_intptr) s & 3; - s += k; - n -= k; - n &= -4; - - *cast(zpl_u32 *)(s + 0) = c32; - *cast(zpl_u32 *)(s + n - 4) = c32; - if (n < 9) return dest; - *cast(zpl_u32 *)(s + 4) = c32; - *cast(zpl_u32 *)(s + 8) = c32; - *cast(zpl_u32 *)(s + n - 12) = c32; - *cast(zpl_u32 *)(s + n - 8) = c32; - if (n < 25) return dest; - *cast(zpl_u32 *)(s + 12) = c32; - *cast(zpl_u32 *)(s + 16) = c32; - *cast(zpl_u32 *)(s + 20) = c32; - *cast(zpl_u32 *)(s + 24) = c32; - *cast(zpl_u32 *)(s + n - 28) = c32; - *cast(zpl_u32 *)(s + n - 24) = c32; - *cast(zpl_u32 *)(s + n - 20) = c32; - *cast(zpl_u32 *)(s + n - 16) = c32; - - k = 24 + (cast(zpl_uintptr) s & 4); - s += k; - n -= k; - - { - zpl_u64 c64 = (cast(zpl_u64) c32 << 32) | c32; - while (n > 31) { - *cast(zpl_u64 *)(s + 0) = c64; - *cast(zpl_u64 *)(s + 8) = c64; - *cast(zpl_u64 *)(s + 16) = c64; - *cast(zpl_u64 *)(s + 24) = c64; - - n -= 32; - s += 32; - } - } - - return dest; - } - - ZPL_IMPL_INLINE zpl_i32 zpl_memcompare(void const *s1, void const *s2, zpl_isize size) { - zpl_u8 const *s1p8 = cast(zpl_u8 const *) s1; - zpl_u8 const *s2p8 = cast(zpl_u8 const *) s2; - - if (s1 == NULL || s2 == NULL) { return 0; } - - while (size--) { - zpl_isize d; - if ((d = (*s1p8++ - *s2p8++)) != 0) return cast(zpl_i32) d; - } - return 0; - } - - ZPL_IMPL_INLINE zpl_b32 zpl_is_power_of_two(zpl_isize x) { - if (x <= 0) return false; - return !(x & (x - 1)); - } - - ZPL_END_C_DECLS - // file: header/essentials/memory_custom.h - - //////////////////////////////////////////////////////////////// - // - // Custom Allocation - // - // - - ZPL_BEGIN_C_DECLS - - typedef enum zpl_alloc_type { - ZPL_ALLOCATION_ALLOC, - ZPL_ALLOCATION_FREE, - ZPL_ALLOCATION_FREE_ALL, - ZPL_ALLOCATION_RESIZE, - } zpl_alloc_type; - - // NOTE: This is useful so you can define an allocator of the same type and parameters - #define ZPL_ALLOCATOR_PROC(name) \ - void *name(void *allocator_data, zpl_alloc_type type, zpl_isize size, zpl_isize alignment, void *old_memory, \ - zpl_isize old_size, zpl_u64 flags) - typedef ZPL_ALLOCATOR_PROC(zpl_allocator_proc); - - - typedef struct zpl_allocator { - zpl_allocator_proc *proc; - void *data; - } zpl_allocator; - - typedef enum zpl_alloc_flag { - ZPL_ALLOCATOR_FLAG_CLEAR_TO_ZERO = ZPL_BIT(0), - } zpl_alloc_flag; - - #ifndef ZPL_DEFAULT_MEMORY_ALIGNMENT - #define ZPL_DEFAULT_MEMORY_ALIGNMENT (2 * zpl_size_of(void *)) - #endif - - #ifndef ZPL_DEFAULT_ALLOCATOR_FLAGS - #define ZPL_DEFAULT_ALLOCATOR_FLAGS (ZPL_ALLOCATOR_FLAG_CLEAR_TO_ZERO) - #endif +//! Alias to heap allocator. +#define zpl_heap zpl_heap_allocator +#endif - //! Allocate memory with specified alignment. - ZPL_DEF_INLINE void *zpl_alloc_align(zpl_allocator a, zpl_isize size, zpl_isize alignment); +// +// Arena Allocator +// - //! Allocate memory with default alignment. - ZPL_DEF_INLINE void *zpl_alloc(zpl_allocator a, zpl_isize size); +typedef struct zpl_arena { + zpl_allocator backing; + void *physical_start; + zpl_isize total_size; + zpl_isize total_allocated; + zpl_isize temp_count; +} zpl_arena; - //! Free allocated memory. - ZPL_DEF_INLINE void zpl_free(zpl_allocator a, void *ptr); +//! Initialize memory arena from existing memory region. +ZPL_DEF_INLINE void zpl_arena_init_from_memory(zpl_arena *arena, void *start, zpl_isize size); - //! Free all memory allocated by an allocator. - ZPL_DEF_INLINE void zpl_free_all(zpl_allocator a); +//! Initialize memory arena using existing memory allocator. +ZPL_DEF_INLINE void zpl_arena_init_from_allocator(zpl_arena *arena, zpl_allocator backing, zpl_isize size); - //! Resize an allocated memory. - ZPL_DEF_INLINE void *zpl_resize(zpl_allocator a, void *ptr, zpl_isize old_size, zpl_isize new_size); +//! Initialize memory arena within an existing parent memory arena. +ZPL_DEF_INLINE void zpl_arena_init_sub(zpl_arena *arena, zpl_arena *parent_arena, zpl_isize size); - //! Resize an allocated memory with specified alignment. - ZPL_DEF_INLINE void *zpl_resize_align(zpl_allocator a, void *ptr, zpl_isize old_size, zpl_isize new_size, zpl_isize alignment); +//! Release the memory used by memory arena. +ZPL_DEF_INLINE void zpl_arena_free(zpl_arena *arena); - //! Allocate memory and copy data into it. - ZPL_DEF_INLINE void *zpl_alloc_copy(zpl_allocator a, void const *src, zpl_isize size); - //! Allocate memory with specified alignment and copy data into it. - ZPL_DEF_INLINE void *zpl_alloc_copy_align(zpl_allocator a, void const *src, zpl_isize size, zpl_isize alignment); +//! Retrieve memory arena's aligned allocation address. +ZPL_DEF_INLINE zpl_isize zpl_arena_alignment_of(zpl_arena *arena, zpl_isize alignment); - //! Allocate memory for null-terminated C-String. - ZPL_DEF char *zpl_alloc_str(zpl_allocator a, char const *str); +//! Retrieve memory arena's remaining size. +ZPL_DEF_INLINE zpl_isize zpl_arena_size_remaining(zpl_arena *arena, zpl_isize alignment); - //! Allocate memory for C-String with specified size. - ZPL_DEF_INLINE char *zpl_alloc_str_len(zpl_allocator a, char const *str, zpl_isize len); +//! Check whether memory arena has any temporary snapshots. +ZPL_DEF_INLINE void zpl_arena_check(zpl_arena *arena); - #ifndef zpl_alloc_item +//! Allocation Types: alloc, free_all, resize +ZPL_DEF_INLINE zpl_allocator zpl_arena_allocator(zpl_arena *arena); +ZPL_DEF ZPL_ALLOCATOR_PROC(zpl_arena_allocator_proc); - //! Allocate memory for an item. - #define zpl_alloc_item(allocator_, Type) (Type *)zpl_alloc(allocator_, zpl_size_of(Type)) - //! Allocate memory for an array of items. - #define zpl_alloc_array(allocator_, Type, count) (Type *)zpl_alloc(allocator_, zpl_size_of(Type) * (count)) - #endif +typedef struct zpl_arena_snapshot { + zpl_arena *arena; + zpl_isize original_count; +} zpl_arena_snapshot; - /* heap memory analysis tools */ - /* define ZPL_HEAP_ANALYSIS to enable this feature */ - /* call zpl_heap_stats_init at the beginning of the entry point */ - /* you can call zpl_heap_stats_check near the end of the execution to validate any possible leaks */ - ZPL_DEF void zpl_heap_stats_init(void); - ZPL_DEF zpl_isize zpl_heap_stats_used_memory(void); - ZPL_DEF zpl_isize zpl_heap_stats_alloc_count(void); - ZPL_DEF void zpl_heap_stats_check(void); +//! Capture a snapshot of used memory in a memory arena. +ZPL_DEF_INLINE zpl_arena_snapshot zpl_arena_snapshot_begin(zpl_arena *arena); - //! Allocate/Resize memory using default options. +//! Reset memory arena's usage by a captured snapshot. +ZPL_DEF_INLINE void zpl_arena_snapshot_end(zpl_arena_snapshot tmp_mem); - //! Use this if you don't need a "fancy" resize allocation - ZPL_DEF_INLINE void *zpl_default_resize_align(zpl_allocator a, void *ptr, zpl_isize old_size, zpl_isize new_size, zpl_isize alignment); +// +// Pool Allocator +// - //! The heap allocator backed by operating system's memory manager. - ZPL_DEF_INLINE zpl_allocator zpl_heap_allocator(void); - ZPL_DEF ZPL_ALLOCATOR_PROC(zpl_heap_allocator_proc); - #ifndef zpl_malloc +typedef struct zpl_pool { + zpl_allocator backing; + void *physical_start; + void *free_list; + zpl_isize block_size; + zpl_isize block_align; + zpl_isize total_size; + zpl_isize num_blocks; +} zpl_pool; - //! Helper to allocate memory using heap allocator. - #define zpl_malloc(sz) zpl_alloc(zpl_heap_allocator( ), sz) - //! Helper to free memory allocated by heap allocator. - #define zpl_mfree(ptr) zpl_free(zpl_heap_allocator( ), ptr) +//! Initialize pool allocator. +ZPL_DEF_INLINE void zpl_pool_init(zpl_pool *pool, zpl_allocator backing, zpl_isize num_blocks, zpl_isize block_size); - //! Alias to heap allocator. - #define zpl_heap zpl_heap_allocator - #endif +//! Initialize pool allocator with specific block alignment. +ZPL_DEF void zpl_pool_init_align(zpl_pool *pool, zpl_allocator backing, zpl_isize num_blocks, zpl_isize block_size, + zpl_isize block_align); - // - // Arena Allocator - // +//! Release the resources used by pool allocator. +ZPL_DEF_INLINE void zpl_pool_free(zpl_pool *pool); - typedef struct zpl_arena { - zpl_allocator backing; - void *physical_start; - zpl_isize total_size; - zpl_isize total_allocated; - zpl_isize temp_count; - } zpl_arena; +//! Allocation Types: alloc, free +ZPL_DEF_INLINE zpl_allocator zpl_pool_allocator(zpl_pool *pool); +ZPL_DEF ZPL_ALLOCATOR_PROC(zpl_pool_allocator_proc); - //! Initialize memory arena from existing memory region. - ZPL_DEF_INLINE void zpl_arena_init_from_memory(zpl_arena *arena, void *start, zpl_isize size); - //! Initialize memory arena using existing memory allocator. - ZPL_DEF_INLINE void zpl_arena_init_from_allocator(zpl_arena *arena, zpl_allocator backing, zpl_isize size); +typedef struct zpl_allocation_header_ev { + zpl_isize size; +} zpl_allocation_header_ev; - //! Initialize memory arena within an existing parent memory arena. - ZPL_DEF_INLINE void zpl_arena_init_sub(zpl_arena *arena, zpl_arena *parent_arena, zpl_isize size); +ZPL_DEF_INLINE zpl_allocation_header_ev *zpl_allocation_header(void *data); +ZPL_DEF_INLINE void zpl_allocation_header_fill(zpl_allocation_header_ev *header, void *data, zpl_isize size); - //! Release the memory used by memory arena. - ZPL_DEF_INLINE void zpl_arena_free(zpl_arena *arena); +#if defined(ZPL_ARCH_32_BIT) +#define ZPL_ISIZE_HIGH_BIT 0x80000000 +#elif defined(ZPL_ARCH_64_BIT) +#define ZPL_ISIZE_HIGH_BIT 0x8000000000000000ll +#else +#error +#endif +// +// Scratch Memory Allocator - Ring Buffer Based Arena +// - //! Retrieve memory arena's aligned allocation address. - ZPL_DEF_INLINE zpl_isize zpl_arena_alignment_of(zpl_arena *arena, zpl_isize alignment); - //! Retrieve memory arena's remaining size. - ZPL_DEF_INLINE zpl_isize zpl_arena_size_remaining(zpl_arena *arena, zpl_isize alignment); +typedef struct zpl_scratch_memory { + void *physical_start; + zpl_isize total_size; + void *alloc_point; + void *free_point; +} zpl_scratch_memory; - //! Check whether memory arena has any temporary snapshots. - ZPL_DEF_INLINE void zpl_arena_check(zpl_arena *arena); +//! Initialize ring buffer arena. +ZPL_DEF void zpl_scratch_memory_init(zpl_scratch_memory *s, void *start, zpl_isize size); - //! Allocation Types: alloc, free_all, resize - ZPL_DEF_INLINE zpl_allocator zpl_arena_allocator(zpl_arena *arena); - ZPL_DEF ZPL_ALLOCATOR_PROC(zpl_arena_allocator_proc); +//! Check whether ring buffer arena is in use. +ZPL_DEF zpl_b32 zpl_scratch_memory_is_in_use(zpl_scratch_memory *s, void *ptr); +//! Allocation Types: alloc, free, free_all, resize +ZPL_DEF zpl_allocator zpl_scratch_allocator(zpl_scratch_memory *s); +ZPL_DEF ZPL_ALLOCATOR_PROC(zpl_scratch_allocator_proc); - typedef struct zpl_arena_snapshot { - zpl_arena *arena; - zpl_isize original_count; - } zpl_arena_snapshot; +// +// Stack Memory Allocator +// - //! Capture a snapshot of used memory in a memory arena. - ZPL_DEF_INLINE zpl_arena_snapshot zpl_arena_snapshot_begin(zpl_arena *arena); - //! Reset memory arena's usage by a captured snapshot. - ZPL_DEF_INLINE void zpl_arena_snapshot_end(zpl_arena_snapshot tmp_mem); +typedef struct zpl_stack_memory { + zpl_allocator backing; + + void *physical_start; + zpl_usize total_size; + zpl_usize allocated; +} zpl_stack_memory; - // - // Pool Allocator - // +//! Initialize stack allocator from existing memory. +ZPL_DEF_INLINE void zpl_stack_memory_init_from_memory(zpl_stack_memory *s, void *start, zpl_isize size); - - typedef struct zpl_pool { - zpl_allocator backing; - void *physical_start; - void *free_list; - zpl_isize block_size; - zpl_isize block_align; - zpl_isize total_size; - zpl_isize num_blocks; - } zpl_pool; - - - //! Initialize pool allocator. - ZPL_DEF_INLINE void zpl_pool_init(zpl_pool *pool, zpl_allocator backing, zpl_isize num_blocks, zpl_isize block_size); - - //! Initialize pool allocator with specific block alignment. - ZPL_DEF void zpl_pool_init_align(zpl_pool *pool, zpl_allocator backing, zpl_isize num_blocks, zpl_isize block_size, - zpl_isize block_align); - - //! Release the resources used by pool allocator. - ZPL_DEF_INLINE void zpl_pool_free(zpl_pool *pool); - - //! Allocation Types: alloc, free - ZPL_DEF_INLINE zpl_allocator zpl_pool_allocator(zpl_pool *pool); - ZPL_DEF ZPL_ALLOCATOR_PROC(zpl_pool_allocator_proc); - - - typedef struct zpl_allocation_header_ev { - zpl_isize size; - } zpl_allocation_header_ev; - - ZPL_DEF_INLINE zpl_allocation_header_ev *zpl_allocation_header(void *data); - ZPL_DEF_INLINE void zpl_allocation_header_fill(zpl_allocation_header_ev *header, void *data, zpl_isize size); - - #if defined(ZPL_ARCH_32_BIT) - #define ZPL_ISIZE_HIGH_BIT 0x80000000 - #elif defined(ZPL_ARCH_64_BIT) - #define ZPL_ISIZE_HIGH_BIT 0x8000000000000000ll - #else - #error - #endif - - // - // Scratch Memory Allocator - Ring Buffer Based Arena - // - - - typedef struct zpl_scratch_memory { - void *physical_start; - zpl_isize total_size; - void *alloc_point; - void *free_point; - } zpl_scratch_memory; - - //! Initialize ring buffer arena. - ZPL_DEF void zpl_scratch_memory_init(zpl_scratch_memory *s, void *start, zpl_isize size); - - //! Check whether ring buffer arena is in use. - ZPL_DEF zpl_b32 zpl_scratch_memory_is_in_use(zpl_scratch_memory *s, void *ptr); - - //! Allocation Types: alloc, free, free_all, resize - ZPL_DEF zpl_allocator zpl_scratch_allocator(zpl_scratch_memory *s); - ZPL_DEF ZPL_ALLOCATOR_PROC(zpl_scratch_allocator_proc); - - // - // Stack Memory Allocator - // - - - typedef struct zpl_stack_memory { - zpl_allocator backing; - - void *physical_start; - zpl_usize total_size; - zpl_usize allocated; - } zpl_stack_memory; - - //! Initialize stack allocator from existing memory. - ZPL_DEF_INLINE void zpl_stack_memory_init_from_memory(zpl_stack_memory *s, void *start, zpl_isize size); - - //! Initialize stack allocator using existing memory allocator. - ZPL_DEF_INLINE void zpl_stack_memory_init(zpl_stack_memory *s, zpl_allocator backing, zpl_isize size); - - //! Check whether stack allocator is in use. - ZPL_DEF_INLINE zpl_b32 zpl_stack_memory_is_in_use(zpl_stack_memory *s, void *ptr); - - //! Release the resources used by stack allocator. - ZPL_DEF_INLINE void zpl_stack_memory_free(zpl_stack_memory *s); - - //! Allocation Types: alloc, free, free_all - ZPL_DEF_INLINE zpl_allocator zpl_stack_allocator(zpl_stack_memory *s); - ZPL_DEF ZPL_ALLOCATOR_PROC(zpl_stack_allocator_proc); - - // TODO: Fixed heap allocator - // TODO: General heap allocator. Maybe a TCMalloc like clone? - - - /* inlines */ - - ZPL_IMPL_INLINE void *zpl_alloc_align(zpl_allocator a, zpl_isize size, zpl_isize alignment) { - return a.proc(a.data, ZPL_ALLOCATION_ALLOC, size, alignment, NULL, 0, ZPL_DEFAULT_ALLOCATOR_FLAGS); - } - ZPL_IMPL_INLINE void *zpl_alloc(zpl_allocator a, zpl_isize size) { - return zpl_alloc_align(a, size, ZPL_DEFAULT_MEMORY_ALIGNMENT); - } - ZPL_IMPL_INLINE void zpl_free(zpl_allocator a, void *ptr) { - if (ptr != NULL) a.proc(a.data, ZPL_ALLOCATION_FREE, 0, 0, ptr, 0, ZPL_DEFAULT_ALLOCATOR_FLAGS); - } - ZPL_IMPL_INLINE void zpl_free_all(zpl_allocator a) { - a.proc(a.data, ZPL_ALLOCATION_FREE_ALL, 0, 0, NULL, 0, ZPL_DEFAULT_ALLOCATOR_FLAGS); - } - ZPL_IMPL_INLINE void *zpl_resize(zpl_allocator a, void *ptr, zpl_isize old_size, zpl_isize new_size) { - return zpl_resize_align(a, ptr, old_size, new_size, ZPL_DEFAULT_MEMORY_ALIGNMENT); - } - ZPL_IMPL_INLINE void *zpl_resize_align(zpl_allocator a, void *ptr, zpl_isize old_size, zpl_isize new_size, zpl_isize alignment) { - return a.proc(a.data, ZPL_ALLOCATION_RESIZE, new_size, alignment, ptr, old_size, ZPL_DEFAULT_ALLOCATOR_FLAGS); - } - - ZPL_IMPL_INLINE void *zpl_alloc_copy(zpl_allocator a, void const *src, zpl_isize size) { - return zpl_memcopy(zpl_alloc(a, size), src, size); - } - ZPL_IMPL_INLINE void *zpl_alloc_copy_align(zpl_allocator a, void const *src, zpl_isize size, zpl_isize alignment) { - return zpl_memcopy(zpl_alloc_align(a, size, alignment), src, size); - } - - ZPL_IMPL_INLINE char *zpl_alloc_str_len(zpl_allocator a, char const *str, zpl_isize len) { - char *result; - result = cast(char *) zpl_alloc(a, len + 1); - zpl_memmove(result, str, len); - result[len] = '\0'; - return result; - } - - ZPL_IMPL_INLINE void *zpl_default_resize_align(zpl_allocator a, void *old_memory, zpl_isize old_size, zpl_isize new_size, +//! Initialize stack allocator using existing memory allocator. +ZPL_DEF_INLINE void zpl_stack_memory_init(zpl_stack_memory *s, zpl_allocator backing, zpl_isize size); + +//! Check whether stack allocator is in use. +ZPL_DEF_INLINE zpl_b32 zpl_stack_memory_is_in_use(zpl_stack_memory *s, void *ptr); + +//! Release the resources used by stack allocator. +ZPL_DEF_INLINE void zpl_stack_memory_free(zpl_stack_memory *s); + +//! Allocation Types: alloc, free, free_all +ZPL_DEF_INLINE zpl_allocator zpl_stack_allocator(zpl_stack_memory *s); +ZPL_DEF ZPL_ALLOCATOR_PROC(zpl_stack_allocator_proc); + +// TODO: Fixed heap allocator +// TODO: General heap allocator. Maybe a TCMalloc like clone? + + +/* inlines */ + +ZPL_IMPL_INLINE void *zpl_alloc_align(zpl_allocator a, zpl_isize size, zpl_isize alignment) { + return a.proc(a.data, ZPL_ALLOCATION_ALLOC, size, alignment, NULL, 0, ZPL_DEFAULT_ALLOCATOR_FLAGS); +} +ZPL_IMPL_INLINE void *zpl_alloc(zpl_allocator a, zpl_isize size) { + return zpl_alloc_align(a, size, ZPL_DEFAULT_MEMORY_ALIGNMENT); +} +ZPL_IMPL_INLINE void zpl_free(zpl_allocator a, void *ptr) { + if (ptr != NULL) a.proc(a.data, ZPL_ALLOCATION_FREE, 0, 0, ptr, 0, ZPL_DEFAULT_ALLOCATOR_FLAGS); +} +ZPL_IMPL_INLINE void zpl_free_all(zpl_allocator a) { + a.proc(a.data, ZPL_ALLOCATION_FREE_ALL, 0, 0, NULL, 0, ZPL_DEFAULT_ALLOCATOR_FLAGS); +} +ZPL_IMPL_INLINE void *zpl_resize(zpl_allocator a, void *ptr, zpl_isize old_size, zpl_isize new_size) { + return zpl_resize_align(a, ptr, old_size, new_size, ZPL_DEFAULT_MEMORY_ALIGNMENT); +} +ZPL_IMPL_INLINE void *zpl_resize_align(zpl_allocator a, void *ptr, zpl_isize old_size, zpl_isize new_size, zpl_isize alignment) { + return a.proc(a.data, ZPL_ALLOCATION_RESIZE, new_size, alignment, ptr, old_size, ZPL_DEFAULT_ALLOCATOR_FLAGS); +} + +ZPL_IMPL_INLINE void *zpl_alloc_copy(zpl_allocator a, void const *src, zpl_isize size) { + return zpl_memcopy(zpl_alloc(a, size), src, size); +} +ZPL_IMPL_INLINE void *zpl_alloc_copy_align(zpl_allocator a, void const *src, zpl_isize size, zpl_isize alignment) { + return zpl_memcopy(zpl_alloc_align(a, size, alignment), src, size); +} + +ZPL_IMPL_INLINE char *zpl_alloc_str_len(zpl_allocator a, char const *str, zpl_isize len) { + char *result; + result = cast(char *) zpl_alloc(a, len + 1); + zpl_memmove(result, str, len); + result[len] = '\0'; + return result; +} + +ZPL_IMPL_INLINE void *zpl_default_resize_align(zpl_allocator a, void *old_memory, zpl_isize old_size, zpl_isize new_size, zpl_isize alignment) { - if (!old_memory) return zpl_alloc_align(a, new_size, alignment); - - if (new_size == 0) { - zpl_free(a, old_memory); - return NULL; - } - - if (new_size < old_size) new_size = old_size; - - if (old_size == new_size) { - return old_memory; - } else { - void *new_memory = zpl_alloc_align(a, new_size, alignment); - if (!new_memory) return NULL; - zpl_memmove(new_memory, old_memory, zpl_min(new_size, old_size)); - zpl_free(a, old_memory); - return new_memory; - } - } - - - // - // Heap Allocator - // - - ZPL_IMPL_INLINE zpl_allocator zpl_heap_allocator(void) { - zpl_allocator a; - a.proc = zpl_heap_allocator_proc; - a.data = NULL; - return a; - } - - // - // Arena Allocator - // - - ZPL_IMPL_INLINE void zpl_arena_init_from_memory(zpl_arena *arena, void *start, zpl_isize size) { - arena->backing.proc = NULL; - arena->backing.data = NULL; - arena->physical_start = start; - arena->total_size = size; - arena->total_allocated = 0; - arena->temp_count = 0; - } - - ZPL_IMPL_INLINE void zpl_arena_init_from_allocator(zpl_arena *arena, zpl_allocator backing, zpl_isize size) { - arena->backing = backing; - arena->physical_start = zpl_alloc(backing, size); // NOTE: Uses default alignment - arena->total_size = size; - arena->total_allocated = 0; - arena->temp_count = 0; - } - - ZPL_IMPL_INLINE void zpl_arena_init_sub(zpl_arena *arena, zpl_arena *parent_arena, zpl_isize size) { - zpl_arena_init_from_allocator(arena, zpl_arena_allocator(parent_arena), size); - } - - ZPL_IMPL_INLINE void zpl_arena_free(zpl_arena *arena) { - if (arena->backing.proc) { - zpl_free(arena->backing, arena->physical_start); - arena->physical_start = NULL; - } - } - - ZPL_IMPL_INLINE zpl_isize zpl_arena_alignment_of(zpl_arena *arena, zpl_isize alignment) { - zpl_isize alignment_offset, result_pointer, mask; - ZPL_ASSERT(zpl_is_power_of_two(alignment)); - - alignment_offset = 0; - result_pointer = cast(zpl_isize) arena->physical_start + arena->total_allocated; - mask = alignment - 1; - if (result_pointer & mask) alignment_offset = alignment - (result_pointer & mask); - - return alignment_offset; - } - - ZPL_IMPL_INLINE zpl_isize zpl_arena_size_remaining(zpl_arena *arena, zpl_isize alignment) { - zpl_isize result = arena->total_size - (arena->total_allocated + zpl_arena_alignment_of(arena, alignment)); - return result; - } - - ZPL_IMPL_INLINE void zpl_arena_check(zpl_arena *arena) { ZPL_ASSERT(arena->temp_count == 0); } - - ZPL_IMPL_INLINE zpl_allocator zpl_arena_allocator(zpl_arena *arena) { - zpl_allocator allocator; - allocator.proc = zpl_arena_allocator_proc; - allocator.data = arena; - return allocator; - } - - ZPL_IMPL_INLINE zpl_arena_snapshot zpl_arena_snapshot_begin(zpl_arena *arena) { - zpl_arena_snapshot tmp; - tmp.arena = arena; - tmp.original_count = arena->total_allocated; - arena->temp_count++; - return tmp; - } - - ZPL_IMPL_INLINE void zpl_arena_snapshot_end(zpl_arena_snapshot tmp) { - ZPL_ASSERT(tmp.arena->total_allocated >= tmp.original_count); - ZPL_ASSERT(tmp.arena->temp_count > 0); - tmp.arena->total_allocated = tmp.original_count; - tmp.arena->temp_count--; - } - - // - // Pool Allocator - // - - ZPL_IMPL_INLINE void zpl_pool_init(zpl_pool *pool, zpl_allocator backing, zpl_isize num_blocks, zpl_isize block_size) { - zpl_pool_init_align(pool, backing, num_blocks, block_size, ZPL_DEFAULT_MEMORY_ALIGNMENT); - } - - ZPL_IMPL_INLINE void zpl_pool_free(zpl_pool *pool) { - if (pool->backing.proc) { zpl_free(pool->backing, pool->physical_start); } - } - - ZPL_IMPL_INLINE zpl_allocator zpl_pool_allocator(zpl_pool *pool) { - zpl_allocator allocator; - allocator.proc = zpl_pool_allocator_proc; - allocator.data = pool; - return allocator; - } - - ZPL_IMPL_INLINE zpl_allocation_header_ev *zpl_allocation_header(void *data) { - zpl_isize *p = cast(zpl_isize *) data; - while (p[-1] == cast(zpl_isize)(-1)) p--; - return cast(zpl_allocation_header_ev *) p - 1; - } - - ZPL_IMPL_INLINE void zpl_allocation_header_fill(zpl_allocation_header_ev *header, void *data, zpl_isize size) { - zpl_isize *ptr; - header->size = size; - ptr = cast(zpl_isize *)(header + 1); - while (cast(void *) ptr < data) *ptr++ = cast(zpl_isize)(-1); - } - - // - // Stack Memory Allocator - // - - #define ZPL_STACK_ALLOC_OFFSET sizeof(zpl_u64) - ZPL_STATIC_ASSERT(ZPL_STACK_ALLOC_OFFSET == 8, "ZPL_STACK_ALLOC_OFFSET != 8"); - - ZPL_IMPL_INLINE void zpl_stack_memory_init_from_memory(zpl_stack_memory *s, void *start, zpl_isize size) { - s->physical_start = start; - s->total_size = size; - s->allocated = 0; - } - - ZPL_IMPL_INLINE void zpl_stack_memory_init(zpl_stack_memory *s, zpl_allocator backing, zpl_isize size) { - s->backing = backing; - s->physical_start = zpl_alloc(backing, size); - s->total_size = size; - s->allocated = 0; - } - - ZPL_IMPL_INLINE zpl_b32 zpl_stack_memory_is_in_use(zpl_stack_memory *s, void *ptr) { - if (s->allocated == 0) return false; - - if (ptr > s->physical_start && ptr < zpl_pointer_add(s->physical_start, s->total_size)) { return true; } - - return false; - } - - ZPL_IMPL_INLINE void zpl_stack_memory_free(zpl_stack_memory *s) { - if (s->backing.proc) { - zpl_free(s->backing, s->physical_start); - s->physical_start = NULL; - } - } - - ZPL_IMPL_INLINE zpl_allocator zpl_stack_allocator(zpl_stack_memory *s) { - zpl_allocator a; - a.proc = zpl_stack_allocator_proc; - a.data = s; - return a; - } - - ZPL_END_C_DECLS - // file: header/essentials/collections/array.h - - //////////////////////////////////////////////////////////////// - // - // Dynamic Array (POD Types) - // - // zpl_array(Type) works like zpl_string or zpl_buffer where the actual type is just a pointer to the first - // element. - // - // Available Procedures for zpl_array(Type) - // zpl_array_init - // zpl_array_free - // zpl_array_set_capacity - // zpl_array_grow - // zpl_array_append - // zpl_array_appendv - // zpl_array_pop - // zpl_array_clear - // zpl_array_back - // zpl_array_front - // zpl_array_resize - // zpl_array_reserve - // - - #if 0 // Example - void foo(void) { - zpl_isize i; - int test_values[] = {4, 2, 1, 7}; - zpl_allocator a = zpl_heap_allocator(); - zpl_array(int) items; - - zpl_array_init(items, a); - - zpl_array_append(items, 1); - zpl_array_append(items, 4); - zpl_array_append(items, 9); - zpl_array_append(items, 16); - - items[1] = 3; // Manually set value - // NOTE: No array bounds checking - - for (i = 0; i < items.count; i++) - zpl_printf("%d\n", items[i]); - // 1 - // 3 - // 9 - // 16 - - zpl_array_clear(items); - - zpl_array_appendv(items, test_values, zpl_count_of(test_values)); - for (i = 0; i < items.count; i++) - zpl_printf("%d\n", items[i]); - // 4 - // 2 - // 1 - // 7 - - zpl_array_free(items); - } - #endif - - - ZPL_BEGIN_C_DECLS - - typedef struct zpl_array_header { - char *data; - zpl_isize count; - zpl_isize capacity; - zpl_allocator allocator; - } zpl_array_header; - - #define zpl_array(Type) Type * - - #define zpl_array_make(Type, Name, allocator) Type *Name; zpl_array_init(Name, allocator) - - #ifndef ZPL_ARRAY_GROW_FORMULA - #define ZPL_ARRAY_GROW_FORMULA(x) (2 * (x) + 8) - #endif - - ZPL_STATIC_ASSERT(ZPL_ARRAY_GROW_FORMULA(0) > 0, "ZPL_ARRAY_GROW_FORMULA(0) <= 0"); - - #define ZPL_ARRAY_HEADER(x) (cast(zpl_array_header *)(x) - 1) - #define zpl_array_allocator(x) (ZPL_ARRAY_HEADER(x)->allocator) - #define zpl_array_count(x) (ZPL_ARRAY_HEADER(x)->count) - #define zpl_array_capacity(x) (ZPL_ARRAY_HEADER(x)->capacity) - #define zpl_array_end(x) (x + (zpl_array_count(x) - 1)) - - #define zpl_array_init_reserve(x, allocator_, cap) \ - do { \ - void **zpl__array_ = cast(void **) & (x); \ - zpl_array_header *zpl__ah = \ - cast(zpl_array_header *) zpl_alloc(allocator_, zpl_size_of(zpl_array_header) + zpl_size_of(*(x)) * (cap)); \ - zpl__ah->allocator = allocator_; \ - zpl__ah->count = 0; \ - zpl__ah->data = (char *)x; \ - zpl__ah->capacity = cap; \ - *zpl__array_ = cast(void *)(zpl__ah + 1); \ - } while (0) - - // NOTE: Give it an initial default capacity - #define zpl_array_init(x, allocator) zpl_array_init_reserve(x, allocator, ZPL_ARRAY_GROW_FORMULA(0)) - - #define zpl_array_free(x) \ - do { \ - zpl_array_header *zpl__ah = ZPL_ARRAY_HEADER(x); \ - zpl_free(zpl__ah->allocator, zpl__ah); \ - } while (0) - - #define zpl_array_set_capacity(x, capacity) \ - do { \ - if (x) { \ - void **zpl__array_ = cast(void **) & (x); \ - *zpl__array_ = zpl__array_set_capacity((x), (capacity), zpl_size_of(*(x))); \ - } \ - } while (0) - - // NOTE: Do not use the thing below directly, use the macro - ZPL_DEF void *zpl__array_set_capacity(void *array, zpl_isize capacity, zpl_isize element_size); - - #define zpl_array_grow(x, min_capacity) \ - do { \ - zpl_isize new_capacity = ZPL_ARRAY_GROW_FORMULA(zpl_array_capacity(x)); \ - if (new_capacity < (min_capacity)) new_capacity = (min_capacity); \ - zpl_array_set_capacity(x, new_capacity); \ - } while (0) - - #define zpl_array_append(x, item) \ - do { \ - if (zpl_array_capacity(x) < zpl_array_count(x) + 1) zpl_array_grow(x, 0); \ - (x)[zpl_array_count(x)++] = (item); \ - } while (0) - - #define zpl_array_append_at(x, item, ind) \ - do { \ - zpl_array_header *zpl__ah = ZPL_ARRAY_HEADER(x); \ - if (ind >= zpl__ah->count) { zpl_array_append(x, item); break; } \ - if (zpl_array_capacity(x) < zpl_array_count(x) + 1) zpl_array_grow(x, 0); \ - zpl_memmove(&(x)[ind + 1], (x + ind), zpl_size_of(x[0]) * (zpl__ah->count - ind)); \ - x[ind] = item; \ - zpl__ah->count++; \ - } while (0) - - #define zpl_array_appendv(x, items, item_count) \ - do { \ - zpl_array_header *zpl__ah = ZPL_ARRAY_HEADER(x); \ - ZPL_ASSERT(zpl_size_of((items)[0]) == zpl_size_of((x)[0])); \ - if (zpl__ah->capacity < zpl__ah->count + (item_count)) zpl_array_grow(x, zpl__ah->count + (item_count)); \ - zpl_memcopy(&(x)[zpl__ah->count], (items), zpl_size_of((x)[0]) * (item_count)); \ - zpl__ah->count += (item_count); \ - } while (0) - - #define zpl_array_appendv_at(x, items, item_count, ind) \ - do { \ - zpl_array_header *zpl__ah = ZPL_ARRAY_HEADER(x); \ - if (ind >= zpl__ah->count) { zpl_array_appendv(x, items, item_count); break; } \ - ZPL_ASSERT(zpl_size_of((items)[0]) == zpl_size_of((x)[0])); \ - if (zpl__ah->capacity < zpl__ah->count + (item_count)) zpl_array_grow(x, zpl__ah->count + (item_count)); \ - zpl_memmove(x + ind + (item_count), x + ind, zpl_size_of((x)[0]) * zpl__ah->count); \ - zpl_memcopy(&(x)[ind], (items), zpl_size_of((x)[0]) * (item_count)); \ - zpl__ah->count += (item_count); \ - } while (0) - - #define zpl_array_fill(x, begin, end, value) \ - do { \ - zpl_array_header *zpl__ah = ZPL_ARRAY_HEADER(x); \ - ZPL_ASSERT((begin) >= 0 && (end) < zpl__ah->count); \ - ZPL_ASSERT(zpl_size_of(value) == zpl_size_of((x)[0])); \ - for (zpl_isize i = (begin); i < (end); i++) { x[i] = value; } \ - } while (0) - - #define zpl_array_remove_at(x, index) \ - do { \ - zpl_array_header *zpl__ah = ZPL_ARRAY_HEADER(x); \ - ZPL_ASSERT(index < zpl__ah->count); \ - zpl_memmove(x + index, x + index + 1, zpl_size_of(x[0]) * (zpl__ah->count - index - 1)); \ - --zpl__ah->count; \ - } while (0) - - #define zpl_array_copy_init(y, x) \ - do { \ - zpl_array_init_reserve(y, zpl_array_allocator(x), zpl_array_capacity(x)); \ - zpl_memcopy(y, x, zpl_array_capacity(x) * zpl_size_of(*x)); \ - zpl_array_count(y) = zpl_array_count(x); \ - } while (0) - - #define zpl_array_pop(x) \ - do { \ - ZPL_ASSERT(ZPL_ARRAY_HEADER(x)->count > 0); \ - ZPL_ARRAY_HEADER(x)->count--; \ - } while (0) - #define zpl_array_back(x) x[ZPL_ARRAY_HEADER(x)->count - 1] - #define zpl_array_front(x) x[0] - #define zpl_array_clear(x) \ - do { ZPL_ARRAY_HEADER(x)->count = 0; } while (0) - - #define zpl_array_resize(x, new_count) \ - do { \ - if (ZPL_ARRAY_HEADER(x)->capacity < (new_count)) zpl_array_grow(x, (new_count)); \ - ZPL_ARRAY_HEADER(x)->count = (new_count); \ - } while (0) - - #define zpl_array_reserve(x, new_capacity) \ - do { \ - if (ZPL_ARRAY_HEADER(x)->capacity < (new_capacity)) zpl_array_set_capacity(x, new_capacity); \ - } while (0) - - ZPL_END_C_DECLS - // file: header/essentials/collections/buffer.h - - //////////////////////////////////////////////////////////////// - // - // Fixed Capacity Buffer (POD Types) - // - // - // zpl_buffer(Type) works like zpl_string or zpl_array where the actual type is just a pointer to the first - // element. - // - // Available Procedures for zpl_buffer(Type) - // zpl_buffer_init - // zpl_buffer_free - // zpl_buffer_append - // zpl_buffer_appendv - // zpl_buffer_pop - // zpl_buffer_clear - - - ZPL_BEGIN_C_DECLS - - typedef struct zpl_buffer_header { - zpl_allocator backing; - zpl_isize count; - zpl_isize capacity; - } zpl_buffer_header; - - #define zpl_buffer(Type) Type * - - #define zpl_buffer_make(Type, Name, allocator, cap) Type *Name; zpl_buffer_init(Name, allocator, cap) - - #define ZPL_BUFFER_HEADER(x) (cast(zpl_buffer_header *)(x) - 1) - #define zpl_buffer_count(x) (ZPL_BUFFER_HEADER(x)->count) - #define zpl_buffer_capacity(x) (ZPL_BUFFER_HEADER(x)->capacity) - #define zpl_buffer_end(x) (x + (zpl_buffer_count(x) - 1)) - - #define zpl_buffer_init(x, allocator, cap) \ - do { \ - void **nx = cast(void **) & (x); \ - zpl_buffer_header *zpl__bh = \ - cast(zpl_buffer_header *) zpl_alloc((allocator), sizeof(zpl_buffer_header) + (cap)*zpl_size_of(*(x))); \ - zpl__bh->backing = allocator; \ - zpl__bh->count = 0; \ - zpl__bh->capacity = cap; \ - *nx = cast(void *)(zpl__bh + 1); \ - } while (0) - - #define zpl_buffer_free(x) (zpl_free(ZPL_BUFFER_HEADER(x)->backing, ZPL_BUFFER_HEADER(x))) - - #define zpl_buffer_append(x, item) \ - do { (x)[zpl_buffer_count(x)++] = (item); } while (0) - - #define zpl_buffer_appendv(x, items, item_count) \ - do { \ - ZPL_ASSERT(zpl_size_of(*(items)) == zpl_size_of(*(x))); \ - ZPL_ASSERT(zpl_buffer_count(x) + item_count <= zpl_buffer_capacity(x)); \ - zpl_memcopy(&(x)[zpl_buffer_count(x)], (items), zpl_size_of(*(x)) * (item_count)); \ - zpl_buffer_count(x) += (item_count); \ - } while (0) - - #define zpl_buffer_copy_init(y, x) \ - do { \ - zpl_buffer_init_reserve(y, zpl_buffer_allocator(x), zpl_buffer_capacity(x)); \ - zpl_memcopy(y, x, zpl_buffer_capacity(x) * zpl_size_of(*x)); \ - zpl_buffer_count(y) = zpl_buffer_count(x); \ - } while (0) - - #define zpl_buffer_pop(x) \ - do { \ - ZPL_ASSERT(zpl_buffer_count(x) > 0); \ - zpl_buffer_count(x)--; \ - } while (0) - #define zpl_buffer_clear(x) \ - do { zpl_buffer_count(x) = 0; } while (0) - - ZPL_END_C_DECLS - // file: header/essentials/collections/list.h - - //////////////////////////////////////////////////////////////// - // - // Linked List - // - // zpl_list encapsulates pointer to data and points to the next and the previous element in the list. - // - // Available Procedures for zpl_list - // zpl_list_init - // zpl_list_add - // zpl_list_remove - - - ZPL_BEGIN_C_DECLS - - #if 0 - #define ZPL_IMPLEMENTATION - #include "zpl.h" - int main(void) - { - zpl_list s, *head, *cursor; - zpl_list_init(&s, "it is optional to call init: "); - head = cursor = &s; - - // since we can construct an element implicitly this way - // the second field gets overwritten once we add it to a list. - zpl_list a = {"hello"}; - cursor = zpl_list_add(cursor, &a); - - zpl_list b = {"world"}; - cursor = zpl_list_add(cursor, &b); - - zpl_list c = {"!!! OK"}; - cursor = zpl_list_add(cursor, &c); - - for (zpl_list *l=head; l; l=l->next) { - zpl_printf("%s ", cast(char *)l->ptr); - } - zpl_printf("\n"); - - return 0; - } - #endif - - - typedef struct zpl__list { - void const *ptr; - struct zpl__list *next, *prev; - } zpl_list; - - ZPL_DEF_INLINE void zpl_list_init(zpl_list *list, void const *ptr); - ZPL_DEF_INLINE zpl_list *zpl_list_add(zpl_list *list, zpl_list *item); - - // NOTE(zaklaus): Returns a pointer to the next node (or NULL if the removed node has no trailing node.) - ZPL_DEF_INLINE zpl_list *zpl_list_remove(zpl_list *list); - - - ZPL_IMPL_INLINE void zpl_list_init(zpl_list *list, void const *ptr) { - zpl_list list_ = { 0 }; - *list = list_; - list->ptr = ptr; - } - - ZPL_IMPL_INLINE zpl_list *zpl_list_add(zpl_list *list, zpl_list *item) { - item->next = NULL; - - if (list->next) { item->next = list->next; } - - list->next = item; - item->prev = list; - return item; - } - - ZPL_IMPL_INLINE zpl_list *zpl_list_remove(zpl_list *list) { - if (list->prev) { list->prev->next = list->next; } - - return list->next; - } - - ZPL_END_C_DECLS - // file: header/essentials/collections/ring.h - - //////////////////////////////////////////////////////////////// - // - // Instantiated Circular buffer - // - - - ZPL_BEGIN_C_DECLS - - #define ZPL_RING_DECLARE(prefix,type) \ - typedef struct { \ - zpl_allocator backing; \ - zpl_buffer(type) buf; \ - zpl_usize head, tail; \ - zpl_usize capacity; \ - } ZPL_JOIN2(prefix, type); \ - \ - ZPL_DEF void ZPL_JOIN2(prefix, init)(ZPL_JOIN2(prefix, type) * pad, zpl_allocator a, zpl_isize max_size); \ - ZPL_DEF void ZPL_JOIN2(prefix, free)(ZPL_JOIN2(prefix, type) * pad); \ - ZPL_DEF zpl_b32 ZPL_JOIN2(prefix, full)(ZPL_JOIN2(prefix, type) * pad); \ - ZPL_DEF zpl_b32 ZPL_JOIN2(prefix, empty)(ZPL_JOIN2(prefix, type) * pad); \ - ZPL_DEF void ZPL_JOIN2(prefix, append)(ZPL_JOIN2(prefix, type) * pad, type data); \ - ZPL_DEF void ZPL_JOIN2(prefix, append_array)(ZPL_JOIN2(prefix, type) * pad, zpl_array(type) data); \ - ZPL_DEF type *ZPL_JOIN2(prefix, get)(ZPL_JOIN2(prefix, type) * pad); \ - ZPL_DEF zpl_array(type) \ - ZPL_JOIN2(prefix, get_array)(ZPL_JOIN2(prefix, type) * pad, zpl_usize max_size, zpl_allocator a); - - #define ZPL_RING_DEFINE(prefix,type) \ - void ZPL_JOIN2(prefix, init)(ZPL_JOIN2(prefix, type) * pad, zpl_allocator a, zpl_isize max_size) { \ - ZPL_JOIN2(prefix, type) pad_ = { 0 }; \ - *pad = pad_; \ - \ - pad->backing = a; \ - zpl_buffer_init(pad->buf, a, max_size + 1); \ - pad->capacity = max_size + 1; \ - pad->head = pad->tail = 0; \ - } \ - void ZPL_JOIN2(prefix, free)(ZPL_JOIN2(prefix, type) * pad) { \ - zpl_buffer_free(pad->buf); \ - } \ - \ - zpl_b32 ZPL_JOIN2(prefix, full)(ZPL_JOIN2(prefix, type) * pad) { \ - return ((pad->head + 1) % pad->capacity) == pad->tail; \ - } \ - \ - zpl_b32 ZPL_JOIN2(prefix, empty)(ZPL_JOIN2(prefix, type) * pad) { return pad->head == pad->tail; } \ - \ - void ZPL_JOIN2(prefix, append)(ZPL_JOIN2(prefix, type) * pad, type data) { \ - pad->buf[pad->head] = data; \ - pad->head = (pad->head + 1) % pad->capacity; \ - \ - if (pad->head == pad->tail) { pad->tail = (pad->tail + 1) % pad->capacity; } \ - } \ - \ - void ZPL_JOIN2(prefix, append_array)(ZPL_JOIN2(prefix, type) * pad, zpl_array(type) data) { \ - zpl_usize c = zpl_array_count(data); \ - for (zpl_usize i = 0; i < c; ++i) { ZPL_JOIN2(prefix, append)(pad, data[i]); } \ - } \ - \ - type *ZPL_JOIN2(prefix, get)(ZPL_JOIN2(prefix, type) * pad) { \ - if (ZPL_JOIN2(prefix, empty)(pad)) { return NULL; } \ - \ - type *data = &pad->buf[pad->tail]; \ - pad->tail = (pad->tail + 1) % pad->capacity; \ - \ - return data; \ - } \ - \ - zpl_array(type) \ - ZPL_JOIN2(prefix, get_array)(ZPL_JOIN2(prefix, type) * pad, zpl_usize max_size, zpl_allocator a) { \ - zpl_array(type) vals = 0; \ - zpl_array_init(vals, a); \ - while (--max_size && !ZPL_JOIN2(prefix, empty)(pad)) { \ - zpl_array_append(vals, *ZPL_JOIN2(prefix, get)(pad)); \ - } \ - return vals; \ - } - - ZPL_END_C_DECLS - // file: header/essentials/collections/hashtable.h - - /** @file hashtable.c - @brief Instantiated hash table - @defgroup hashtable Instantiated hash table - - @n - @n This is an attempt to implement a templated hash table - @n NOTE: The key is always a zpl_u64 for simplicity and you will _probably_ _never_ need anything bigger. - @n - @n Hash table type and function declaration, call: ZPL_TABLE_DECLARE(PREFIX, NAME, N, VALUE) - @n Hash table function definitions, call: ZPL_TABLE_DEFINE(NAME, N, VALUE) - @n - @n PREFIX - a prefix for function prototypes e.g. extern, static, etc. - @n NAME - Name of the Hash Table - @n FUNC - the name will prefix function names - @n VALUE - the type of the value to be stored - @n - @n tablename_init(NAME * h, zpl_allocator a); - @n tablename_destroy(NAME * h); - @n tablename_get(NAME * h, zpl_u64 key); - @n tablename_set(NAME * h, zpl_u64 key, VALUE value); - @n tablename_grow(NAME * h); - @n tablename_rehash(NAME * h, zpl_isize new_count); - @n tablename_remove(NAME * h, zpl_u64 key); - - @{ - */ - - - ZPL_BEGIN_C_DECLS - - typedef struct zpl_hash_table_find_result { - zpl_isize hash_index; - zpl_isize entry_prev; - zpl_isize entry_index; - } zpl_hash_table_find_result; - - #define ZPL_TABLE(PREFIX, NAME, FUNC, VALUE) \ - ZPL_TABLE_DECLARE(PREFIX, NAME, FUNC, VALUE); \ - ZPL_TABLE_DEFINE(NAME, FUNC, VALUE); - - #define ZPL_TABLE_DECLARE(PREFIX, NAME, FUNC, VALUE) \ - typedef struct ZPL_JOIN2(NAME, Entry) { \ - zpl_u64 key; \ - zpl_isize next; \ - VALUE value; \ - } ZPL_JOIN2(NAME, Entry); \ - \ - typedef struct NAME { \ - zpl_array(zpl_isize) hashes; \ - zpl_array(ZPL_JOIN2(NAME, Entry)) entries; \ - } NAME; \ - \ - PREFIX void ZPL_JOIN2(FUNC, init)(NAME * h, zpl_allocator a); \ - PREFIX void ZPL_JOIN2(FUNC, destroy)(NAME * h); \ - PREFIX VALUE *ZPL_JOIN2(FUNC, get)(NAME * h, zpl_u64 key); \ - PREFIX void ZPL_JOIN2(FUNC, set)(NAME * h, zpl_u64 key, VALUE value); \ - PREFIX void ZPL_JOIN2(FUNC, grow)(NAME * h); \ - PREFIX void ZPL_JOIN2(FUNC, rehash)(NAME * h, zpl_isize new_count); \ - PREFIX void ZPL_JOIN2(FUNC, map)(NAME * h, void (*map_proc)(zpl_u64 key, VALUE value)); \ - PREFIX void ZPL_JOIN2(FUNC, map_mut)(NAME * h, void (*map_proc)(zpl_u64 key, VALUE * value)); \ - PREFIX void ZPL_JOIN2(FUNC, remove)(NAME * h, zpl_u64 key); - - #define ZPL_TABLE_DEFINE(NAME, FUNC, VALUE) \ - void ZPL_JOIN2(FUNC, init)(NAME * h, zpl_allocator a) { \ - zpl_array_init(h->hashes, a); \ - zpl_array_init(h->entries, a); \ - } \ - \ - void ZPL_JOIN2(FUNC, destroy)(NAME * h) { \ - if (h->entries) zpl_array_free(h->entries); \ - if (h->hashes) zpl_array_free(h->hashes); \ - } \ - \ - zpl_internal zpl_isize ZPL_JOIN2(FUNC, _add_entry)(NAME * h, zpl_u64 key) { \ - zpl_isize index; \ - ZPL_JOIN2(NAME, Entry) e = { 0 }; \ - e.key = key; \ - e.next = -1; \ - index = zpl_array_count(h->entries); \ - zpl_array_append(h->entries, e); \ - return index; \ - } \ - \ - zpl_internal zpl_hash_table_find_result ZPL_JOIN2(FUNC, _find)(NAME * h, zpl_u64 key) { \ - zpl_hash_table_find_result r = { -1, -1, -1 }; \ - if (zpl_array_count(h->hashes) > 0) { \ - r.hash_index = key % zpl_array_count(h->hashes); \ - r.entry_index = h->hashes[r.hash_index]; \ - while (r.entry_index >= 0) { \ - if (h->entries[r.entry_index].key == key) return r; \ - r.entry_prev = r.entry_index; \ - r.entry_index = h->entries[r.entry_index].next; \ - } \ - } \ - return r; \ - } \ - \ - zpl_internal zpl_b32 ZPL_JOIN2(FUNC, _full)(NAME * h) { \ - return 0.75f * zpl_array_count(h->hashes) < zpl_array_count(h->entries); \ - } \ - \ - void ZPL_JOIN2(FUNC, grow)(NAME * h) { \ - zpl_isize new_count = ZPL_ARRAY_GROW_FORMULA(zpl_array_count(h->entries)); \ - ZPL_JOIN2(FUNC, rehash)(h, new_count); \ - } \ - \ - void ZPL_JOIN2(FUNC, rehash)(NAME * h, zpl_isize new_count) { \ - zpl_isize i, j; \ - NAME nh = { 0 }; \ - ZPL_JOIN2(FUNC, init)(&nh, zpl_array_allocator(h->hashes)); \ - zpl_array_resize(nh.hashes, new_count); \ - zpl_array_reserve(nh.entries, zpl_array_count(h->entries)); \ - for (i = 0; i < new_count; i++) nh.hashes[i] = -1; \ - for (i = 0; i < zpl_array_count(h->entries); i++) { \ - ZPL_JOIN2(NAME, Entry) * e; \ - zpl_hash_table_find_result fr; \ - if (zpl_array_count(nh.hashes) == 0) ZPL_JOIN2(FUNC, grow)(&nh); \ - e = &h->entries[i]; \ - fr = ZPL_JOIN2(FUNC, _find)(&nh, e->key); \ - j = ZPL_JOIN2(FUNC, _add_entry)(&nh, e->key); \ - if (fr.entry_prev < 0) \ - nh.hashes[fr.hash_index] = j; \ - else \ - nh.entries[fr.entry_prev].next = j; \ - nh.entries[j].next = fr.entry_index; \ - nh.entries[j].value = e->value; \ - } \ - ZPL_JOIN2(FUNC, destroy)(h); \ - h->hashes = nh.hashes; \ - h->entries = nh.entries; \ - } \ - \ - VALUE *ZPL_JOIN2(FUNC, get)(NAME * h, zpl_u64 key) { \ - zpl_isize index = ZPL_JOIN2(FUNC, _find)(h, key).entry_index; \ - if (index >= 0) return &h->entries[index].value; \ - return NULL; \ - } \ - \ - void ZPL_JOIN2(FUNC, remove)(NAME * h, zpl_u64 key) { \ - zpl_hash_table_find_result fr = ZPL_JOIN2(FUNC, _find)(h, key); \ - if (fr.entry_index >= 0) { \ - if (fr.entry_prev >= 0) { \ - h->entries[fr.entry_prev].next = h->entries[fr.entry_index].next; \ - } else { \ - h->hashes[fr.hash_index] = fr.entry_index; \ - } \ - zpl_array_remove_at(h->entries, fr.entry_index); \ - } \ - ZPL_JOIN2(FUNC, rehash)(h, zpl_array_count(h->entries)); \ - } \ - \ - void ZPL_JOIN2(FUNC, map)(NAME * h, void (*map_proc)(zpl_u64 key, VALUE value)) { \ - ZPL_ASSERT_NOT_NULL(h); \ - ZPL_ASSERT_NOT_NULL(map_proc); \ - for (zpl_isize i = 0; i < zpl_array_count(h->entries); ++i) { \ - map_proc(h->entries[i].key, h->entries[i].value); \ - } \ - } \ - void ZPL_JOIN2(FUNC, map_mut)(NAME * h, void (*map_proc)(zpl_u64 key, VALUE * value)) { \ - ZPL_ASSERT_NOT_NULL(h); \ - ZPL_ASSERT_NOT_NULL(map_proc); \ - for (zpl_isize i = 0; i < zpl_array_count(h->entries); ++i) { \ - map_proc(h->entries[i].key, &h->entries[i].value); \ - } \ - } \ - \ - void ZPL_JOIN2(FUNC, set)(NAME * h, zpl_u64 key, VALUE value) { \ - zpl_isize index; \ - zpl_hash_table_find_result fr; \ - if (zpl_array_count(h->hashes) == 0) ZPL_JOIN2(FUNC, grow)(h); \ - fr = ZPL_JOIN2(FUNC, _find)(h, key); \ - if (fr.entry_index >= 0) { \ - index = fr.entry_index; \ - } else { \ - index = ZPL_JOIN2(FUNC, _add_entry)(h, key); \ - if (fr.entry_prev >= 0) { \ - h->entries[fr.entry_prev].next = index; \ - } else { \ - h->hashes[fr.hash_index] = index; \ - } \ - } \ - h->entries[index].value = value; \ - if (ZPL_JOIN2(FUNC, _full)(h)) ZPL_JOIN2(FUNC, grow)(h); \ - }\ - - //! @} - - ZPL_END_C_DECLS + if (!old_memory) return zpl_alloc_align(a, new_size, alignment); + + if (new_size == 0) { + zpl_free(a, old_memory); + return NULL; + } + + if (new_size < old_size) new_size = old_size; + + if (old_size == new_size) { + return old_memory; + } else { + void *new_memory = zpl_alloc_align(a, new_size, alignment); + if (!new_memory) return NULL; + zpl_memmove(new_memory, old_memory, zpl_min(new_size, old_size)); + zpl_free(a, old_memory); + return new_memory; + } +} + + +// +// Heap Allocator +// + +ZPL_IMPL_INLINE zpl_allocator zpl_heap_allocator(void) { + zpl_allocator a; + a.proc = zpl_heap_allocator_proc; + a.data = NULL; + return a; +} + +// +// Arena Allocator +// + +ZPL_IMPL_INLINE void zpl_arena_init_from_memory(zpl_arena *arena, void *start, zpl_isize size) { + arena->backing.proc = NULL; + arena->backing.data = NULL; + arena->physical_start = start; + arena->total_size = size; + arena->total_allocated = 0; + arena->temp_count = 0; +} + +ZPL_IMPL_INLINE void zpl_arena_init_from_allocator(zpl_arena *arena, zpl_allocator backing, zpl_isize size) { + arena->backing = backing; + arena->physical_start = zpl_alloc(backing, size); // NOTE: Uses default alignment + arena->total_size = size; + arena->total_allocated = 0; + arena->temp_count = 0; +} + +ZPL_IMPL_INLINE void zpl_arena_init_sub(zpl_arena *arena, zpl_arena *parent_arena, zpl_isize size) { + zpl_arena_init_from_allocator(arena, zpl_arena_allocator(parent_arena), size); +} + +ZPL_IMPL_INLINE void zpl_arena_free(zpl_arena *arena) { + if (arena->backing.proc) { + zpl_free(arena->backing, arena->physical_start); + arena->physical_start = NULL; + } +} + +ZPL_IMPL_INLINE zpl_isize zpl_arena_alignment_of(zpl_arena *arena, zpl_isize alignment) { + zpl_isize alignment_offset, result_pointer, mask; + ZPL_ASSERT(zpl_is_power_of_two(alignment)); + + alignment_offset = 0; + result_pointer = cast(zpl_isize) arena->physical_start + arena->total_allocated; + mask = alignment - 1; + if (result_pointer & mask) alignment_offset = alignment - (result_pointer & mask); + + return alignment_offset; +} + +ZPL_IMPL_INLINE zpl_isize zpl_arena_size_remaining(zpl_arena *arena, zpl_isize alignment) { + zpl_isize result = arena->total_size - (arena->total_allocated + zpl_arena_alignment_of(arena, alignment)); + return result; +} + +ZPL_IMPL_INLINE void zpl_arena_check(zpl_arena *arena) { ZPL_ASSERT(arena->temp_count == 0); } + +ZPL_IMPL_INLINE zpl_allocator zpl_arena_allocator(zpl_arena *arena) { + zpl_allocator allocator; + allocator.proc = zpl_arena_allocator_proc; + allocator.data = arena; + return allocator; +} + +ZPL_IMPL_INLINE zpl_arena_snapshot zpl_arena_snapshot_begin(zpl_arena *arena) { + zpl_arena_snapshot tmp; + tmp.arena = arena; + tmp.original_count = arena->total_allocated; + arena->temp_count++; + return tmp; +} + +ZPL_IMPL_INLINE void zpl_arena_snapshot_end(zpl_arena_snapshot tmp) { + ZPL_ASSERT(tmp.arena->total_allocated >= tmp.original_count); + ZPL_ASSERT(tmp.arena->temp_count > 0); + tmp.arena->total_allocated = tmp.original_count; + tmp.arena->temp_count--; +} + +// +// Pool Allocator +// + +ZPL_IMPL_INLINE void zpl_pool_init(zpl_pool *pool, zpl_allocator backing, zpl_isize num_blocks, zpl_isize block_size) { + zpl_pool_init_align(pool, backing, num_blocks, block_size, ZPL_DEFAULT_MEMORY_ALIGNMENT); +} + +ZPL_IMPL_INLINE void zpl_pool_free(zpl_pool *pool) { + if (pool->backing.proc) { zpl_free(pool->backing, pool->physical_start); } +} + +ZPL_IMPL_INLINE zpl_allocator zpl_pool_allocator(zpl_pool *pool) { + zpl_allocator allocator; + allocator.proc = zpl_pool_allocator_proc; + allocator.data = pool; + return allocator; +} + +ZPL_IMPL_INLINE zpl_allocation_header_ev *zpl_allocation_header(void *data) { + zpl_isize *p = cast(zpl_isize *) data; + while (p[-1] == cast(zpl_isize)(-1)) p--; + return cast(zpl_allocation_header_ev *) p - 1; +} + +ZPL_IMPL_INLINE void zpl_allocation_header_fill(zpl_allocation_header_ev *header, void *data, zpl_isize size) { + zpl_isize *ptr; + header->size = size; + ptr = cast(zpl_isize *)(header + 1); + while (cast(void *) ptr < data) *ptr++ = cast(zpl_isize)(-1); +} + +// +// Stack Memory Allocator +// + +#define ZPL_STACK_ALLOC_OFFSET sizeof(zpl_u64) +ZPL_STATIC_ASSERT(ZPL_STACK_ALLOC_OFFSET == 8, "ZPL_STACK_ALLOC_OFFSET != 8"); + +ZPL_IMPL_INLINE void zpl_stack_memory_init_from_memory(zpl_stack_memory *s, void *start, zpl_isize size) { + s->physical_start = start; + s->total_size = size; + s->allocated = 0; +} + +ZPL_IMPL_INLINE void zpl_stack_memory_init(zpl_stack_memory *s, zpl_allocator backing, zpl_isize size) { + s->backing = backing; + s->physical_start = zpl_alloc(backing, size); + s->total_size = size; + s->allocated = 0; +} + +ZPL_IMPL_INLINE zpl_b32 zpl_stack_memory_is_in_use(zpl_stack_memory *s, void *ptr) { + if (s->allocated == 0) return false; + + if (ptr > s->physical_start && ptr < zpl_pointer_add(s->physical_start, s->total_size)) { return true; } + + return false; +} + +ZPL_IMPL_INLINE void zpl_stack_memory_free(zpl_stack_memory *s) { + if (s->backing.proc) { + zpl_free(s->backing, s->physical_start); + s->physical_start = NULL; + } +} + +ZPL_IMPL_INLINE zpl_allocator zpl_stack_allocator(zpl_stack_memory *s) { + zpl_allocator a; + a.proc = zpl_stack_allocator_proc; + a.data = s; + return a; +} + +ZPL_END_C_DECLS +// file: header/essentials/collections/array.h + +//////////////////////////////////////////////////////////////// +// +// Dynamic Array (POD Types) +// +// zpl_array(Type) works like zpl_string or zpl_buffer where the actual type is just a pointer to the first +// element. +// +// Available Procedures for zpl_array(Type) +// zpl_array_init +// zpl_array_free +// zpl_array_set_capacity +// zpl_array_grow +// zpl_array_append +// zpl_array_appendv +// zpl_array_pop +// zpl_array_clear +// zpl_array_back +// zpl_array_front +// zpl_array_resize +// zpl_array_reserve +// + +#if 0 // Example +void foo(void) { + zpl_isize i; + int test_values[] = {4, 2, 1, 7}; + zpl_allocator a = zpl_heap_allocator(); + zpl_array(int) items; + + zpl_array_init(items, a); + + zpl_array_append(items, 1); + zpl_array_append(items, 4); + zpl_array_append(items, 9); + zpl_array_append(items, 16); + + items[1] = 3; // Manually set value + // NOTE: No array bounds checking + + for (i = 0; i < items.count; i++) + zpl_printf("%d\n", items[i]); + // 1 + // 3 + // 9 + // 16 + + zpl_array_clear(items); + + zpl_array_appendv(items, test_values, zpl_count_of(test_values)); + for (i = 0; i < items.count; i++) + zpl_printf("%d\n", items[i]); + // 4 + // 2 + // 1 + // 7 + + zpl_array_free(items); +} +#endif + + +ZPL_BEGIN_C_DECLS + +typedef struct zpl_array_header { + char *data; + zpl_isize count; + zpl_isize capacity; + zpl_allocator allocator; +} zpl_array_header; + +#define zpl_array(Type) Type * + +#define zpl_array_make(Type, Name, allocator) Type *Name; zpl_array_init(Name, allocator) + +#ifndef ZPL_ARRAY_GROW_FORMULA +#define ZPL_ARRAY_GROW_FORMULA(x) (2 * (x) + 8) +#endif + +ZPL_STATIC_ASSERT(ZPL_ARRAY_GROW_FORMULA(0) > 0, "ZPL_ARRAY_GROW_FORMULA(0) <= 0"); + +#define ZPL_ARRAY_HEADER(x) (cast(zpl_array_header *)(x) - 1) +#define zpl_array_allocator(x) (ZPL_ARRAY_HEADER(x)->allocator) +#define zpl_array_count(x) (ZPL_ARRAY_HEADER(x)->count) +#define zpl_array_capacity(x) (ZPL_ARRAY_HEADER(x)->capacity) +#define zpl_array_end(x) (x + (zpl_array_count(x) - 1)) + +#define zpl_array_init_reserve(x, allocator_, cap) \ +do { \ +void **zpl__array_ = cast(void **) & (x); \ +zpl_array_header *zpl__ah = \ +cast(zpl_array_header *) zpl_alloc(allocator_, zpl_size_of(zpl_array_header) + zpl_size_of(*(x)) * (cap)); \ +zpl__ah->allocator = allocator_; \ +zpl__ah->count = 0; \ +zpl__ah->data = (char *)(zpl__ah + 1); \ +zpl__ah->capacity = cap; \ +*zpl__array_ = cast(void *)(zpl__ah + 1); \ +} while (0) + +// NOTE: Give it an initial default capacity +#define zpl_array_init(x, allocator) zpl_array_init_reserve(x, allocator, ZPL_ARRAY_GROW_FORMULA(0)) + +#define zpl_array_free(x) \ +do { \ +zpl_array_header *zpl__ah = ZPL_ARRAY_HEADER(x); \ +zpl_free(zpl__ah->allocator, zpl__ah); \ +} while (0) + +#define zpl_array_set_capacity(x, capacity) \ +do { \ +if (x) { \ +void **zpl__array_ = cast(void **) & (x); \ +*zpl__array_ = zpl__array_set_capacity((x), (capacity), zpl_size_of(*(x))); \ +} \ +} while (0) + +// NOTE: Do not use the thing below directly, use the macro +ZPL_DEF void *zpl__array_set_capacity(void *array, zpl_isize capacity, zpl_isize element_size); + +#define zpl_array_grow(x, min_capacity) \ +do { \ +zpl_isize new_capacity = ZPL_ARRAY_GROW_FORMULA(zpl_array_capacity(x)); \ +if (new_capacity < (min_capacity)) new_capacity = (min_capacity); \ +zpl_array_set_capacity(x, new_capacity); \ +} while (0) + +#define zpl_array_append(x, item) \ +do { \ +if (zpl_array_capacity(x) < zpl_array_count(x) + 1) zpl_array_grow(x, 0); \ +(x)[zpl_array_count(x)++] = (item); \ +} while (0) + +#define zpl_array_append_at(x, item, ind) \ +do { \ +if (ind >= zpl_array_count(x)) { zpl_array_append(x, item); break; } \ +if (zpl_array_capacity(x) < zpl_array_count(x) + 1) zpl_array_grow(x, 0); \ +zpl_printf("OK\n");\ +zpl_memmove(&(x)[ind + 1], &(x)[ind], zpl_size_of(x[0]) * (zpl_array_count(x) - ind)); \ +x[ind] = item; \ +zpl_array_count(x)++; \ +} while (0) + +#define zpl_array_appendv(x, items, item_count) \ +do { \ +ZPL_ASSERT(zpl_size_of((items)[0]) == zpl_size_of((x)[0])); \ +if (zpl_array_capacity(x) < zpl_array_count(x) + (item_count)) zpl_array_grow(x, zpl_array_count(x) + (item_count)); \ +zpl_memcopy(&(x)[zpl_array_count(x)], (items), zpl_size_of((x)[0]) * (item_count)); \ +zpl_array_count(x) += (item_count); \ +} while (0) + +#define zpl_array_appendv_at(x, items, item_count, ind) \ +do { \ +if (ind >= zpl_array_count(x)) { zpl_array_appendv(x, items, item_count); break; } \ +ZPL_ASSERT(zpl_size_of((items)[0]) == zpl_size_of((x)[0])); \ +if (zpl_array_capacity(x) < zpl_array_count(x) + (item_count)) zpl_array_grow(x, zpl_array_count(x) + (item_count)); \ +zpl_memmove(x + ind + (item_count), x + ind, zpl_size_of((x)[0]) * zpl_array_count(x)); \ +zpl_memcopy(&(x)[ind], (items), zpl_size_of((x)[0]) * (item_count)); \ +zpl_array_count(x) += (item_count); \ +} while (0) + +#define zpl_array_fill(x, begin, end, value) \ +do { \ +ZPL_ASSERT((begin) >= 0 && (end) < zpl_array_count(x)); \ +ZPL_ASSERT(zpl_size_of(value) == zpl_size_of((x)[0])); \ +for (zpl_isize i = (begin); i < (end); i++) { x[i] = value; } \ +} while (0) + +#define zpl_array_remove_at(x, index) \ +do { \ +zpl_array_header *zpl__ah = ZPL_ARRAY_HEADER(x); \ +ZPL_ASSERT(index < zpl__ah->count); \ +zpl_memmove(x + index, x + index + 1, zpl_size_of(x[0]) * (zpl__ah->count - index - 1)); \ +--zpl__ah->count; \ +} while (0) + +#define zpl_array_copy_init(y, x) \ +do { \ +zpl_array_init_reserve(y, zpl_array_allocator(x), zpl_array_capacity(x)); \ +zpl_memcopy(y, x, zpl_array_capacity(x) * zpl_size_of(*x)); \ +zpl_array_count(y) = zpl_array_count(x); \ +} while (0) + +#define zpl_array_pop(x) \ +do { \ +ZPL_ASSERT(ZPL_ARRAY_HEADER(x)->count > 0); \ +ZPL_ARRAY_HEADER(x)->count--; \ +} while (0) +#define zpl_array_back(x) x[ZPL_ARRAY_HEADER(x)->count - 1] +#define zpl_array_front(x) x[0] +#define zpl_array_clear(x) \ +do { ZPL_ARRAY_HEADER(x)->count = 0; } while (0) + +#define zpl_array_resize(x, new_count) \ +do { \ +if (ZPL_ARRAY_HEADER(x)->capacity < (new_count)) zpl_array_grow(x, (new_count)); \ +ZPL_ARRAY_HEADER(x)->count = (new_count); \ +} while (0) + +#define zpl_array_reserve(x, new_capacity) \ +do { \ +if (ZPL_ARRAY_HEADER(x)->capacity < (new_capacity)) zpl_array_set_capacity(x, new_capacity); \ +} while (0) + +ZPL_END_C_DECLS +// file: header/essentials/collections/buffer.h + +//////////////////////////////////////////////////////////////// +// +// Fixed Capacity Buffer (POD Types) +// +// +// zpl_buffer(Type) works like zpl_string or zpl_array where the actual type is just a pointer to the first +// element. +// +// Available Procedures for zpl_buffer(Type) +// zpl_buffer_init +// zpl_buffer_free +// zpl_buffer_append +// zpl_buffer_appendv +// zpl_buffer_pop +// zpl_buffer_clear + + +ZPL_BEGIN_C_DECLS + +typedef struct zpl_buffer_header { + zpl_allocator backing; + zpl_isize count; + zpl_isize capacity; +} zpl_buffer_header; + +#define zpl_buffer(Type) Type * + +#define zpl_buffer_make(Type, Name, allocator, cap) Type *Name; zpl_buffer_init(Name, allocator, cap) + +#define ZPL_BUFFER_HEADER(x) (cast(zpl_buffer_header *)(x) - 1) +#define zpl_buffer_count(x) (ZPL_BUFFER_HEADER(x)->count) +#define zpl_buffer_capacity(x) (ZPL_BUFFER_HEADER(x)->capacity) +#define zpl_buffer_end(x) (x + (zpl_buffer_count(x) - 1)) + +#define zpl_buffer_init(x, allocator, cap) \ +do { \ +void **nx = cast(void **) & (x); \ +zpl_buffer_header *zpl__bh = \ +cast(zpl_buffer_header *) zpl_alloc((allocator), sizeof(zpl_buffer_header) + (cap)*zpl_size_of(*(x))); \ +zpl__bh->backing = allocator; \ +zpl__bh->count = 0; \ +zpl__bh->capacity = cap; \ +*nx = cast(void *)(zpl__bh + 1); \ +} while (0) + +#define zpl_buffer_free(x) (zpl_free(ZPL_BUFFER_HEADER(x)->backing, ZPL_BUFFER_HEADER(x))) + +#define zpl_buffer_append(x, item) \ +do { (x)[zpl_buffer_count(x)++] = (item); } while (0) + +#define zpl_buffer_appendv(x, items, item_count) \ +do { \ +ZPL_ASSERT(zpl_size_of(*(items)) == zpl_size_of(*(x))); \ +ZPL_ASSERT(zpl_buffer_count(x) + item_count <= zpl_buffer_capacity(x)); \ +zpl_memcopy(&(x)[zpl_buffer_count(x)], (items), zpl_size_of(*(x)) * (item_count)); \ +zpl_buffer_count(x) += (item_count); \ +} while (0) + +#define zpl_buffer_copy_init(y, x) \ +do { \ +zpl_buffer_init_reserve(y, zpl_buffer_allocator(x), zpl_buffer_capacity(x)); \ +zpl_memcopy(y, x, zpl_buffer_capacity(x) * zpl_size_of(*x)); \ +zpl_buffer_count(y) = zpl_buffer_count(x); \ +} while (0) + +#define zpl_buffer_pop(x) \ +do { \ +ZPL_ASSERT(zpl_buffer_count(x) > 0); \ +zpl_buffer_count(x)--; \ +} while (0) +#define zpl_buffer_clear(x) \ +do { zpl_buffer_count(x) = 0; } while (0) + +ZPL_END_C_DECLS +// file: header/essentials/collections/list.h + +//////////////////////////////////////////////////////////////// +// +// Linked List +// +// zpl_list encapsulates pointer to data and points to the next and the previous element in the list. +// +// Available Procedures for zpl_list +// zpl_list_init +// zpl_list_add +// zpl_list_remove + + +ZPL_BEGIN_C_DECLS + +#if 0 +#define ZPL_IMPLEMENTATION +#include "zpl.h" +int main(void) +{ + zpl_list s, *head, *cursor; + zpl_list_init(&s, "it is optional to call init: "); + head = cursor = &s; + + // since we can construct an element implicitly this way + // the second field gets overwritten once we add it to a list. + zpl_list a = {"hello"}; + cursor = zpl_list_add(cursor, &a); + + zpl_list b = {"world"}; + cursor = zpl_list_add(cursor, &b); + + zpl_list c = {"!!! OK"}; + cursor = zpl_list_add(cursor, &c); + + for (zpl_list *l=head; l; l=l->next) { + zpl_printf("%s ", cast(char *)l->ptr); + } + zpl_printf("\n"); + + return 0; +} +#endif + + +typedef struct zpl__list { + void const *ptr; + struct zpl__list *next, *prev; +} zpl_list; + +ZPL_DEF_INLINE void zpl_list_init(zpl_list *list, void const *ptr); +ZPL_DEF_INLINE zpl_list *zpl_list_add(zpl_list *list, zpl_list *item); + +// NOTE(zaklaus): Returns a pointer to the next node (or NULL if the removed node has no trailing node.) +ZPL_DEF_INLINE zpl_list *zpl_list_remove(zpl_list *list); + + +ZPL_IMPL_INLINE void zpl_list_init(zpl_list *list, void const *ptr) { + zpl_list list_ = { 0 }; + *list = list_; + list->ptr = ptr; +} + +ZPL_IMPL_INLINE zpl_list *zpl_list_add(zpl_list *list, zpl_list *item) { + item->next = NULL; + + if (list->next) { item->next = list->next; } + + list->next = item; + item->prev = list; + return item; +} + +ZPL_IMPL_INLINE zpl_list *zpl_list_remove(zpl_list *list) { + if (list->prev) { list->prev->next = list->next; } + + return list->next; +} + +ZPL_END_C_DECLS +// file: header/essentials/collections/ring.h + +//////////////////////////////////////////////////////////////// +// +// Instantiated Circular buffer +// + + +ZPL_BEGIN_C_DECLS + +#define ZPL_RING_DECLARE(prefix,type) \ +typedef struct { \ +zpl_allocator backing; \ +zpl_buffer(type) buf; \ +zpl_usize head, tail; \ +zpl_usize capacity; \ +} ZPL_JOIN2(prefix, type); \ +\ +ZPL_DEF void ZPL_JOIN2(prefix, init)(ZPL_JOIN2(prefix, type) * pad, zpl_allocator a, zpl_isize max_size); \ +ZPL_DEF void ZPL_JOIN2(prefix, free)(ZPL_JOIN2(prefix, type) * pad); \ +ZPL_DEF zpl_b32 ZPL_JOIN2(prefix, full)(ZPL_JOIN2(prefix, type) * pad); \ +ZPL_DEF zpl_b32 ZPL_JOIN2(prefix, empty)(ZPL_JOIN2(prefix, type) * pad); \ +ZPL_DEF void ZPL_JOIN2(prefix, append)(ZPL_JOIN2(prefix, type) * pad, type data); \ +ZPL_DEF void ZPL_JOIN2(prefix, append_array)(ZPL_JOIN2(prefix, type) * pad, zpl_array(type) data); \ +ZPL_DEF type *ZPL_JOIN2(prefix, get)(ZPL_JOIN2(prefix, type) * pad); \ +ZPL_DEF zpl_array(type) \ +ZPL_JOIN2(prefix, get_array)(ZPL_JOIN2(prefix, type) * pad, zpl_usize max_size, zpl_allocator a); + +#define ZPL_RING_DEFINE(prefix,type) \ +void ZPL_JOIN2(prefix, init)(ZPL_JOIN2(prefix, type) * pad, zpl_allocator a, zpl_isize max_size) { \ +ZPL_JOIN2(prefix, type) pad_ = { 0 }; \ +*pad = pad_; \ +\ +pad->backing = a; \ +zpl_buffer_init(pad->buf, a, max_size + 1); \ +pad->capacity = max_size + 1; \ +pad->head = pad->tail = 0; \ +} \ +void ZPL_JOIN2(prefix, free)(ZPL_JOIN2(prefix, type) * pad) { \ +zpl_buffer_free(pad->buf); \ +} \ +\ +zpl_b32 ZPL_JOIN2(prefix, full)(ZPL_JOIN2(prefix, type) * pad) { \ +return ((pad->head + 1) % pad->capacity) == pad->tail; \ +} \ +\ +zpl_b32 ZPL_JOIN2(prefix, empty)(ZPL_JOIN2(prefix, type) * pad) { return pad->head == pad->tail; } \ +\ +void ZPL_JOIN2(prefix, append)(ZPL_JOIN2(prefix, type) * pad, type data) { \ +pad->buf[pad->head] = data; \ +pad->head = (pad->head + 1) % pad->capacity; \ +\ +if (pad->head == pad->tail) { pad->tail = (pad->tail + 1) % pad->capacity; } \ +} \ +\ +void ZPL_JOIN2(prefix, append_array)(ZPL_JOIN2(prefix, type) * pad, zpl_array(type) data) { \ +zpl_usize c = zpl_array_count(data); \ +for (zpl_usize i = 0; i < c; ++i) { ZPL_JOIN2(prefix, append)(pad, data[i]); } \ +} \ +\ +type *ZPL_JOIN2(prefix, get)(ZPL_JOIN2(prefix, type) * pad) { \ +if (ZPL_JOIN2(prefix, empty)(pad)) { return NULL; } \ +\ +type *data = &pad->buf[pad->tail]; \ +pad->tail = (pad->tail + 1) % pad->capacity; \ +\ +return data; \ +} \ +\ +zpl_array(type) \ +ZPL_JOIN2(prefix, get_array)(ZPL_JOIN2(prefix, type) * pad, zpl_usize max_size, zpl_allocator a) { \ +zpl_array(type) vals = 0; \ +zpl_array_init(vals, a); \ +while (--max_size && !ZPL_JOIN2(prefix, empty)(pad)) { \ +zpl_array_append(vals, *ZPL_JOIN2(prefix, get)(pad)); \ +} \ +return vals; \ +} + +ZPL_END_C_DECLS +// file: header/essentials/collections/hashtable.h + +/** @file hashtable.c +@brief Instantiated hash table +@defgroup hashtable Instantiated hash table + +@n +@n This is an attempt to implement a templated hash table +@n NOTE: The key is always a zpl_u64 for simplicity and you will _probably_ _never_ need anything bigger. +@n +@n Hash table type and function declaration, call: ZPL_TABLE_DECLARE(PREFIX, NAME, N, VALUE) +@n Hash table function definitions, call: ZPL_TABLE_DEFINE(NAME, N, VALUE) +@n +@n PREFIX - a prefix for function prototypes e.g. extern, static, etc. +@n NAME - Name of the Hash Table +@n FUNC - the name will prefix function names +@n VALUE - the type of the value to be stored +@n +@n tablename_init(NAME * h, zpl_allocator a); +@n tablename_destroy(NAME * h); +@n tablename_get(NAME * h, zpl_u64 key); +@n tablename_set(NAME * h, zpl_u64 key, VALUE value); +@n tablename_grow(NAME * h); +@n tablename_rehash(NAME * h, zpl_isize new_count); +@n tablename_remove(NAME * h, zpl_u64 key); + + @{ +*/ + + +ZPL_BEGIN_C_DECLS + +typedef struct zpl_hash_table_find_result { + zpl_isize hash_index; + zpl_isize entry_prev; + zpl_isize entry_index; +} zpl_hash_table_find_result; + +#define ZPL_TABLE(PREFIX, NAME, FUNC, VALUE) \ +ZPL_TABLE_DECLARE(PREFIX, NAME, FUNC, VALUE); \ +ZPL_TABLE_DEFINE(NAME, FUNC, VALUE); + +#define ZPL_TABLE_DECLARE(PREFIX, NAME, FUNC, VALUE) \ +typedef struct ZPL_JOIN2(NAME, Entry) { \ +zpl_u64 key; \ +zpl_isize next; \ +VALUE value; \ +} ZPL_JOIN2(NAME, Entry); \ +\ +typedef struct NAME { \ +zpl_array(zpl_isize) hashes; \ +zpl_array(ZPL_JOIN2(NAME, Entry)) entries; \ +} NAME; \ +\ +PREFIX void ZPL_JOIN2(FUNC, init)(NAME * h, zpl_allocator a); \ +PREFIX void ZPL_JOIN2(FUNC, destroy)(NAME * h); \ +PREFIX VALUE *ZPL_JOIN2(FUNC, get)(NAME * h, zpl_u64 key); \ +PREFIX void ZPL_JOIN2(FUNC, set)(NAME * h, zpl_u64 key, VALUE value); \ +PREFIX void ZPL_JOIN2(FUNC, grow)(NAME * h); \ +PREFIX void ZPL_JOIN2(FUNC, rehash)(NAME * h, zpl_isize new_count); \ +PREFIX void ZPL_JOIN2(FUNC, map)(NAME * h, void (*map_proc)(zpl_u64 key, VALUE value)); \ +PREFIX void ZPL_JOIN2(FUNC, map_mut)(NAME * h, void (*map_proc)(zpl_u64 key, VALUE * value)); \ +PREFIX void ZPL_JOIN2(FUNC, remove)(NAME * h, zpl_u64 key); + +#define ZPL_TABLE_DEFINE(NAME, FUNC, VALUE) \ +void ZPL_JOIN2(FUNC, init)(NAME * h, zpl_allocator a) { \ +zpl_array_init(h->hashes, a); \ +zpl_array_init(h->entries, a); \ +} \ +\ +void ZPL_JOIN2(FUNC, destroy)(NAME * h) { \ +if (h->entries) zpl_array_free(h->entries); \ +if (h->hashes) zpl_array_free(h->hashes); \ +} \ +\ +zpl_internal zpl_isize ZPL_JOIN2(FUNC, _add_entry)(NAME * h, zpl_u64 key) { \ +zpl_isize index; \ +ZPL_JOIN2(NAME, Entry) e = { 0 }; \ +e.key = key; \ +e.next = -1; \ +index = zpl_array_count(h->entries); \ +zpl_array_append(h->entries, e); \ +return index; \ +} \ +\ +zpl_internal zpl_hash_table_find_result ZPL_JOIN2(FUNC, _find)(NAME * h, zpl_u64 key) { \ +zpl_hash_table_find_result r = { -1, -1, -1 }; \ +if (zpl_array_count(h->hashes) > 0) { \ +r.hash_index = key % zpl_array_count(h->hashes); \ +r.entry_index = h->hashes[r.hash_index]; \ +while (r.entry_index >= 0) { \ +if (h->entries[r.entry_index].key == key) return r; \ +r.entry_prev = r.entry_index; \ +r.entry_index = h->entries[r.entry_index].next; \ +} \ +} \ +return r; \ +} \ +\ +zpl_internal zpl_b32 ZPL_JOIN2(FUNC, _full)(NAME * h) { \ +return 0.75f * zpl_array_count(h->hashes) < zpl_array_count(h->entries); \ +} \ +\ +void ZPL_JOIN2(FUNC, grow)(NAME * h) { \ +zpl_isize new_count = ZPL_ARRAY_GROW_FORMULA(zpl_array_count(h->entries)); \ +ZPL_JOIN2(FUNC, rehash)(h, new_count); \ +} \ +\ +void ZPL_JOIN2(FUNC, rehash)(NAME * h, zpl_isize new_count) { \ +zpl_isize i, j; \ +NAME nh = { 0 }; \ +ZPL_JOIN2(FUNC, init)(&nh, zpl_array_allocator(h->hashes)); \ +zpl_array_resize(nh.hashes, new_count); \ +zpl_array_reserve(nh.entries, zpl_array_count(h->entries)); \ +for (i = 0; i < new_count; i++) nh.hashes[i] = -1; \ +for (i = 0; i < zpl_array_count(h->entries); i++) { \ +ZPL_JOIN2(NAME, Entry) * e; \ +zpl_hash_table_find_result fr; \ +if (zpl_array_count(nh.hashes) == 0) ZPL_JOIN2(FUNC, grow)(&nh); \ +e = &h->entries[i]; \ +fr = ZPL_JOIN2(FUNC, _find)(&nh, e->key); \ +j = ZPL_JOIN2(FUNC, _add_entry)(&nh, e->key); \ +if (fr.entry_prev < 0) \ +nh.hashes[fr.hash_index] = j; \ +else \ +nh.entries[fr.entry_prev].next = j; \ +nh.entries[j].next = fr.entry_index; \ +nh.entries[j].value = e->value; \ +} \ +ZPL_JOIN2(FUNC, destroy)(h); \ +h->hashes = nh.hashes; \ +h->entries = nh.entries; \ +} \ +\ +VALUE *ZPL_JOIN2(FUNC, get)(NAME * h, zpl_u64 key) { \ +zpl_isize index = ZPL_JOIN2(FUNC, _find)(h, key).entry_index; \ +if (index >= 0) return &h->entries[index].value; \ +return NULL; \ +} \ +\ +void ZPL_JOIN2(FUNC, remove)(NAME * h, zpl_u64 key) { \ +zpl_hash_table_find_result fr = ZPL_JOIN2(FUNC, _find)(h, key); \ +if (fr.entry_index >= 0) { \ +if (fr.entry_prev >= 0) { \ +h->entries[fr.entry_prev].next = h->entries[fr.entry_index].next; \ +} else { \ +h->hashes[fr.hash_index] = fr.entry_index; \ +} \ +zpl_array_remove_at(h->entries, fr.entry_index); \ +} \ +ZPL_JOIN2(FUNC, rehash)(h, zpl_array_count(h->entries)); \ +} \ +\ +void ZPL_JOIN2(FUNC, map)(NAME * h, void (*map_proc)(zpl_u64 key, VALUE value)) { \ +ZPL_ASSERT_NOT_NULL(h); \ +ZPL_ASSERT_NOT_NULL(map_proc); \ +for (zpl_isize i = 0; i < zpl_array_count(h->entries); ++i) { \ +map_proc(h->entries[i].key, h->entries[i].value); \ +} \ +} \ +void ZPL_JOIN2(FUNC, map_mut)(NAME * h, void (*map_proc)(zpl_u64 key, VALUE * value)) { \ +ZPL_ASSERT_NOT_NULL(h); \ +ZPL_ASSERT_NOT_NULL(map_proc); \ +for (zpl_isize i = 0; i < zpl_array_count(h->entries); ++i) { \ +map_proc(h->entries[i].key, &h->entries[i].value); \ +} \ +} \ +\ +void ZPL_JOIN2(FUNC, set)(NAME * h, zpl_u64 key, VALUE value) { \ +zpl_isize index; \ +zpl_hash_table_find_result fr; \ +if (zpl_array_count(h->hashes) == 0) ZPL_JOIN2(FUNC, grow)(h); \ +fr = ZPL_JOIN2(FUNC, _find)(h, key); \ +if (fr.entry_index >= 0) { \ +index = fr.entry_index; \ +} else { \ +index = ZPL_JOIN2(FUNC, _add_entry)(h, key); \ +if (fr.entry_prev >= 0) { \ +h->entries[fr.entry_prev].next = index; \ +} else { \ +h->hashes[fr.hash_index] = index; \ +} \ +} \ +h->entries[index].value = value; \ +if (ZPL_JOIN2(FUNC, _full)(h)) ZPL_JOIN2(FUNC, grow)(h); \ +}\ + +//! @} + +ZPL_END_C_DECLS # if defined(ZPL_MODULE_CORE) - // file: header/core/memory_virtual.h +// file: header/core/memory_virtual.h - //////////////////////////////////////////////////////////////// - // - // Virtual Memory - // - // +//////////////////////////////////////////////////////////////// +// +// Virtual Memory +// +// - ZPL_BEGIN_C_DECLS +ZPL_BEGIN_C_DECLS - typedef struct zpl_virtual_memory { - void *data; - zpl_isize size; - } zpl_virtual_memory; +typedef struct zpl_virtual_memory { + void *data; + zpl_isize size; +} zpl_virtual_memory; - //! Initialize virtual memory from existing data. - ZPL_DEF zpl_virtual_memory zpl_vm(void *data, zpl_isize size); +//! Initialize virtual memory from existing data. +ZPL_DEF zpl_virtual_memory zpl_vm(void *data, zpl_isize size); - //! Allocate virtual memory at address with size. +//! Allocate virtual memory at address with size. - //! @param addr The starting address of the region to reserve. If NULL, it lets operating system to decide where to allocate it. - //! @param size The size to server. - ZPL_DEF zpl_virtual_memory zpl_vm_alloc(void *addr, zpl_isize size); +//! @param addr The starting address of the region to reserve. If NULL, it lets operating system to decide where to allocate it. +//! @param size The size to server. +ZPL_DEF zpl_virtual_memory zpl_vm_alloc(void *addr, zpl_isize size); - //! Release the virtual memory. - ZPL_DEF zpl_b32 zpl_vm_free(zpl_virtual_memory vm); +//! Release the virtual memory. +ZPL_DEF zpl_b32 zpl_vm_free(zpl_virtual_memory vm); - //! Trim virtual memory. - ZPL_DEF zpl_virtual_memory zpl_vm_trim(zpl_virtual_memory vm, zpl_isize lead_size, zpl_isize size); +//! Trim virtual memory. +ZPL_DEF zpl_virtual_memory zpl_vm_trim(zpl_virtual_memory vm, zpl_isize lead_size, zpl_isize size); - //! Purge virtual memory. - ZPL_DEF zpl_b32 zpl_vm_purge(zpl_virtual_memory vm); +//! Purge virtual memory. +ZPL_DEF zpl_b32 zpl_vm_purge(zpl_virtual_memory vm); - //! Retrieve VM's page size and alignment. - ZPL_DEF zpl_isize zpl_virtual_memory_page_size(zpl_isize *alignment_out); - - ZPL_END_C_DECLS - // file: header/core/string.h +//! Retrieve VM's page size and alignment. +ZPL_DEF zpl_isize zpl_virtual_memory_page_size(zpl_isize *alignment_out); + +ZPL_END_C_DECLS +// file: header/core/string.h - /** @file string.c - @brief String operations and library - @defgroup string String library - - Offers methods for c-string manipulation, but also a string library based on gb_string, which is c-string friendly. +/** @file string.c +@brief String operations and library +@defgroup string String library + +Offers methods for c-string manipulation, but also a string library based on gb_string, which is c-string friendly. - @{ - */ - - //////////////////////////////////////////////////////////////// - // - // Char Functions - // - // +@{ +*/ + +//////////////////////////////////////////////////////////////// +// +// Char Functions +// +// - ZPL_BEGIN_C_DECLS - - ZPL_DEF_INLINE char zpl_char_to_lower(char c); - ZPL_DEF_INLINE char zpl_char_to_upper(char c); - ZPL_DEF_INLINE zpl_b32 zpl_char_is_space(char c); - ZPL_DEF_INLINE zpl_b32 zpl_char_is_digit(char c); - ZPL_DEF_INLINE zpl_b32 zpl_char_is_hex_digit(char c); - ZPL_DEF_INLINE zpl_b32 zpl_char_is_alpha(char c); - ZPL_DEF_INLINE zpl_b32 zpl_char_is_alphanumeric(char c); - ZPL_DEF_INLINE zpl_i32 zpl_digit_to_int(char c); - ZPL_DEF_INLINE zpl_i32 zpl_hex_digit_to_int(char c); - ZPL_DEF_INLINE zpl_u8 zpl_char_to_hex_digit(char c); - ZPL_DEF_INLINE zpl_b32 zpl_char_is_control(char c); - - // NOTE: ASCII only - ZPL_DEF_INLINE void zpl_str_to_lower(char *str); - ZPL_DEF_INLINE void zpl_str_to_upper(char *str); - - ZPL_DEF_INLINE char const *zpl_str_trim(char const *str, zpl_b32 catch_newline); - ZPL_DEF_INLINE char const *zpl_str_skip(char const *str, char c); - ZPL_DEF_INLINE char const *zpl_str_skip_any(char const *str, char const*char_list); - ZPL_DEF_INLINE char const *zpl_str_skip_literal(char const *str, char c); - ZPL_DEF_INLINE char const *zpl_str_control_skip(char const *str, char c); - - ZPL_DEF_INLINE zpl_isize zpl_strlen(const char *str); - ZPL_DEF_INLINE zpl_isize zpl_strnlen(const char *str, zpl_isize max_len); - ZPL_DEF_INLINE zpl_i32 zpl_strcmp(const char *s1, const char *s2); - ZPL_DEF_INLINE zpl_i32 zpl_strncmp(const char *s1, const char *s2, zpl_isize len); - ZPL_DEF_INLINE char *zpl_strcpy(char *dest, const char *source); - ZPL_DEF_INLINE char *zpl_strcat(char *dest, const char *source); - ZPL_DEF_INLINE char *zpl_strncpy(char *dest, const char *source, zpl_isize len); - ZPL_DEF_INLINE zpl_isize zpl_strlcpy(char *dest, const char *source, zpl_isize len); - ZPL_DEF_INLINE char *zpl_strrev(char *str); // NOTE: ASCII only - ZPL_DEF_INLINE const char *zpl_strtok(char *output, const char *src, const char *delimit); - - ZPL_DEF_INLINE char *zpl_strdup(zpl_allocator a, char *src, zpl_isize max_len); - ZPL_DEF_INLINE char **zpl_str_split_lines(zpl_allocator alloc, char *source, zpl_b32 strip_whitespace); - - #define zpl_str_expand(str) str, zpl_strlen(str) - #define zpl_str_advance_while(str, cond) \ - do { \ - ++str; \ - } while ((cond)); - - ZPL_DEF_INLINE zpl_b32 zpl_str_has_prefix(const char *str, const char *prefix); - ZPL_DEF_INLINE zpl_b32 zpl_str_has_suffix(const char *str, const char *suffix); - - ZPL_DEF_INLINE const char *zpl_char_first_occurence(const char *str, char c); - ZPL_DEF_INLINE const char *zpl_char_last_occurence(const char *str, char c); - #define zpl_strchr zpl_char_first_occurence - - ZPL_DEF_INLINE void zpl_str_concat(char *dest, zpl_isize dest_len, const char *src_a, zpl_isize src_a_len, const char *src_b, zpl_isize src_b_len); - - ZPL_DEF zpl_u64 zpl_str_to_u64(const char *str, char **end_ptr, zpl_i32 base); // TODO: Support more than just decimal and hexadecimal - ZPL_DEF zpl_i64 zpl_str_to_i64(const char *str, char **end_ptr, zpl_i32 base); // TODO: Support more than just decimal and hexadecimal - ZPL_DEF zpl_f64 zpl_str_to_f64(const char *str, char **end_ptr); - ZPL_DEF void zpl_i64_to_str(zpl_i64 value, char *string, zpl_i32 base); - ZPL_DEF void zpl_u64_to_str(zpl_u64 value, char *string, zpl_i32 base); - - ZPL_DEF_INLINE zpl_f32 zpl_str_to_f32(const char *str, char **end_ptr); - - //////////////////////////////////////////////////////////////// - // - // UTF-8 Handling - // - // - - // NOTE: Does not check if utf-8 string is valid - ZPL_IMPL_INLINE zpl_isize zpl_utf8_strlen(zpl_u8 const *str); - ZPL_IMPL_INLINE zpl_isize zpl_utf8_strnlen(zpl_u8 const *str, zpl_isize max_len); - - // NOTE: Windows doesn't handle 8 bit filenames well - ZPL_DEF zpl_u16 *zpl_utf8_to_ucs2(zpl_u16 *buffer, zpl_isize len, zpl_u8 const *str); - ZPL_DEF zpl_u8 *zpl_ucs2_to_utf8(zpl_u8 *buffer, zpl_isize len, zpl_u16 const *str); - ZPL_DEF zpl_u16 *zpl_utf8_to_ucs2_buf(zpl_u8 const *str); // NOTE: Uses locally persisting buffer - ZPL_DEF zpl_u8 *zpl_ucs2_to_utf8_buf(zpl_u16 const *str); // NOTE: Uses locally persisting buffer - - // NOTE: Returns size of codepoint in bytes - ZPL_DEF zpl_isize zpl_utf8_decode(zpl_u8 const *str, zpl_isize str_len, zpl_rune *codepoint); - ZPL_DEF zpl_isize zpl_utf8_codepoint_size(zpl_u8 const *str, zpl_isize str_len); - ZPL_DEF zpl_isize zpl_utf8_encode_rune(zpl_u8 buf[4], zpl_rune r); - - /* inlines */ - - ZPL_IMPL_INLINE char zpl_char_to_lower(char c) { - if (c >= 'A' && c <= 'Z') return 'a' + (c - 'A'); - return c; - } - - ZPL_IMPL_INLINE char zpl_char_to_upper(char c) { - if (c >= 'a' && c <= 'z') return 'A' + (c - 'a'); - return c; - } - - ZPL_IMPL_INLINE zpl_b32 zpl_char_is_space(char c) { - if (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v') return true; - return false; - } - - ZPL_IMPL_INLINE zpl_b32 zpl_char_is_digit(char c) { - if (c >= '0' && c <= '9') return true; - return false; - } - - ZPL_IMPL_INLINE zpl_b32 zpl_char_is_hex_digit(char c) { - if (zpl_char_is_digit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) return true; - return false; - } - - ZPL_IMPL_INLINE zpl_b32 zpl_char_is_alpha(char c) { - if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) return true; - return false; - } - - ZPL_IMPL_INLINE zpl_b32 zpl_char_is_alphanumeric(char c) { return zpl_char_is_alpha(c) || zpl_char_is_digit(c); } - - ZPL_IMPL_INLINE zpl_i32 zpl_digit_to_int(char c) { return zpl_char_is_digit(c) ? c - '0' : c - 'W'; } - - ZPL_IMPL_INLINE zpl_i32 zpl_hex_digit_to_int(char c) { - if (zpl_char_is_digit(c)) - return zpl_digit_to_int(c); - else if (zpl_is_between(c, 'a', 'f')) - return c - 'a' + 10; - else if (zpl_is_between(c, 'A', 'F')) - return c - 'A' + 10; - return -1; - } - - ZPL_IMPL_INLINE zpl_u8 zpl_char_to_hex_digit(char c) { - if (c >= '0' && c <= '9') - return (zpl_u8)(c - '0'); - if (c >= 'a' && c <= 'f') - return (zpl_u8)(c - 'a'); - if (c >= 'A' && c <= 'F') - return (zpl_u8)(c - 'A'); - return 0; - } - - ZPL_IMPL_INLINE void zpl_str_to_lower(char *str) { - if (!str) return; - while (*str) { - *str = zpl_char_to_lower(*str); - str++; - } - } - - ZPL_IMPL_INLINE void zpl_str_to_upper(char *str) { - if (!str) return; - while (*str) { - *str = zpl_char_to_upper(*str); - str++; - } - } - - ZPL_IMPL_INLINE zpl_isize zpl_strlen(const char *str) { - if (str == NULL) { return 0; } - const char *p = str; - while (*str) str++; - return str-p; - } - - ZPL_IMPL_INLINE zpl_isize zpl_strnlen(const char *str, zpl_isize max_len) { - const char *end = cast(const char *) zpl_memchr(str, 0, max_len); - if (end) return end - str; - return max_len; - } - - ZPL_IMPL_INLINE zpl_isize zpl_utf8_strlen(zpl_u8 const *str) { - zpl_isize count = 0; - for (; *str; count++) { - zpl_u8 c = *str; - zpl_isize inc = 0; - if (c < 0x80) - inc = 1; - else if ((c & 0xe0) == 0xc0) - inc = 2; - else if ((c & 0xf0) == 0xe0) - inc = 3; - else if ((c & 0xf8) == 0xf0) - inc = 4; - else - return -1; - - str += inc; - } - return count; - } - - ZPL_IMPL_INLINE zpl_isize zpl_utf8_strnlen(zpl_u8 const *str, zpl_isize max_len) { - zpl_isize count = 0; - for (; *str && max_len > 0; count++) { - zpl_u8 c = *str; - zpl_isize inc = 0; - if (c < 0x80) - inc = 1; - else if ((c & 0xe0) == 0xc0) - inc = 2; - else if ((c & 0xf0) == 0xe0) - inc = 3; - else if ((c & 0xf8) == 0xf0) - inc = 4; - else - return -1; - - str += inc; - max_len -= inc; - } - return count; - } - - ZPL_IMPL_INLINE zpl_i32 zpl_strcmp(const char *s1, const char *s2) { - while (*s1 && (*s1 == *s2)) { s1++, s2++; } - return *(zpl_u8 *)s1 - *(zpl_u8 *)s2; - } - - ZPL_IMPL_INLINE char *zpl_strcpy(char *dest, const char *source) { - ZPL_ASSERT_NOT_NULL(dest); - if (source) { - char *str = dest; - while (*source) *str++ = *source++; - } - return dest; - } - - ZPL_IMPL_INLINE char *zpl_strcat(char *dest, const char *source) { - ZPL_ASSERT_NOT_NULL(dest); - if (source) { - char *str = dest; - while (*str) ++str; - while (*source) *str++ = *source++; - } - return dest; - } - - ZPL_IMPL_INLINE char *zpl_strncpy(char *dest, const char *source, zpl_isize len) { - ZPL_ASSERT_NOT_NULL(dest); - if (source) { - char *str = dest; - while (len > 0 && *source) { - *str++ = *source++; - len--; - } - while (len > 0) { - *str++ = '\0'; - len--; - } - } - return dest; - } - - ZPL_IMPL_INLINE zpl_isize zpl_strlcpy(char *dest, const char *source, zpl_isize len) { - zpl_isize result = 0; - ZPL_ASSERT_NOT_NULL(dest); - if (source) { - const char *source_start = source; - char *str = dest; - while (len > 0 && *source) { - *str++ = *source++; - len--; - } - while (len > 0) { - *str++ = '\0'; - len--; - } - - result = source - source_start; - } - return result; - } - - ZPL_IMPL_INLINE char *zpl_strrev(char *str) { - zpl_isize len = zpl_strlen(str); - char *a = str + 0; - char *b = str + len - 1; - len /= 2; - while (len--) { - zpl_swap(char, *a, *b); - a++, b--; - } - return str; - } - - ZPL_IMPL_INLINE zpl_i32 zpl_strncmp(const char *s1, const char *s2, zpl_isize len) { - for (; len > 0; s1++, s2++, len--) { - if (*s1 != *s2) - return ((s1 < s2) ? -1 : +1); - else if (*s1 == '\0') - return 0; - } - return 0; - } - - ZPL_IMPL_INLINE const char *zpl_strtok(char *output, const char *src, const char *delimit) { - while (*src && zpl_char_first_occurence(delimit, *src) == NULL) *output++ = *src++; - - *output = 0; - return *src ? src + 1 : src; - } - - ZPL_IMPL_INLINE zpl_b32 zpl_char_is_control(char c) { - return !!zpl_strchr("\"\\/bfnrt", c); - } - - ZPL_IMPL_INLINE zpl_b32 zpl__is_special_char(char c) { return !!zpl_strchr("<>:/", c); } - ZPL_IMPL_INLINE zpl_b32 zpl__is_assign_char(char c) { return !!zpl_strchr(":=|", c); } - ZPL_IMPL_INLINE zpl_b32 zpl__is_delim_char(char c) { return !!zpl_strchr(",|\n", c); } - - - ZPL_IMPL_INLINE char const *zpl_str_control_skip(char const *str, char c) { - while ((*str && *str != c) || (*(str - 1) == '\\' && *str == c && zpl_char_is_control(c))) { ++str; } - - return str; - } - - - ZPL_IMPL_INLINE zpl_b32 zpl_str_has_prefix(const char *str, const char *prefix) { - while (*prefix) { - if (*str++ != *prefix++) return false; - } - return true; - } - - ZPL_IMPL_INLINE zpl_b32 zpl_str_has_suffix(const char *str, const char *suffix) { - zpl_isize i = zpl_strlen(str); - zpl_isize j = zpl_strlen(suffix); - if (j <= i) return zpl_strcmp(str + i - j, suffix) == 0; - return false; - } - - ZPL_IMPL_INLINE const char *zpl_char_first_occurence(const char *s, char c) { - char ch = c; - for (; *s != ch; s++) { - if (*s == '\0') return NULL; - } - return s; - } - - ZPL_IMPL_INLINE const char *zpl_char_last_occurence(const char *s, char c) { - char *result = (char*)NULL; - do { - if (*s == c) result = (char *)s; - } while (*s++); - - return result; - } - - ZPL_IMPL_INLINE char const *zpl_str_trim(char const *str, zpl_b32 catch_newline) - { - while (*str && zpl_char_is_space(*str) && (!catch_newline || (catch_newline && *str != '\n'))) { ++str; } - return str; - } - - ZPL_IMPL_INLINE char const *zpl_str_skip(char const *str, char c) { - while (*str && *str != c) { ++str; } - return str; - } - - ZPL_IMPL_INLINE char const *zpl_str_skip_any(char const *str, char const*char_list) { - char const *closest_ptr = cast(char const *) zpl_ptr_add((void*)str, zpl_strlen(str)); - zpl_isize char_list_count = zpl_strlen(char_list); - for (zpl_isize i = 0; i < char_list_count; i++) { - char const *p = zpl_str_skip(str, char_list[i]); - closest_ptr = zpl_min(closest_ptr, p); - } - return closest_ptr; - } - - ZPL_IMPL_INLINE char const *zpl_str_skip_literal(char const *str, char c) { - while ((*str && *str != c) || (*str == c && *(str-1) == '\\')) { ++str; } - return str; - } - - ZPL_IMPL_INLINE void zpl_str_concat(char *dest, zpl_isize dest_len, const char *src_a, zpl_isize src_a_len, const char *src_b, - zpl_isize src_b_len) { - ZPL_ASSERT(dest_len >= src_a_len + src_b_len + 1); - if (dest) { - zpl_memcopy(dest, src_a, src_a_len); - zpl_memcopy(dest + src_a_len, src_b, src_b_len); - dest[src_a_len + src_b_len] = '\0'; - } - } - - ZPL_IMPL_INLINE zpl_f32 zpl_str_to_f32(const char *str, char **end_ptr) { - zpl_f64 f = zpl_str_to_f64(str, end_ptr); - zpl_f32 r = cast(zpl_f32) f; - return r; - } - - ZPL_IMPL_INLINE char *zpl_strdup(zpl_allocator a, char *src, zpl_isize max_len) { - ZPL_ASSERT_NOT_NULL(src); - zpl_isize len = zpl_strlen(src); - char *dest = cast(char *) zpl_alloc(a, max_len); - zpl_memset(dest + len, 0, max_len - len); - zpl_strncpy(dest, src, max_len); - - return dest; - } - - ZPL_IMPL_INLINE char **zpl_str_split_lines(zpl_allocator alloc, char *source, zpl_b32 strip_whitespace) { - char **lines = NULL, *p = source, *pd = p; - zpl_array_init(lines, alloc); - - while (*p) { - if (*pd == '\n') { - *pd = 0; - if (*(pd - 1) == '\r') *(pd - 1) = 0; - if (strip_whitespace && (pd - p) == 0) { - p = pd + 1; - continue; - } - zpl_array_append(lines, p); - p = pd + 1; - } - ++pd; - } - return lines; - } - - ZPL_END_C_DECLS - // file: header/core/stringlib.h - - - ZPL_BEGIN_C_DECLS - - typedef char *zpl_string; - - typedef struct zpl_string_header { - zpl_allocator allocator; - zpl_isize length; - zpl_isize capacity; - } zpl_string_header; - - #define ZPL_STRING_HEADER(str) (cast(zpl_string_header *)(str) - 1) - - ZPL_DEF zpl_string zpl_string_make_reserve(zpl_allocator a, zpl_isize capacity); - ZPL_DEF zpl_string zpl_string_make_length(zpl_allocator a, void const *str, zpl_isize num_bytes); - ZPL_DEF zpl_string zpl_string_sprintf(zpl_allocator a, char *buf, zpl_isize num_bytes, const char *fmt, ...); - ZPL_DEF zpl_string zpl_string_sprintf_buf(zpl_allocator a, const char *fmt, ...); // NOTE: Uses locally persistent buffer - ZPL_DEF zpl_string zpl_string_append_length(zpl_string str, void const *other, zpl_isize num_bytes); - ZPL_DEF zpl_string zpl_string_appendc(zpl_string str, const char *other); - ZPL_DEF zpl_string zpl_string_join(zpl_allocator a, const char **parts, zpl_isize count, const char *glue); - ZPL_DEF zpl_string zpl_string_set(zpl_string str, const char *cstr); - ZPL_DEF zpl_string zpl_string_make_space_for(zpl_string str, zpl_isize add_len); - ZPL_DEF zpl_isize zpl_string_allocation_size(zpl_string const str); - ZPL_DEF zpl_b32 zpl_string_are_equal(zpl_string const lhs, zpl_string const rhs); - ZPL_DEF zpl_string zpl_string_trim(zpl_string str, const char *cut_set); - ZPL_DEF zpl_string zpl_string_append_rune(zpl_string str, zpl_rune r); - ZPL_DEF zpl_string zpl_string_append_fmt(zpl_string str, const char *fmt, ...); - - ZPL_DEF_INLINE zpl_string zpl_string_make(zpl_allocator a, const char *str); - ZPL_DEF_INLINE void zpl_string_free(zpl_string str); - ZPL_DEF_INLINE void zpl_string_clear(zpl_string str); - ZPL_DEF_INLINE zpl_string zpl_string_duplicate(zpl_allocator a, zpl_string const str); - ZPL_DEF_INLINE zpl_isize zpl_string_length(zpl_string const str); - ZPL_DEF_INLINE zpl_isize zpl_string_capacity(zpl_string const str); - ZPL_DEF_INLINE zpl_isize zpl_string_available_space(zpl_string const str); - ZPL_DEF_INLINE zpl_string zpl_string_append(zpl_string str, zpl_string const other); - ZPL_DEF_INLINE zpl_string zpl_string_trim_space(zpl_string str); // Whitespace ` \t\r\n\v\f` - ZPL_DEF_INLINE void zpl__set_string_length(zpl_string str, zpl_isize len); - ZPL_DEF_INLINE void zpl__set_string_capacity(zpl_string str, zpl_isize cap); - - ZPL_IMPL_INLINE void zpl__set_string_length(zpl_string str, zpl_isize len) { ZPL_STRING_HEADER(str)->length = len; } - ZPL_IMPL_INLINE void zpl__set_string_capacity(zpl_string str, zpl_isize cap) { ZPL_STRING_HEADER(str)->capacity = cap; } - ZPL_IMPL_INLINE zpl_string zpl_string_make(zpl_allocator a, const char *str) { - zpl_isize len = str ? zpl_strlen(str) : 0; - return zpl_string_make_length(a, str, len); - } - - ZPL_IMPL_INLINE void zpl_string_free(zpl_string str) { - if (str) { - zpl_string_header *header = ZPL_STRING_HEADER(str); - zpl_free(header->allocator, header); - } - } - - ZPL_IMPL_INLINE zpl_string zpl_string_duplicate(zpl_allocator a, zpl_string const str) { - return zpl_string_make_length(a, str, zpl_string_length(str)); - } - - ZPL_IMPL_INLINE zpl_isize zpl_string_length(zpl_string const str) { return ZPL_STRING_HEADER(str)->length; } - ZPL_IMPL_INLINE zpl_isize zpl_string_capacity(zpl_string const str) { return ZPL_STRING_HEADER(str)->capacity; } - - ZPL_IMPL_INLINE zpl_isize zpl_string_available_space(zpl_string const str) { - zpl_string_header *h = ZPL_STRING_HEADER(str); - if (h->capacity > h->length) return h->capacity - h->length; - return 0; - } - - ZPL_IMPL_INLINE void zpl_string_clear(zpl_string str) { - zpl__set_string_length(str, 0); - str[0] = '\0'; - } - - ZPL_IMPL_INLINE zpl_string zpl_string_append(zpl_string str, zpl_string const other) { - return zpl_string_append_length(str, other, zpl_string_length(other)); - } - - ZPL_IMPL_INLINE zpl_string zpl_string_trim_space(zpl_string str) { return zpl_string_trim(str, " \t\r\n\v\f"); } - - - ZPL_END_C_DECLS - // file: header/core/file.h - - /** @file file.c - @brief File handling - @defgroup fileio File handling - - File I/O operations as well as path and folder structure manipulation methods. With threading enabled, it also offers async read/write methods. - - @{ - */ - - ZPL_BEGIN_C_DECLS - - typedef zpl_u32 zpl_file_mode; - - typedef enum zpl_file_mode_flag { - ZPL_FILE_MODE_READ = ZPL_BIT(0), - ZPL_FILE_MODE_WRITE = ZPL_BIT(1), - ZPL_FILE_MODE_APPEND = ZPL_BIT(2), - ZPL_FILE_MODE_RW = ZPL_BIT(3), - ZPL_FILE_MODES = ZPL_FILE_MODE_READ | ZPL_FILE_MODE_WRITE | ZPL_FILE_MODE_APPEND | ZPL_FILE_MODE_RW, - } zpl_file_mode_flag; - - // NOTE: Only used internally and for the file operations - typedef enum zpl_seek_whence_type { - ZPL_SEEK_WHENCE_BEGIN = 0, - ZPL_SEEK_WHENCE_CURRENT = 1, - ZPL_SEEK_WHENCE_END = 2, - } zpl_seek_whence_type; - - typedef enum zpl_file_error { - ZPL_FILE_ERROR_NONE, - ZPL_FILE_ERROR_INVALID, - ZPL_FILE_ERROR_INVALID_FILENAME, - ZPL_FILE_ERROR_EXISTS, - ZPL_FILE_ERROR_NOT_EXISTS, - ZPL_FILE_ERROR_PERMISSION, - ZPL_FILE_ERROR_TRUNCATION_FAILURE, - ZPL_FILE_ERROR_NOT_EMPTY, - ZPL_FILE_ERROR_NAME_TOO_LONG, - ZPL_FILE_ERROR_UNKNOWN, - } zpl_file_error; - - typedef union zpl_file_descriptor { - void *p; - zpl_intptr i; - zpl_uintptr u; - } zpl_file_descriptor; - - typedef struct zpl_file_operations zpl_file_operations; - - #define ZPL_FILE_OPEN_PROC(name) zpl_file_error name(zpl_file_descriptor *fd, zpl_file_operations *ops, zpl_file_mode mode, char const *filename) - #define ZPL_FILE_READ_AT_PROC(name) zpl_b32 name(zpl_file_descriptor fd, void *buffer, zpl_isize size, zpl_i64 offset, zpl_isize *bytes_read, zpl_b32 stop_at_newline) - #define ZPL_FILE_WRITE_AT_PROC(name) zpl_b32 name(zpl_file_descriptor fd, void const *buffer, zpl_isize size, zpl_i64 offset, zpl_isize *bytes_written) - #define ZPL_FILE_SEEK_PROC(name) zpl_b32 name(zpl_file_descriptor fd, zpl_i64 offset, zpl_seek_whence_type whence, zpl_i64 *new_offset) - #define ZPL_FILE_CLOSE_PROC(name) void name(zpl_file_descriptor fd) - - typedef ZPL_FILE_OPEN_PROC(zpl_file_open_proc); - typedef ZPL_FILE_READ_AT_PROC(zpl_file_read_proc); - typedef ZPL_FILE_WRITE_AT_PROC(zpl_file_write_proc); - typedef ZPL_FILE_SEEK_PROC(zpl_file_seek_proc); - typedef ZPL_FILE_CLOSE_PROC(zpl_file_close_proc); - - struct zpl_file_operations { - zpl_file_read_proc *read_at; - zpl_file_write_proc *write_at; - zpl_file_seek_proc *seek; - zpl_file_close_proc *close; - }; - - extern zpl_file_operations const zpl_default_file_operations; - - typedef zpl_u64 zpl_file_time; - typedef enum zpl_dir_type { - ZPL_DIR_TYPE_FILE, - ZPL_DIR_TYPE_FOLDER, - ZPL_DIR_TYPE_UNKNOWN, - } zpl_dir_type; - - struct zpl_dir_info; - - typedef struct zpl_dir_entry { - char const *filename; - struct zpl_dir_info *dir_info; - zpl_u8 type; - } zpl_dir_entry; - - typedef struct zpl_dir_info { - char const *fullpath; - zpl_dir_entry *entries; // zpl_array - - // Internals - char **filenames; // zpl_array - zpl_string buf; - } zpl_dir_info; - - typedef struct zpl_file { - zpl_file_operations ops; - zpl_file_descriptor fd; - zpl_b32 is_temp; - - char const *filename; - zpl_file_time last_write_time; - zpl_dir_entry *dir; - } zpl_file; - - typedef enum zpl_file_standard_type { - ZPL_FILE_STANDARD_INPUT, - ZPL_FILE_STANDARD_OUTPUT, - ZPL_FILE_STANDARD_ERROR, - - ZPL_FILE_STANDARD_COUNT, - } zpl_file_standard_type; - - /** - * Get standard file I/O. - * @param std Check zpl_file_standard_type - * @return File handle to standard I/O - */ - ZPL_DEF zpl_file *zpl_file_get_standard(zpl_file_standard_type std); - - /** - * Connects a system handle to a zpl file. - * @param file Pointer to zpl file - * @param handle Low-level OS handle to connect - */ - ZPL_DEF void zpl_file_connect_handle(zpl_file *file, void *handle); - - /** - * Creates a new file - * @param file - * @param filename - */ - ZPL_DEF zpl_file_error zpl_file_create(zpl_file *file, char const *filename); - - /** - * Opens a file - * @param file - * @param filename - */ - ZPL_DEF zpl_file_error zpl_file_open(zpl_file *file, char const *filename); - - /** - * Opens a file using a specified mode - * @param file - * @param mode Access mode to use - * @param filename - */ - ZPL_DEF zpl_file_error zpl_file_open_mode(zpl_file *file, zpl_file_mode mode, char const *filename); - - /** - * Constructs a new file from data - * @param file - * @param fd Low-level file descriptor to use - * @param ops File operations to rely upon - * @param filename - */ - ZPL_DEF zpl_file_error zpl_file_new(zpl_file *file, zpl_file_descriptor fd, zpl_file_operations ops, char const *filename); - - /** - * Returns a size of the file - * @param file - * @return File size - */ - ZPL_DEF zpl_i64 zpl_file_size(zpl_file *file); - - /** - * Returns the currently opened file's name - * @param file - */ - ZPL_DEF char const *zpl_file_name(zpl_file *file); - - /** - * Truncates the file by a specified size - * @param file - * @param size Size to truncate - */ - ZPL_DEF zpl_file_error zpl_file_truncate(zpl_file *file, zpl_i64 size); - - /** - * Checks whether a file's been changed since the last check - * @param file - */ - ZPL_DEF zpl_b32 zpl_file_has_changed(zpl_file *file); - - /** - * Retrieves a directory listing relative to the file - * @param file - */ - ZPL_DEF void zpl_file_dirinfo_refresh(zpl_file *file); - - /** - * Creates a temporary file - * @param file - */ - zpl_file_error zpl_file_temp(zpl_file *file); - - /** - * Closes the file - * @param file - */ - ZPL_DEF zpl_file_error zpl_file_close(zpl_file *file); - - /** - * Reads file safely - * @param file - * @param buffer Buffer to read to - * @param size Size to read - * @param offset Offset to read from - * @param bytes_read How much data we've actually read - */ - ZPL_DEF_INLINE zpl_b32 zpl_file_read_at_check(zpl_file *file, void *buffer, zpl_isize size, zpl_i64 offset, zpl_isize *bytes_read); - - /** - * Writes to file safely - * @param file - * @param buffer Buffer to read from - * @param size Size to write - * @param offset Offset to write to - * @param bytes_written How much data we've actually written - */ - ZPL_DEF_INLINE zpl_b32 zpl_file_write_at_check(zpl_file *file, void const *buffer, zpl_isize size, zpl_i64 offset, zpl_isize *bytes_written); - - - /** - * Reads file at a specific offset - * @param file - * @param buffer Buffer to read to - * @param size Size to read - * @param offset Offset to read from - * @param bytes_read How much data we've actually read - */ - ZPL_DEF_INLINE zpl_b32 zpl_file_read_at(zpl_file *file, void *buffer, zpl_isize size, zpl_i64 offset); - - /** - * Writes to file at a specific offset - * @param file - * @param buffer Buffer to read from - * @param size Size to write - * @param offset Offset to write to - * @param bytes_written How much data we've actually written - */ - ZPL_DEF_INLINE zpl_b32 zpl_file_write_at(zpl_file *file, void const *buffer, zpl_isize size, zpl_i64 offset); - - /** - * Seeks the file cursor from the beginning of file to a specific position - * @param file - * @param offset Offset to seek to - */ - ZPL_DEF_INLINE zpl_i64 zpl_file_seek(zpl_file *file, zpl_i64 offset); - - /** - * Seeks the file cursor to the end of the file - * @param file - */ - ZPL_DEF_INLINE zpl_i64 zpl_file_seek_to_end(zpl_file *file); - - /** - * Skips N bytes at the current position - * @param file - * @param bytes Bytes to skip - */ - ZPL_DEF_INLINE zpl_i64 zpl_file_skip(zpl_file *file, zpl_i64 bytes); // NOTE: Skips a certain amount of bytes - - /** - * Returns the length from the beginning of the file we've read so far - * @param file - * @return Our current position in file - */ - ZPL_DEF_INLINE zpl_i64 zpl_file_tell(zpl_file *file); - - /** - * Reads from a file - * @param file - * @param buffer Buffer to read to - * @param size Size to read - */ - ZPL_DEF_INLINE zpl_b32 zpl_file_read(zpl_file *file, void *buffer, zpl_isize size); - - /** - * Writes to a file - * @param file - * @param buffer Buffer to read from - * @param size Size to read - */ - ZPL_DEF_INLINE zpl_b32 zpl_file_write(zpl_file *file, void const *buffer, zpl_isize size); - - - typedef struct zpl_file_contents { - zpl_allocator allocator; - void *data; - zpl_isize size; - } zpl_file_contents; - - /** - * Reads the whole file contents - * @param a Allocator to use - * @param zero_terminate End the read data with null terminator - * @param filepath Path to the file - * @return File contents data - */ - ZPL_DEF zpl_file_contents zpl_file_read_contents(zpl_allocator a, zpl_b32 zero_terminate, char const *filepath); - - /** - * Frees the file content data previously read - * @param fc - */ - ZPL_DEF void zpl_file_free_contents(zpl_file_contents *fc); - - /** - * Writes content to a file - */ - ZPL_DEF zpl_b32 zpl_file_write_contents(char const* filepath, void const* buffer, zpl_isize size, zpl_file_error* err); - - /** - * Reads the file as array of lines - * - * Make sure you free both the returned buffer and the lines (zpl_array) - * @param alloc Allocator to use - * @param lines Reference to zpl_array container we store lines to - * @param filename Path to the file - * @param strip_whitespace Strip whitespace when we split to lines? - * @return File content we've read itself - */ - ZPL_DEF char *zpl_file_read_lines(zpl_allocator alloc, zpl_array(char *)*lines, char const *filename, zpl_b32 strip_whitespace); - - //! @} - - /* inlines */ - - - ZPL_IMPL_INLINE zpl_b32 zpl_file_read_at_check(zpl_file *f, void *buffer, zpl_isize size, zpl_i64 offset, zpl_isize *bytes_read) { - if (!f->ops.read_at) f->ops = zpl_default_file_operations; - return f->ops.read_at(f->fd, buffer, size, offset, bytes_read, false); - } - - ZPL_IMPL_INLINE zpl_b32 zpl_file_write_at_check(zpl_file *f, void const *buffer, zpl_isize size, zpl_i64 offset, zpl_isize *bytes_written) { - if (!f->ops.read_at) f->ops = zpl_default_file_operations; - return f->ops.write_at(f->fd, buffer, size, offset, bytes_written); - } - - ZPL_IMPL_INLINE zpl_b32 zpl_file_read_at(zpl_file *f, void *buffer, zpl_isize size, zpl_i64 offset) { - return zpl_file_read_at_check(f, buffer, size, offset, NULL); - } - - ZPL_IMPL_INLINE zpl_b32 zpl_file_write_at(zpl_file *f, void const *buffer, zpl_isize size, zpl_i64 offset) { - return zpl_file_write_at_check(f, buffer, size, offset, NULL); - } - - ZPL_IMPL_INLINE zpl_i64 zpl_file_seek(zpl_file *f, zpl_i64 offset) { - zpl_i64 new_offset = 0; - if (!f->ops.read_at) f->ops = zpl_default_file_operations; - f->ops.seek(f->fd, offset, ZPL_SEEK_WHENCE_BEGIN, &new_offset); - return new_offset; - } - - ZPL_IMPL_INLINE zpl_i64 zpl_file_seek_to_end(zpl_file *f) { - zpl_i64 new_offset = 0; - if (!f->ops.read_at) f->ops = zpl_default_file_operations; - f->ops.seek(f->fd, 0, ZPL_SEEK_WHENCE_END, &new_offset); - return new_offset; - } - - // NOTE: Skips a certain amount of bytes - ZPL_IMPL_INLINE zpl_i64 zpl_file_skip(zpl_file *f, zpl_i64 bytes) { - zpl_i64 new_offset = 0; - if (!f->ops.read_at) f->ops = zpl_default_file_operations; - f->ops.seek(f->fd, bytes, ZPL_SEEK_WHENCE_CURRENT, &new_offset); - return new_offset; - } - - ZPL_IMPL_INLINE zpl_i64 zpl_file_tell(zpl_file *f) { - zpl_i64 new_offset = 0; - if (!f->ops.read_at) f->ops = zpl_default_file_operations; - f->ops.seek(f->fd, 0, ZPL_SEEK_WHENCE_CURRENT, &new_offset); - return new_offset; - } - - ZPL_IMPL_INLINE zpl_b32 zpl_file_read(zpl_file *f, void *buffer, zpl_isize size) { - zpl_i64 cur_offset = zpl_file_tell(f); - zpl_b32 result = zpl_file_read_at(f, buffer, size, zpl_file_tell(f)); - zpl_file_seek(f, cur_offset + size); - return result; - } - - ZPL_IMPL_INLINE zpl_b32 zpl_file_write(zpl_file *f, void const *buffer, zpl_isize size) { - zpl_i64 cur_offset = zpl_file_tell(f); - zpl_b32 result = zpl_file_write_at(f, buffer, size, zpl_file_tell(f)); - zpl_file_seek(f, cur_offset + size); - return result; - } - - ZPL_END_C_DECLS - // file: header/core/file_stream.h - - /** @file file_stream.c - @brief File stream - @defgroup fileio File stream - - File streaming operations on memory. - - @{ - */ - - ZPL_BEGIN_C_DECLS - - typedef enum { - /* Allows us to write to the buffer directly. Beware: you can not append a new data! */ - ZPL_FILE_STREAM_WRITABLE = ZPL_BIT(0), - - /* Clones the input buffer so you can write (zpl_file_write*) data into it. */ - /* Since we work with a clone, the buffer size can dynamically grow as well. */ - ZPL_FILE_STREAM_CLONE_WRITABLE = ZPL_BIT(1), - } zpl_file_stream_flags; - - /** - * Opens a new memory stream - * @param file - * @param allocator - */ - ZPL_DEF void zpl_file_stream_new(zpl_file* file, zpl_allocator allocator); - - /** - * Opens a memory stream over an existing buffer - * @param file - * @param allocator - * @param buffer Memory to create stream from - * @param size Buffer's size - * @param flags - */ - ZPL_DEF void zpl_file_stream_open(zpl_file* file, zpl_allocator allocator, zpl_u8 *buffer, zpl_isize size, zpl_file_stream_flags flags); - - /** - * Retrieves the stream's underlying buffer and buffer size. - * @param file memory stream - * @param size (Optional) buffer size - */ - ZPL_DEF zpl_u8 *zpl_file_stream_buf(zpl_file* file, zpl_isize *size); - - extern zpl_file_operations const zpl_memory_file_operations; - - //! @} - - ZPL_END_C_DECLS - // file: header/core/file_misc.h - - - ZPL_BEGIN_C_DECLS - - #ifndef ZPL_PATH_SEPARATOR - # if defined(ZPL_SYSTEM_WINDOWS) - # define ZPL_PATH_SEPARATOR '\\' - # else - # define ZPL_PATH_SEPARATOR '/' - # endif - #endif - - #ifndef ZPL_MAX_PATH - # if defined(ZPL_SYSTEM_WINDOWS) - # define ZPL_MAX_PATH MAX_PATH - # elif defined(ZPL_SYSTEM_UNIX) && !defined(ZPL_SYSTEM_EMSCRIPTEN) - # define ZPL_MAX_PATH PATH_MAX - # else - # define ZPL_MAX_PATH 4096 - # endif - #endif - - /** - * Checks if file/directory exists - * @param filepath - */ - ZPL_DEF zpl_b32 zpl_fs_exists(char const *filepath); - - /** - * Retrieves node's type (file, folder, ...) - * @param path - */ - ZPL_DEF zpl_u8 zpl_fs_get_type(char const *path); - - /** - * Retrieves file's last write time - * @param filepath - */ - ZPL_DEF zpl_file_time zpl_fs_last_write_time(char const *filepath); - - /** - * Copies the file to a directory - * @param existing_filename - * @param new_filename - * @param fail_if_exists - */ - ZPL_DEF zpl_b32 zpl_fs_copy(char const *existing_filename, char const *new_filename, zpl_b32 fail_if_exists); - - /** - * Moves the file to a directory - * @param existing_filename - * @param new_filename - */ - ZPL_DEF zpl_b32 zpl_fs_move(char const *existing_filename, char const *new_filename); - - /** - * Removes a file from a directory - * @param filename - */ - ZPL_DEF zpl_b32 zpl_fs_remove(char const *filename); - - ZPL_DEF_INLINE zpl_b32 zpl_path_is_absolute(char const *path); - ZPL_DEF_INLINE zpl_b32 zpl_path_is_relative(char const *path); - ZPL_DEF_INLINE zpl_b32 zpl_path_is_root(char const *path); - - ZPL_DEF_INLINE char const *zpl_path_base_name(char const *path); - ZPL_DEF_INLINE char const *zpl_path_extension(char const *path); - - ZPL_DEF void zpl_path_fix_slashes(char *path); - - ZPL_DEF zpl_file_error zpl_path_mkdir(char const *path, zpl_i32 mode); - ZPL_DEF zpl_isize zpl_path_mkdir_recursive(char const *path, zpl_i32 mode); - ZPL_DEF zpl_file_error zpl_path_rmdir(char const *path); - - ZPL_DEF char *zpl_path_get_full_name(zpl_allocator a, char const *path); - - /** - * Returns file paths terminated by newline (\n) - * @param alloc [description] - * @param dirname [description] - * @param recurse [description] - * @return [description] - */ - ZPL_DEF /*zpl_string*/char * zpl_path_dirlist(zpl_allocator alloc, char const *dirname, zpl_b32 recurse); - - /** - * Initialize dirinfo from specified path - * @param dir [description] - * @param path [description] - */ - ZPL_DEF void zpl_dirinfo_init(zpl_dir_info *dir, char const *path); - ZPL_DEF void zpl_dirinfo_free(zpl_dir_info *dir); - - /** - * Analyze the entry's dirinfo - * @param dir_entry [description] - */ - ZPL_DEF void zpl_dirinfo_step(zpl_dir_entry *dir_entry); - - - /* inlines */ - - ZPL_IMPL_INLINE zpl_b32 zpl_path_is_absolute(char const *path) { - zpl_b32 result = false; - ZPL_ASSERT_NOT_NULL(path); - #if defined(ZPL_SYSTEM_WINDOWS) - result = (zpl_strlen(path) > 2) && zpl_char_is_alpha(path[0]) && (path[1] == ':' && path[2] == ZPL_PATH_SEPARATOR); - #else - result = (zpl_strlen(path) > 0 && path[0] == ZPL_PATH_SEPARATOR); - #endif - return result; - } - - ZPL_IMPL_INLINE zpl_b32 zpl_path_is_relative(char const *path) { return !zpl_path_is_absolute(path); } - - ZPL_IMPL_INLINE zpl_b32 zpl_path_is_root(char const *path) { - zpl_b32 result = false; - ZPL_ASSERT_NOT_NULL(path); - #if defined(ZPL_SYSTEM_WINDOWS) - result = zpl_path_is_absolute(path) && (zpl_strlen(path) == 3); - #else - result = zpl_path_is_absolute(path) && (zpl_strlen(path) == 1); - #endif - return result; - } - - ZPL_IMPL_INLINE char const *zpl_path_base_name(char const *path) { - char const *ls; - ZPL_ASSERT_NOT_NULL(path); - zpl_path_fix_slashes((char *)path); - ls = zpl_char_last_occurence(path, ZPL_PATH_SEPARATOR); - return (ls == NULL) ? path : ls + 1; - } - - ZPL_IMPL_INLINE char const *zpl_path_extension(char const *path) { - char const *ld; - ZPL_ASSERT_NOT_NULL(path); - ld = zpl_char_last_occurence(path, '.'); - return (ld == NULL) ? NULL : ld + 1; - } - - ZPL_END_C_DECLS - // file: header/core/file_tar.h - - /** @file file_tar.c - @brief Tar archiving module - @defgroup fileio Tar module - - Allows to easily pack/unpack files. - Based on: https://github.com/rxi/microtar/ - - Disclaimer: The pack method does not support file permissions nor GID/UID information. Only regular files are supported. - Use zpl_tar_pack_dir to pack an entire directory recursively. Empty folders are ignored. - - @{ - */ - - - ZPL_BEGIN_C_DECLS - - typedef enum { - ZPL_TAR_ERROR_NONE, - ZPL_TAR_ERROR_INTERRUPTED, - ZPL_TAR_ERROR_IO_ERROR, - ZPL_TAR_ERROR_BAD_CHECKSUM, - ZPL_TAR_ERROR_FILE_NOT_FOUND, - ZPL_TAR_ERROR_INVALID_INPUT, - } zpl_tar_errors; - - typedef enum { - ZPL_TAR_TYPE_REGULAR = '0', - ZPL_TAR_TYPE_LINK = '1', - ZPL_TAR_TYPE_SYMBOL = '2', - ZPL_TAR_TYPE_CHR = '3', - ZPL_TAR_TYPE_BLK = '4', - ZPL_TAR_TYPE_DIR = '5', - ZPL_TAR_TYPE_FIFO = '6' - } zpl_tar_file_type; - - typedef struct { - char type; - char *path; - zpl_i64 offset; - zpl_i64 length; - zpl_isize error; - } zpl_tar_record; - - #define ZPL_TAR_UNPACK_PROC(name) zpl_isize name(zpl_file *archive, zpl_tar_record *file, void* user_data) - typedef ZPL_TAR_UNPACK_PROC(zpl_tar_unpack_proc); - - /** - * @brief Packs a list of files - * Packs a list of provided files. Note that this method only supports regular files - * and does not provide extended info such as GID/UID or permissions. - * @param archive archive we pack files into - * @param paths list of files - * @param paths_len number of files provided - * @return error - */ - ZPL_DEF zpl_isize zpl_tar_pack(zpl_file *archive, char const **paths, zpl_isize paths_len); - - /** - * @brief Packs an entire directory - * Packs an entire directory of files recursively. - * @param archive archive we pack files to - * @param path folder to pack - * @param alloc memory allocator to use (ex. zpl_heap()) - * @return error - */ - ZPL_DEF zpl_isize zpl_tar_pack_dir(zpl_file *archive, char const *path, zpl_allocator alloc); - - /** - * @brief Unpacks an existing archive - * Unpacks an existing archive. Users provide a callback in which information about file is provided. - * Library does not unpack files to the filesystem nor reads any file data. - * @param archive archive we unpack files from - * @param unpack_proc callback we call per each file parsed - * @param user_data user provided data - * @return error - */ - ZPL_DEF zpl_isize zpl_tar_unpack(zpl_file *archive, zpl_tar_unpack_proc *unpack_proc, void *user_data); - - /** - * @brief Unpacks an existing archive into directory - * Unpacks an existing archive into directory. The folder structure will be re-created automatically. - * @param archive archive we unpack files from - * @param dest directory to unpack files to - * @return error - */ - ZPL_DEF_INLINE zpl_isize zpl_tar_unpack_dir(zpl_file *archive, char const *dest); - - ZPL_DEF ZPL_TAR_UNPACK_PROC(zpl_tar_default_list_file); - ZPL_DEF ZPL_TAR_UNPACK_PROC(zpl_tar_default_unpack_file); +ZPL_BEGIN_C_DECLS + +ZPL_DEF_INLINE char zpl_char_to_lower(char c); +ZPL_DEF_INLINE char zpl_char_to_upper(char c); +ZPL_DEF_INLINE zpl_b32 zpl_char_is_space(char c); +ZPL_DEF_INLINE zpl_b32 zpl_char_is_digit(char c); +ZPL_DEF_INLINE zpl_b32 zpl_char_is_hex_digit(char c); +ZPL_DEF_INLINE zpl_b32 zpl_char_is_alpha(char c); +ZPL_DEF_INLINE zpl_b32 zpl_char_is_alphanumeric(char c); +ZPL_DEF_INLINE zpl_i32 zpl_digit_to_int(char c); +ZPL_DEF_INLINE zpl_i32 zpl_hex_digit_to_int(char c); +ZPL_DEF_INLINE zpl_u8 zpl_char_to_hex_digit(char c); +ZPL_DEF_INLINE zpl_b32 zpl_char_is_control(char c); + +// NOTE: ASCII only +ZPL_DEF_INLINE void zpl_str_to_lower(char *str); +ZPL_DEF_INLINE void zpl_str_to_upper(char *str); + +ZPL_DEF_INLINE char const *zpl_str_trim(char const *str, zpl_b32 catch_newline); +ZPL_DEF_INLINE char const *zpl_str_skip(char const *str, char c); +ZPL_DEF_INLINE char const *zpl_str_skip_any(char const *str, char const*char_list); +ZPL_DEF_INLINE char const *zpl_str_skip_literal(char const *str, char c); +ZPL_DEF_INLINE char const *zpl_str_control_skip(char const *str, char c); + +ZPL_DEF_INLINE zpl_isize zpl_strlen(const char *str); +ZPL_DEF_INLINE zpl_isize zpl_strnlen(const char *str, zpl_isize max_len); +ZPL_DEF_INLINE zpl_i32 zpl_strcmp(const char *s1, const char *s2); +ZPL_DEF_INLINE zpl_i32 zpl_strncmp(const char *s1, const char *s2, zpl_isize len); +ZPL_DEF_INLINE char *zpl_strcpy(char *dest, const char *source); +ZPL_DEF_INLINE char *zpl_strcat(char *dest, const char *source); +ZPL_DEF_INLINE char *zpl_strncpy(char *dest, const char *source, zpl_isize len); +ZPL_DEF_INLINE zpl_isize zpl_strlcpy(char *dest, const char *source, zpl_isize len); +ZPL_DEF_INLINE char *zpl_strrev(char *str); // NOTE: ASCII only +ZPL_DEF_INLINE const char *zpl_strtok(char *output, const char *src, const char *delimit); + +ZPL_DEF_INLINE char *zpl_strdup(zpl_allocator a, char *src, zpl_isize max_len); +ZPL_DEF_INLINE char **zpl_str_split_lines(zpl_allocator alloc, char *source, zpl_b32 strip_whitespace); + +#define zpl_str_expand(str) str, zpl_strlen(str) +#define zpl_str_advance_while(str, cond) \ +do { \ +++str; \ +} while ((cond)); + +ZPL_DEF_INLINE zpl_b32 zpl_str_has_prefix(const char *str, const char *prefix); +ZPL_DEF_INLINE zpl_b32 zpl_str_has_suffix(const char *str, const char *suffix); + +ZPL_DEF_INLINE const char *zpl_char_first_occurence(const char *str, char c); +ZPL_DEF_INLINE const char *zpl_char_last_occurence(const char *str, char c); +#define zpl_strchr zpl_char_first_occurence + +ZPL_DEF_INLINE void zpl_str_concat(char *dest, zpl_isize dest_len, const char *src_a, zpl_isize src_a_len, const char *src_b, zpl_isize src_b_len); + +ZPL_DEF zpl_u64 zpl_str_to_u64(const char *str, char **end_ptr, zpl_i32 base); // TODO: Support more than just decimal and hexadecimal +ZPL_DEF zpl_i64 zpl_str_to_i64(const char *str, char **end_ptr, zpl_i32 base); // TODO: Support more than just decimal and hexadecimal +ZPL_DEF zpl_f64 zpl_str_to_f64(const char *str, char **end_ptr); +ZPL_DEF void zpl_i64_to_str(zpl_i64 value, char *string, zpl_i32 base); +ZPL_DEF void zpl_u64_to_str(zpl_u64 value, char *string, zpl_i32 base); + +ZPL_DEF_INLINE zpl_f32 zpl_str_to_f32(const char *str, char **end_ptr); + +//////////////////////////////////////////////////////////////// +// +// UTF-8 Handling +// +// + +// NOTE: Does not check if utf-8 string is valid +ZPL_IMPL_INLINE zpl_isize zpl_utf8_strlen(zpl_u8 const *str); +ZPL_IMPL_INLINE zpl_isize zpl_utf8_strnlen(zpl_u8 const *str, zpl_isize max_len); + +// NOTE: Windows doesn't handle 8 bit filenames well +ZPL_DEF zpl_u16 *zpl_utf8_to_ucs2(zpl_u16 *buffer, zpl_isize len, zpl_u8 const *str); +ZPL_DEF zpl_u8 *zpl_ucs2_to_utf8(zpl_u8 *buffer, zpl_isize len, zpl_u16 const *str); +ZPL_DEF zpl_u16 *zpl_utf8_to_ucs2_buf(zpl_u8 const *str); // NOTE: Uses locally persisting buffer +ZPL_DEF zpl_u8 *zpl_ucs2_to_utf8_buf(zpl_u16 const *str); // NOTE: Uses locally persisting buffer + +// NOTE: Returns size of codepoint in bytes +ZPL_DEF zpl_isize zpl_utf8_decode(zpl_u8 const *str, zpl_isize str_len, zpl_rune *codepoint); +ZPL_DEF zpl_isize zpl_utf8_codepoint_size(zpl_u8 const *str, zpl_isize str_len); +ZPL_DEF zpl_isize zpl_utf8_encode_rune(zpl_u8 buf[4], zpl_rune r); + +/* inlines */ + +ZPL_IMPL_INLINE char zpl_char_to_lower(char c) { + if (c >= 'A' && c <= 'Z') return 'a' + (c - 'A'); + return c; +} + +ZPL_IMPL_INLINE char zpl_char_to_upper(char c) { + if (c >= 'a' && c <= 'z') return 'A' + (c - 'a'); + return c; +} + +ZPL_IMPL_INLINE zpl_b32 zpl_char_is_space(char c) { + if (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v') return true; + return false; +} + +ZPL_IMPL_INLINE zpl_b32 zpl_char_is_digit(char c) { + if (c >= '0' && c <= '9') return true; + return false; +} + +ZPL_IMPL_INLINE zpl_b32 zpl_char_is_hex_digit(char c) { + if (zpl_char_is_digit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) return true; + return false; +} + +ZPL_IMPL_INLINE zpl_b32 zpl_char_is_alpha(char c) { + if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) return true; + return false; +} + +ZPL_IMPL_INLINE zpl_b32 zpl_char_is_alphanumeric(char c) { return zpl_char_is_alpha(c) || zpl_char_is_digit(c); } + +ZPL_IMPL_INLINE zpl_i32 zpl_digit_to_int(char c) { return zpl_char_is_digit(c) ? c - '0' : c - 'W'; } + +ZPL_IMPL_INLINE zpl_i32 zpl_hex_digit_to_int(char c) { + if (zpl_char_is_digit(c)) + return zpl_digit_to_int(c); + else if (zpl_is_between(c, 'a', 'f')) + return c - 'a' + 10; + else if (zpl_is_between(c, 'A', 'F')) + return c - 'A' + 10; + return -1; +} + +ZPL_IMPL_INLINE zpl_u8 zpl_char_to_hex_digit(char c) { + if (c >= '0' && c <= '9') + return (zpl_u8)(c - '0'); + if (c >= 'a' && c <= 'f') + return (zpl_u8)(c - 'a'); + if (c >= 'A' && c <= 'F') + return (zpl_u8)(c - 'A'); + return 0; +} + +ZPL_IMPL_INLINE void zpl_str_to_lower(char *str) { + if (!str) return; + while (*str) { + *str = zpl_char_to_lower(*str); + str++; + } +} + +ZPL_IMPL_INLINE void zpl_str_to_upper(char *str) { + if (!str) return; + while (*str) { + *str = zpl_char_to_upper(*str); + str++; + } +} + +ZPL_IMPL_INLINE zpl_isize zpl_strlen(const char *str) { + if (str == NULL) { return 0; } + const char *p = str; + while (*str) str++; + return str-p; +} + +ZPL_IMPL_INLINE zpl_isize zpl_strnlen(const char *str, zpl_isize max_len) { + const char *end = cast(const char *) zpl_memchr(str, 0, max_len); + if (end) return end - str; + return max_len; +} + +ZPL_IMPL_INLINE zpl_isize zpl_utf8_strlen(zpl_u8 const *str) { + zpl_isize count = 0; + for (; *str; count++) { + zpl_u8 c = *str; + zpl_isize inc = 0; + if (c < 0x80) + inc = 1; + else if ((c & 0xe0) == 0xc0) + inc = 2; + else if ((c & 0xf0) == 0xe0) + inc = 3; + else if ((c & 0xf8) == 0xf0) + inc = 4; + else + return -1; + + str += inc; + } + return count; +} + +ZPL_IMPL_INLINE zpl_isize zpl_utf8_strnlen(zpl_u8 const *str, zpl_isize max_len) { + zpl_isize count = 0; + for (; *str && max_len > 0; count++) { + zpl_u8 c = *str; + zpl_isize inc = 0; + if (c < 0x80) + inc = 1; + else if ((c & 0xe0) == 0xc0) + inc = 2; + else if ((c & 0xf0) == 0xe0) + inc = 3; + else if ((c & 0xf8) == 0xf0) + inc = 4; + else + return -1; + + str += inc; + max_len -= inc; + } + return count; +} + +ZPL_IMPL_INLINE zpl_i32 zpl_strcmp(const char *s1, const char *s2) { + while (*s1 && (*s1 == *s2)) { s1++, s2++; } + return *(zpl_u8 *)s1 - *(zpl_u8 *)s2; +} + +ZPL_IMPL_INLINE char *zpl_strcpy(char *dest, const char *source) { + ZPL_ASSERT_NOT_NULL(dest); + if (source) { + char *str = dest; + while (*source) *str++ = *source++; + } + return dest; +} + +ZPL_IMPL_INLINE char *zpl_strcat(char *dest, const char *source) { + ZPL_ASSERT_NOT_NULL(dest); + if (source) { + char *str = dest; + while (*str) ++str; + while (*source) *str++ = *source++; + } + return dest; +} + +ZPL_IMPL_INLINE char *zpl_strncpy(char *dest, const char *source, zpl_isize len) { + ZPL_ASSERT_NOT_NULL(dest); + if (source) { + char *str = dest; + while (len > 0 && *source) { + *str++ = *source++; + len--; + } + while (len > 0) { + *str++ = '\0'; + len--; + } + } + return dest; +} + +ZPL_IMPL_INLINE zpl_isize zpl_strlcpy(char *dest, const char *source, zpl_isize len) { + zpl_isize result = 0; + ZPL_ASSERT_NOT_NULL(dest); + if (source) { + const char *source_start = source; + char *str = dest; + while (len > 0 && *source) { + *str++ = *source++; + len--; + } + while (len > 0) { + *str++ = '\0'; + len--; + } + + result = source - source_start; + } + return result; +} + +ZPL_IMPL_INLINE char *zpl_strrev(char *str) { + zpl_isize len = zpl_strlen(str); + char *a = str + 0; + char *b = str + len - 1; + len /= 2; + while (len--) { + zpl_swap(char, *a, *b); + a++, b--; + } + return str; +} + +ZPL_IMPL_INLINE zpl_i32 zpl_strncmp(const char *s1, const char *s2, zpl_isize len) { + for (; len > 0; s1++, s2++, len--) { + if (*s1 != *s2) + return ((s1 < s2) ? -1 : +1); + else if (*s1 == '\0') + return 0; + } + return 0; +} + +ZPL_IMPL_INLINE const char *zpl_strtok(char *output, const char *src, const char *delimit) { + while (*src && zpl_char_first_occurence(delimit, *src) == NULL) *output++ = *src++; + + *output = 0; + return *src ? src + 1 : src; +} + +ZPL_IMPL_INLINE zpl_b32 zpl_char_is_control(char c) { + return !!zpl_strchr("\"\\/bfnrt", c); +} + +ZPL_IMPL_INLINE zpl_b32 zpl__is_special_char(char c) { return !!zpl_strchr("<>:/", c); } +ZPL_IMPL_INLINE zpl_b32 zpl__is_assign_char(char c) { return !!zpl_strchr(":=|", c); } +ZPL_IMPL_INLINE zpl_b32 zpl__is_delim_char(char c) { return !!zpl_strchr(",|\n", c); } + + +ZPL_IMPL_INLINE char const *zpl_str_control_skip(char const *str, char c) { + while ((*str && *str != c) || (*(str - 1) == '\\' && *str == c && zpl_char_is_control(c))) { ++str; } + + return str; +} + + +ZPL_IMPL_INLINE zpl_b32 zpl_str_has_prefix(const char *str, const char *prefix) { + while (*prefix) { + if (*str++ != *prefix++) return false; + } + return true; +} + +ZPL_IMPL_INLINE zpl_b32 zpl_str_has_suffix(const char *str, const char *suffix) { + zpl_isize i = zpl_strlen(str); + zpl_isize j = zpl_strlen(suffix); + if (j <= i) return zpl_strcmp(str + i - j, suffix) == 0; + return false; +} + +ZPL_IMPL_INLINE const char *zpl_char_first_occurence(const char *s, char c) { + char ch = c; + for (; *s != ch; s++) { + if (*s == '\0') return NULL; + } + return s; +} + +ZPL_IMPL_INLINE const char *zpl_char_last_occurence(const char *s, char c) { + char *result = (char*)NULL; + do { + if (*s == c) result = (char *)s; + } while (*s++); + + return result; +} + +ZPL_IMPL_INLINE char const *zpl_str_trim(char const *str, zpl_b32 catch_newline) +{ + while (*str && zpl_char_is_space(*str) && (!catch_newline || (catch_newline && *str != '\n'))) { ++str; } + return str; +} + +ZPL_IMPL_INLINE char const *zpl_str_skip(char const *str, char c) { + while (*str && *str != c) { ++str; } + return str; +} + +ZPL_IMPL_INLINE char const *zpl_str_skip_any(char const *str, char const*char_list) { + char const *closest_ptr = cast(char const *) zpl_ptr_add((void*)str, zpl_strlen(str)); + zpl_isize char_list_count = zpl_strlen(char_list); + for (zpl_isize i = 0; i < char_list_count; i++) { + char const *p = zpl_str_skip(str, char_list[i]); + closest_ptr = zpl_min(closest_ptr, p); + } + return closest_ptr; +} + +ZPL_IMPL_INLINE char const *zpl_str_skip_literal(char const *str, char c) { + while ((*str && *str != c) || (*str == c && *(str-1) == '\\')) { ++str; } + return str; +} + +ZPL_IMPL_INLINE void zpl_str_concat(char *dest, zpl_isize dest_len, const char *src_a, zpl_isize src_a_len, const char *src_b, + zpl_isize src_b_len) { + ZPL_ASSERT(dest_len >= src_a_len + src_b_len + 1); + if (dest) { + zpl_memcopy(dest, src_a, src_a_len); + zpl_memcopy(dest + src_a_len, src_b, src_b_len); + dest[src_a_len + src_b_len] = '\0'; + } +} + +ZPL_IMPL_INLINE zpl_f32 zpl_str_to_f32(const char *str, char **end_ptr) { + zpl_f64 f = zpl_str_to_f64(str, end_ptr); + zpl_f32 r = cast(zpl_f32) f; + return r; +} + +ZPL_IMPL_INLINE char *zpl_strdup(zpl_allocator a, char *src, zpl_isize max_len) { + ZPL_ASSERT_NOT_NULL(src); + zpl_isize len = zpl_strlen(src); + char *dest = cast(char *) zpl_alloc(a, max_len); + zpl_memset(dest + len, 0, max_len - len); + zpl_strncpy(dest, src, max_len); + + return dest; +} + +ZPL_IMPL_INLINE char **zpl_str_split_lines(zpl_allocator alloc, char *source, zpl_b32 strip_whitespace) { + char **lines = NULL, *p = source, *pd = p; + zpl_array_init(lines, alloc); + + while (*p) { + if (*pd == '\n') { + *pd = 0; + if (*(pd - 1) == '\r') *(pd - 1) = 0; + if (strip_whitespace && (pd - p) == 0) { + p = pd + 1; + continue; + } + zpl_array_append(lines, p); + p = pd + 1; + } + ++pd; + } + return lines; +} + +ZPL_END_C_DECLS +// file: header/core/stringlib.h + + +ZPL_BEGIN_C_DECLS + +typedef char *zpl_string; + +typedef struct zpl_string_header { + zpl_allocator allocator; + zpl_isize length; + zpl_isize capacity; +} zpl_string_header; + +#define ZPL_STRING_HEADER(str) (cast(zpl_string_header *)(str) - 1) + +ZPL_DEF zpl_string zpl_string_make_reserve(zpl_allocator a, zpl_isize capacity); +ZPL_DEF zpl_string zpl_string_make_length(zpl_allocator a, void const *str, zpl_isize num_bytes); +ZPL_DEF zpl_string zpl_string_sprintf(zpl_allocator a, char *buf, zpl_isize num_bytes, const char *fmt, ...); +ZPL_DEF zpl_string zpl_string_sprintf_buf(zpl_allocator a, const char *fmt, ...); // NOTE: Uses locally persistent buffer +ZPL_DEF zpl_string zpl_string_append_length(zpl_string str, void const *other, zpl_isize num_bytes); +ZPL_DEF zpl_string zpl_string_appendc(zpl_string str, const char *other); +ZPL_DEF zpl_string zpl_string_join(zpl_allocator a, const char **parts, zpl_isize count, const char *glue); +ZPL_DEF zpl_string zpl_string_set(zpl_string str, const char *cstr); +ZPL_DEF zpl_string zpl_string_make_space_for(zpl_string str, zpl_isize add_len); +ZPL_DEF zpl_isize zpl_string_allocation_size(zpl_string const str); +ZPL_DEF zpl_b32 zpl_string_are_equal(zpl_string const lhs, zpl_string const rhs); +ZPL_DEF zpl_string zpl_string_trim(zpl_string str, const char *cut_set); +ZPL_DEF zpl_string zpl_string_append_rune(zpl_string str, zpl_rune r); +ZPL_DEF zpl_string zpl_string_append_fmt(zpl_string str, const char *fmt, ...); + +ZPL_DEF_INLINE zpl_string zpl_string_make(zpl_allocator a, const char *str); +ZPL_DEF_INLINE void zpl_string_free(zpl_string str); +ZPL_DEF_INLINE void zpl_string_clear(zpl_string str); +ZPL_DEF_INLINE zpl_string zpl_string_duplicate(zpl_allocator a, zpl_string const str); +ZPL_DEF_INLINE zpl_isize zpl_string_length(zpl_string const str); +ZPL_DEF_INLINE zpl_isize zpl_string_capacity(zpl_string const str); +ZPL_DEF_INLINE zpl_isize zpl_string_available_space(zpl_string const str); +ZPL_DEF_INLINE zpl_string zpl_string_append(zpl_string str, zpl_string const other); +ZPL_DEF_INLINE zpl_string zpl_string_trim_space(zpl_string str); // Whitespace ` \t\r\n\v\f` +ZPL_DEF_INLINE void zpl__set_string_length(zpl_string str, zpl_isize len); +ZPL_DEF_INLINE void zpl__set_string_capacity(zpl_string str, zpl_isize cap); + +ZPL_IMPL_INLINE void zpl__set_string_length(zpl_string str, zpl_isize len) { ZPL_STRING_HEADER(str)->length = len; } +ZPL_IMPL_INLINE void zpl__set_string_capacity(zpl_string str, zpl_isize cap) { ZPL_STRING_HEADER(str)->capacity = cap; } +ZPL_IMPL_INLINE zpl_string zpl_string_make(zpl_allocator a, const char *str) { + zpl_isize len = str ? zpl_strlen(str) : 0; + return zpl_string_make_length(a, str, len); +} + +ZPL_IMPL_INLINE void zpl_string_free(zpl_string str) { + if (str) { + zpl_string_header *header = ZPL_STRING_HEADER(str); + zpl_free(header->allocator, header); + } +} + +ZPL_IMPL_INLINE zpl_string zpl_string_duplicate(zpl_allocator a, zpl_string const str) { + return zpl_string_make_length(a, str, zpl_string_length(str)); +} + +ZPL_IMPL_INLINE zpl_isize zpl_string_length(zpl_string const str) { return ZPL_STRING_HEADER(str)->length; } +ZPL_IMPL_INLINE zpl_isize zpl_string_capacity(zpl_string const str) { return ZPL_STRING_HEADER(str)->capacity; } + +ZPL_IMPL_INLINE zpl_isize zpl_string_available_space(zpl_string const str) { + zpl_string_header *h = ZPL_STRING_HEADER(str); + if (h->capacity > h->length) return h->capacity - h->length; + return 0; +} + +ZPL_IMPL_INLINE void zpl_string_clear(zpl_string str) { + zpl__set_string_length(str, 0); + str[0] = '\0'; +} + +ZPL_IMPL_INLINE zpl_string zpl_string_append(zpl_string str, zpl_string const other) { + return zpl_string_append_length(str, other, zpl_string_length(other)); +} + +ZPL_IMPL_INLINE zpl_string zpl_string_trim_space(zpl_string str) { return zpl_string_trim(str, " \t\r\n\v\f"); } + + +ZPL_END_C_DECLS +// file: header/core/file.h + +/** @file file.c +@brief File handling +@defgroup fileio File handling + +File I/O operations as well as path and folder structure manipulation methods. With threading enabled, it also offers async read/write methods. + +@{ +*/ + +ZPL_BEGIN_C_DECLS + +typedef zpl_u32 zpl_file_mode; + +typedef enum zpl_file_mode_flag { + ZPL_FILE_MODE_READ = ZPL_BIT(0), + ZPL_FILE_MODE_WRITE = ZPL_BIT(1), + ZPL_FILE_MODE_APPEND = ZPL_BIT(2), + ZPL_FILE_MODE_RW = ZPL_BIT(3), + ZPL_FILE_MODES = ZPL_FILE_MODE_READ | ZPL_FILE_MODE_WRITE | ZPL_FILE_MODE_APPEND | ZPL_FILE_MODE_RW, +} zpl_file_mode_flag; + +// NOTE: Only used internally and for the file operations +typedef enum zpl_seek_whence_type { + ZPL_SEEK_WHENCE_BEGIN = 0, + ZPL_SEEK_WHENCE_CURRENT = 1, + ZPL_SEEK_WHENCE_END = 2, +} zpl_seek_whence_type; + +typedef enum zpl_file_error { + ZPL_FILE_ERROR_NONE, + ZPL_FILE_ERROR_INVALID, + ZPL_FILE_ERROR_INVALID_FILENAME, + ZPL_FILE_ERROR_EXISTS, + ZPL_FILE_ERROR_NOT_EXISTS, + ZPL_FILE_ERROR_PERMISSION, + ZPL_FILE_ERROR_TRUNCATION_FAILURE, + ZPL_FILE_ERROR_NOT_EMPTY, + ZPL_FILE_ERROR_NAME_TOO_LONG, + ZPL_FILE_ERROR_UNKNOWN, +} zpl_file_error; + +typedef union zpl_file_descriptor { + void *p; + zpl_intptr i; + zpl_uintptr u; +} zpl_file_descriptor; + +typedef struct zpl_file_operations zpl_file_operations; + +#define ZPL_FILE_OPEN_PROC(name) zpl_file_error name(zpl_file_descriptor *fd, zpl_file_operations *ops, zpl_file_mode mode, char const *filename) +#define ZPL_FILE_READ_AT_PROC(name) zpl_b32 name(zpl_file_descriptor fd, void *buffer, zpl_isize size, zpl_i64 offset, zpl_isize *bytes_read, zpl_b32 stop_at_newline) +#define ZPL_FILE_WRITE_AT_PROC(name) zpl_b32 name(zpl_file_descriptor fd, void const *buffer, zpl_isize size, zpl_i64 offset, zpl_isize *bytes_written) +#define ZPL_FILE_SEEK_PROC(name) zpl_b32 name(zpl_file_descriptor fd, zpl_i64 offset, zpl_seek_whence_type whence, zpl_i64 *new_offset) +#define ZPL_FILE_CLOSE_PROC(name) void name(zpl_file_descriptor fd) + +typedef ZPL_FILE_OPEN_PROC(zpl_file_open_proc); +typedef ZPL_FILE_READ_AT_PROC(zpl_file_read_proc); +typedef ZPL_FILE_WRITE_AT_PROC(zpl_file_write_proc); +typedef ZPL_FILE_SEEK_PROC(zpl_file_seek_proc); +typedef ZPL_FILE_CLOSE_PROC(zpl_file_close_proc); + +struct zpl_file_operations { + zpl_file_read_proc *read_at; + zpl_file_write_proc *write_at; + zpl_file_seek_proc *seek; + zpl_file_close_proc *close; +}; + +extern zpl_file_operations const zpl_default_file_operations; + +typedef zpl_u64 zpl_file_time; +typedef enum zpl_dir_type { + ZPL_DIR_TYPE_FILE, + ZPL_DIR_TYPE_FOLDER, + ZPL_DIR_TYPE_UNKNOWN, +} zpl_dir_type; + +struct zpl_dir_info; + +typedef struct zpl_dir_entry { + char const *filename; + struct zpl_dir_info *dir_info; + zpl_u8 type; +} zpl_dir_entry; + +typedef struct zpl_dir_info { + char const *fullpath; + zpl_dir_entry *entries; // zpl_array + + // Internals + char **filenames; // zpl_array + zpl_string buf; +} zpl_dir_info; + +typedef struct zpl_file { + zpl_file_operations ops; + zpl_file_descriptor fd; + zpl_b32 is_temp; + + char const *filename; + zpl_file_time last_write_time; + zpl_dir_entry *dir; +} zpl_file; + +typedef enum zpl_file_standard_type { + ZPL_FILE_STANDARD_INPUT, + ZPL_FILE_STANDARD_OUTPUT, + ZPL_FILE_STANDARD_ERROR, + + ZPL_FILE_STANDARD_COUNT, +} zpl_file_standard_type; + +/** + * Get standard file I/O. + * @param std Check zpl_file_standard_type + * @return File handle to standard I/O + */ +ZPL_DEF zpl_file *zpl_file_get_standard(zpl_file_standard_type std); + +/** + * Connects a system handle to a zpl file. + * @param file Pointer to zpl file + * @param handle Low-level OS handle to connect + */ +ZPL_DEF void zpl_file_connect_handle(zpl_file *file, void *handle); + +/** + * Creates a new file + * @param file + * @param filename + */ +ZPL_DEF zpl_file_error zpl_file_create(zpl_file *file, char const *filename); + +/** + * Opens a file + * @param file + * @param filename + */ +ZPL_DEF zpl_file_error zpl_file_open(zpl_file *file, char const *filename); + +/** + * Opens a file using a specified mode + * @param file + * @param mode Access mode to use + * @param filename + */ +ZPL_DEF zpl_file_error zpl_file_open_mode(zpl_file *file, zpl_file_mode mode, char const *filename); + +/** + * Constructs a new file from data + * @param file + * @param fd Low-level file descriptor to use + * @param ops File operations to rely upon + * @param filename + */ +ZPL_DEF zpl_file_error zpl_file_new(zpl_file *file, zpl_file_descriptor fd, zpl_file_operations ops, char const *filename); + +/** + * Returns a size of the file + * @param file + * @return File size + */ +ZPL_DEF zpl_i64 zpl_file_size(zpl_file *file); + +/** + * Returns the currently opened file's name + * @param file + */ +ZPL_DEF char const *zpl_file_name(zpl_file *file); + +/** + * Truncates the file by a specified size + * @param file + * @param size Size to truncate + */ +ZPL_DEF zpl_file_error zpl_file_truncate(zpl_file *file, zpl_i64 size); + +/** + * Checks whether a file's been changed since the last check + * @param file + */ +ZPL_DEF zpl_b32 zpl_file_has_changed(zpl_file *file); + +/** + * Retrieves a directory listing relative to the file + * @param file + */ +ZPL_DEF void zpl_file_dirinfo_refresh(zpl_file *file); + +/** + * Creates a temporary file + * @param file + */ +zpl_file_error zpl_file_temp(zpl_file *file); + +/** + * Closes the file + * @param file + */ +ZPL_DEF zpl_file_error zpl_file_close(zpl_file *file); + +/** + * Reads file safely + * @param file + * @param buffer Buffer to read to + * @param size Size to read + * @param offset Offset to read from + * @param bytes_read How much data we've actually read + */ +ZPL_DEF_INLINE zpl_b32 zpl_file_read_at_check(zpl_file *file, void *buffer, zpl_isize size, zpl_i64 offset, zpl_isize *bytes_read); + +/** + * Writes to file safely + * @param file + * @param buffer Buffer to read from + * @param size Size to write + * @param offset Offset to write to + * @param bytes_written How much data we've actually written + */ +ZPL_DEF_INLINE zpl_b32 zpl_file_write_at_check(zpl_file *file, void const *buffer, zpl_isize size, zpl_i64 offset, zpl_isize *bytes_written); + + +/** + * Reads file at a specific offset + * @param file + * @param buffer Buffer to read to + * @param size Size to read + * @param offset Offset to read from + * @param bytes_read How much data we've actually read + */ +ZPL_DEF_INLINE zpl_b32 zpl_file_read_at(zpl_file *file, void *buffer, zpl_isize size, zpl_i64 offset); + +/** + * Writes to file at a specific offset + * @param file + * @param buffer Buffer to read from + * @param size Size to write + * @param offset Offset to write to + * @param bytes_written How much data we've actually written + */ +ZPL_DEF_INLINE zpl_b32 zpl_file_write_at(zpl_file *file, void const *buffer, zpl_isize size, zpl_i64 offset); + +/** + * Seeks the file cursor from the beginning of file to a specific position + * @param file + * @param offset Offset to seek to + */ +ZPL_DEF_INLINE zpl_i64 zpl_file_seek(zpl_file *file, zpl_i64 offset); + +/** + * Seeks the file cursor to the end of the file + * @param file + */ +ZPL_DEF_INLINE zpl_i64 zpl_file_seek_to_end(zpl_file *file); + +/** + * Skips N bytes at the current position + * @param file + * @param bytes Bytes to skip + */ +ZPL_DEF_INLINE zpl_i64 zpl_file_skip(zpl_file *file, zpl_i64 bytes); // NOTE: Skips a certain amount of bytes + +/** + * Returns the length from the beginning of the file we've read so far + * @param file + * @return Our current position in file + */ +ZPL_DEF_INLINE zpl_i64 zpl_file_tell(zpl_file *file); + +/** + * Reads from a file + * @param file + * @param buffer Buffer to read to + * @param size Size to read + */ +ZPL_DEF_INLINE zpl_b32 zpl_file_read(zpl_file *file, void *buffer, zpl_isize size); + +/** + * Writes to a file + * @param file + * @param buffer Buffer to read from + * @param size Size to read + */ +ZPL_DEF_INLINE zpl_b32 zpl_file_write(zpl_file *file, void const *buffer, zpl_isize size); + + +typedef struct zpl_file_contents { + zpl_allocator allocator; + void *data; + zpl_isize size; +} zpl_file_contents; + +/** + * Reads the whole file contents + * @param a Allocator to use + * @param zero_terminate End the read data with null terminator + * @param filepath Path to the file + * @return File contents data + */ +ZPL_DEF zpl_file_contents zpl_file_read_contents(zpl_allocator a, zpl_b32 zero_terminate, char const *filepath); + +/** + * Frees the file content data previously read + * @param fc + */ +ZPL_DEF void zpl_file_free_contents(zpl_file_contents *fc); + +/** + * Writes content to a file + */ +ZPL_DEF zpl_b32 zpl_file_write_contents(char const* filepath, void const* buffer, zpl_isize size, zpl_file_error* err); + +/** + * Reads the file as array of lines + * + * Make sure you free both the returned buffer and the lines (zpl_array) + * @param alloc Allocator to use + * @param lines Reference to zpl_array container we store lines to + * @param filename Path to the file + * @param strip_whitespace Strip whitespace when we split to lines? + * @return File content we've read itself + */ +ZPL_DEF char *zpl_file_read_lines(zpl_allocator alloc, zpl_array(char *)*lines, char const *filename, zpl_b32 strip_whitespace); + +//! @} + +/* inlines */ + + +ZPL_IMPL_INLINE zpl_b32 zpl_file_read_at_check(zpl_file *f, void *buffer, zpl_isize size, zpl_i64 offset, zpl_isize *bytes_read) { + if (!f->ops.read_at) f->ops = zpl_default_file_operations; + return f->ops.read_at(f->fd, buffer, size, offset, bytes_read, false); +} + +ZPL_IMPL_INLINE zpl_b32 zpl_file_write_at_check(zpl_file *f, void const *buffer, zpl_isize size, zpl_i64 offset, zpl_isize *bytes_written) { + if (!f->ops.read_at) f->ops = zpl_default_file_operations; + return f->ops.write_at(f->fd, buffer, size, offset, bytes_written); +} + +ZPL_IMPL_INLINE zpl_b32 zpl_file_read_at(zpl_file *f, void *buffer, zpl_isize size, zpl_i64 offset) { + return zpl_file_read_at_check(f, buffer, size, offset, NULL); +} + +ZPL_IMPL_INLINE zpl_b32 zpl_file_write_at(zpl_file *f, void const *buffer, zpl_isize size, zpl_i64 offset) { + return zpl_file_write_at_check(f, buffer, size, offset, NULL); +} + +ZPL_IMPL_INLINE zpl_i64 zpl_file_seek(zpl_file *f, zpl_i64 offset) { + zpl_i64 new_offset = 0; + if (!f->ops.read_at) f->ops = zpl_default_file_operations; + f->ops.seek(f->fd, offset, ZPL_SEEK_WHENCE_BEGIN, &new_offset); + return new_offset; +} + +ZPL_IMPL_INLINE zpl_i64 zpl_file_seek_to_end(zpl_file *f) { + zpl_i64 new_offset = 0; + if (!f->ops.read_at) f->ops = zpl_default_file_operations; + f->ops.seek(f->fd, 0, ZPL_SEEK_WHENCE_END, &new_offset); + return new_offset; +} + +// NOTE: Skips a certain amount of bytes +ZPL_IMPL_INLINE zpl_i64 zpl_file_skip(zpl_file *f, zpl_i64 bytes) { + zpl_i64 new_offset = 0; + if (!f->ops.read_at) f->ops = zpl_default_file_operations; + f->ops.seek(f->fd, bytes, ZPL_SEEK_WHENCE_CURRENT, &new_offset); + return new_offset; +} + +ZPL_IMPL_INLINE zpl_i64 zpl_file_tell(zpl_file *f) { + zpl_i64 new_offset = 0; + if (!f->ops.read_at) f->ops = zpl_default_file_operations; + f->ops.seek(f->fd, 0, ZPL_SEEK_WHENCE_CURRENT, &new_offset); + return new_offset; +} + +ZPL_IMPL_INLINE zpl_b32 zpl_file_read(zpl_file *f, void *buffer, zpl_isize size) { + zpl_i64 cur_offset = zpl_file_tell(f); + zpl_b32 result = zpl_file_read_at(f, buffer, size, zpl_file_tell(f)); + zpl_file_seek(f, cur_offset + size); + return result; +} + +ZPL_IMPL_INLINE zpl_b32 zpl_file_write(zpl_file *f, void const *buffer, zpl_isize size) { + zpl_i64 cur_offset = zpl_file_tell(f); + zpl_b32 result = zpl_file_write_at(f, buffer, size, zpl_file_tell(f)); + zpl_file_seek(f, cur_offset + size); + return result; +} + +ZPL_END_C_DECLS +// file: header/core/file_stream.h + +/** @file file_stream.c +@brief File stream +@defgroup fileio File stream + +File streaming operations on memory. + +@{ +*/ + +ZPL_BEGIN_C_DECLS + +typedef enum { + /* Allows us to write to the buffer directly. Beware: you can not append a new data! */ + ZPL_FILE_STREAM_WRITABLE = ZPL_BIT(0), + + /* Clones the input buffer so you can write (zpl_file_write*) data into it. */ + /* Since we work with a clone, the buffer size can dynamically grow as well. */ + ZPL_FILE_STREAM_CLONE_WRITABLE = ZPL_BIT(1), +} zpl_file_stream_flags; + +/** + * Opens a new memory stream + * @param file + * @param allocator + */ +ZPL_DEF void zpl_file_stream_new(zpl_file* file, zpl_allocator allocator); + +/** + * Opens a memory stream over an existing buffer + * @param file + * @param allocator + * @param buffer Memory to create stream from + * @param size Buffer's size + * @param flags + */ +ZPL_DEF void zpl_file_stream_open(zpl_file* file, zpl_allocator allocator, zpl_u8 *buffer, zpl_isize size, zpl_file_stream_flags flags); + +/** + * Retrieves the stream's underlying buffer and buffer size. + * @param file memory stream + * @param size (Optional) buffer size + */ +ZPL_DEF zpl_u8 *zpl_file_stream_buf(zpl_file* file, zpl_isize *size); + +extern zpl_file_operations const zpl_memory_file_operations; + +//! @} + +ZPL_END_C_DECLS +// file: header/core/file_misc.h + + +ZPL_BEGIN_C_DECLS + +#ifndef ZPL_PATH_SEPARATOR +# if defined(ZPL_SYSTEM_WINDOWS) +# define ZPL_PATH_SEPARATOR '\\' +# else +# define ZPL_PATH_SEPARATOR '/' +# endif +#endif + +#ifndef ZPL_MAX_PATH +# if defined(ZPL_SYSTEM_WINDOWS) +# define ZPL_MAX_PATH MAX_PATH +# elif defined(ZPL_SYSTEM_UNIX) && !defined(ZPL_SYSTEM_EMSCRIPTEN) +# define ZPL_MAX_PATH PATH_MAX +# else +# define ZPL_MAX_PATH 4096 +# endif +#endif + +/** + * Checks if file/directory exists + * @param filepath + */ +ZPL_DEF zpl_b32 zpl_fs_exists(char const *filepath); + +/** + * Retrieves node's type (file, folder, ...) + * @param path + */ +ZPL_DEF zpl_u8 zpl_fs_get_type(char const *path); + +/** + * Retrieves file's last write time + * @param filepath + */ +ZPL_DEF zpl_file_time zpl_fs_last_write_time(char const *filepath); + +/** + * Copies the file to a directory + * @param existing_filename + * @param new_filename + * @param fail_if_exists + */ +ZPL_DEF zpl_b32 zpl_fs_copy(char const *existing_filename, char const *new_filename, zpl_b32 fail_if_exists); + +/** + * Moves the file to a directory + * @param existing_filename + * @param new_filename + */ +ZPL_DEF zpl_b32 zpl_fs_move(char const *existing_filename, char const *new_filename); + +/** + * Removes a file from a directory + * @param filename + */ +ZPL_DEF zpl_b32 zpl_fs_remove(char const *filename); + +ZPL_DEF_INLINE zpl_b32 zpl_path_is_absolute(char const *path); +ZPL_DEF_INLINE zpl_b32 zpl_path_is_relative(char const *path); +ZPL_DEF_INLINE zpl_b32 zpl_path_is_root(char const *path); + +ZPL_DEF_INLINE char const *zpl_path_base_name(char const *path); +ZPL_DEF_INLINE char const *zpl_path_extension(char const *path); + +ZPL_DEF void zpl_path_fix_slashes(char *path); + +ZPL_DEF zpl_file_error zpl_path_mkdir(char const *path, zpl_i32 mode); +ZPL_DEF zpl_isize zpl_path_mkdir_recursive(char const *path, zpl_i32 mode); +ZPL_DEF zpl_file_error zpl_path_rmdir(char const *path); + +ZPL_DEF char *zpl_path_get_full_name(zpl_allocator a, char const *path); + +/** + * Returns file paths terminated by newline (\n) + * @param alloc [description] + * @param dirname [description] + * @param recurse [description] + * @return [description] + */ +ZPL_DEF /*zpl_string*/char * zpl_path_dirlist(zpl_allocator alloc, char const *dirname, zpl_b32 recurse); + +/** + * Initialize dirinfo from specified path + * @param dir [description] + * @param path [description] + */ +ZPL_DEF void zpl_dirinfo_init(zpl_dir_info *dir, char const *path); +ZPL_DEF void zpl_dirinfo_free(zpl_dir_info *dir); + +/** + * Analyze the entry's dirinfo + * @param dir_entry [description] + */ +ZPL_DEF void zpl_dirinfo_step(zpl_dir_entry *dir_entry); + + +/* inlines */ + +ZPL_IMPL_INLINE zpl_b32 zpl_path_is_absolute(char const *path) { + zpl_b32 result = false; + ZPL_ASSERT_NOT_NULL(path); +#if defined(ZPL_SYSTEM_WINDOWS) + result = (zpl_strlen(path) > 2) && zpl_char_is_alpha(path[0]) && (path[1] == ':' && path[2] == ZPL_PATH_SEPARATOR); +#else + result = (zpl_strlen(path) > 0 && path[0] == ZPL_PATH_SEPARATOR); +#endif + return result; +} + +ZPL_IMPL_INLINE zpl_b32 zpl_path_is_relative(char const *path) { return !zpl_path_is_absolute(path); } + +ZPL_IMPL_INLINE zpl_b32 zpl_path_is_root(char const *path) { + zpl_b32 result = false; + ZPL_ASSERT_NOT_NULL(path); +#if defined(ZPL_SYSTEM_WINDOWS) + result = zpl_path_is_absolute(path) && (zpl_strlen(path) == 3); +#else + result = zpl_path_is_absolute(path) && (zpl_strlen(path) == 1); +#endif + return result; +} + +ZPL_IMPL_INLINE char const *zpl_path_base_name(char const *path) { + char const *ls; + ZPL_ASSERT_NOT_NULL(path); + zpl_path_fix_slashes((char *)path); + ls = zpl_char_last_occurence(path, ZPL_PATH_SEPARATOR); + return (ls == NULL) ? path : ls + 1; +} + +ZPL_IMPL_INLINE char const *zpl_path_extension(char const *path) { + char const *ld; + ZPL_ASSERT_NOT_NULL(path); + ld = zpl_char_last_occurence(path, '.'); + return (ld == NULL) ? NULL : ld + 1; +} + +ZPL_END_C_DECLS +// file: header/core/file_tar.h + +/** @file file_tar.c +@brief Tar archiving module +@defgroup fileio Tar module + +Allows to easily pack/unpack files. +Based on: https://github.com/rxi/microtar/ + +Disclaimer: The pack method does not support file permissions nor GID/UID information. Only regular files are supported. +Use zpl_tar_pack_dir to pack an entire directory recursively. Empty folders are ignored. + +@{ +*/ + + +ZPL_BEGIN_C_DECLS + +typedef enum { + ZPL_TAR_ERROR_NONE, + ZPL_TAR_ERROR_INTERRUPTED, + ZPL_TAR_ERROR_IO_ERROR, + ZPL_TAR_ERROR_BAD_CHECKSUM, + ZPL_TAR_ERROR_FILE_NOT_FOUND, + ZPL_TAR_ERROR_INVALID_INPUT, +} zpl_tar_errors; + +typedef enum { + ZPL_TAR_TYPE_REGULAR = '0', + ZPL_TAR_TYPE_LINK = '1', + ZPL_TAR_TYPE_SYMBOL = '2', + ZPL_TAR_TYPE_CHR = '3', + ZPL_TAR_TYPE_BLK = '4', + ZPL_TAR_TYPE_DIR = '5', + ZPL_TAR_TYPE_FIFO = '6' +} zpl_tar_file_type; + +typedef struct { + char type; + char *path; + zpl_i64 offset; + zpl_i64 length; + zpl_isize error; +} zpl_tar_record; + +#define ZPL_TAR_UNPACK_PROC(name) zpl_isize name(zpl_file *archive, zpl_tar_record *file, void* user_data) +typedef ZPL_TAR_UNPACK_PROC(zpl_tar_unpack_proc); + +/** + * @brief Packs a list of files + * Packs a list of provided files. Note that this method only supports regular files + * and does not provide extended info such as GID/UID or permissions. + * @param archive archive we pack files into + * @param paths list of files + * @param paths_len number of files provided + * @return error + */ +ZPL_DEF zpl_isize zpl_tar_pack(zpl_file *archive, char const **paths, zpl_isize paths_len); + +/** + * @brief Packs an entire directory + * Packs an entire directory of files recursively. + * @param archive archive we pack files to + * @param path folder to pack + * @param alloc memory allocator to use (ex. zpl_heap()) + * @return error + */ +ZPL_DEF zpl_isize zpl_tar_pack_dir(zpl_file *archive, char const *path, zpl_allocator alloc); + +/** + * @brief Unpacks an existing archive + * Unpacks an existing archive. Users provide a callback in which information about file is provided. + * Library does not unpack files to the filesystem nor reads any file data. + * @param archive archive we unpack files from + * @param unpack_proc callback we call per each file parsed + * @param user_data user provided data + * @return error + */ +ZPL_DEF zpl_isize zpl_tar_unpack(zpl_file *archive, zpl_tar_unpack_proc *unpack_proc, void *user_data); + +/** + * @brief Unpacks an existing archive into directory + * Unpacks an existing archive into directory. The folder structure will be re-created automatically. + * @param archive archive we unpack files from + * @param dest directory to unpack files to + * @return error + */ +ZPL_DEF_INLINE zpl_isize zpl_tar_unpack_dir(zpl_file *archive, char const *dest); + +ZPL_DEF ZPL_TAR_UNPACK_PROC(zpl_tar_default_list_file); +ZPL_DEF ZPL_TAR_UNPACK_PROC(zpl_tar_default_unpack_file); - //! @} +//! @} - ZPL_IMPL_INLINE zpl_isize zpl_tar_unpack_dir(zpl_file *archive, char const *dest) { - return zpl_tar_unpack(archive, zpl_tar_default_unpack_file, cast(void*)dest); - } +ZPL_IMPL_INLINE zpl_isize zpl_tar_unpack_dir(zpl_file *archive, char const *dest) { + return zpl_tar_unpack(archive, zpl_tar_default_unpack_file, cast(void*)dest); +} - ZPL_END_C_DECLS - // file: header/core/print.h +ZPL_END_C_DECLS +// file: header/core/print.h - /** @file print.c - @brief Printing methods - @defgroup print Printing methods +/** @file print.c +@brief Printing methods +@defgroup print Printing methods - Various printing methods. - @{ - */ +Various printing methods. +@{ +*/ - ZPL_BEGIN_C_DECLS +ZPL_BEGIN_C_DECLS - #ifndef ZPL_PRINTF_MAXLEN - #define ZPL_PRINTF_MAXLEN 4096 - #endif +#ifndef ZPL_PRINTF_MAXLEN +#define ZPL_PRINTF_MAXLEN 4096 +#endif - ZPL_DEF zpl_isize zpl_printf(char const *fmt, ...); - ZPL_DEF zpl_isize zpl_printf_va(char const *fmt, va_list va); - ZPL_DEF zpl_isize zpl_printf_err(char const *fmt, ...); - ZPL_DEF zpl_isize zpl_printf_err_va(char const *fmt, va_list va); - ZPL_DEF zpl_isize zpl_fprintf(zpl_file *f, char const *fmt, ...); - ZPL_DEF zpl_isize zpl_fprintf_va(zpl_file *f, char const *fmt, va_list va); +ZPL_DEF zpl_isize zpl_printf(char const *fmt, ...); +ZPL_DEF zpl_isize zpl_printf_va(char const *fmt, va_list va); +ZPL_DEF zpl_isize zpl_printf_err(char const *fmt, ...); +ZPL_DEF zpl_isize zpl_printf_err_va(char const *fmt, va_list va); +ZPL_DEF zpl_isize zpl_fprintf(zpl_file *f, char const *fmt, ...); +ZPL_DEF zpl_isize zpl_fprintf_va(zpl_file *f, char const *fmt, va_list va); - // NOTE: A locally persisting buffer is used internally - ZPL_DEF char *zpl_bprintf(char const *fmt, ...); +// NOTE: A locally persisting buffer is used internally +ZPL_DEF char *zpl_bprintf(char const *fmt, ...); - // NOTE: A locally persisting buffer is used internally - ZPL_DEF char *zpl_bprintf_va(char const *fmt, va_list va); +// NOTE: A locally persisting buffer is used internally +ZPL_DEF char *zpl_bprintf_va(char const *fmt, va_list va); - ZPL_DEF zpl_isize zpl_asprintf(zpl_allocator allocator, char **buffer, char const *fmt, ...); - ZPL_DEF zpl_isize zpl_asprintf_va(zpl_allocator allocator, char **buffer, char const *fmt, va_list va); +ZPL_DEF zpl_isize zpl_asprintf(zpl_allocator allocator, char **buffer, char const *fmt, ...); +ZPL_DEF zpl_isize zpl_asprintf_va(zpl_allocator allocator, char **buffer, char const *fmt, va_list va); - ZPL_DEF zpl_isize zpl_snprintf(char *str, zpl_isize n, char const *fmt, ...); - ZPL_DEF zpl_isize zpl_snprintf_va(char *str, zpl_isize n, char const *fmt, va_list va); +ZPL_DEF zpl_isize zpl_snprintf(char *str, zpl_isize n, char const *fmt, ...); +ZPL_DEF zpl_isize zpl_snprintf_va(char *str, zpl_isize n, char const *fmt, va_list va); - ZPL_END_C_DECLS - // file: header/core/time.h +ZPL_END_C_DECLS +// file: header/core/time.h - /** @file time.c - @brief Time helper methods. - @defgroup time Time helpers +/** @file time.c +@brief Time helper methods. +@defgroup time Time helpers - Helper methods for retrieving the current time in many forms under different precisions. It also offers a simple to use timer library. + Helper methods for retrieving the current time in many forms under different precisions. It also offers a simple to use timer library. - @{ - */ + @{ + */ - ZPL_BEGIN_C_DECLS +ZPL_BEGIN_C_DECLS - //! Return CPU timestamp. - ZPL_DEF zpl_u64 zpl_rdtsc(void); +//! Return CPU timestamp. +ZPL_DEF zpl_u64 zpl_rdtsc(void); - //! Return relative time (in seconds) since the application start. - ZPL_DEF zpl_f64 zpl_time_rel(void); +//! Return relative time (in seconds) since the application start. +ZPL_DEF zpl_f64 zpl_time_rel(void); - //! Return relative time since the application start. - ZPL_DEF zpl_u64 zpl_time_rel_ms(void); +//! Return relative time since the application start. +ZPL_DEF zpl_u64 zpl_time_rel_ms(void); - //! Return time (in seconds) since 1601-01-01 UTC. - ZPL_DEF zpl_f64 zpl_time_utc(void); +//! Return time (in seconds) since 1601-01-01 UTC. +ZPL_DEF zpl_f64 zpl_time_utc(void); - //! Return time since 1601-01-01 UTC. - ZPL_DEF zpl_u64 zpl_time_utc_ms(void); +//! Return time since 1601-01-01 UTC. +ZPL_DEF zpl_u64 zpl_time_utc_ms(void); - //! Return local system time since 1601-01-01 - ZPL_DEF zpl_u64 zpl_time_tz_ms(void); +//! Return local system time since 1601-01-01 +ZPL_DEF zpl_u64 zpl_time_tz_ms(void); - //! Return local system time in seconds since 1601-01-01 - ZPL_DEF zpl_f64 zpl_time_tz(void); +//! Return local system time in seconds since 1601-01-01 +ZPL_DEF zpl_f64 zpl_time_tz(void); - //! Convert Win32 epoch (1601-01-01 UTC) to UNIX (1970-01-01 UTC) - ZPL_DEF_INLINE zpl_u64 zpl_time_win32_to_unix(zpl_u64 ms); +//! Convert Win32 epoch (1601-01-01 UTC) to UNIX (1970-01-01 UTC) +ZPL_DEF_INLINE zpl_u64 zpl_time_win32_to_unix(zpl_u64 ms); - //! Convert UNIX (1970-01-01 UTC) to Win32 epoch (1601-01-01 UTC) - ZPL_DEF_INLINE zpl_u64 zpl_time_unix_to_win32(zpl_u64 ms); +//! Convert UNIX (1970-01-01 UTC) to Win32 epoch (1601-01-01 UTC) +ZPL_DEF_INLINE zpl_u64 zpl_time_unix_to_win32(zpl_u64 ms); - //! Sleep for specified number of milliseconds. - ZPL_DEF void zpl_sleep_ms(zpl_u32 ms); +//! Sleep for specified number of milliseconds. +ZPL_DEF void zpl_sleep_ms(zpl_u32 ms); - //! Sleep for specified number of seconds. - ZPL_DEF_INLINE void zpl_sleep(zpl_f32 s); +//! Sleep for specified number of seconds. +ZPL_DEF_INLINE void zpl_sleep(zpl_f32 s); - // Deprecated methods - ZPL_DEPRECATED_FOR(10.9.0, zpl_time_rel) - ZPL_DEF_INLINE zpl_f64 zpl_time_now(void); +// Deprecated methods +ZPL_DEPRECATED_FOR(10.9.0, zpl_time_rel) +ZPL_DEF_INLINE zpl_f64 zpl_time_now(void); - ZPL_DEPRECATED_FOR(10.9.0, zpl_time_utc) - ZPL_DEF_INLINE zpl_f64 zpl_utc_time_now(void); +ZPL_DEPRECATED_FOR(10.9.0, zpl_time_utc) +ZPL_DEF_INLINE zpl_f64 zpl_utc_time_now(void); - #ifndef ZPL__UNIX_TO_WIN32_EPOCH - #define ZPL__UNIX_TO_WIN32_EPOCH 11644473600000ull - #endif +#ifndef ZPL__UNIX_TO_WIN32_EPOCH +#define ZPL__UNIX_TO_WIN32_EPOCH 11644473600000ull +#endif - ZPL_IMPL_INLINE zpl_u64 zpl_time_win32_to_unix(zpl_u64 ms) { - return ms - ZPL__UNIX_TO_WIN32_EPOCH; - } +ZPL_IMPL_INLINE zpl_u64 zpl_time_win32_to_unix(zpl_u64 ms) { + return ms - ZPL__UNIX_TO_WIN32_EPOCH; +} - ZPL_IMPL_INLINE zpl_u64 zpl_time_unix_to_win32(zpl_u64 ms) { - return ms + ZPL__UNIX_TO_WIN32_EPOCH; - } +ZPL_IMPL_INLINE zpl_u64 zpl_time_unix_to_win32(zpl_u64 ms) { + return ms + ZPL__UNIX_TO_WIN32_EPOCH; +} - ZPL_IMPL_INLINE void zpl_sleep(zpl_f32 s) { - zpl_sleep_ms((zpl_u32)(s * 1000)); - } +ZPL_IMPL_INLINE void zpl_sleep(zpl_f32 s) { + zpl_sleep_ms((zpl_u32)(s * 1000)); +} - ZPL_IMPL_INLINE zpl_f64 zpl_time_now() { - return zpl_time_rel(); - } +ZPL_IMPL_INLINE zpl_f64 zpl_time_now() { + return zpl_time_rel(); +} - ZPL_IMPL_INLINE zpl_f64 zpl_utc_time_now() { - return zpl_time_utc(); - } +ZPL_IMPL_INLINE zpl_f64 zpl_utc_time_now() { + return zpl_time_utc(); +} - ZPL_END_C_DECLS - // file: header/core/random.h +ZPL_END_C_DECLS +// file: header/core/random.h - ZPL_BEGIN_C_DECLS +ZPL_BEGIN_C_DECLS - typedef struct zpl_random { - zpl_u32 offsets[8]; - zpl_u32 value; - } zpl_random; +typedef struct zpl_random { + zpl_u32 offsets[8]; + zpl_u32 value; +} zpl_random; - // NOTE: Generates from numerous sources to produce a decent pseudo-random seed - ZPL_DEF void zpl_random_init(zpl_random *r); - ZPL_DEF zpl_u32 zpl_random_gen_u32(zpl_random *r); - ZPL_DEF zpl_u32 zpl_random_gen_u32_unique(zpl_random *r); - ZPL_DEF zpl_u64 zpl_random_gen_u64(zpl_random *r); // NOTE: (zpl_random_gen_u32() << 32) | zpl_random_gen_u32() - ZPL_DEF zpl_isize zpl_random_gen_isize(zpl_random *r); - ZPL_DEF zpl_i64 zpl_random_range_i64(zpl_random *r, zpl_i64 lower_inc, zpl_i64 higher_inc); - ZPL_DEF zpl_isize zpl_random_range_isize(zpl_random *r, zpl_isize lower_inc, zpl_isize higher_inc); - ZPL_DEF zpl_f64 zpl_random_range_f64(zpl_random *r, zpl_f64 lower_inc, zpl_f64 higher_inc); +// NOTE: Generates from numerous sources to produce a decent pseudo-random seed +ZPL_DEF void zpl_random_init(zpl_random *r); +ZPL_DEF zpl_u32 zpl_random_gen_u32(zpl_random *r); +ZPL_DEF zpl_u32 zpl_random_gen_u32_unique(zpl_random *r); +ZPL_DEF zpl_u64 zpl_random_gen_u64(zpl_random *r); // NOTE: (zpl_random_gen_u32() << 32) | zpl_random_gen_u32() +ZPL_DEF zpl_isize zpl_random_gen_isize(zpl_random *r); +ZPL_DEF zpl_i64 zpl_random_range_i64(zpl_random *r, zpl_i64 lower_inc, zpl_i64 higher_inc); +ZPL_DEF zpl_isize zpl_random_range_isize(zpl_random *r, zpl_isize lower_inc, zpl_isize higher_inc); +ZPL_DEF zpl_f64 zpl_random_range_f64(zpl_random *r, zpl_f64 lower_inc, zpl_f64 higher_inc); - ZPL_END_C_DECLS - // file: header/core/misc.h +ZPL_END_C_DECLS +// file: header/core/misc.h - /** @file misc.c - @brief Various other stuff - @defgroup misc Various other stuff +/** @file misc.c +@brief Various other stuff +@defgroup misc Various other stuff - Methods that don't belong anywhere but are still very useful in many occasions. + Methods that don't belong anywhere but are still very useful in many occasions. - @{ - */ + @{ + */ - ZPL_BEGIN_C_DECLS +ZPL_BEGIN_C_DECLS - ZPL_DEF void zpl_yield(void); +ZPL_DEF void zpl_yield(void); - //! Returns allocated buffer - ZPL_DEF const char *zpl_get_env(const char *name); - ZPL_DEF const char *zpl_get_env_buf(const char *name); - ZPL_DEF zpl_string zpl_get_env_str(const char *name); - ZPL_DEF void zpl_set_env(const char *name, const char *value); - ZPL_DEF void zpl_unset_env(const char *name); +//! Returns allocated buffer +ZPL_DEF const char *zpl_get_env(const char *name); +ZPL_DEF const char *zpl_get_env_buf(const char *name); +ZPL_DEF zpl_string zpl_get_env_str(const char *name); +ZPL_DEF void zpl_set_env(const char *name, const char *value); +ZPL_DEF void zpl_unset_env(const char *name); - ZPL_DEF zpl_u32 zpl_system_command(const char *command, zpl_usize buffer_len, char *buffer); - ZPL_DEF zpl_string zpl_system_command_str(const char *command, zpl_allocator backing); +ZPL_DEF zpl_u32 zpl_system_command(const char *command, zpl_usize buffer_len, char *buffer); +ZPL_DEF zpl_string zpl_system_command_str(const char *command, zpl_allocator backing); - ZPL_DEF_INLINE zpl_u16 zpl_endian_swap16(zpl_u16 i); - ZPL_DEF_INLINE zpl_u32 zpl_endian_swap32(zpl_u32 i); - ZPL_DEF_INLINE zpl_u64 zpl_endian_swap64(zpl_u64 i); +ZPL_DEF_INLINE zpl_u16 zpl_endian_swap16(zpl_u16 i); +ZPL_DEF_INLINE zpl_u32 zpl_endian_swap32(zpl_u32 i); +ZPL_DEF_INLINE zpl_u64 zpl_endian_swap64(zpl_u64 i); - ZPL_DEF_INLINE zpl_isize zpl_count_set_bits(zpl_u64 mask); +ZPL_DEF_INLINE zpl_isize zpl_count_set_bits(zpl_u64 mask); - //! @} - //$$ +//! @} +//$$ - ZPL_IMPL_INLINE zpl_u16 zpl_endian_swap16(zpl_u16 i) { - return (i>>8) | (i<<8); - } +ZPL_IMPL_INLINE zpl_u16 zpl_endian_swap16(zpl_u16 i) { + return (i>>8) | (i<<8); +} - ZPL_IMPL_INLINE zpl_u32 zpl_endian_swap32(zpl_u32 i) { - return (i>>24) |(i<<24) | - ((i&0x00ff0000u)>>8) | ((i&0x0000ff00u)<<8); - } +ZPL_IMPL_INLINE zpl_u32 zpl_endian_swap32(zpl_u32 i) { + return (i>>24) |(i<<24) | + ((i&0x00ff0000u)>>8) | ((i&0x0000ff00u)<<8); +} - ZPL_IMPL_INLINE zpl_u64 zpl_endian_swap64(zpl_u64 i) { - return (i>>56) | (i<<56) | - ((i&0x00ff000000000000ull)>>40) | ((i&0x000000000000ff00ull)<<40) | - ((i&0x0000ff0000000000ull)>>24) | ((i&0x0000000000ff0000ull)<<24) | - ((i&0x000000ff00000000ull)>>8) | ((i&0x00000000ff000000ull)<<8); - } +ZPL_IMPL_INLINE zpl_u64 zpl_endian_swap64(zpl_u64 i) { + return (i>>56) | (i<<56) | + ((i&0x00ff000000000000ull)>>40) | ((i&0x000000000000ff00ull)<<40) | + ((i&0x0000ff0000000000ull)>>24) | ((i&0x0000000000ff0000ull)<<24) | + ((i&0x000000ff00000000ull)>>8) | ((i&0x00000000ff000000ull)<<8); +} - ZPL_IMPL_INLINE zpl_i32 zpl_next_pow2(zpl_i32 x) { - x--; - x |= x >> 1; - x |= x >> 2; - x |= x >> 4; - x |= x >> 8; - x |= x >> 16; - return x + 1; - } +ZPL_IMPL_INLINE zpl_i32 zpl_next_pow2(zpl_i32 x) { + x--; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + return x + 1; +} - ZPL_IMPL_INLINE void zpl_bit_set(zpl_u32* x, zpl_u32 bit) { *x = *x | (1 << bit); } - ZPL_IMPL_INLINE zpl_b8 zpl_bit_get(zpl_u32 x, zpl_u32 bit) { return (x & (1 << bit)); } - ZPL_IMPL_INLINE void zpl_bit_reset(zpl_u32* x, zpl_u32 bit) { *x = *x & ~(1 << bit); } +ZPL_IMPL_INLINE void zpl_bit_set(zpl_u32* x, zpl_u32 bit) { *x = *x | (1 << bit); } +ZPL_IMPL_INLINE zpl_b8 zpl_bit_get(zpl_u32 x, zpl_u32 bit) { return (x & (1 << bit)); } +ZPL_IMPL_INLINE void zpl_bit_reset(zpl_u32* x, zpl_u32 bit) { *x = *x & ~(1 << bit); } - ZPL_IMPL_INLINE zpl_isize zpl_count_set_bits(zpl_u64 mask) { - zpl_isize count = 0; - while (mask) { - count += (mask & 1); - mask >>= 1; - } - return count; - } +ZPL_IMPL_INLINE zpl_isize zpl_count_set_bits(zpl_u64 mask) { + zpl_isize count = 0; + while (mask) { + count += (mask & 1); + mask >>= 1; + } + return count; +} - ZPL_END_C_DECLS - // file: header/core/sort.h +ZPL_END_C_DECLS +// file: header/core/sort.h - /** @file sort.c - @brief Sorting and searching methods. - @defgroup sort Sorting and searching +/** @file sort.c +@brief Sorting and searching methods. +@defgroup sort Sorting and searching - Methods for sorting arrays using either Quick/Merge-sort combo or Radix sort. It also contains simple implementation of binary search, as well as an easy to use API to define your own comparators. +Methods for sorting arrays using either Quick/Merge-sort combo or Radix sort. It also contains simple implementation of binary search, as well as an easy to use API to define your own comparators. - @{ - */ +@{ +*/ - ZPL_BEGIN_C_DECLS +ZPL_BEGIN_C_DECLS - #define ZPL_COMPARE_PROC(name) int name(void const *a, void const *b) - typedef ZPL_COMPARE_PROC(zpl_compare_proc); +#define ZPL_COMPARE_PROC(name) int name(void const *a, void const *b) +typedef ZPL_COMPARE_PROC(zpl_compare_proc); - #define ZPL_COMPARE_PROC_PTR(def) ZPL_COMPARE_PROC((*def)) +#define ZPL_COMPARE_PROC_PTR(def) ZPL_COMPARE_PROC((*def)) - // Procedure pointers - // NOTE: The offset parameter specifies the offset in the structure - // e.g. zpl_i32_cmp(zpl_offset_of(Thing, value)) - // Use 0 if it's just the type instead. +// Procedure pointers +// NOTE: The offset parameter specifies the offset in the structure +// e.g. zpl_i32_cmp(zpl_offset_of(Thing, value)) +// Use 0 if it's just the type instead. - ZPL_DEF ZPL_COMPARE_PROC_PTR(i16_cmp(zpl_isize offset)); - ZPL_DEF ZPL_COMPARE_PROC_PTR(u8_cmp(zpl_isize offset)); - ZPL_DEF ZPL_COMPARE_PROC_PTR(i32_cmp(zpl_isize offset)); - ZPL_DEF ZPL_COMPARE_PROC_PTR(i64_cmp(zpl_isize offset)); - ZPL_DEF ZPL_COMPARE_PROC_PTR(isize_cmp(zpl_isize offset)); - ZPL_DEF ZPL_COMPARE_PROC_PTR(str_cmp(zpl_isize offset)); - ZPL_DEF ZPL_COMPARE_PROC_PTR(f32_cmp(zpl_isize offset)); - ZPL_DEF ZPL_COMPARE_PROC_PTR(f64_cmp(zpl_isize offset)); +ZPL_DEF ZPL_COMPARE_PROC_PTR(i16_cmp(zpl_isize offset)); +ZPL_DEF ZPL_COMPARE_PROC_PTR(u8_cmp(zpl_isize offset)); +ZPL_DEF ZPL_COMPARE_PROC_PTR(i32_cmp(zpl_isize offset)); +ZPL_DEF ZPL_COMPARE_PROC_PTR(i64_cmp(zpl_isize offset)); +ZPL_DEF ZPL_COMPARE_PROC_PTR(isize_cmp(zpl_isize offset)); +ZPL_DEF ZPL_COMPARE_PROC_PTR(str_cmp(zpl_isize offset)); +ZPL_DEF ZPL_COMPARE_PROC_PTR(f32_cmp(zpl_isize offset)); +ZPL_DEF ZPL_COMPARE_PROC_PTR(f64_cmp(zpl_isize offset)); - // TODO: Better sorting algorithms +// TODO: Better sorting algorithms - //! Sorts an array. +//! Sorts an array. - //! Uses quick sort for large arrays but insertion sort for small ones. - #define zpl_sort_array(array, count, compare_proc) zpl_sort(array, count, zpl_size_of(*(array)), compare_proc) +//! Uses quick sort for large arrays but insertion sort for small ones. +#define zpl_sort_array(array, count, compare_proc) zpl_sort(array, count, zpl_size_of(*(array)), compare_proc) - //! Perform sorting operation on a memory location with a specified item count and size. - ZPL_DEF void zpl_sort(void *base, zpl_isize count, zpl_isize size, zpl_compare_proc compare_proc); +//! Perform sorting operation on a memory location with a specified item count and size. +ZPL_DEF void zpl_sort(void *base, zpl_isize count, zpl_isize size, zpl_compare_proc compare_proc); - // NOTE: the count of temp == count of items - #define zpl_radix_sort(Type) zpl_radix_sort_##Type - #define ZPL_RADIX_SORT_PROC(Type) void zpl_radix_sort(Type)(zpl_##Type * items, zpl_##Type * temp, zpl_isize count) +// NOTE: the count of temp == count of items +#define zpl_radix_sort(Type) zpl_radix_sort_##Type +#define ZPL_RADIX_SORT_PROC(Type) void zpl_radix_sort(Type)(zpl_##Type * items, zpl_##Type * temp, zpl_isize count) - ZPL_DEF ZPL_RADIX_SORT_PROC(u8); - ZPL_DEF ZPL_RADIX_SORT_PROC(u16); - ZPL_DEF ZPL_RADIX_SORT_PROC(u32); - ZPL_DEF ZPL_RADIX_SORT_PROC(u64); +ZPL_DEF ZPL_RADIX_SORT_PROC(u8); +ZPL_DEF ZPL_RADIX_SORT_PROC(u16); +ZPL_DEF ZPL_RADIX_SORT_PROC(u32); +ZPL_DEF ZPL_RADIX_SORT_PROC(u64); - //! Performs binary search on an array. +//! Performs binary search on an array. - //! Returns index or -1 if not found - #define zpl_binary_search_array(array, count, key, compare_proc) \ - zpl_binary_search(array, count, zpl_size_of(*(array)), key, compare_proc) +//! Returns index or -1 if not found +#define zpl_binary_search_array(array, count, key, compare_proc) \ +zpl_binary_search(array, count, zpl_size_of(*(array)), key, compare_proc) - //! Performs binary search on a memory location with specified item count and size. - ZPL_DEF_INLINE zpl_isize zpl_binary_search(void const *base, zpl_isize count, zpl_isize size, void const *key, - zpl_compare_proc compare_proc); +//! Performs binary search on a memory location with specified item count and size. +ZPL_DEF_INLINE zpl_isize zpl_binary_search(void const *base, zpl_isize count, zpl_isize size, void const *key, + zpl_compare_proc compare_proc); - #define zpl_shuffle_array(array, count) zpl_shuffle(array, count, zpl_size_of(*(array))) +#define zpl_shuffle_array(array, count) zpl_shuffle(array, count, zpl_size_of(*(array))) - //! Shuffles a memory. - ZPL_DEF void zpl_shuffle(void *base, zpl_isize count, zpl_isize size); +//! Shuffles a memory. +ZPL_DEF void zpl_shuffle(void *base, zpl_isize count, zpl_isize size); - #define zpl_reverse_array(array, count) zpl_reverse(array, count, zpl_size_of(*(array))) +#define zpl_reverse_array(array, count) zpl_reverse(array, count, zpl_size_of(*(array))) - //! Reverses memory's contents - ZPL_DEF void zpl_reverse(void *base, zpl_isize count, zpl_isize size); +//! Reverses memory's contents +ZPL_DEF void zpl_reverse(void *base, zpl_isize count, zpl_isize size); - //! @} +//! @} - ZPL_IMPL_INLINE zpl_isize zpl_binary_search(void const *base, zpl_isize count, zpl_isize size, void const *key, +ZPL_IMPL_INLINE zpl_isize zpl_binary_search(void const *base, zpl_isize count, zpl_isize size, void const *key, zpl_compare_proc compare_proc) { - zpl_isize start = 0; - zpl_isize end = count; + zpl_isize start = 0; + zpl_isize end = count; + + while (start < end) { + zpl_isize mid = start + (end - start) / 2; + zpl_isize result = compare_proc(key, cast(zpl_u8 *) base + mid * size); + if (result < 0) + end = mid; + else if (result > 0) + start = mid + 1; + else + return mid; + } + + return -1; +} - while (start < end) { - zpl_isize mid = start + (end - start) / 2; - zpl_isize result = compare_proc(key, cast(zpl_u8 *) base + mid * size); - if (result < 0) - end = mid; - else if (result > 0) - start = mid + 1; - else - return mid; - } - - return -1; - } - - ZPL_END_C_DECLS +ZPL_END_C_DECLS # endif #endif #if defined(ZPL_MODULE_TIMER) - // file: header/timer.h +// file: header/timer.h - ZPL_BEGIN_C_DECLS +ZPL_BEGIN_C_DECLS - typedef void (*zpl_timer_cb)(void *data); +typedef void (*zpl_timer_cb)(void *data); - //! Timer data structure - typedef struct zpl_timer { - zpl_timer_cb callback; - zpl_b32 enabled; - zpl_i32 remaining_calls; - zpl_i32 initial_calls; - zpl_f64 next_call_ts; - zpl_f64 duration; - void *user_data; - } zpl_timer; +//! Timer data structure +typedef struct zpl_timer { + zpl_timer_cb callback; + zpl_b32 enabled; + zpl_i32 remaining_calls; + zpl_i32 initial_calls; + zpl_f64 next_call_ts; + zpl_f64 duration; + void *user_data; +} zpl_timer; - typedef zpl_timer *zpl_timer_pool; ///< zpl_array +typedef zpl_timer *zpl_timer_pool; ///< zpl_array - //! Initialize timer pool. - #define zpl_timer_init(pool, allocator) zpl_array_init(pool, allocator) +//! Initialize timer pool. +#define zpl_timer_init(pool, allocator) zpl_array_init(pool, allocator) - //! Add new timer to pool and return it. - ZPL_DEF zpl_timer *zpl_timer_add(zpl_timer_pool pool); +//! Add new timer to pool and return it. +ZPL_DEF zpl_timer *zpl_timer_add(zpl_timer_pool pool); - //! Perform timer pool update. +//! Perform timer pool update. - //! Traverse over all timers and update them accordingly. Should be called by Main Thread in a tight loop. - ZPL_DEF void zpl_timer_update_array(zpl_timer_pool pool); +//! Traverse over all timers and update them accordingly. Should be called by Main Thread in a tight loop. +ZPL_DEF void zpl_timer_update_array(zpl_timer_pool pool); - ZPL_DEF void zpl_timer_update(zpl_timer *timer); +ZPL_DEF void zpl_timer_update(zpl_timer *timer); - //! Set up timer. +//! Set up timer. - //! Set up timer with specific options. - //! @param timer - //! @param duration How long/often to fire a timer. - //! @param count How many times we fire a timer. Use -1 for infinity. - //! @param callback A method to execute once a timer triggers. - ZPL_DEF void zpl_timer_set(zpl_timer *timer, zpl_f64 /* microseconds */ duration, zpl_i32 /* -1 for INFINITY */ count, - zpl_timer_cb callback); +//! Set up timer with specific options. +//! @param timer +//! @param duration How long/often to fire a timer. +//! @param count How many times we fire a timer. Use -1 for infinity. +//! @param callback A method to execute once a timer triggers. +ZPL_DEF void zpl_timer_set(zpl_timer *timer, zpl_f64 /* microseconds */ duration, zpl_i32 /* -1 for INFINITY */ count, + zpl_timer_cb callback); - //! Start timer with specified delay. - ZPL_DEF void zpl_timer_start(zpl_timer *timer, zpl_f64 delay_start); +//! Start timer with specified delay. +ZPL_DEF void zpl_timer_start(zpl_timer *timer, zpl_f64 delay_start); - //! Stop timer and prevent it from triggering. - ZPL_DEF void zpl_timer_stop(zpl_timer *timer); +//! Stop timer and prevent it from triggering. +ZPL_DEF void zpl_timer_stop(zpl_timer *timer); - ZPL_END_C_DECLS +ZPL_END_C_DECLS #endif #if defined(ZPL_MODULE_HASHING) - // file: header/hashing.h +// file: header/hashing.h - /** @file hashing.c - @brief Hashing and Checksum Functions - @defgroup hashing Hashing and Checksum Functions +/** @file hashing.c +@brief Hashing and Checksum Functions +@defgroup hashing Hashing and Checksum Functions - Several hashing methods used by zpl internally but possibly useful outside of it. Contains: adler32, crc32/64, fnv32/64/a and murmur32/64 +Several hashing methods used by zpl internally but possibly useful outside of it. Contains: adler32, crc32/64, fnv32/64/a and murmur32/64 - @{ - */ +@{ +*/ - ZPL_BEGIN_C_DECLS +ZPL_BEGIN_C_DECLS - ZPL_DEF zpl_u32 zpl_adler32(void const *data, zpl_isize len); +ZPL_DEF zpl_u32 zpl_adler32(void const *data, zpl_isize len); - ZPL_DEF zpl_u32 zpl_crc32(void const *data, zpl_isize len); - ZPL_DEF zpl_u64 zpl_crc64(void const *data, zpl_isize len); +ZPL_DEF zpl_u32 zpl_crc32(void const *data, zpl_isize len); +ZPL_DEF zpl_u64 zpl_crc64(void const *data, zpl_isize len); - // These use FNV-1 algorithm - ZPL_DEF zpl_u32 zpl_fnv32(void const *data, zpl_isize len); - ZPL_DEF zpl_u64 zpl_fnv64(void const *data, zpl_isize len); - ZPL_DEF zpl_u32 zpl_fnv32a(void const *data, zpl_isize len); - ZPL_DEF zpl_u64 zpl_fnv64a(void const *data, zpl_isize len); +// These use FNV-1 algorithm +ZPL_DEF zpl_u32 zpl_fnv32(void const *data, zpl_isize len); +ZPL_DEF zpl_u64 zpl_fnv64(void const *data, zpl_isize len); +ZPL_DEF zpl_u32 zpl_fnv32a(void const *data, zpl_isize len); +ZPL_DEF zpl_u64 zpl_fnv64a(void const *data, zpl_isize len); - ZPL_DEF zpl_u8 *zpl_base64_encode(zpl_allocator a, void const *data, zpl_isize len); - ZPL_DEF zpl_u8 *zpl_base64_decode(zpl_allocator a, void const *data, zpl_isize len); +ZPL_DEF zpl_u8 *zpl_base64_encode(zpl_allocator a, void const *data, zpl_isize len); +ZPL_DEF zpl_u8 *zpl_base64_decode(zpl_allocator a, void const *data, zpl_isize len); - //! Based on MurmurHash3 - ZPL_DEF zpl_u32 zpl_murmur32_seed(void const *data, zpl_isize len, zpl_u32 seed); +//! Based on MurmurHash3 +ZPL_DEF zpl_u32 zpl_murmur32_seed(void const *data, zpl_isize len, zpl_u32 seed); - //! Based on MurmurHash2 - ZPL_DEF zpl_u64 zpl_murmur64_seed(void const *data, zpl_isize len, zpl_u64 seed); +//! Based on MurmurHash2 +ZPL_DEF zpl_u64 zpl_murmur64_seed(void const *data, zpl_isize len, zpl_u64 seed); - //! Default seed of 0x9747b28c - ZPL_DEF_INLINE zpl_u32 zpl_murmur32(void const *data, zpl_isize len); +//! Default seed of 0x9747b28c +ZPL_DEF_INLINE zpl_u32 zpl_murmur32(void const *data, zpl_isize len); - //! Default seed of 0x9747b28c - ZPL_DEF_INLINE zpl_u64 zpl_murmur64(void const *data, zpl_isize len); +//! Default seed of 0x9747b28c +ZPL_DEF_INLINE zpl_u64 zpl_murmur64(void const *data, zpl_isize len); - //! @} +//! @} - ZPL_IMPL_INLINE zpl_u32 zpl_murmur32(void const *data, zpl_isize len) { return zpl_murmur32_seed(data, len, 0x9747b28c); } - ZPL_IMPL_INLINE zpl_u64 zpl_murmur64(void const *data, zpl_isize len) { return zpl_murmur64_seed(data, len, 0x9747b28c); } +ZPL_IMPL_INLINE zpl_u32 zpl_murmur32(void const *data, zpl_isize len) { return zpl_murmur32_seed(data, len, 0x9747b28c); } +ZPL_IMPL_INLINE zpl_u64 zpl_murmur64(void const *data, zpl_isize len) { return zpl_murmur64_seed(data, len, 0x9747b28c); } - ZPL_END_C_DECLS +ZPL_END_C_DECLS #endif #if defined(ZPL_MODULE_REGEX) - // file: header/regex.h +// file: header/regex.h - /** @file regex.c - @brief Regular expressions parser. - @defgroup regex Regex processor +/** @file regex.c +@brief Regular expressions parser. +@defgroup regex Regex processor - Port of gb_regex with several bugfixes applied. This is a simple regex library and is fast to perform. +Port of gb_regex with several bugfixes applied. This is a simple regex library and is fast to perform. - Supported Matching: - @n ^ - Beginning of string - @n $ - End of string - @n . - Match one (anything) - @n | - Branch (or) - @n () - Capturing group - @n [] - Any character included in set - @n [^] - Any character excluded from set - @n + - One or more (greedy) - @n +? - One or more (non-greedy) - @n * - Zero or more (greedy) - @n *? - Zero or more (non-greedy) - @n ? - Zero or once - @n [BACKSLASH]XX - Hex decimal digit (must be 2 digits) - @n [BACKSLASH]meta - Meta character - @n [BACKSLASH]s - Whitespace - @n [BACKSLASH]S - Not whitespace - @n [BACKSLASH]d - Digit - @n [BACKSLASH]D - Not digit - @n [BACKSLASH]a - Alphabetic character - @n [BACKSLASH]l - Lower case letter - @n [BACKSLASH]u - Upper case letter - @n [BACKSLASH]w - Word - @n [BACKSLASH]W - Not word - @n [BACKSLASH]x - Hex Digit - @n [BACKSLASH]p - Printable ASCII character - @n --Whitespace-- - @n [BACKSLASH]t - Tab - @n [BACKSLASH]n - New line - @n [BACKSLASH]r - Return carriage - @n [BACKSLASH]v - Vertical Tab - @n [BACKSLASH]f - Form feed +Supported Matching: + @n ^ - Beginning of string + @n $ - End of string + @n . - Match one (anything) + @n | - Branch (or) + @n () - Capturing group + @n [] - Any character included in set + @n [^] - Any character excluded from set + @n + - One or more (greedy) + @n +? - One or more (non-greedy) + @n * - Zero or more (greedy) + @n *? - Zero or more (non-greedy) + @n ? - Zero or once + @n [BACKSLASH]XX - Hex decimal digit (must be 2 digits) + @n [BACKSLASH]meta - Meta character + @n [BACKSLASH]s - Whitespace + @n [BACKSLASH]S - Not whitespace + @n [BACKSLASH]d - Digit + @n [BACKSLASH]D - Not digit + @n [BACKSLASH]a - Alphabetic character + @n [BACKSLASH]l - Lower case letter + @n [BACKSLASH]u - Upper case letter + @n [BACKSLASH]w - Word + @n [BACKSLASH]W - Not word + @n [BACKSLASH]x - Hex Digit + @n [BACKSLASH]p - Printable ASCII character + @n --Whitespace-- + @n [BACKSLASH]t - Tab + @n [BACKSLASH]n - New line + @n [BACKSLASH]r - Return carriage + @n [BACKSLASH]v - Vertical Tab + @n [BACKSLASH]f - Form feed - @{ - */ + @{ +*/ - ZPL_BEGIN_C_DECLS +ZPL_BEGIN_C_DECLS - typedef struct zpl_re { - zpl_allocator backing; - zpl_isize capture_count; - char *buf; - zpl_isize buf_len, buf_cap; - zpl_b32 can_realloc; - } zpl_re; +typedef struct zpl_re { + zpl_allocator backing; + zpl_isize capture_count; + char *buf; + zpl_isize buf_len, buf_cap; + zpl_b32 can_realloc; +} zpl_re; - typedef struct zpl_re_capture { - char const *str; - zpl_isize len; - } zpl_re_capture; +typedef struct zpl_re_capture { + char const *str; + zpl_isize len; +} zpl_re_capture; - #define zplRegexError zpl_regex_error - typedef enum zpl_regex_error { - ZPL_RE_ERROR_NONE, - ZPL_RE_ERROR_NO_MATCH, - ZPL_RE_ERROR_TOO_LONG, - ZPL_RE_ERROR_MISMATCHED_CAPTURES, - ZPL_RE_ERROR_MISMATCHED_BLOCKS, - ZPL_RE_ERROR_BRANCH_FAILURE, - ZPL_RE_ERROR_INVALID_QUANTIFIER, - ZPL_RE_ERROR_INTERNAL_FAILURE, - } zpl_regex_error; +#define zplRegexError zpl_regex_error +typedef enum zpl_regex_error { + ZPL_RE_ERROR_NONE, + ZPL_RE_ERROR_NO_MATCH, + ZPL_RE_ERROR_TOO_LONG, + ZPL_RE_ERROR_MISMATCHED_CAPTURES, + ZPL_RE_ERROR_MISMATCHED_BLOCKS, + ZPL_RE_ERROR_BRANCH_FAILURE, + ZPL_RE_ERROR_INVALID_QUANTIFIER, + ZPL_RE_ERROR_INTERNAL_FAILURE, +} zpl_regex_error; - //! Compile regex pattern. - ZPL_DEF zpl_regex_error zpl_re_compile(zpl_re *re, zpl_allocator backing, char const *pattern, zpl_isize pattern_len); +//! Compile regex pattern. +ZPL_DEF zpl_regex_error zpl_re_compile(zpl_re *re, zpl_allocator backing, char const *pattern, zpl_isize pattern_len); - //! Compile regex pattern using a buffer. - ZPL_DEF zpl_regex_error zpl_re_compile_from_buffer(zpl_re *re, char const *pattern, zpl_isize pattern_len, void *buffer, zpl_isize buffer_len); +//! Compile regex pattern using a buffer. +ZPL_DEF zpl_regex_error zpl_re_compile_from_buffer(zpl_re *re, char const *pattern, zpl_isize pattern_len, void *buffer, zpl_isize buffer_len); - //! Destroy regex object. - ZPL_DEF void zpl_re_destroy(zpl_re *re); +//! Destroy regex object. +ZPL_DEF void zpl_re_destroy(zpl_re *re); - //! Retrieve number of retrievable captures. - ZPL_DEF zpl_isize zpl_re_capture_count(zpl_re *re); +//! Retrieve number of retrievable captures. +ZPL_DEF zpl_isize zpl_re_capture_count(zpl_re *re); - //! Match input string and output captures of the occurence. - ZPL_DEF zpl_b32 zpl_re_match(zpl_re *re, char const *str, zpl_isize str_len, zpl_re_capture *captures, zpl_isize max_capture_count, zpl_isize *offset); +//! Match input string and output captures of the occurence. +ZPL_DEF zpl_b32 zpl_re_match(zpl_re *re, char const *str, zpl_isize str_len, zpl_re_capture *captures, zpl_isize max_capture_count, zpl_isize *offset); - //! Match all occurences in an input string and output them into captures. Array of captures is allocated on the heap and needs to be freed afterwards. - ZPL_DEF zpl_b32 zpl_re_match_all(zpl_re *re, char const *str, zpl_isize str_len, zpl_isize max_capture_count, zpl_re_capture **out_captures); +//! Match all occurences in an input string and output them into captures. Array of captures is allocated on the heap and needs to be freed afterwards. +ZPL_DEF zpl_b32 zpl_re_match_all(zpl_re *re, char const *str, zpl_isize str_len, zpl_isize max_capture_count, zpl_re_capture **out_captures); - ZPL_END_C_DECLS +ZPL_END_C_DECLS #endif #if defined(ZPL_MODULE_DLL) - // file: header/dll.h +// file: header/dll.h - /** @file dll.c - @brief DLL Handling - @defgroup dll DLL handling +/** @file dll.c +@brief DLL Handling +@defgroup dll DLL handling - @{ - */ +@{ +*/ - ZPL_BEGIN_C_DECLS +ZPL_BEGIN_C_DECLS - typedef void *zpl_dll_handle; - typedef void (*zpl_dll_proc)(void); +typedef void *zpl_dll_handle; +typedef void (*zpl_dll_proc)(void); - ZPL_DEF zpl_dll_handle zpl_dll_load(char const *filepath); - ZPL_DEF void zpl_dll_unload(zpl_dll_handle dll); - ZPL_DEF zpl_dll_proc zpl_dll_proc_address(zpl_dll_handle dll, char const *proc_name); +ZPL_DEF zpl_dll_handle zpl_dll_load(char const *filepath); +ZPL_DEF void zpl_dll_unload(zpl_dll_handle dll); +ZPL_DEF zpl_dll_proc zpl_dll_proc_address(zpl_dll_handle dll, char const *proc_name); - //! @} +//! @} - ZPL_END_C_DECLS +ZPL_END_C_DECLS #endif #if defined(ZPL_MODULE_OPTS) - // file: header/opts.h +// file: header/opts.h - /** @file opts.c - @brief CLI options processor - @defgroup cli CLI options processor +/** @file opts.c +@brief CLI options processor +@defgroup cli CLI options processor - Opts is a CLI options parser, it can parse flags, switches and arguments from command line - and offers an easy way to express input errors as well as the ability to display help screen. + Opts is a CLI options parser, it can parse flags, switches and arguments from command line + and offers an easy way to express input errors as well as the ability to display help screen. - @{ - */ +@{ + */ - ZPL_BEGIN_C_DECLS +ZPL_BEGIN_C_DECLS - typedef enum { - ZPL_OPTS_STRING, - ZPL_OPTS_FLOAT, - ZPL_OPTS_FLAG, - ZPL_OPTS_INT, - } zpl_opts_types; +typedef enum { + ZPL_OPTS_STRING, + ZPL_OPTS_FLOAT, + ZPL_OPTS_FLAG, + ZPL_OPTS_INT, +} zpl_opts_types; - typedef struct { - char const *name, *lname, *desc; - zpl_u8 type; - zpl_b32 met, pos; +typedef struct { + char const *name, *lname, *desc; + zpl_u8 type; + zpl_b32 met, pos; + + //! values + union { + zpl_string text; + zpl_i64 integer; + zpl_f64 real; + }; +} zpl_opts_entry; - //! values - union { - zpl_string text; - zpl_i64 integer; - zpl_f64 real; - }; - } zpl_opts_entry; +typedef enum { + ZPL_OPTS_ERR_VALUE, + ZPL_OPTS_ERR_OPTION, + ZPL_OPTS_ERR_EXTRA_VALUE, + ZPL_OPTS_ERR_MISSING_VALUE, +} zpl_opts_err_type; - typedef enum { - ZPL_OPTS_ERR_VALUE, - ZPL_OPTS_ERR_OPTION, - ZPL_OPTS_ERR_EXTRA_VALUE, - ZPL_OPTS_ERR_MISSING_VALUE, - } zpl_opts_err_type; +typedef struct { + char *val; + zpl_u8 type; +} zpl_opts_err; - typedef struct { - char *val; - zpl_u8 type; - } zpl_opts_err; +typedef struct { + zpl_allocator alloc; + zpl_opts_entry *entries; ///< zpl_array + zpl_opts_err *errors; ///< zpl_array + zpl_opts_entry **positioned; ///< zpl_array + char const *appname; +} zpl_opts; - typedef struct { - zpl_allocator alloc; - zpl_opts_entry *entries; ///< zpl_array - zpl_opts_err *errors; ///< zpl_array - zpl_opts_entry **positioned; ///< zpl_array - char const *appname; - } zpl_opts; +//! Initializes options parser. - //! Initializes options parser. +//! Initializes CLI options parser using specified memory allocator and provided application name. +//! @param opts Options parser to initialize. +//! @param allocator Memory allocator to use. (ex. zpl_heap()) +//! @param app Application name displayed in help screen. +ZPL_DEF void zpl_opts_init(zpl_opts *opts, zpl_allocator allocator, char const *app); - //! Initializes CLI options parser using specified memory allocator and provided application name. - //! @param opts Options parser to initialize. - //! @param allocator Memory allocator to use. (ex. zpl_heap()) - //! @param app Application name displayed in help screen. - ZPL_DEF void zpl_opts_init(zpl_opts *opts, zpl_allocator allocator, char const *app); +//! Releases the resources used by options parser. +ZPL_DEF void zpl_opts_free(zpl_opts *opts); - //! Releases the resources used by options parser. - ZPL_DEF void zpl_opts_free(zpl_opts *opts); +//! Registers an option. - //! Registers an option. +//! Registers an option with its short and long name, specifies option's type and its description. +//! @param opts Options parser to add to. +//! @param lname Shorter name of option. (ex. "f") +//! @param name Full name of option. (ex. "foo") Note that rest of the module uses longer names to manipulate opts. +//! @param desc Description shown in the help screen. +//! @param type Option's type (see zpl_opts_types) +//! @see zpl_opts_types +ZPL_DEF void zpl_opts_add(zpl_opts *opts, char const *name, char const *lname, const char *desc, zpl_u8 type); - //! Registers an option with its short and long name, specifies option's type and its description. - //! @param opts Options parser to add to. - //! @param lname Shorter name of option. (ex. "f") - //! @param name Full name of option. (ex. "foo") Note that rest of the module uses longer names to manipulate opts. - //! @param desc Description shown in the help screen. - //! @param type Option's type (see zpl_opts_types) - //! @see zpl_opts_types - ZPL_DEF void zpl_opts_add(zpl_opts *opts, char const *name, char const *lname, const char *desc, zpl_u8 type); +//! Registers option as positional. - //! Registers option as positional. +//! Registers added option as positional, so that we can pass it anonymously. Arguments are expected on the command input in the same order they were registered as. +//! @param opts +//! @param name Name of already registered option. +ZPL_DEF void zpl_opts_positional_add(zpl_opts *opts, char const *name); - //! Registers added option as positional, so that we can pass it anonymously. Arguments are expected on the command input in the same order they were registered as. - //! @param opts - //! @param name Name of already registered option. - ZPL_DEF void zpl_opts_positional_add(zpl_opts *opts, char const *name); +//! Compiles CLI arguments. - //! Compiles CLI arguments. +// This method takes CLI arguments as input and processes them based on rules that were set up. +//! @param opts +//! @param argc Argument count in an array. +//! @param argv Array of arguments. +ZPL_DEF zpl_b32 zpl_opts_compile(zpl_opts *opts, int argc, char **argv); - // This method takes CLI arguments as input and processes them based on rules that were set up. - //! @param opts - //! @param argc Argument count in an array. - //! @param argv Array of arguments. - ZPL_DEF zpl_b32 zpl_opts_compile(zpl_opts *opts, int argc, char **argv); +//! Prints out help screen. - //! Prints out help screen. +//! Prints out help screen with example usage of application as well as with all the flags available. +ZPL_DEF void zpl_opts_print_help(zpl_opts *opts); - //! Prints out help screen with example usage of application as well as with all the flags available. - ZPL_DEF void zpl_opts_print_help(zpl_opts *opts); +//! Prints out parsing errors. - //! Prints out parsing errors. +//! Prints out possible errors caused by CLI input. +ZPL_DEF void zpl_opts_print_errors(zpl_opts *opts); - //! Prints out possible errors caused by CLI input. - ZPL_DEF void zpl_opts_print_errors(zpl_opts *opts); +//! Fetches a string from an option. - //! Fetches a string from an option. +//! @param opts +//! @param name Name of an option. +//! @param fallback Fallback string we return if option wasn't found. +ZPL_DEF zpl_string zpl_opts_string(zpl_opts *opts, char const *name, char const *fallback); - //! @param opts - //! @param name Name of an option. - //! @param fallback Fallback string we return if option wasn't found. - ZPL_DEF zpl_string zpl_opts_string(zpl_opts *opts, char const *name, char const *fallback); +//! Fetches a real number from an option. - //! Fetches a real number from an option. +//! @param opts +//! @param name Name of an option. +//! @param fallback Fallback real number we return if option was not found. +ZPL_DEF zpl_f64 zpl_opts_real(zpl_opts *opts, char const *name, zpl_f64 fallback); - //! @param opts - //! @param name Name of an option. - //! @param fallback Fallback real number we return if option was not found. - ZPL_DEF zpl_f64 zpl_opts_real(zpl_opts *opts, char const *name, zpl_f64 fallback); +//! Fetches an integer number from an option. - //! Fetches an integer number from an option. +//! @param opts +//! @param name Name of an option. +//! @param fallback Fallback integer number we return if option was not found. +ZPL_DEF zpl_i64 zpl_opts_integer(zpl_opts *opts, char const *name, zpl_i64 fallback); - //! @param opts - //! @param name Name of an option. - //! @param fallback Fallback integer number we return if option was not found. - ZPL_DEF zpl_i64 zpl_opts_integer(zpl_opts *opts, char const *name, zpl_i64 fallback); +//! Checks whether an option was used. - //! Checks whether an option was used. +//! @param opts +//! @param name Name of an option. +ZPL_DEF zpl_b32 zpl_opts_has_arg(zpl_opts *opts, char const *name); - //! @param opts - //! @param name Name of an option. - ZPL_DEF zpl_b32 zpl_opts_has_arg(zpl_opts *opts, char const *name); +//! Checks whether all positionals have been passed in. +ZPL_DEF zpl_b32 zpl_opts_positionals_filled(zpl_opts *opts); - //! Checks whether all positionals have been passed in. - ZPL_DEF zpl_b32 zpl_opts_positionals_filled(zpl_opts *opts); +//! @} - //! @} - - ZPL_END_C_DECLS +ZPL_END_C_DECLS #endif #if defined(ZPL_MODULE_PROCESS) - // file: header/process.h +// file: header/process.h - /** @file process.c - @brief Process creation and manipulation methods - @defgroup process Process creation and manipulation methods +/** @file process.c +@brief Process creation and manipulation methods +@defgroup process Process creation and manipulation methods - Gives you the ability to create a new process, wait for it to end or terminate it. - It also exposes standard I/O with configurable options. +Gives you the ability to create a new process, wait for it to end or terminate it. +It also exposes standard I/O with configurable options. - @{ - */ +@{ +*/ - ZPL_BEGIN_C_DECLS - // TODO(zaklaus): Add Linux support +ZPL_BEGIN_C_DECLS +// TODO(zaklaus): Add Linux support - typedef enum { - ZPL_PR_OPTS_COMBINE_STD_OUTPUT = ZPL_BIT(1), - ZPL_PR_OPTS_INHERIT_ENV = ZPL_BIT(2), - ZPL_PR_OPTS_CUSTOM_ENV = ZPL_BIT(3), - } zpl_pr_opts; +typedef enum { + ZPL_PR_OPTS_COMBINE_STD_OUTPUT = ZPL_BIT(1), + ZPL_PR_OPTS_INHERIT_ENV = ZPL_BIT(2), + ZPL_PR_OPTS_CUSTOM_ENV = ZPL_BIT(3), +} zpl_pr_opts; - typedef struct { - zpl_file in, out, err; - void *f_stdin, *f_stdout, *f_stderr; - #ifdef ZPL_SYSTEM_WINDOWS - void *win32_handle; - #else - // todo - #endif - } zpl_pr; +typedef struct { + zpl_file in, out, err; + void *f_stdin, *f_stdout, *f_stderr; +#ifdef ZPL_SYSTEM_WINDOWS + void *win32_handle; +#else + // todo +#endif +} zpl_pr; - typedef struct { - char *con_title; - char *workdir; +typedef struct { + char *con_title; + char *workdir; + + zpl_isize env_count; + char **env; // format: "var=name" + + zpl_u32 posx, posy; + zpl_u32 resx, resy; + zpl_u32 bufx, bufy; + zpl_u32 fill_attr; + zpl_u32 flags; + zpl_b32 show_window; +} zpl_pr_si; - zpl_isize env_count; - char **env; // format: "var=name" +ZPL_DEF zpl_i32 zpl_pr_create(zpl_pr *process, const char **args, zpl_isize argc, zpl_pr_si si, zpl_pr_opts options); +ZPL_DEF void zpl_pr_destroy(zpl_pr *process); +ZPL_DEF void zpl_pr_terminate(zpl_pr *process, zpl_i32 err_code); +ZPL_DEF zpl_i32 zpl_pr_join(zpl_pr *process); - zpl_u32 posx, posy; - zpl_u32 resx, resy; - zpl_u32 bufx, bufy; - zpl_u32 fill_attr; - zpl_u32 flags; - zpl_b32 show_window; - } zpl_pr_si; - - ZPL_DEF zpl_i32 zpl_pr_create(zpl_pr *process, const char **args, zpl_isize argc, zpl_pr_si si, zpl_pr_opts options); - ZPL_DEF void zpl_pr_destroy(zpl_pr *process); - ZPL_DEF void zpl_pr_terminate(zpl_pr *process, zpl_i32 err_code); - ZPL_DEF zpl_i32 zpl_pr_join(zpl_pr *process); - - //! @} - ZPL_END_C_DECLS +//! @} +ZPL_END_C_DECLS #endif #if defined(ZPL_MODULE_MATH) - // file: header/math.h - - /** @file math.c - @brief Math operations - @defgroup math Math operations - - OpenGL gamedev friendly library for math. - - @{ - */ - - ZPL_BEGIN_C_DECLS - - typedef union zpl_vec2 { - struct { - zpl_f32 x, y; - }; - struct { - zpl_f32 s, t; - }; - zpl_f32 e[2]; - } zpl_vec2; - - typedef union zpl_vec3 { - struct { - zpl_f32 x, y, z; - }; - struct { - zpl_f32 r, g, b; - }; - struct { - zpl_f32 s, t, p; - }; - - zpl_vec2 xy; - zpl_vec2 st; - zpl_f32 e[3]; - } zpl_vec3; - - typedef union zpl_vec4 { - struct { - zpl_f32 x, y, z, w; - }; - struct { - zpl_f32 r, g, b, a; - }; - struct { - zpl_f32 s, t, p, q; - }; - struct { - zpl_vec2 xy, zw; - }; - struct { - zpl_vec2 st, pq; - }; - zpl_vec3 xyz; - zpl_vec3 rgb; - zpl_f32 e[4]; - } zpl_vec4; - - typedef union zpl_mat2 { - struct { - zpl_vec2 x, y; - }; - zpl_vec2 col[2]; - zpl_f32 e[4]; - } zpl_mat2; - - typedef union zpl_mat3 { - struct { - zpl_vec3 x, y, z; - }; - zpl_vec3 col[3]; - zpl_f32 e[9]; - } zpl_mat3; - - typedef union zpl_mat4 { - struct { - zpl_vec4 x, y, z, w; - }; - zpl_vec4 col[4]; - zpl_f32 e[16]; - } zpl_mat4; - - typedef union zpl_quat { - struct { - zpl_f32 x, y, z, w; - }; - zpl_vec4 xyzw; - zpl_vec3 xyz; - zpl_f32 e[4]; - } zpl_quat; - - typedef union zpl_plane { - struct { - zpl_f32 a, b, c, d; - }; - zpl_vec4 xyzw; - zpl_vec3 n; - zpl_f32 e[4]; - } zpl_plane; - - typedef struct zpl_frustum { - zpl_plane x1; - zpl_plane x2; - zpl_plane y1; - zpl_plane y2; - zpl_plane z1; - zpl_plane z2; - } zpl_frustum; - - typedef zpl_f32 zpl_float2[2]; - typedef zpl_f32 zpl_float3[3]; - typedef zpl_f32 zpl_float4[4]; - - typedef struct zpl_rect2 { - zpl_vec2 pos, dim; - } zpl_rect2; - typedef struct zpl_rect3 { - zpl_vec3 pos, dim; - } zpl_rect3; - - typedef struct zpl_aabb2 { - zpl_vec2 min, max; - } zpl_aabb2; - typedef struct zpl_aabb3 { - zpl_vec3 min, max; - } zpl_aabb3; - - typedef short zpl_half; - - #ifndef ZPL_CONSTANTS - #define ZPL_CONSTANTS - #define ZPL_EPSILON 1.19209290e-7f - #define ZPL_ZERO 0.0f - #define ZPL_ONE 1.0f - #define ZPL_TWO_THIRDS 0.666666666666666666666666666666666666667f - - #define ZPL_TAU 6.28318530717958647692528676655900576f - #define ZPL_PI 3.14159265358979323846264338327950288f - #define ZPL_ONE_OVER_TAU 0.636619772367581343075535053490057448f - #define ZPL_ONE_OVER_PI 0.159154943091895335768883763372514362f - - #define ZPL_TAU_OVER_2 3.14159265358979323846264338327950288f - #define ZPL_TAU_OVER_4 1.570796326794896619231321691639751442f - #define ZPL_TAU_OVER_8 0.785398163397448309615660845819875721f - - #define ZPL_E 2.71828182845904523536f - #define ZPL_SQRT_TWO 1.41421356237309504880168872420969808f - #define ZPL_SQRT_THREE 1.73205080756887729352744634150587236f - #define ZPL_SQRT_FIVE 2.23606797749978969640917366873127623f - - #define ZPL_LOG_TWO 0.693147180559945309417232121458176568f - #define ZPL_LOG_TEN 2.30258509299404568401799145468436421f - #endif // ZPL_CONSTANTS - - #ifndef zpl_square - #define zpl_square(x) ((x) * (x)) - #endif - - #ifndef zpl_cube - #define zpl_cube(x) ((x) * (x) * (x)) - #endif - - #ifndef zpl_sign - #define zpl_sign(x) ((x) >= 0 ? 1 : -1) - #endif - - ZPL_DEF zpl_f32 zpl_to_radians(zpl_f32 degrees); - ZPL_DEF zpl_f32 zpl_to_degrees(zpl_f32 radians); - - /* NOTE: Because to interpolate angles */ - ZPL_DEF zpl_f32 zpl_angle_diff(zpl_f32 radians_a, zpl_f32 radians_b); - - ZPL_DEF zpl_f32 zpl_copy_sign(zpl_f32 x, zpl_f32 y); - ZPL_DEF zpl_f32 zpl_remainder(zpl_f32 x, zpl_f32 y); - ZPL_DEF zpl_f32 zpl_mod(zpl_f32 x, zpl_f32 y); - ZPL_DEF zpl_f64 zpl_copy_sign64(zpl_f64 x, zpl_f64 y); - ZPL_DEF zpl_f64 zpl_floor64(zpl_f64 x); - ZPL_DEF zpl_f64 zpl_ceil64(zpl_f64 x); - ZPL_DEF zpl_f64 zpl_round64(zpl_f64 x); - ZPL_DEF zpl_f64 zpl_remainder64(zpl_f64 x, zpl_f64 y); - ZPL_DEF zpl_f64 zpl_abs64(zpl_f64 x); - ZPL_DEF zpl_f64 zpl_sign64(zpl_f64 x); - ZPL_DEF zpl_f64 zpl_mod64(zpl_f64 x, zpl_f64 y); - ZPL_DEF zpl_f32 zpl_sqrt(zpl_f32 a); - ZPL_DEF zpl_f32 zpl_rsqrt(zpl_f32 a); - ZPL_DEF zpl_f32 zpl_quake_rsqrt(zpl_f32 a); /* NOTE: It's probably better to use 1.0f/zpl_sqrt(a) - * And for simd, there is usually isqrt functions too! - */ - ZPL_DEF zpl_f32 zpl_sin(zpl_f32 radians); - ZPL_DEF zpl_f32 zpl_cos(zpl_f32 radians); - ZPL_DEF zpl_f32 zpl_tan(zpl_f32 radians); - ZPL_DEF zpl_f32 zpl_arcsin(zpl_f32 a); - ZPL_DEF zpl_f32 zpl_arccos(zpl_f32 a); - ZPL_DEF zpl_f32 zpl_arctan(zpl_f32 a); - ZPL_DEF zpl_f32 zpl_arctan2(zpl_f32 y, zpl_f32 x); - - ZPL_DEF zpl_f32 zpl_exp(zpl_f32 x); - ZPL_DEF zpl_f32 zpl_exp2(zpl_f32 x); - ZPL_DEF zpl_f32 zpl_log(zpl_f32 x); - ZPL_DEF zpl_f32 zpl_log2(zpl_f32 x); - ZPL_DEF zpl_f32 zpl_fast_exp(zpl_f32 x); /* NOTE: Only valid from -1 <= x <= +1 */ - ZPL_DEF zpl_f32 zpl_fast_exp2(zpl_f32 x); /* NOTE: Only valid from -1 <= x <= +1 */ - ZPL_DEF zpl_f32 zpl_pow(zpl_f32 x, zpl_f32 y); /* x^y */ - - ZPL_DEF zpl_f32 zpl_round(zpl_f32 x); - ZPL_DEF zpl_f32 zpl_floor(zpl_f32 x); - ZPL_DEF zpl_f32 zpl_ceil(zpl_f32 x); - - ZPL_DEF zpl_f32 zpl_half_to_float(zpl_half value); - ZPL_DEF zpl_half zpl_float_to_half(zpl_f32 value); - - ZPL_DEF zpl_vec2 zpl_vec2f_zero(void); - ZPL_DEF zpl_vec2 zpl_vec2f(zpl_f32 x, zpl_f32 y); - ZPL_DEF zpl_vec2 zpl_vec2fv(zpl_f32 x[2]); - - ZPL_DEF zpl_vec3 zpl_vec3f_zero(void); - ZPL_DEF zpl_vec3 zpl_vec3f(zpl_f32 x, zpl_f32 y, zpl_f32 z); - ZPL_DEF zpl_vec3 zpl_vec3fv(zpl_f32 x[3]); - - ZPL_DEF zpl_vec4 zpl_vec4f_zero(void); - ZPL_DEF zpl_vec4 zpl_vec4f(zpl_f32 x, zpl_f32 y, zpl_f32 z, zpl_f32 w); - ZPL_DEF zpl_vec4 zpl_vec4fv(zpl_f32 x[4]); - - ZPL_DEF zpl_f32 zpl_vec2_max(zpl_vec2 v); - ZPL_DEF zpl_f32 zpl_vec2_side(zpl_vec2 p, zpl_vec2 q, zpl_vec2 r); - ZPL_DEF void zpl_vec2_add(zpl_vec2 *d, zpl_vec2 v0, zpl_vec2 v1); - ZPL_DEF void zpl_vec2_sub(zpl_vec2 *d, zpl_vec2 v0, zpl_vec2 v1); - ZPL_DEF void zpl_vec2_mul(zpl_vec2 *d, zpl_vec2 v, zpl_f32 s); - ZPL_DEF void zpl_vec2_div(zpl_vec2 *d, zpl_vec2 v, zpl_f32 s); - - ZPL_DEF zpl_f32 zpl_vec3_max(zpl_vec3 v); - ZPL_DEF void zpl_vec3_add(zpl_vec3 *d, zpl_vec3 v0, zpl_vec3 v1); - ZPL_DEF void zpl_vec3_sub(zpl_vec3 *d, zpl_vec3 v0, zpl_vec3 v1); - ZPL_DEF void zpl_vec3_mul(zpl_vec3 *d, zpl_vec3 v, zpl_f32 s); - ZPL_DEF void zpl_vec3_div(zpl_vec3 *d, zpl_vec3 v, zpl_f32 s); - - ZPL_DEF void zpl_vec4_add(zpl_vec4 *d, zpl_vec4 v0, zpl_vec4 v1); - ZPL_DEF void zpl_vec4_sub(zpl_vec4 *d, zpl_vec4 v0, zpl_vec4 v1); - ZPL_DEF void zpl_vec4_mul(zpl_vec4 *d, zpl_vec4 v, zpl_f32 s); - ZPL_DEF void zpl_vec4_div(zpl_vec4 *d, zpl_vec4 v, zpl_f32 s); - - ZPL_DEF void zpl_vec2_addeq(zpl_vec2 *d, zpl_vec2 v); - ZPL_DEF void zpl_vec2_subeq(zpl_vec2 *d, zpl_vec2 v); - ZPL_DEF void zpl_vec2_muleq(zpl_vec2 *d, zpl_f32 s); - ZPL_DEF void zpl_vec2_diveq(zpl_vec2 *d, zpl_f32 s); - - ZPL_DEF void zpl_vec3_addeq(zpl_vec3 *d, zpl_vec3 v); - ZPL_DEF void zpl_vec3_subeq(zpl_vec3 *d, zpl_vec3 v); - ZPL_DEF void zpl_vec3_muleq(zpl_vec3 *d, zpl_f32 s); - ZPL_DEF void zpl_vec3_diveq(zpl_vec3 *d, zpl_f32 s); - - ZPL_DEF void zpl_vec4_addeq(zpl_vec4 *d, zpl_vec4 v); - ZPL_DEF void zpl_vec4_subeq(zpl_vec4 *d, zpl_vec4 v); - ZPL_DEF void zpl_vec4_muleq(zpl_vec4 *d, zpl_f32 s); - ZPL_DEF void zpl_vec4_diveq(zpl_vec4 *d, zpl_f32 s); - - ZPL_DEF zpl_f32 zpl_vec2_dot(zpl_vec2 v0, zpl_vec2 v1); - ZPL_DEF zpl_f32 zpl_vec3_dot(zpl_vec3 v0, zpl_vec3 v1); - ZPL_DEF zpl_f32 zpl_vec4_dot(zpl_vec4 v0, zpl_vec4 v1); - - ZPL_DEF void zpl_vec2_cross(zpl_f32 *d, zpl_vec2 v0, zpl_vec2 v1); - ZPL_DEF void zpl_vec3_cross(zpl_vec3 *d, zpl_vec3 v0, zpl_vec3 v1); - - ZPL_DEF zpl_f32 zpl_vec2_mag2(zpl_vec2 v); - ZPL_DEF zpl_f32 zpl_vec3_mag2(zpl_vec3 v); - ZPL_DEF zpl_f32 zpl_vec4_mag2(zpl_vec4 v); - - ZPL_DEF zpl_f32 zpl_vec2_mag(zpl_vec2 v); - ZPL_DEF zpl_f32 zpl_vec3_mag(zpl_vec3 v); - ZPL_DEF zpl_f32 zpl_vec4_mag(zpl_vec4 v); - - ZPL_DEF void zpl_vec2_norm(zpl_vec2 *d, zpl_vec2 v); - ZPL_DEF void zpl_vec3_norm(zpl_vec3 *d, zpl_vec3 v); - ZPL_DEF void zpl_vec4_norm(zpl_vec4 *d, zpl_vec4 v); - - ZPL_DEF void zpl_vec2_norm0(zpl_vec2 *d, zpl_vec2 v); - ZPL_DEF void zpl_vec3_norm0(zpl_vec3 *d, zpl_vec3 v); - ZPL_DEF void zpl_vec4_norm0(zpl_vec4 *d, zpl_vec4 v); - - ZPL_DEF void zpl_vec2_reflect(zpl_vec2 *d, zpl_vec2 i, zpl_vec2 n); - ZPL_DEF void zpl_vec3_reflect(zpl_vec3 *d, zpl_vec3 i, zpl_vec3 n); - ZPL_DEF void zpl_vec2_refract(zpl_vec2 *d, zpl_vec2 i, zpl_vec2 n, zpl_f32 eta); - ZPL_DEF void zpl_vec3_refract(zpl_vec3 *d, zpl_vec3 i, zpl_vec3 n, zpl_f32 eta); - - ZPL_DEF zpl_f32 zpl_vec2_aspect_ratio(zpl_vec2 v); - - ZPL_DEF void zpl_mat2_identity(zpl_mat2 *m); - ZPL_DEF void zpl_float22_identity(zpl_f32 m[2][2]); - - ZPL_DEF void zpl_mat2_transpose(zpl_mat2 *m); - ZPL_DEF void zpl_mat2_mul(zpl_mat2 *out, zpl_mat2 *m1, zpl_mat2 *m2); - ZPL_DEF void zpl_mat2_mul_vec2(zpl_vec2 *out, zpl_mat2 *m, zpl_vec2 in); - ZPL_DEF void zpl_mat2_inverse(zpl_mat2 *out, zpl_mat2 *in); - ZPL_DEF zpl_f32 zpl_mat2_determinate(zpl_mat2 *m); - - ZPL_DEF zpl_mat2 *zpl_mat2_v(zpl_vec2 m[2]); - ZPL_DEF zpl_mat2 *zpl_mat2_f(zpl_f32 m[2][2]); - ZPL_DEF zpl_float2 *zpl_float22_m(zpl_mat2 *m); - ZPL_DEF zpl_float2 *zpl_float22_v(zpl_vec2 m[2]); - ZPL_DEF zpl_float2 *zpl_float22_4(zpl_f32 m[4]); - - ZPL_DEF void zpl_float22_transpose(zpl_f32 (*vec)[2]); - ZPL_DEF void zpl_float22_mul(zpl_f32 (*out)[2], zpl_f32 (*mat1)[2], zpl_f32 (*mat2)[2]); - ZPL_DEF void zpl_float22_mul_vec2(zpl_vec2 *out, zpl_f32 m[2][2], zpl_vec2 in); - - ZPL_DEF void zpl_mat3_identity(zpl_mat3 *m); - ZPL_DEF void zpl_float33_identity(zpl_f32 m[3][3]); - - ZPL_DEF void zpl_mat3_transpose(zpl_mat3 *m); - ZPL_DEF void zpl_mat3_mul(zpl_mat3 *out, zpl_mat3 *m1, zpl_mat3 *m2); - ZPL_DEF void zpl_mat3_mul_vec3(zpl_vec3 *out, zpl_mat3 *m, zpl_vec3 in); - ZPL_DEF void zpl_mat3_inverse(zpl_mat3 *out, zpl_mat3 *in); - ZPL_DEF zpl_f32 zpl_mat3_determinate(zpl_mat3 *m); - - ZPL_DEF zpl_mat3 *zpl_mat3_v(zpl_vec3 m[3]); - ZPL_DEF zpl_mat3 *zpl_mat3_f(zpl_f32 m[3][3]); - - ZPL_DEF zpl_float3 *zpl_float33_m(zpl_mat3 *m); - ZPL_DEF zpl_float3 *zpl_float33_v(zpl_vec3 m[3]); - ZPL_DEF zpl_float3 *zpl_float33_9(zpl_f32 m[9]); - - ZPL_DEF void zpl_float33_transpose(zpl_f32 (*vec)[3]); - ZPL_DEF void zpl_float33_mul(zpl_f32 (*out)[3], zpl_f32 (*mat1)[3], zpl_f32 (*mat2)[3]); - ZPL_DEF void zpl_float33_mul_vec3(zpl_vec3 *out, zpl_f32 m[3][3], zpl_vec3 in); - - ZPL_DEF void zpl_mat4_identity(zpl_mat4 *m); - ZPL_DEF void zpl_float44_identity(zpl_f32 m[4][4]); - ZPL_DEF void zpl_mat4_copy(zpl_mat4* out, zpl_mat4* m); - - ZPL_DEF void zpl_mat4_transpose(zpl_mat4 *m); - ZPL_DEF void zpl_mat4_mul(zpl_mat4 *out, zpl_mat4 *m1, zpl_mat4 *m2); - ZPL_DEF void zpl_mat4_mul_vec4(zpl_vec4 *out, zpl_mat4 *m, zpl_vec4 in); - ZPL_DEF void zpl_mat4_inverse(zpl_mat4 *out, zpl_mat4 *in); - - ZPL_DEF zpl_mat4 *zpl_mat4_v(zpl_vec4 m[4]); - ZPL_DEF zpl_mat4 *zpl_mat4_f(zpl_f32 m[4][4]); - - ZPL_DEF zpl_float4 *zpl_float44_m(zpl_mat4 *m); - ZPL_DEF zpl_float4 *zpl_float44_v(zpl_vec4 m[4]); - ZPL_DEF zpl_float4 *zpl_float44_16(zpl_f32 m[16]); - - ZPL_DEF void zpl_float44_transpose(zpl_f32 (*vec)[4]); - ZPL_DEF void zpl_float44_mul(zpl_f32 (*out)[4], zpl_f32 (*mat1)[4], zpl_f32 (*mat2)[4]); - ZPL_DEF void zpl_float44_mul_vec4(zpl_vec4 *out, zpl_f32 m[4][4], zpl_vec4 in); - - ZPL_DEF void zpl_mat4_axis_angle(zpl_mat4* out, zpl_vec3 v, zpl_f32 angle_radians); - ZPL_DEF void zpl_mat4_to_translate(zpl_mat4* out, zpl_vec3 v); - ZPL_DEF void zpl_mat4_to_rotate(zpl_mat4* out, zpl_vec3 v, zpl_f32 angle_radians); - ZPL_DEF void zpl_mat4_to_scale(zpl_mat4* out, zpl_vec3 v); - ZPL_DEF void zpl_mat4_to_scalef(zpl_mat4* out, zpl_f32 s); - ZPL_DEF void zpl_mat4_translate(zpl_mat4* out, zpl_vec3 v); - ZPL_DEF void zpl_mat4_rotate(zpl_mat4* out, zpl_vec3 v, zpl_f32 angle_radians); - ZPL_DEF void zpl_mat4_scale(zpl_mat4* out, zpl_vec3 v); - ZPL_DEF void zpl_mat4_scalef(zpl_mat4 *out, zpl_f32 s); - ZPL_DEF void zpl_mat4_ortho2d(zpl_mat4 *out, zpl_f32 left, zpl_f32 right, zpl_f32 bottom, zpl_f32 top); - ZPL_DEF void zpl_mat4_ortho3d(zpl_mat4 *out, zpl_f32 left, zpl_f32 right, zpl_f32 bottom, zpl_f32 top, zpl_f32 z_near, zpl_f32 z_far); - ZPL_DEF void zpl_mat4_perspective(zpl_mat4 *out, zpl_f32 fovy, zpl_f32 aspect, zpl_f32 z_near, zpl_f32 z_far); - ZPL_DEF void zpl_mat4_infinite_perspective(zpl_mat4 *out, zpl_f32 fovy, zpl_f32 aspect, zpl_f32 z_near); - - ZPL_DEF void zpl_mat4_ortho2d_dx(zpl_mat4 *out, zpl_f32 left, zpl_f32 right, zpl_f32 bottom, zpl_f32 top); - ZPL_DEF void zpl_mat4_ortho3d_dx(zpl_mat4 *out, zpl_f32 left, zpl_f32 right, zpl_f32 bottom, zpl_f32 top, zpl_f32 z_near, zpl_f32 z_far); - ZPL_DEF void zpl_mat4_perspective_dx(zpl_mat4 *out, zpl_f32 fovy, zpl_f32 aspect, zpl_f32 z_near, zpl_f32 z_far); - ZPL_DEF void zpl_mat4_infinite_perspective_dx(zpl_mat4 *out, zpl_f32 fovy, zpl_f32 aspect, zpl_f32 z_near); - - ZPL_DEF void zpl_mat4_look_at(zpl_mat4 *out, zpl_vec3 eye, zpl_vec3 centre, zpl_vec3 up); - - ZPL_DEF void zpl_mat4_look_at_lh(zpl_mat4 *out, zpl_vec3 eye, zpl_vec3 centre, zpl_vec3 up); - - ZPL_DEF zpl_quat zpl_quatf(zpl_f32 x, zpl_f32 y, zpl_f32 z, zpl_f32 w); - ZPL_DEF zpl_quat zpl_quatfv(zpl_f32 e[4]); - ZPL_DEF zpl_quat zpl_quat_axis_angle(zpl_vec3 axis, zpl_f32 angle_radians); - ZPL_DEF zpl_quat zpl_quat_euler_angles(zpl_f32 pitch, zpl_f32 yaw, zpl_f32 roll); - ZPL_DEF zpl_quat zpl_quat_identity(void); - - ZPL_DEF void zpl_quat_add(zpl_quat *d, zpl_quat q0, zpl_quat q1); - ZPL_DEF void zpl_quat_sub(zpl_quat *d, zpl_quat q0, zpl_quat q1); - ZPL_DEF void zpl_quat_mul(zpl_quat *d, zpl_quat q0, zpl_quat q1); - ZPL_DEF void zpl_quat_div(zpl_quat *d, zpl_quat q0, zpl_quat q1); - - ZPL_DEF void zpl_quat_mulf(zpl_quat *d, zpl_quat q, zpl_f32 s); - ZPL_DEF void zpl_quat_divf(zpl_quat *d, zpl_quat q, zpl_f32 s); - - ZPL_DEF void zpl_quat_addeq(zpl_quat *d, zpl_quat q); - ZPL_DEF void zpl_quat_subeq(zpl_quat *d, zpl_quat q); - ZPL_DEF void zpl_quat_muleq(zpl_quat *d, zpl_quat q); - ZPL_DEF void zpl_quat_diveq(zpl_quat *d, zpl_quat q); - - ZPL_DEF void zpl_quat_muleqf(zpl_quat *d, zpl_f32 s); - ZPL_DEF void zpl_quat_diveqf(zpl_quat *d, zpl_f32 s); - - ZPL_DEF zpl_f32 zpl_quat_dot(zpl_quat q0, zpl_quat q1); - ZPL_DEF zpl_f32 zpl_quat_mag(zpl_quat q); - - ZPL_DEF void zpl_quat_norm(zpl_quat *d, zpl_quat q); - ZPL_DEF void zpl_quat_conj(zpl_quat *d, zpl_quat q); - ZPL_DEF void zpl_quat_inverse(zpl_quat *d, zpl_quat q); - - ZPL_DEF void zpl_quat_axis(zpl_vec3 *axis, zpl_quat q); - ZPL_DEF zpl_f32 zpl_quat_angle(zpl_quat q); - - ZPL_DEF zpl_f32 zpl_quat_pitch(zpl_quat q); - ZPL_DEF zpl_f32 zpl_quat_yaw(zpl_quat q); - ZPL_DEF zpl_f32 zpl_quat_roll(zpl_quat q); - - /* NOTE: Rotate v by q */ - ZPL_DEF void zpl_quat_rotate_vec3(zpl_vec3 *d, zpl_quat q, zpl_vec3 v); - ZPL_DEF void zpl_mat4_from_quat(zpl_mat4 *out, zpl_quat q); - ZPL_DEF void zpl_quat_from_mat4(zpl_quat *out, zpl_mat4 *m); - - /* Plane math. */ - ZPL_DEF zpl_f32 zpl_plane_distance(zpl_plane* p, zpl_vec3 v); - - /* Frustum culling. */ - ZPL_DEF void zpl_frustum_create(zpl_frustum* out, zpl_mat4* camera, zpl_mat4* proj); - ZPL_DEF zpl_b8 zpl_frustum_sphere_inside(zpl_frustum* frustum, zpl_vec3 center, zpl_f32 radius); - ZPL_DEF zpl_b8 zpl_frustum_point_inside(zpl_frustum* frustum, zpl_vec3 point); - ZPL_DEF zpl_b8 zpl_frustum_box_inside(zpl_frustum* frustum, zpl_aabb3 box); - - /* Interpolations */ - ZPL_DEF zpl_f32 zpl_lerp(zpl_f32 a, zpl_f32 b, zpl_f32 t); - ZPL_DEF zpl_f32 zpl_unlerp(zpl_f32 t, zpl_f32 a, zpl_f32 b); - ZPL_DEF zpl_f32 zpl_smooth_step(zpl_f32 a, zpl_f32 b, zpl_f32 t); - ZPL_DEF zpl_f32 zpl_smoother_step(zpl_f32 a, zpl_f32 b, zpl_f32 t); - - ZPL_DEF void zpl_vec2_lerp(zpl_vec2 *d, zpl_vec2 a, zpl_vec2 b, zpl_f32 t); - ZPL_DEF void zpl_vec3_lerp(zpl_vec3 *d, zpl_vec3 a, zpl_vec3 b, zpl_f32 t); - ZPL_DEF void zpl_vec4_lerp(zpl_vec4 *d, zpl_vec4 a, zpl_vec4 b, zpl_f32 t); - - ZPL_DEF void zpl_vec2_cslerp(zpl_vec2 *d, zpl_vec2 a, zpl_vec2 v0, zpl_vec2 b, zpl_vec2 v1, zpl_f32 t); - ZPL_DEF void zpl_vec3_cslerp(zpl_vec3 *d, zpl_vec3 a, zpl_vec3 v0, zpl_vec3 b, zpl_vec3 v1, zpl_f32 t); - ZPL_DEF void zpl_vec2_dcslerp(zpl_vec2 *d, zpl_vec2 a, zpl_vec2 v0, zpl_vec2 b, zpl_vec2 v1, zpl_f32 t); - ZPL_DEF void zpl_vec3_dcslerp(zpl_vec3 *d, zpl_vec3 a, zpl_vec3 v0, zpl_vec3 b, zpl_vec3 v1, zpl_f32 t); - - ZPL_DEF void zpl_quat_lerp(zpl_quat *d, zpl_quat a, zpl_quat b, zpl_f32 t); - ZPL_DEF void zpl_quat_nlerp(zpl_quat *d, zpl_quat a, zpl_quat b, zpl_f32 t); - ZPL_DEF void zpl_quat_slerp(zpl_quat *d, zpl_quat a, zpl_quat b, zpl_f32 t); - ZPL_DEF void zpl_quat_nquad(zpl_quat *d, zpl_quat p, zpl_quat a, zpl_quat b, zpl_quat q, zpl_f32 t); - ZPL_DEF void zpl_quat_squad(zpl_quat *d, zpl_quat p, zpl_quat a, zpl_quat b, zpl_quat q, zpl_f32 t); - ZPL_DEF void zpl_quat_slerp_approx(zpl_quat *d, zpl_quat a, zpl_quat b, zpl_f32 t); - ZPL_DEF void zpl_quat_squad_approx(zpl_quat *d, zpl_quat p, zpl_quat a, zpl_quat b, zpl_quat q, zpl_f32 t); - - /* rects */ - ZPL_DEF zpl_rect2 zpl_rect2f(zpl_vec2 pos, zpl_vec2 dim); - ZPL_DEF zpl_rect3 zpl_rect3f(zpl_vec3 pos, zpl_vec3 dim); +// file: header/math.h + +/** @file math.c +@brief Math operations +@defgroup math Math operations + +OpenGL gamedev friendly library for math. + +@{ +*/ + +ZPL_BEGIN_C_DECLS + +typedef union zpl_vec2 { + struct { + zpl_f32 x, y; + }; + struct { + zpl_f32 s, t; + }; + zpl_f32 e[2]; +} zpl_vec2; + +typedef union zpl_vec3 { + struct { + zpl_f32 x, y, z; + }; + struct { + zpl_f32 r, g, b; + }; + struct { + zpl_f32 s, t, p; + }; + + zpl_vec2 xy; + zpl_vec2 st; + zpl_f32 e[3]; +} zpl_vec3; + +typedef union zpl_vec4 { + struct { + zpl_f32 x, y, z, w; + }; + struct { + zpl_f32 r, g, b, a; + }; + struct { + zpl_f32 s, t, p, q; + }; + struct { + zpl_vec2 xy, zw; + }; + struct { + zpl_vec2 st, pq; + }; + zpl_vec3 xyz; + zpl_vec3 rgb; + zpl_f32 e[4]; +} zpl_vec4; + +typedef union zpl_mat2 { + struct { + zpl_vec2 x, y; + }; + zpl_vec2 col[2]; + zpl_f32 e[4]; +} zpl_mat2; + +typedef union zpl_mat3 { + struct { + zpl_vec3 x, y, z; + }; + zpl_vec3 col[3]; + zpl_f32 e[9]; +} zpl_mat3; + +typedef union zpl_mat4 { + struct { + zpl_vec4 x, y, z, w; + }; + zpl_vec4 col[4]; + zpl_f32 e[16]; +} zpl_mat4; + +typedef union zpl_quat { + struct { + zpl_f32 x, y, z, w; + }; + zpl_vec4 xyzw; + zpl_vec3 xyz; + zpl_f32 e[4]; +} zpl_quat; + +typedef union zpl_plane { + struct { + zpl_f32 a, b, c, d; + }; + zpl_vec4 xyzw; + zpl_vec3 n; + zpl_f32 e[4]; +} zpl_plane; + +typedef struct zpl_frustum { + zpl_plane x1; + zpl_plane x2; + zpl_plane y1; + zpl_plane y2; + zpl_plane z1; + zpl_plane z2; +} zpl_frustum; + +typedef zpl_f32 zpl_float2[2]; +typedef zpl_f32 zpl_float3[3]; +typedef zpl_f32 zpl_float4[4]; + +typedef struct zpl_rect2 { + zpl_vec2 pos, dim; +} zpl_rect2; +typedef struct zpl_rect3 { + zpl_vec3 pos, dim; +} zpl_rect3; + +typedef struct zpl_aabb2 { + zpl_vec2 min, max; +} zpl_aabb2; +typedef struct zpl_aabb3 { + zpl_vec3 min, max; +} zpl_aabb3; + +typedef short zpl_half; + +#ifndef ZPL_CONSTANTS +#define ZPL_CONSTANTS +#define ZPL_EPSILON 1.19209290e-7f +#define ZPL_ZERO 0.0f +#define ZPL_ONE 1.0f +#define ZPL_TWO_THIRDS 0.666666666666666666666666666666666666667f + +#define ZPL_TAU 6.28318530717958647692528676655900576f +#define ZPL_PI 3.14159265358979323846264338327950288f +#define ZPL_ONE_OVER_TAU 0.636619772367581343075535053490057448f +#define ZPL_ONE_OVER_PI 0.159154943091895335768883763372514362f + +#define ZPL_TAU_OVER_2 3.14159265358979323846264338327950288f +#define ZPL_TAU_OVER_4 1.570796326794896619231321691639751442f +#define ZPL_TAU_OVER_8 0.785398163397448309615660845819875721f + +#define ZPL_E 2.71828182845904523536f +#define ZPL_SQRT_TWO 1.41421356237309504880168872420969808f +#define ZPL_SQRT_THREE 1.73205080756887729352744634150587236f +#define ZPL_SQRT_FIVE 2.23606797749978969640917366873127623f + +#define ZPL_LOG_TWO 0.693147180559945309417232121458176568f +#define ZPL_LOG_TEN 2.30258509299404568401799145468436421f +#endif // ZPL_CONSTANTS + +#ifndef zpl_square +#define zpl_square(x) ((x) * (x)) +#endif + +#ifndef zpl_cube +#define zpl_cube(x) ((x) * (x) * (x)) +#endif + +#ifndef zpl_sign +#define zpl_sign(x) ((x) >= 0 ? 1 : -1) +#endif + +ZPL_DEF zpl_f32 zpl_to_radians(zpl_f32 degrees); +ZPL_DEF zpl_f32 zpl_to_degrees(zpl_f32 radians); + +/* NOTE: Because to interpolate angles */ +ZPL_DEF zpl_f32 zpl_angle_diff(zpl_f32 radians_a, zpl_f32 radians_b); + +ZPL_DEF zpl_f32 zpl_copy_sign(zpl_f32 x, zpl_f32 y); +ZPL_DEF zpl_f32 zpl_remainder(zpl_f32 x, zpl_f32 y); +ZPL_DEF zpl_f32 zpl_mod(zpl_f32 x, zpl_f32 y); +ZPL_DEF zpl_f64 zpl_copy_sign64(zpl_f64 x, zpl_f64 y); +ZPL_DEF zpl_f64 zpl_floor64(zpl_f64 x); +ZPL_DEF zpl_f64 zpl_ceil64(zpl_f64 x); +ZPL_DEF zpl_f64 zpl_round64(zpl_f64 x); +ZPL_DEF zpl_f64 zpl_remainder64(zpl_f64 x, zpl_f64 y); +ZPL_DEF zpl_f64 zpl_abs64(zpl_f64 x); +ZPL_DEF zpl_f64 zpl_sign64(zpl_f64 x); +ZPL_DEF zpl_f64 zpl_mod64(zpl_f64 x, zpl_f64 y); +ZPL_DEF zpl_f32 zpl_sqrt(zpl_f32 a); +ZPL_DEF zpl_f32 zpl_rsqrt(zpl_f32 a); +ZPL_DEF zpl_f32 zpl_quake_rsqrt(zpl_f32 a); /* NOTE: It's probably better to use 1.0f/zpl_sqrt(a) + * And for simd, there is usually isqrt functions too! + */ +ZPL_DEF zpl_f32 zpl_sin(zpl_f32 radians); +ZPL_DEF zpl_f32 zpl_cos(zpl_f32 radians); +ZPL_DEF zpl_f32 zpl_tan(zpl_f32 radians); +ZPL_DEF zpl_f32 zpl_arcsin(zpl_f32 a); +ZPL_DEF zpl_f32 zpl_arccos(zpl_f32 a); +ZPL_DEF zpl_f32 zpl_arctan(zpl_f32 a); +ZPL_DEF zpl_f32 zpl_arctan2(zpl_f32 y, zpl_f32 x); + +ZPL_DEF zpl_f32 zpl_exp(zpl_f32 x); +ZPL_DEF zpl_f32 zpl_exp2(zpl_f32 x); +ZPL_DEF zpl_f32 zpl_log(zpl_f32 x); +ZPL_DEF zpl_f32 zpl_log2(zpl_f32 x); +ZPL_DEF zpl_f32 zpl_fast_exp(zpl_f32 x); /* NOTE: Only valid from -1 <= x <= +1 */ +ZPL_DEF zpl_f32 zpl_fast_exp2(zpl_f32 x); /* NOTE: Only valid from -1 <= x <= +1 */ +ZPL_DEF zpl_f32 zpl_pow(zpl_f32 x, zpl_f32 y); /* x^y */ + +ZPL_DEF zpl_f32 zpl_round(zpl_f32 x); +ZPL_DEF zpl_f32 zpl_floor(zpl_f32 x); +ZPL_DEF zpl_f32 zpl_ceil(zpl_f32 x); + +ZPL_DEF zpl_f32 zpl_half_to_float(zpl_half value); +ZPL_DEF zpl_half zpl_float_to_half(zpl_f32 value); + +ZPL_DEF zpl_vec2 zpl_vec2f_zero(void); +ZPL_DEF zpl_vec2 zpl_vec2f(zpl_f32 x, zpl_f32 y); +ZPL_DEF zpl_vec2 zpl_vec2fv(zpl_f32 x[2]); + +ZPL_DEF zpl_vec3 zpl_vec3f_zero(void); +ZPL_DEF zpl_vec3 zpl_vec3f(zpl_f32 x, zpl_f32 y, zpl_f32 z); +ZPL_DEF zpl_vec3 zpl_vec3fv(zpl_f32 x[3]); + +ZPL_DEF zpl_vec4 zpl_vec4f_zero(void); +ZPL_DEF zpl_vec4 zpl_vec4f(zpl_f32 x, zpl_f32 y, zpl_f32 z, zpl_f32 w); +ZPL_DEF zpl_vec4 zpl_vec4fv(zpl_f32 x[4]); + +ZPL_DEF zpl_f32 zpl_vec2_max(zpl_vec2 v); +ZPL_DEF zpl_f32 zpl_vec2_side(zpl_vec2 p, zpl_vec2 q, zpl_vec2 r); +ZPL_DEF void zpl_vec2_add(zpl_vec2 *d, zpl_vec2 v0, zpl_vec2 v1); +ZPL_DEF void zpl_vec2_sub(zpl_vec2 *d, zpl_vec2 v0, zpl_vec2 v1); +ZPL_DEF void zpl_vec2_mul(zpl_vec2 *d, zpl_vec2 v, zpl_f32 s); +ZPL_DEF void zpl_vec2_div(zpl_vec2 *d, zpl_vec2 v, zpl_f32 s); + +ZPL_DEF zpl_f32 zpl_vec3_max(zpl_vec3 v); +ZPL_DEF void zpl_vec3_add(zpl_vec3 *d, zpl_vec3 v0, zpl_vec3 v1); +ZPL_DEF void zpl_vec3_sub(zpl_vec3 *d, zpl_vec3 v0, zpl_vec3 v1); +ZPL_DEF void zpl_vec3_mul(zpl_vec3 *d, zpl_vec3 v, zpl_f32 s); +ZPL_DEF void zpl_vec3_div(zpl_vec3 *d, zpl_vec3 v, zpl_f32 s); + +ZPL_DEF void zpl_vec4_add(zpl_vec4 *d, zpl_vec4 v0, zpl_vec4 v1); +ZPL_DEF void zpl_vec4_sub(zpl_vec4 *d, zpl_vec4 v0, zpl_vec4 v1); +ZPL_DEF void zpl_vec4_mul(zpl_vec4 *d, zpl_vec4 v, zpl_f32 s); +ZPL_DEF void zpl_vec4_div(zpl_vec4 *d, zpl_vec4 v, zpl_f32 s); + +ZPL_DEF void zpl_vec2_addeq(zpl_vec2 *d, zpl_vec2 v); +ZPL_DEF void zpl_vec2_subeq(zpl_vec2 *d, zpl_vec2 v); +ZPL_DEF void zpl_vec2_muleq(zpl_vec2 *d, zpl_f32 s); +ZPL_DEF void zpl_vec2_diveq(zpl_vec2 *d, zpl_f32 s); + +ZPL_DEF void zpl_vec3_addeq(zpl_vec3 *d, zpl_vec3 v); +ZPL_DEF void zpl_vec3_subeq(zpl_vec3 *d, zpl_vec3 v); +ZPL_DEF void zpl_vec3_muleq(zpl_vec3 *d, zpl_f32 s); +ZPL_DEF void zpl_vec3_diveq(zpl_vec3 *d, zpl_f32 s); + +ZPL_DEF void zpl_vec4_addeq(zpl_vec4 *d, zpl_vec4 v); +ZPL_DEF void zpl_vec4_subeq(zpl_vec4 *d, zpl_vec4 v); +ZPL_DEF void zpl_vec4_muleq(zpl_vec4 *d, zpl_f32 s); +ZPL_DEF void zpl_vec4_diveq(zpl_vec4 *d, zpl_f32 s); + +ZPL_DEF zpl_f32 zpl_vec2_dot(zpl_vec2 v0, zpl_vec2 v1); +ZPL_DEF zpl_f32 zpl_vec3_dot(zpl_vec3 v0, zpl_vec3 v1); +ZPL_DEF zpl_f32 zpl_vec4_dot(zpl_vec4 v0, zpl_vec4 v1); + +ZPL_DEF void zpl_vec2_cross(zpl_f32 *d, zpl_vec2 v0, zpl_vec2 v1); +ZPL_DEF void zpl_vec3_cross(zpl_vec3 *d, zpl_vec3 v0, zpl_vec3 v1); + +ZPL_DEF zpl_f32 zpl_vec2_mag2(zpl_vec2 v); +ZPL_DEF zpl_f32 zpl_vec3_mag2(zpl_vec3 v); +ZPL_DEF zpl_f32 zpl_vec4_mag2(zpl_vec4 v); + +ZPL_DEF zpl_f32 zpl_vec2_mag(zpl_vec2 v); +ZPL_DEF zpl_f32 zpl_vec3_mag(zpl_vec3 v); +ZPL_DEF zpl_f32 zpl_vec4_mag(zpl_vec4 v); + +ZPL_DEF void zpl_vec2_norm(zpl_vec2 *d, zpl_vec2 v); +ZPL_DEF void zpl_vec3_norm(zpl_vec3 *d, zpl_vec3 v); +ZPL_DEF void zpl_vec4_norm(zpl_vec4 *d, zpl_vec4 v); + +ZPL_DEF void zpl_vec2_norm0(zpl_vec2 *d, zpl_vec2 v); +ZPL_DEF void zpl_vec3_norm0(zpl_vec3 *d, zpl_vec3 v); +ZPL_DEF void zpl_vec4_norm0(zpl_vec4 *d, zpl_vec4 v); + +ZPL_DEF void zpl_vec2_reflect(zpl_vec2 *d, zpl_vec2 i, zpl_vec2 n); +ZPL_DEF void zpl_vec3_reflect(zpl_vec3 *d, zpl_vec3 i, zpl_vec3 n); +ZPL_DEF void zpl_vec2_refract(zpl_vec2 *d, zpl_vec2 i, zpl_vec2 n, zpl_f32 eta); +ZPL_DEF void zpl_vec3_refract(zpl_vec3 *d, zpl_vec3 i, zpl_vec3 n, zpl_f32 eta); + +ZPL_DEF zpl_f32 zpl_vec2_aspect_ratio(zpl_vec2 v); + +ZPL_DEF void zpl_mat2_identity(zpl_mat2 *m); +ZPL_DEF void zpl_float22_identity(zpl_f32 m[2][2]); + +ZPL_DEF void zpl_mat2_transpose(zpl_mat2 *m); +ZPL_DEF void zpl_mat2_mul(zpl_mat2 *out, zpl_mat2 *m1, zpl_mat2 *m2); +ZPL_DEF void zpl_mat2_mul_vec2(zpl_vec2 *out, zpl_mat2 *m, zpl_vec2 in); +ZPL_DEF void zpl_mat2_inverse(zpl_mat2 *out, zpl_mat2 *in); +ZPL_DEF zpl_f32 zpl_mat2_determinate(zpl_mat2 *m); + +ZPL_DEF zpl_mat2 *zpl_mat2_v(zpl_vec2 m[2]); +ZPL_DEF zpl_mat2 *zpl_mat2_f(zpl_f32 m[2][2]); +ZPL_DEF zpl_float2 *zpl_float22_m(zpl_mat2 *m); +ZPL_DEF zpl_float2 *zpl_float22_v(zpl_vec2 m[2]); +ZPL_DEF zpl_float2 *zpl_float22_4(zpl_f32 m[4]); + +ZPL_DEF void zpl_float22_transpose(zpl_f32 (*vec)[2]); +ZPL_DEF void zpl_float22_mul(zpl_f32 (*out)[2], zpl_f32 (*mat1)[2], zpl_f32 (*mat2)[2]); +ZPL_DEF void zpl_float22_mul_vec2(zpl_vec2 *out, zpl_f32 m[2][2], zpl_vec2 in); + +ZPL_DEF void zpl_mat3_identity(zpl_mat3 *m); +ZPL_DEF void zpl_float33_identity(zpl_f32 m[3][3]); + +ZPL_DEF void zpl_mat3_transpose(zpl_mat3 *m); +ZPL_DEF void zpl_mat3_mul(zpl_mat3 *out, zpl_mat3 *m1, zpl_mat3 *m2); +ZPL_DEF void zpl_mat3_mul_vec3(zpl_vec3 *out, zpl_mat3 *m, zpl_vec3 in); +ZPL_DEF void zpl_mat3_inverse(zpl_mat3 *out, zpl_mat3 *in); +ZPL_DEF zpl_f32 zpl_mat3_determinate(zpl_mat3 *m); + +ZPL_DEF zpl_mat3 *zpl_mat3_v(zpl_vec3 m[3]); +ZPL_DEF zpl_mat3 *zpl_mat3_f(zpl_f32 m[3][3]); + +ZPL_DEF zpl_float3 *zpl_float33_m(zpl_mat3 *m); +ZPL_DEF zpl_float3 *zpl_float33_v(zpl_vec3 m[3]); +ZPL_DEF zpl_float3 *zpl_float33_9(zpl_f32 m[9]); + +ZPL_DEF void zpl_float33_transpose(zpl_f32 (*vec)[3]); +ZPL_DEF void zpl_float33_mul(zpl_f32 (*out)[3], zpl_f32 (*mat1)[3], zpl_f32 (*mat2)[3]); +ZPL_DEF void zpl_float33_mul_vec3(zpl_vec3 *out, zpl_f32 m[3][3], zpl_vec3 in); + +ZPL_DEF void zpl_mat4_identity(zpl_mat4 *m); +ZPL_DEF void zpl_float44_identity(zpl_f32 m[4][4]); +ZPL_DEF void zpl_mat4_copy(zpl_mat4* out, zpl_mat4* m); + +ZPL_DEF void zpl_mat4_transpose(zpl_mat4 *m); +ZPL_DEF void zpl_mat4_mul(zpl_mat4 *out, zpl_mat4 *m1, zpl_mat4 *m2); +ZPL_DEF void zpl_mat4_mul_vec4(zpl_vec4 *out, zpl_mat4 *m, zpl_vec4 in); +ZPL_DEF void zpl_mat4_inverse(zpl_mat4 *out, zpl_mat4 *in); + +ZPL_DEF zpl_mat4 *zpl_mat4_v(zpl_vec4 m[4]); +ZPL_DEF zpl_mat4 *zpl_mat4_f(zpl_f32 m[4][4]); + +ZPL_DEF zpl_float4 *zpl_float44_m(zpl_mat4 *m); +ZPL_DEF zpl_float4 *zpl_float44_v(zpl_vec4 m[4]); +ZPL_DEF zpl_float4 *zpl_float44_16(zpl_f32 m[16]); + +ZPL_DEF void zpl_float44_transpose(zpl_f32 (*vec)[4]); +ZPL_DEF void zpl_float44_mul(zpl_f32 (*out)[4], zpl_f32 (*mat1)[4], zpl_f32 (*mat2)[4]); +ZPL_DEF void zpl_float44_mul_vec4(zpl_vec4 *out, zpl_f32 m[4][4], zpl_vec4 in); + +ZPL_DEF void zpl_mat4_axis_angle(zpl_mat4* out, zpl_vec3 v, zpl_f32 angle_radians); +ZPL_DEF void zpl_mat4_to_translate(zpl_mat4* out, zpl_vec3 v); +ZPL_DEF void zpl_mat4_to_rotate(zpl_mat4* out, zpl_vec3 v, zpl_f32 angle_radians); +ZPL_DEF void zpl_mat4_to_scale(zpl_mat4* out, zpl_vec3 v); +ZPL_DEF void zpl_mat4_to_scalef(zpl_mat4* out, zpl_f32 s); +ZPL_DEF void zpl_mat4_translate(zpl_mat4* out, zpl_vec3 v); +ZPL_DEF void zpl_mat4_rotate(zpl_mat4* out, zpl_vec3 v, zpl_f32 angle_radians); +ZPL_DEF void zpl_mat4_scale(zpl_mat4* out, zpl_vec3 v); +ZPL_DEF void zpl_mat4_scalef(zpl_mat4 *out, zpl_f32 s); +ZPL_DEF void zpl_mat4_ortho2d(zpl_mat4 *out, zpl_f32 left, zpl_f32 right, zpl_f32 bottom, zpl_f32 top); +ZPL_DEF void zpl_mat4_ortho3d(zpl_mat4 *out, zpl_f32 left, zpl_f32 right, zpl_f32 bottom, zpl_f32 top, zpl_f32 z_near, zpl_f32 z_far); +ZPL_DEF void zpl_mat4_perspective(zpl_mat4 *out, zpl_f32 fovy, zpl_f32 aspect, zpl_f32 z_near, zpl_f32 z_far); +ZPL_DEF void zpl_mat4_infinite_perspective(zpl_mat4 *out, zpl_f32 fovy, zpl_f32 aspect, zpl_f32 z_near); + +ZPL_DEF void zpl_mat4_ortho2d_dx(zpl_mat4 *out, zpl_f32 left, zpl_f32 right, zpl_f32 bottom, zpl_f32 top); +ZPL_DEF void zpl_mat4_ortho3d_dx(zpl_mat4 *out, zpl_f32 left, zpl_f32 right, zpl_f32 bottom, zpl_f32 top, zpl_f32 z_near, zpl_f32 z_far); +ZPL_DEF void zpl_mat4_perspective_dx(zpl_mat4 *out, zpl_f32 fovy, zpl_f32 aspect, zpl_f32 z_near, zpl_f32 z_far); +ZPL_DEF void zpl_mat4_infinite_perspective_dx(zpl_mat4 *out, zpl_f32 fovy, zpl_f32 aspect, zpl_f32 z_near); + +ZPL_DEF void zpl_mat4_look_at(zpl_mat4 *out, zpl_vec3 eye, zpl_vec3 centre, zpl_vec3 up); + +ZPL_DEF void zpl_mat4_look_at_lh(zpl_mat4 *out, zpl_vec3 eye, zpl_vec3 centre, zpl_vec3 up); + +ZPL_DEF zpl_quat zpl_quatf(zpl_f32 x, zpl_f32 y, zpl_f32 z, zpl_f32 w); +ZPL_DEF zpl_quat zpl_quatfv(zpl_f32 e[4]); +ZPL_DEF zpl_quat zpl_quat_axis_angle(zpl_vec3 axis, zpl_f32 angle_radians); +ZPL_DEF zpl_quat zpl_quat_euler_angles(zpl_f32 pitch, zpl_f32 yaw, zpl_f32 roll); +ZPL_DEF zpl_quat zpl_quat_identity(void); + +ZPL_DEF void zpl_quat_add(zpl_quat *d, zpl_quat q0, zpl_quat q1); +ZPL_DEF void zpl_quat_sub(zpl_quat *d, zpl_quat q0, zpl_quat q1); +ZPL_DEF void zpl_quat_mul(zpl_quat *d, zpl_quat q0, zpl_quat q1); +ZPL_DEF void zpl_quat_div(zpl_quat *d, zpl_quat q0, zpl_quat q1); + +ZPL_DEF void zpl_quat_mulf(zpl_quat *d, zpl_quat q, zpl_f32 s); +ZPL_DEF void zpl_quat_divf(zpl_quat *d, zpl_quat q, zpl_f32 s); + +ZPL_DEF void zpl_quat_addeq(zpl_quat *d, zpl_quat q); +ZPL_DEF void zpl_quat_subeq(zpl_quat *d, zpl_quat q); +ZPL_DEF void zpl_quat_muleq(zpl_quat *d, zpl_quat q); +ZPL_DEF void zpl_quat_diveq(zpl_quat *d, zpl_quat q); + +ZPL_DEF void zpl_quat_muleqf(zpl_quat *d, zpl_f32 s); +ZPL_DEF void zpl_quat_diveqf(zpl_quat *d, zpl_f32 s); + +ZPL_DEF zpl_f32 zpl_quat_dot(zpl_quat q0, zpl_quat q1); +ZPL_DEF zpl_f32 zpl_quat_mag(zpl_quat q); + +ZPL_DEF void zpl_quat_norm(zpl_quat *d, zpl_quat q); +ZPL_DEF void zpl_quat_conj(zpl_quat *d, zpl_quat q); +ZPL_DEF void zpl_quat_inverse(zpl_quat *d, zpl_quat q); + +ZPL_DEF void zpl_quat_axis(zpl_vec3 *axis, zpl_quat q); +ZPL_DEF zpl_f32 zpl_quat_angle(zpl_quat q); + +ZPL_DEF zpl_f32 zpl_quat_pitch(zpl_quat q); +ZPL_DEF zpl_f32 zpl_quat_yaw(zpl_quat q); +ZPL_DEF zpl_f32 zpl_quat_roll(zpl_quat q); + +/* NOTE: Rotate v by q */ +ZPL_DEF void zpl_quat_rotate_vec3(zpl_vec3 *d, zpl_quat q, zpl_vec3 v); +ZPL_DEF void zpl_mat4_from_quat(zpl_mat4 *out, zpl_quat q); +ZPL_DEF void zpl_quat_from_mat4(zpl_quat *out, zpl_mat4 *m); + +/* Plane math. */ +ZPL_DEF zpl_f32 zpl_plane_distance(zpl_plane* p, zpl_vec3 v); + +/* Frustum culling. */ +ZPL_DEF void zpl_frustum_create(zpl_frustum* out, zpl_mat4* camera, zpl_mat4* proj); +ZPL_DEF zpl_b8 zpl_frustum_sphere_inside(zpl_frustum* frustum, zpl_vec3 center, zpl_f32 radius); +ZPL_DEF zpl_b8 zpl_frustum_point_inside(zpl_frustum* frustum, zpl_vec3 point); +ZPL_DEF zpl_b8 zpl_frustum_box_inside(zpl_frustum* frustum, zpl_aabb3 box); + +/* Interpolations */ +ZPL_DEF zpl_f32 zpl_lerp(zpl_f32 a, zpl_f32 b, zpl_f32 t); +ZPL_DEF zpl_f32 zpl_unlerp(zpl_f32 t, zpl_f32 a, zpl_f32 b); +ZPL_DEF zpl_f32 zpl_smooth_step(zpl_f32 a, zpl_f32 b, zpl_f32 t); +ZPL_DEF zpl_f32 zpl_smoother_step(zpl_f32 a, zpl_f32 b, zpl_f32 t); + +ZPL_DEF void zpl_vec2_lerp(zpl_vec2 *d, zpl_vec2 a, zpl_vec2 b, zpl_f32 t); +ZPL_DEF void zpl_vec3_lerp(zpl_vec3 *d, zpl_vec3 a, zpl_vec3 b, zpl_f32 t); +ZPL_DEF void zpl_vec4_lerp(zpl_vec4 *d, zpl_vec4 a, zpl_vec4 b, zpl_f32 t); + +ZPL_DEF void zpl_vec2_cslerp(zpl_vec2 *d, zpl_vec2 a, zpl_vec2 v0, zpl_vec2 b, zpl_vec2 v1, zpl_f32 t); +ZPL_DEF void zpl_vec3_cslerp(zpl_vec3 *d, zpl_vec3 a, zpl_vec3 v0, zpl_vec3 b, zpl_vec3 v1, zpl_f32 t); +ZPL_DEF void zpl_vec2_dcslerp(zpl_vec2 *d, zpl_vec2 a, zpl_vec2 v0, zpl_vec2 b, zpl_vec2 v1, zpl_f32 t); +ZPL_DEF void zpl_vec3_dcslerp(zpl_vec3 *d, zpl_vec3 a, zpl_vec3 v0, zpl_vec3 b, zpl_vec3 v1, zpl_f32 t); + +ZPL_DEF void zpl_quat_lerp(zpl_quat *d, zpl_quat a, zpl_quat b, zpl_f32 t); +ZPL_DEF void zpl_quat_nlerp(zpl_quat *d, zpl_quat a, zpl_quat b, zpl_f32 t); +ZPL_DEF void zpl_quat_slerp(zpl_quat *d, zpl_quat a, zpl_quat b, zpl_f32 t); +ZPL_DEF void zpl_quat_nquad(zpl_quat *d, zpl_quat p, zpl_quat a, zpl_quat b, zpl_quat q, zpl_f32 t); +ZPL_DEF void zpl_quat_squad(zpl_quat *d, zpl_quat p, zpl_quat a, zpl_quat b, zpl_quat q, zpl_f32 t); +ZPL_DEF void zpl_quat_slerp_approx(zpl_quat *d, zpl_quat a, zpl_quat b, zpl_f32 t); +ZPL_DEF void zpl_quat_squad_approx(zpl_quat *d, zpl_quat p, zpl_quat a, zpl_quat b, zpl_quat q, zpl_f32 t); + +/* rects */ +ZPL_DEF zpl_rect2 zpl_rect2f(zpl_vec2 pos, zpl_vec2 dim); +ZPL_DEF zpl_rect3 zpl_rect3f(zpl_vec3 pos, zpl_vec3 dim); - ZPL_DEF zpl_aabb2 zpl_aabb2f(zpl_f32 minx, zpl_f32 miny, zpl_f32 maxx, zpl_f32 maxy); - ZPL_DEF zpl_aabb3 zpl_aabb3f(zpl_f32 minx, zpl_f32 miny, zpl_f32 minz, zpl_f32 maxx, zpl_f32 maxy, zpl_f32 maxz); +ZPL_DEF zpl_aabb2 zpl_aabb2f(zpl_f32 minx, zpl_f32 miny, zpl_f32 maxx, zpl_f32 maxy); +ZPL_DEF zpl_aabb3 zpl_aabb3f(zpl_f32 minx, zpl_f32 miny, zpl_f32 minz, zpl_f32 maxx, zpl_f32 maxy, zpl_f32 maxz); - ZPL_DEF zpl_aabb2 zpl_aabb2_rect2(zpl_rect2 a); - ZPL_DEF zpl_aabb3 zpl_aabb3_rect3(zpl_rect3 a); - ZPL_DEF zpl_rect2 zpl_rect2_aabb2(zpl_aabb2 a); - ZPL_DEF zpl_rect3 zpl_rect3_aabb3(zpl_aabb3 a); +ZPL_DEF zpl_aabb2 zpl_aabb2_rect2(zpl_rect2 a); +ZPL_DEF zpl_aabb3 zpl_aabb3_rect3(zpl_rect3 a); +ZPL_DEF zpl_rect2 zpl_rect2_aabb2(zpl_aabb2 a); +ZPL_DEF zpl_rect3 zpl_rect3_aabb3(zpl_aabb3 a); - ZPL_DEF int zpl_rect2_contains(zpl_rect2 a, zpl_f32 x, zpl_f32 y); - ZPL_DEF int zpl_rect2_contains_vec2(zpl_rect2 a, zpl_vec2 p); - ZPL_DEF int zpl_rect2_intersects(zpl_rect2 a, zpl_rect2 b); - ZPL_DEF int zpl_rect2_intersection_result(zpl_rect2 a, zpl_rect2 b, zpl_rect2 *intersection); - ZPL_DEF int zpl_aabb2_contains(zpl_aabb2 a, zpl_f32 x, zpl_f32 y); - ZPL_DEF int zpl_aabb3_contains(zpl_aabb3 a, zpl_f32 x, zpl_f32 y, zpl_f32 z); +ZPL_DEF int zpl_rect2_contains(zpl_rect2 a, zpl_f32 x, zpl_f32 y); +ZPL_DEF int zpl_rect2_contains_vec2(zpl_rect2 a, zpl_vec2 p); +ZPL_DEF int zpl_rect2_intersects(zpl_rect2 a, zpl_rect2 b); +ZPL_DEF int zpl_rect2_intersection_result(zpl_rect2 a, zpl_rect2 b, zpl_rect2 *intersection); +ZPL_DEF int zpl_aabb2_contains(zpl_aabb2 a, zpl_f32 x, zpl_f32 y); +ZPL_DEF int zpl_aabb3_contains(zpl_aabb3 a, zpl_f32 x, zpl_f32 y, zpl_f32 z); - /* rectangle partitioning: based on https://halt.software/dead-simple-layouts/ */ - ZPL_DEF zpl_aabb2 zpl_aabb2_cut_left(zpl_aabb2 *a, zpl_f32 b); - ZPL_DEF zpl_aabb2 zpl_aabb2_cut_right(zpl_aabb2 *a, zpl_f32 b); - ZPL_DEF zpl_aabb2 zpl_aabb2_cut_top(zpl_aabb2 *a, zpl_f32 b); - ZPL_DEF zpl_aabb2 zpl_aabb2_cut_bottom(zpl_aabb2 *a, zpl_f32 b); +/* rectangle partitioning: based on https://halt.software/dead-simple-layouts/ */ +ZPL_DEF zpl_aabb2 zpl_aabb2_cut_left(zpl_aabb2 *a, zpl_f32 b); +ZPL_DEF zpl_aabb2 zpl_aabb2_cut_right(zpl_aabb2 *a, zpl_f32 b); +ZPL_DEF zpl_aabb2 zpl_aabb2_cut_top(zpl_aabb2 *a, zpl_f32 b); +ZPL_DEF zpl_aabb2 zpl_aabb2_cut_bottom(zpl_aabb2 *a, zpl_f32 b); - ZPL_DEF zpl_aabb2 zpl_aabb2_get_left(const zpl_aabb2 *a, zpl_f32 b); - ZPL_DEF zpl_aabb2 zpl_aabb2_get_right(const zpl_aabb2 *a, zpl_f32 b); - ZPL_DEF zpl_aabb2 zpl_aabb2_get_top(const zpl_aabb2 *a, zpl_f32 b); - ZPL_DEF zpl_aabb2 zpl_aabb2_get_bottom(const zpl_aabb2 *a, zpl_f32 b); - - ZPL_DEF zpl_aabb2 zpl_aabb2_add_left(const zpl_aabb2 *a, zpl_f32 b); - ZPL_DEF zpl_aabb2 zpl_aabb2_add_right(const zpl_aabb2 *a, zpl_f32 b); - ZPL_DEF zpl_aabb2 zpl_aabb2_add_top(const zpl_aabb2 *a, zpl_f32 b); - ZPL_DEF zpl_aabb2 zpl_aabb2_add_bottom(const zpl_aabb2 *a, zpl_f32 b); - - ZPL_DEF zpl_aabb2 zpl_aabb2_contract(const zpl_aabb2 *a, zpl_f32 b); - ZPL_DEF zpl_aabb2 zpl_aabb2_expand(const zpl_aabb2 *a, zpl_f32 b); - - //! @} - ZPL_END_C_DECLS - #if defined(__cplusplus) - ZPL_INLINE bool operator==(zpl_vec2 a, zpl_vec2 b) { return (a.x == b.x) && (a.y == b.y); } - ZPL_INLINE bool operator!=(zpl_vec2 a, zpl_vec2 b) { return !operator==(a, b); } - - ZPL_INLINE zpl_vec2 operator+(zpl_vec2 a) { return a; } - ZPL_INLINE zpl_vec2 operator-(zpl_vec2 a) { zpl_vec2 r = {-a.x, -a.y}; return r; } - - ZPL_INLINE zpl_vec2 operator+(zpl_vec2 a, zpl_vec2 b) { zpl_vec2 r; zpl_vec2_add(&r, a, b); return r; } - ZPL_INLINE zpl_vec2 operator-(zpl_vec2 a, zpl_vec2 b) { zpl_vec2 r; zpl_vec2_sub(&r, a, b); return r; } - - ZPL_INLINE zpl_vec2 operator*(zpl_vec2 a, float scalar) { zpl_vec2 r; zpl_vec2_mul(&r, a, scalar); return r; } - ZPL_INLINE zpl_vec2 operator*(float scalar, zpl_vec2 a) { return operator*(a, scalar); } - - ZPL_INLINE zpl_vec2 operator/(zpl_vec2 a, float scalar) { return operator*(a, 1.0f/scalar); } - - /* Hadamard Product */ - ZPL_INLINE zpl_vec2 operator*(zpl_vec2 a, zpl_vec2 b) { zpl_vec2 r = {a.x*b.x, a.y*b.y}; return r; } - ZPL_INLINE zpl_vec2 operator/(zpl_vec2 a, zpl_vec2 b) { zpl_vec2 r = {a.x/b.x, a.y/b.y}; return r; } - - ZPL_INLINE zpl_vec2 &operator+=(zpl_vec2 &a, zpl_vec2 b) { return (a = a + b); } - ZPL_INLINE zpl_vec2 &operator-=(zpl_vec2 &a, zpl_vec2 b) { return (a = a - b); } - ZPL_INLINE zpl_vec2 &operator*=(zpl_vec2 &a, float scalar) { return (a = a * scalar); } - ZPL_INLINE zpl_vec2 &operator/=(zpl_vec2 &a, float scalar) { return (a = a / scalar); } - - - ZPL_INLINE bool operator==(zpl_vec3 a, zpl_vec3 b) { return (a.x == b.x) && (a.y == b.y) && (a.z == b.z); } - ZPL_INLINE bool operator!=(zpl_vec3 a, zpl_vec3 b) { return !operator==(a, b); } - - ZPL_INLINE zpl_vec3 operator+(zpl_vec3 a) { return a; } - ZPL_INLINE zpl_vec3 operator-(zpl_vec3 a) { zpl_vec3 r = {-a.x, -a.y, -a.z}; return r; } - - ZPL_INLINE zpl_vec3 operator+(zpl_vec3 a, zpl_vec3 b) { zpl_vec3 r; zpl_vec3_add(&r, a, b); return r; } - ZPL_INLINE zpl_vec3 operator-(zpl_vec3 a, zpl_vec3 b) { zpl_vec3 r; zpl_vec3_sub(&r, a, b); return r; } - - ZPL_INLINE zpl_vec3 operator*(zpl_vec3 a, float scalar) { zpl_vec3 r; zpl_vec3_mul(&r, a, scalar); return r; } - ZPL_INLINE zpl_vec3 operator*(float scalar, zpl_vec3 a) { return operator*(a, scalar); } - - ZPL_INLINE zpl_vec3 operator/(zpl_vec3 a, float scalar) { return operator*(a, 1.0f/scalar); } - - /* Hadamard Product */ - ZPL_INLINE zpl_vec3 operator*(zpl_vec3 a, zpl_vec3 b) { zpl_vec3 r = {a.x*b.x, a.y*b.y, a.z*b.z}; return r; } - ZPL_INLINE zpl_vec3 operator/(zpl_vec3 a, zpl_vec3 b) { zpl_vec3 r = {a.x/b.x, a.y/b.y, a.z/b.z}; return r; } - - ZPL_INLINE zpl_vec3 &operator+=(zpl_vec3 &a, zpl_vec3 b) { return (a = a + b); } - ZPL_INLINE zpl_vec3 &operator-=(zpl_vec3 &a, zpl_vec3 b) { return (a = a - b); } - ZPL_INLINE zpl_vec3 &operator*=(zpl_vec3 &a, float scalar) { return (a = a * scalar); } - ZPL_INLINE zpl_vec3 &operator/=(zpl_vec3 &a, float scalar) { return (a = a / scalar); } - - - ZPL_INLINE bool operator==(zpl_vec4 a, zpl_vec4 b) { return (a.x == b.x) && (a.y == b.y) && (a.z == b.z) && (a.w == b.w); } - ZPL_INLINE bool operator!=(zpl_vec4 a, zpl_vec4 b) { return !operator==(a, b); } - - ZPL_INLINE zpl_vec4 operator+(zpl_vec4 a) { return a; } - ZPL_INLINE zpl_vec4 operator-(zpl_vec4 a) { zpl_vec4 r = {-a.x, -a.y, -a.z, -a.w}; return r; } - - ZPL_INLINE zpl_vec4 operator+(zpl_vec4 a, zpl_vec4 b) { zpl_vec4 r; zpl_vec4_add(&r, a, b); return r; } - ZPL_INLINE zpl_vec4 operator-(zpl_vec4 a, zpl_vec4 b) { zpl_vec4 r; zpl_vec4_sub(&r, a, b); return r; } - - ZPL_INLINE zpl_vec4 operator*(zpl_vec4 a, float scalar) { zpl_vec4 r; zpl_vec4_mul(&r, a, scalar); return r; } - ZPL_INLINE zpl_vec4 operator*(float scalar, zpl_vec4 a) { return operator*(a, scalar); } - - ZPL_INLINE zpl_vec4 operator/(zpl_vec4 a, float scalar) { return operator*(a, 1.0f/scalar); } - - /* Hadamard Product */ - ZPL_INLINE zpl_vec4 operator*(zpl_vec4 a, zpl_vec4 b) { zpl_vec4 r = {a.x*b.x, a.y*b.y, a.z*b.z, a.w*b.w}; return r; } - ZPL_INLINE zpl_vec4 operator/(zpl_vec4 a, zpl_vec4 b) { zpl_vec4 r = {a.x/b.x, a.y/b.y, a.z/b.z, a.w/b.w}; return r; } - - ZPL_INLINE zpl_vec4 &operator+=(zpl_vec4 &a, zpl_vec4 b) { return (a = a + b); } - ZPL_INLINE zpl_vec4 &operator-=(zpl_vec4 &a, zpl_vec4 b) { return (a = a - b); } - ZPL_INLINE zpl_vec4 &operator*=(zpl_vec4 &a, float scalar) { return (a = a * scalar); } - ZPL_INLINE zpl_vec4 &operator/=(zpl_vec4 &a, float scalar) { return (a = a / scalar); } - - - ZPL_INLINE zpl_mat2 operator+(zpl_mat2 const &a, zpl_mat2 const &b) { - int i, j; - zpl_mat2 r = {0}; - for (j = 0; j < 2; j++) { - for (i = 0; i < 2; i++) - r.e[2*j+i] = a.e[2*j+i] + b.e[2*j+i]; - } - return r; - } - - ZPL_INLINE zpl_mat2 operator-(zpl_mat2 const &a, zpl_mat2 const &b) { - int i, j; - zpl_mat2 r = {0}; - for (j = 0; j < 2; j++) { - for (i = 0; i < 2; i++) - r.e[2*j+i] = a.e[2*j+i] - b.e[2*j+i]; - } - return r; - } - - ZPL_INLINE zpl_mat2 operator*(zpl_mat2 const &a, zpl_mat2 const &b) { zpl_mat2 r; zpl_mat2_mul(&r, (zpl_mat2 *)&a, (zpl_mat2 *)&b); return r; } - ZPL_INLINE zpl_vec2 operator*(zpl_mat2 const &a, zpl_vec2 v) { zpl_vec2 r; zpl_mat2_mul_vec2(&r, (zpl_mat2 *)&a, v); return r; } - ZPL_INLINE zpl_mat2 operator*(zpl_mat2 const &a, float scalar) { - zpl_mat2 r = {0}; - int i; - for (i = 0; i < 2*2; i++) r.e[i] = a.e[i] * scalar; - return r; - } - ZPL_INLINE zpl_mat2 operator*(float scalar, zpl_mat2 const &a) { return operator*(a, scalar); } - ZPL_INLINE zpl_mat2 operator/(zpl_mat2 const &a, float scalar) { return operator*(a, 1.0f/scalar); } - - ZPL_INLINE zpl_mat2& operator+=(zpl_mat2& a, zpl_mat2 const &b) { return (a = a + b); } - ZPL_INLINE zpl_mat2& operator-=(zpl_mat2& a, zpl_mat2 const &b) { return (a = a - b); } - ZPL_INLINE zpl_mat2& operator*=(zpl_mat2& a, zpl_mat2 const &b) { return (a = a * b); } - - - - ZPL_INLINE zpl_mat3 operator+(zpl_mat3 const &a, zpl_mat3 const &b) { - int i, j; - zpl_mat3 r = {0}; - for (j = 0; j < 3; j++) { - for (i = 0; i < 3; i++) - r.e[3*j+i] = a.e[3*j+i] + b.e[3*j+i]; - } - return r; - } - - ZPL_INLINE zpl_mat3 operator-(zpl_mat3 const &a, zpl_mat3 const &b) { - int i, j; - zpl_mat3 r = {0}; - for (j = 0; j < 3; j++) { - for (i = 0; i < 3; i++) - r.e[3*j+i] = a.e[3*j+i] - b.e[3*j+i]; - } - return r; - } - - ZPL_INLINE zpl_mat3 operator*(zpl_mat3 const &a, zpl_mat3 const &b) { zpl_mat3 r; zpl_mat3_mul(&r, (zpl_mat3 *)&a, (zpl_mat3 *)&b); return r; } - ZPL_INLINE zpl_vec3 operator*(zpl_mat3 const &a, zpl_vec3 v) { zpl_vec3 r; zpl_mat3_mul_vec3(&r, (zpl_mat3 *)&a, v); return r; } - ZPL_INLINE zpl_mat3 operator*(zpl_mat3 const &a, float scalar) { - zpl_mat3 r = {0}; - int i; - for (i = 0; i < 3*3; i++) r.e[i] = a.e[i] * scalar; - return r; - } - ZPL_INLINE zpl_mat3 operator*(float scalar, zpl_mat3 const &a) { return operator*(a, scalar); } - ZPL_INLINE zpl_mat3 operator/(zpl_mat3 const &a, float scalar) { return operator*(a, 1.0f/scalar); } - - ZPL_INLINE zpl_mat3& operator+=(zpl_mat3& a, zpl_mat3 const &b) { return (a = a + b); } - ZPL_INLINE zpl_mat3& operator-=(zpl_mat3& a, zpl_mat3 const &b) { return (a = a - b); } - ZPL_INLINE zpl_mat3& operator*=(zpl_mat3& a, zpl_mat3 const &b) { return (a = a * b); } - - - - ZPL_INLINE zpl_mat4 operator+(zpl_mat4 const &a, zpl_mat4 const &b) { - int i, j; - zpl_mat4 r = {0}; - for (j = 0; j < 4; j++) { - for (i = 0; i < 4; i++) - r.e[4*j+i] = a.e[4*j+i] + b.e[4*j+i]; - } - return r; - } - - ZPL_INLINE zpl_mat4 operator-(zpl_mat4 const &a, zpl_mat4 const &b) { - int i, j; - zpl_mat4 r = {0}; - for (j = 0; j < 4; j++) { - for (i = 0; i < 4; i++) - r.e[4*j+i] = a.e[4*j+i] - b.e[4*j+i]; - } - return r; - } - - ZPL_INLINE zpl_mat4 operator*(zpl_mat4 const &a, zpl_mat4 const &b) { zpl_mat4 r; zpl_mat4_mul(&r, (zpl_mat4 *)&a, (zpl_mat4 *)&b); return r; } - ZPL_INLINE zpl_vec4 operator*(zpl_mat4 const &a, zpl_vec4 v) { zpl_vec4 r; zpl_mat4_mul_vec4(&r, (zpl_mat4 *)&a, v); return r; } - ZPL_INLINE zpl_mat4 operator*(zpl_mat4 const &a, float scalar) { - zpl_mat4 r = {0}; - int i; - for (i = 0; i < 4*4; i++) r.e[i] = a.e[i] * scalar; - return r; - } - ZPL_INLINE zpl_mat4 operator*(float scalar, zpl_mat4 const &a) { return operator*(a, scalar); } - ZPL_INLINE zpl_mat4 operator/(zpl_mat4 const &a, float scalar) { return operator*(a, 1.0f/scalar); } - - ZPL_INLINE zpl_mat4& operator+=(zpl_mat4 &a, zpl_mat4 const &b) { return (a = a + b); } - ZPL_INLINE zpl_mat4& operator-=(zpl_mat4 &a, zpl_mat4 const &b) { return (a = a - b); } - ZPL_INLINE zpl_mat4& operator*=(zpl_mat4 &a, zpl_mat4 const &b) { return (a = a * b); } - - - - ZPL_INLINE bool operator==(zpl_quat a, zpl_quat b) { return a.xyzw == b.xyzw; } - ZPL_INLINE bool operator!=(zpl_quat a, zpl_quat b) { return !operator==(a, b); } - - ZPL_INLINE zpl_quat operator+(zpl_quat q) { return q; } - ZPL_INLINE zpl_quat operator-(zpl_quat q) { return zpl_quatf(-q.x, -q.y, -q.z, -q.w); } - - ZPL_INLINE zpl_quat operator+(zpl_quat a, zpl_quat b) { zpl_quat r; zpl_quat_add(&r, a, b); return r; } - ZPL_INLINE zpl_quat operator-(zpl_quat a, zpl_quat b) { zpl_quat r; zpl_quat_sub(&r, a, b); return r; } - - ZPL_INLINE zpl_quat operator*(zpl_quat a, zpl_quat b) { zpl_quat r; zpl_quat_mul(&r, a, b); return r; } - ZPL_INLINE zpl_quat operator*(zpl_quat q, float s) { zpl_quat r; zpl_quat_mulf(&r, q, s); return r; } - ZPL_INLINE zpl_quat operator*(float s, zpl_quat q) { return operator*(q, s); } - ZPL_INLINE zpl_quat operator/(zpl_quat q, float s) { zpl_quat r; zpl_quat_divf(&r, q, s); return r; } - - ZPL_INLINE zpl_quat &operator+=(zpl_quat &a, zpl_quat b) { zpl_quat_addeq(&a, b); return a; } - ZPL_INLINE zpl_quat &operator-=(zpl_quat &a, zpl_quat b) { zpl_quat_subeq(&a, b); return a; } - ZPL_INLINE zpl_quat &operator*=(zpl_quat &a, zpl_quat b) { zpl_quat_muleq(&a, b); return a; } - ZPL_INLINE zpl_quat &operator/=(zpl_quat &a, zpl_quat b) { zpl_quat_diveq(&a, b); return a; } - - ZPL_INLINE zpl_quat &operator*=(zpl_quat &a, float b) { zpl_quat_muleqf(&a, b); return a; } - ZPL_INLINE zpl_quat &operator/=(zpl_quat &a, float b) { zpl_quat_diveqf(&a, b); return a; } - - /* Rotate v by a */ - ZPL_INLINE zpl_vec3 operator*(zpl_quat q, zpl_vec3 v) { zpl_vec3 r; zpl_quat_rotate_vec3(&r, q, v); return r; } - #endif +ZPL_DEF zpl_aabb2 zpl_aabb2_get_left(const zpl_aabb2 *a, zpl_f32 b); +ZPL_DEF zpl_aabb2 zpl_aabb2_get_right(const zpl_aabb2 *a, zpl_f32 b); +ZPL_DEF zpl_aabb2 zpl_aabb2_get_top(const zpl_aabb2 *a, zpl_f32 b); +ZPL_DEF zpl_aabb2 zpl_aabb2_get_bottom(const zpl_aabb2 *a, zpl_f32 b); + +ZPL_DEF zpl_aabb2 zpl_aabb2_add_left(const zpl_aabb2 *a, zpl_f32 b); +ZPL_DEF zpl_aabb2 zpl_aabb2_add_right(const zpl_aabb2 *a, zpl_f32 b); +ZPL_DEF zpl_aabb2 zpl_aabb2_add_top(const zpl_aabb2 *a, zpl_f32 b); +ZPL_DEF zpl_aabb2 zpl_aabb2_add_bottom(const zpl_aabb2 *a, zpl_f32 b); + +ZPL_DEF zpl_aabb2 zpl_aabb2_contract(const zpl_aabb2 *a, zpl_f32 b); +ZPL_DEF zpl_aabb2 zpl_aabb2_expand(const zpl_aabb2 *a, zpl_f32 b); + +//! @} +ZPL_END_C_DECLS +#if defined(__cplusplus) +ZPL_INLINE bool operator==(zpl_vec2 a, zpl_vec2 b) { return (a.x == b.x) && (a.y == b.y); } +ZPL_INLINE bool operator!=(zpl_vec2 a, zpl_vec2 b) { return !operator==(a, b); } + +ZPL_INLINE zpl_vec2 operator+(zpl_vec2 a) { return a; } +ZPL_INLINE zpl_vec2 operator-(zpl_vec2 a) { zpl_vec2 r = {-a.x, -a.y}; return r; } + +ZPL_INLINE zpl_vec2 operator+(zpl_vec2 a, zpl_vec2 b) { zpl_vec2 r; zpl_vec2_add(&r, a, b); return r; } +ZPL_INLINE zpl_vec2 operator-(zpl_vec2 a, zpl_vec2 b) { zpl_vec2 r; zpl_vec2_sub(&r, a, b); return r; } + +ZPL_INLINE zpl_vec2 operator*(zpl_vec2 a, float scalar) { zpl_vec2 r; zpl_vec2_mul(&r, a, scalar); return r; } +ZPL_INLINE zpl_vec2 operator*(float scalar, zpl_vec2 a) { return operator*(a, scalar); } + +ZPL_INLINE zpl_vec2 operator/(zpl_vec2 a, float scalar) { return operator*(a, 1.0f/scalar); } + +/* Hadamard Product */ +ZPL_INLINE zpl_vec2 operator*(zpl_vec2 a, zpl_vec2 b) { zpl_vec2 r = {a.x*b.x, a.y*b.y}; return r; } +ZPL_INLINE zpl_vec2 operator/(zpl_vec2 a, zpl_vec2 b) { zpl_vec2 r = {a.x/b.x, a.y/b.y}; return r; } + +ZPL_INLINE zpl_vec2 &operator+=(zpl_vec2 &a, zpl_vec2 b) { return (a = a + b); } +ZPL_INLINE zpl_vec2 &operator-=(zpl_vec2 &a, zpl_vec2 b) { return (a = a - b); } +ZPL_INLINE zpl_vec2 &operator*=(zpl_vec2 &a, float scalar) { return (a = a * scalar); } +ZPL_INLINE zpl_vec2 &operator/=(zpl_vec2 &a, float scalar) { return (a = a / scalar); } + + +ZPL_INLINE bool operator==(zpl_vec3 a, zpl_vec3 b) { return (a.x == b.x) && (a.y == b.y) && (a.z == b.z); } +ZPL_INLINE bool operator!=(zpl_vec3 a, zpl_vec3 b) { return !operator==(a, b); } + +ZPL_INLINE zpl_vec3 operator+(zpl_vec3 a) { return a; } +ZPL_INLINE zpl_vec3 operator-(zpl_vec3 a) { zpl_vec3 r = {-a.x, -a.y, -a.z}; return r; } + +ZPL_INLINE zpl_vec3 operator+(zpl_vec3 a, zpl_vec3 b) { zpl_vec3 r; zpl_vec3_add(&r, a, b); return r; } +ZPL_INLINE zpl_vec3 operator-(zpl_vec3 a, zpl_vec3 b) { zpl_vec3 r; zpl_vec3_sub(&r, a, b); return r; } + +ZPL_INLINE zpl_vec3 operator*(zpl_vec3 a, float scalar) { zpl_vec3 r; zpl_vec3_mul(&r, a, scalar); return r; } +ZPL_INLINE zpl_vec3 operator*(float scalar, zpl_vec3 a) { return operator*(a, scalar); } + +ZPL_INLINE zpl_vec3 operator/(zpl_vec3 a, float scalar) { return operator*(a, 1.0f/scalar); } + +/* Hadamard Product */ +ZPL_INLINE zpl_vec3 operator*(zpl_vec3 a, zpl_vec3 b) { zpl_vec3 r = {a.x*b.x, a.y*b.y, a.z*b.z}; return r; } +ZPL_INLINE zpl_vec3 operator/(zpl_vec3 a, zpl_vec3 b) { zpl_vec3 r = {a.x/b.x, a.y/b.y, a.z/b.z}; return r; } + +ZPL_INLINE zpl_vec3 &operator+=(zpl_vec3 &a, zpl_vec3 b) { return (a = a + b); } +ZPL_INLINE zpl_vec3 &operator-=(zpl_vec3 &a, zpl_vec3 b) { return (a = a - b); } +ZPL_INLINE zpl_vec3 &operator*=(zpl_vec3 &a, float scalar) { return (a = a * scalar); } +ZPL_INLINE zpl_vec3 &operator/=(zpl_vec3 &a, float scalar) { return (a = a / scalar); } + + +ZPL_INLINE bool operator==(zpl_vec4 a, zpl_vec4 b) { return (a.x == b.x) && (a.y == b.y) && (a.z == b.z) && (a.w == b.w); } +ZPL_INLINE bool operator!=(zpl_vec4 a, zpl_vec4 b) { return !operator==(a, b); } + +ZPL_INLINE zpl_vec4 operator+(zpl_vec4 a) { return a; } +ZPL_INLINE zpl_vec4 operator-(zpl_vec4 a) { zpl_vec4 r = {-a.x, -a.y, -a.z, -a.w}; return r; } + +ZPL_INLINE zpl_vec4 operator+(zpl_vec4 a, zpl_vec4 b) { zpl_vec4 r; zpl_vec4_add(&r, a, b); return r; } +ZPL_INLINE zpl_vec4 operator-(zpl_vec4 a, zpl_vec4 b) { zpl_vec4 r; zpl_vec4_sub(&r, a, b); return r; } + +ZPL_INLINE zpl_vec4 operator*(zpl_vec4 a, float scalar) { zpl_vec4 r; zpl_vec4_mul(&r, a, scalar); return r; } +ZPL_INLINE zpl_vec4 operator*(float scalar, zpl_vec4 a) { return operator*(a, scalar); } + +ZPL_INLINE zpl_vec4 operator/(zpl_vec4 a, float scalar) { return operator*(a, 1.0f/scalar); } + +/* Hadamard Product */ +ZPL_INLINE zpl_vec4 operator*(zpl_vec4 a, zpl_vec4 b) { zpl_vec4 r = {a.x*b.x, a.y*b.y, a.z*b.z, a.w*b.w}; return r; } +ZPL_INLINE zpl_vec4 operator/(zpl_vec4 a, zpl_vec4 b) { zpl_vec4 r = {a.x/b.x, a.y/b.y, a.z/b.z, a.w/b.w}; return r; } + +ZPL_INLINE zpl_vec4 &operator+=(zpl_vec4 &a, zpl_vec4 b) { return (a = a + b); } +ZPL_INLINE zpl_vec4 &operator-=(zpl_vec4 &a, zpl_vec4 b) { return (a = a - b); } +ZPL_INLINE zpl_vec4 &operator*=(zpl_vec4 &a, float scalar) { return (a = a * scalar); } +ZPL_INLINE zpl_vec4 &operator/=(zpl_vec4 &a, float scalar) { return (a = a / scalar); } + + +ZPL_INLINE zpl_mat2 operator+(zpl_mat2 const &a, zpl_mat2 const &b) { + int i, j; + zpl_mat2 r = {0}; + for (j = 0; j < 2; j++) { + for (i = 0; i < 2; i++) + r.e[2*j+i] = a.e[2*j+i] + b.e[2*j+i]; + } + return r; +} + +ZPL_INLINE zpl_mat2 operator-(zpl_mat2 const &a, zpl_mat2 const &b) { + int i, j; + zpl_mat2 r = {0}; + for (j = 0; j < 2; j++) { + for (i = 0; i < 2; i++) + r.e[2*j+i] = a.e[2*j+i] - b.e[2*j+i]; + } + return r; +} + +ZPL_INLINE zpl_mat2 operator*(zpl_mat2 const &a, zpl_mat2 const &b) { zpl_mat2 r; zpl_mat2_mul(&r, (zpl_mat2 *)&a, (zpl_mat2 *)&b); return r; } +ZPL_INLINE zpl_vec2 operator*(zpl_mat2 const &a, zpl_vec2 v) { zpl_vec2 r; zpl_mat2_mul_vec2(&r, (zpl_mat2 *)&a, v); return r; } +ZPL_INLINE zpl_mat2 operator*(zpl_mat2 const &a, float scalar) { + zpl_mat2 r = {0}; + int i; + for (i = 0; i < 2*2; i++) r.e[i] = a.e[i] * scalar; + return r; +} +ZPL_INLINE zpl_mat2 operator*(float scalar, zpl_mat2 const &a) { return operator*(a, scalar); } +ZPL_INLINE zpl_mat2 operator/(zpl_mat2 const &a, float scalar) { return operator*(a, 1.0f/scalar); } + +ZPL_INLINE zpl_mat2& operator+=(zpl_mat2& a, zpl_mat2 const &b) { return (a = a + b); } +ZPL_INLINE zpl_mat2& operator-=(zpl_mat2& a, zpl_mat2 const &b) { return (a = a - b); } +ZPL_INLINE zpl_mat2& operator*=(zpl_mat2& a, zpl_mat2 const &b) { return (a = a * b); } + + + +ZPL_INLINE zpl_mat3 operator+(zpl_mat3 const &a, zpl_mat3 const &b) { + int i, j; + zpl_mat3 r = {0}; + for (j = 0; j < 3; j++) { + for (i = 0; i < 3; i++) + r.e[3*j+i] = a.e[3*j+i] + b.e[3*j+i]; + } + return r; +} + +ZPL_INLINE zpl_mat3 operator-(zpl_mat3 const &a, zpl_mat3 const &b) { + int i, j; + zpl_mat3 r = {0}; + for (j = 0; j < 3; j++) { + for (i = 0; i < 3; i++) + r.e[3*j+i] = a.e[3*j+i] - b.e[3*j+i]; + } + return r; +} + +ZPL_INLINE zpl_mat3 operator*(zpl_mat3 const &a, zpl_mat3 const &b) { zpl_mat3 r; zpl_mat3_mul(&r, (zpl_mat3 *)&a, (zpl_mat3 *)&b); return r; } +ZPL_INLINE zpl_vec3 operator*(zpl_mat3 const &a, zpl_vec3 v) { zpl_vec3 r; zpl_mat3_mul_vec3(&r, (zpl_mat3 *)&a, v); return r; } +ZPL_INLINE zpl_mat3 operator*(zpl_mat3 const &a, float scalar) { + zpl_mat3 r = {0}; + int i; + for (i = 0; i < 3*3; i++) r.e[i] = a.e[i] * scalar; + return r; +} +ZPL_INLINE zpl_mat3 operator*(float scalar, zpl_mat3 const &a) { return operator*(a, scalar); } +ZPL_INLINE zpl_mat3 operator/(zpl_mat3 const &a, float scalar) { return operator*(a, 1.0f/scalar); } + +ZPL_INLINE zpl_mat3& operator+=(zpl_mat3& a, zpl_mat3 const &b) { return (a = a + b); } +ZPL_INLINE zpl_mat3& operator-=(zpl_mat3& a, zpl_mat3 const &b) { return (a = a - b); } +ZPL_INLINE zpl_mat3& operator*=(zpl_mat3& a, zpl_mat3 const &b) { return (a = a * b); } + + + +ZPL_INLINE zpl_mat4 operator+(zpl_mat4 const &a, zpl_mat4 const &b) { + int i, j; + zpl_mat4 r = {0}; + for (j = 0; j < 4; j++) { + for (i = 0; i < 4; i++) + r.e[4*j+i] = a.e[4*j+i] + b.e[4*j+i]; + } + return r; +} + +ZPL_INLINE zpl_mat4 operator-(zpl_mat4 const &a, zpl_mat4 const &b) { + int i, j; + zpl_mat4 r = {0}; + for (j = 0; j < 4; j++) { + for (i = 0; i < 4; i++) + r.e[4*j+i] = a.e[4*j+i] - b.e[4*j+i]; + } + return r; +} + +ZPL_INLINE zpl_mat4 operator*(zpl_mat4 const &a, zpl_mat4 const &b) { zpl_mat4 r; zpl_mat4_mul(&r, (zpl_mat4 *)&a, (zpl_mat4 *)&b); return r; } +ZPL_INLINE zpl_vec4 operator*(zpl_mat4 const &a, zpl_vec4 v) { zpl_vec4 r; zpl_mat4_mul_vec4(&r, (zpl_mat4 *)&a, v); return r; } +ZPL_INLINE zpl_mat4 operator*(zpl_mat4 const &a, float scalar) { + zpl_mat4 r = {0}; + int i; + for (i = 0; i < 4*4; i++) r.e[i] = a.e[i] * scalar; + return r; +} +ZPL_INLINE zpl_mat4 operator*(float scalar, zpl_mat4 const &a) { return operator*(a, scalar); } +ZPL_INLINE zpl_mat4 operator/(zpl_mat4 const &a, float scalar) { return operator*(a, 1.0f/scalar); } + +ZPL_INLINE zpl_mat4& operator+=(zpl_mat4 &a, zpl_mat4 const &b) { return (a = a + b); } +ZPL_INLINE zpl_mat4& operator-=(zpl_mat4 &a, zpl_mat4 const &b) { return (a = a - b); } +ZPL_INLINE zpl_mat4& operator*=(zpl_mat4 &a, zpl_mat4 const &b) { return (a = a * b); } + + + +ZPL_INLINE bool operator==(zpl_quat a, zpl_quat b) { return a.xyzw == b.xyzw; } +ZPL_INLINE bool operator!=(zpl_quat a, zpl_quat b) { return !operator==(a, b); } + +ZPL_INLINE zpl_quat operator+(zpl_quat q) { return q; } +ZPL_INLINE zpl_quat operator-(zpl_quat q) { return zpl_quatf(-q.x, -q.y, -q.z, -q.w); } + +ZPL_INLINE zpl_quat operator+(zpl_quat a, zpl_quat b) { zpl_quat r; zpl_quat_add(&r, a, b); return r; } +ZPL_INLINE zpl_quat operator-(zpl_quat a, zpl_quat b) { zpl_quat r; zpl_quat_sub(&r, a, b); return r; } + +ZPL_INLINE zpl_quat operator*(zpl_quat a, zpl_quat b) { zpl_quat r; zpl_quat_mul(&r, a, b); return r; } +ZPL_INLINE zpl_quat operator*(zpl_quat q, float s) { zpl_quat r; zpl_quat_mulf(&r, q, s); return r; } +ZPL_INLINE zpl_quat operator*(float s, zpl_quat q) { return operator*(q, s); } +ZPL_INLINE zpl_quat operator/(zpl_quat q, float s) { zpl_quat r; zpl_quat_divf(&r, q, s); return r; } + +ZPL_INLINE zpl_quat &operator+=(zpl_quat &a, zpl_quat b) { zpl_quat_addeq(&a, b); return a; } +ZPL_INLINE zpl_quat &operator-=(zpl_quat &a, zpl_quat b) { zpl_quat_subeq(&a, b); return a; } +ZPL_INLINE zpl_quat &operator*=(zpl_quat &a, zpl_quat b) { zpl_quat_muleq(&a, b); return a; } +ZPL_INLINE zpl_quat &operator/=(zpl_quat &a, zpl_quat b) { zpl_quat_diveq(&a, b); return a; } + +ZPL_INLINE zpl_quat &operator*=(zpl_quat &a, float b) { zpl_quat_muleqf(&a, b); return a; } +ZPL_INLINE zpl_quat &operator/=(zpl_quat &a, float b) { zpl_quat_diveqf(&a, b); return a; } + +/* Rotate v by a */ +ZPL_INLINE zpl_vec3 operator*(zpl_quat q, zpl_vec3 v) { zpl_vec3 r; zpl_quat_rotate_vec3(&r, q, v); return r; } +#endif #endif #if defined(ZPL_MODULE_PARSER) - // file: header/adt.h +// file: header/adt.h - ZPL_BEGIN_C_DECLS +ZPL_BEGIN_C_DECLS - typedef enum zpl_adt_type { - ZPL_ADT_TYPE_UNINITIALISED, /* node was not initialised, this is a programming error! */ - ZPL_ADT_TYPE_ARRAY, - ZPL_ADT_TYPE_OBJECT, - ZPL_ADT_TYPE_STRING, - ZPL_ADT_TYPE_MULTISTRING, - ZPL_ADT_TYPE_INTEGER, - ZPL_ADT_TYPE_REAL, - } zpl_adt_type; +typedef enum zpl_adt_type { + ZPL_ADT_TYPE_UNINITIALISED, /* node was not initialised, this is a programming error! */ + ZPL_ADT_TYPE_ARRAY, + ZPL_ADT_TYPE_OBJECT, + ZPL_ADT_TYPE_STRING, + ZPL_ADT_TYPE_MULTISTRING, + ZPL_ADT_TYPE_INTEGER, + ZPL_ADT_TYPE_REAL, +} zpl_adt_type; - typedef enum zpl_adt_props { - ZPL_ADT_PROPS_NONE, - ZPL_ADT_PROPS_NAN, - ZPL_ADT_PROPS_NAN_NEG, - ZPL_ADT_PROPS_INFINITY, - ZPL_ADT_PROPS_INFINITY_NEG, - ZPL_ADT_PROPS_FALSE, - ZPL_ADT_PROPS_TRUE, - ZPL_ADT_PROPS_NULL, - ZPL_ADT_PROPS_IS_EXP, - ZPL_ADT_PROPS_IS_HEX, +typedef enum zpl_adt_props { + ZPL_ADT_PROPS_NONE, + ZPL_ADT_PROPS_NAN, + ZPL_ADT_PROPS_NAN_NEG, + ZPL_ADT_PROPS_INFINITY, + ZPL_ADT_PROPS_INFINITY_NEG, + ZPL_ADT_PROPS_FALSE, + ZPL_ADT_PROPS_TRUE, + ZPL_ADT_PROPS_NULL, + ZPL_ADT_PROPS_IS_EXP, + ZPL_ADT_PROPS_IS_HEX, + + // Used internally so that people can fill in real numbers they plan to write. + ZPL_ADT_PROPS_IS_PARSED_REAL, +} zpl_adt_props; - // Used internally so that people can fill in real numbers they plan to write. - ZPL_ADT_PROPS_IS_PARSED_REAL, - } zpl_adt_props; +typedef enum zpl_adt_naming_style { + ZPL_ADT_NAME_STYLE_DOUBLE_QUOTE, + ZPL_ADT_NAME_STYLE_SINGLE_QUOTE, + ZPL_ADT_NAME_STYLE_NO_QUOTES, +} zpl_adt_naming_style; - typedef enum zpl_adt_naming_style { - ZPL_ADT_NAME_STYLE_DOUBLE_QUOTE, - ZPL_ADT_NAME_STYLE_SINGLE_QUOTE, - ZPL_ADT_NAME_STYLE_NO_QUOTES, - } zpl_adt_naming_style; +typedef enum zpl_adt_assign_style { + ZPL_ADT_ASSIGN_STYLE_COLON, + ZPL_ADT_ASSIGN_STYLE_EQUALS, + ZPL_ADT_ASSIGN_STYLE_LINE, +} zpl_adt_assign_style; - typedef enum zpl_adt_assign_style { - ZPL_ADT_ASSIGN_STYLE_COLON, - ZPL_ADT_ASSIGN_STYLE_EQUALS, - ZPL_ADT_ASSIGN_STYLE_LINE, - } zpl_adt_assign_style; +typedef enum zpl_adt_delim_style { + ZPL_ADT_DELIM_STYLE_COMMA, + ZPL_ADT_DELIM_STYLE_LINE, + ZPL_ADT_DELIM_STYLE_NEWLINE, +} zpl_adt_delim_style; - typedef enum zpl_adt_delim_style { - ZPL_ADT_DELIM_STYLE_COMMA, - ZPL_ADT_DELIM_STYLE_LINE, - ZPL_ADT_DELIM_STYLE_NEWLINE, - } zpl_adt_delim_style; +typedef struct zpl_adt_node { + char const *name; + + /* properties */ + zpl_u8 type :4; + zpl_u8 props :4; + zpl_u8 cfg_mode :1; + zpl_u8 name_style :2; + zpl_u8 assign_style:2; + zpl_u8 delim_style :2; + zpl_u8 delim_line_width :4; + zpl_u8 assign_line_width:4; + + /* adt data */ + union { + char const *string; + struct zpl_adt_node *nodes; ///< zpl_array + struct { + union { + zpl_f64 real; + zpl_i64 integer; + }; + + /* number analysis */ + zpl_i32 base; + zpl_i32 base2; + zpl_u8 base2_offset:4; + zpl_i8 exp :4; + zpl_u8 neg_zero :1; + zpl_u8 lead_digit:1; + }; + }; +} zpl_adt_node; - typedef struct zpl_adt_node { - char const *name; +/* ADT NODE LIMITS + * delimiter and assignment segment width is limited to 128 whitespace symbols each. + * real number limits decimal position to 128 places. + * real number exponent is limited to 64 digits. + */ - /* properties */ - zpl_u8 type :4; - zpl_u8 props :4; - zpl_u8 cfg_mode :1; - zpl_u8 name_style :2; - zpl_u8 assign_style:2; - zpl_u8 delim_style :2; - zpl_u8 delim_line_width :4; - zpl_u8 assign_line_width:4; +ZPL_DEF zpl_u8 zpl_adt_make_branch(zpl_adt_node *node, zpl_allocator backing, char const *name, zpl_u8 type); +ZPL_DEF zpl_u8 zpl_adt_destroy_branch(zpl_adt_node *node); - /* adt data */ - union { - char const *string; - struct zpl_adt_node *nodes; ///< zpl_array - struct { - union { - zpl_f64 real; - zpl_i64 integer; - }; +ZPL_DEF zpl_u8 zpl_adt_make_leaf(zpl_adt_node *node, char const *name, zpl_u8 type); - /* number analysis */ - zpl_i32 base; - zpl_i32 base2; - zpl_u8 base2_offset:4; - zpl_i8 exp :4; - zpl_u8 neg_zero :1; - zpl_u8 lead_digit:1; - }; - }; - } zpl_adt_node; +ZPL_DEF zpl_adt_node *zpl_adt_find(zpl_adt_node *node, char const *name, zpl_b32 deep_search); - /* ADT NODE LIMITS - * delimiter and assignment segment width is limited to 128 whitespace symbols each. - * real number limits decimal position to 128 places. - * real number exponent is limited to 64 digits. - */ +ZPL_DEF zpl_adt_node *zpl_adt_alloc_at(zpl_adt_node *parent, zpl_isize index); +ZPL_DEF zpl_adt_node *zpl_adt_alloc(zpl_adt_node *parent); - ZPL_DEF zpl_u8 zpl_adt_make_branch(zpl_adt_node *node, zpl_allocator backing, char const *name, zpl_u8 type); - ZPL_DEF zpl_u8 zpl_adt_destroy_branch(zpl_adt_node *node); +ZPL_DEF zpl_adt_node *zpl_adt_move_node_at(zpl_adt_node *node, zpl_adt_node *old_parent, zpl_adt_node *new_parent, zpl_isize index); +ZPL_DEF zpl_adt_node *zpl_adt_move_node(zpl_adt_node *node, zpl_adt_node *old_parent, zpl_adt_node *new_parent); +ZPL_DEF void zpl_adt_swap_nodes(zpl_adt_node *node, zpl_adt_node *other_node, zpl_adt_node *parent); +ZPL_DEF void zpl_adt_swap_nodes_between_parents(zpl_adt_node *node, zpl_adt_node *other_node, zpl_adt_node *parent, zpl_adt_node *other_parent); +ZPL_DEF void zpl_adt_remove_node(zpl_adt_node *node, zpl_adt_node *parent); - ZPL_DEF zpl_u8 zpl_adt_make_leaf(zpl_adt_node *node, char const *name, zpl_u8 type); +ZPL_DEF void zpl_adt_set_obj(zpl_adt_node *obj, char const *name, zpl_allocator backing); +ZPL_DEF void zpl_adt_set_arr(zpl_adt_node *obj, char const *name, zpl_allocator backing); +ZPL_DEF void zpl_adt_set_str(zpl_adt_node *obj, char const *name, char const *value); +ZPL_DEF void zpl_adt_set_flt(zpl_adt_node *obj, char const *name, zpl_f64 value); +ZPL_DEF void zpl_adt_set_int(zpl_adt_node *obj, char const *name, zpl_i64 value); - ZPL_DEF zpl_adt_node *zpl_adt_find(zpl_adt_node *node, char const *name, zpl_b32 deep_search); +ZPL_DEF zpl_adt_node *zpl_adt_inset_obj(zpl_adt_node *parent, char const *name); +ZPL_DEF zpl_adt_node *zpl_adt_inset_arr(zpl_adt_node *parent, char const *name); +ZPL_DEF zpl_adt_node *zpl_adt_inset_str(zpl_adt_node *parent, char const *name, char const *value); +ZPL_DEF zpl_adt_node *zpl_adt_inset_flt(zpl_adt_node *parent, char const *name, zpl_f64 value); +ZPL_DEF zpl_adt_node *zpl_adt_inset_int(zpl_adt_node *parent, char const *name, zpl_i64 value); - ZPL_DEF zpl_adt_node *zpl_adt_alloc_at(zpl_adt_node *parent, zpl_isize index); - ZPL_DEF zpl_adt_node *zpl_adt_alloc(zpl_adt_node *parent); +/* parser helpers */ - ZPL_DEF zpl_adt_node *zpl_adt_move_node_at(zpl_adt_node *node, zpl_adt_node *old_parent, zpl_adt_node *new_parent, zpl_isize index); - ZPL_DEF zpl_adt_node *zpl_adt_move_node(zpl_adt_node *node, zpl_adt_node *old_parent, zpl_adt_node *new_parent); - ZPL_DEF void zpl_adt_swap_nodes(zpl_adt_node *node, zpl_adt_node *other_node, zpl_adt_node *parent); - ZPL_DEF void zpl_adt_swap_nodes_between_parents(zpl_adt_node *node, zpl_adt_node *other_node, zpl_adt_node *parent, zpl_adt_node *other_parent); - ZPL_DEF void zpl_adt_remove_node(zpl_adt_node *node, zpl_adt_node *parent); +ZPL_DEF char *zpl_adt_parse_number(zpl_adt_node *node, char* base); +ZPL_DEF void zpl_adt_str_to_number(zpl_adt_node *node); +ZPL_DEF void zpl_adt_print_number(zpl_file *file, zpl_adt_node *node); +ZPL_DEF void zpl_adt_print_string(zpl_file *file, zpl_adt_node *node, char const* escaped_chars, char escape_symbol); - ZPL_DEF void zpl_adt_set_obj(zpl_adt_node *obj, char const *name, zpl_allocator backing); - ZPL_DEF void zpl_adt_set_arr(zpl_adt_node *obj, char const *name, zpl_allocator backing); - ZPL_DEF void zpl_adt_set_str(zpl_adt_node *obj, char const *name, char const *value); - ZPL_DEF void zpl_adt_set_flt(zpl_adt_node *obj, char const *name, zpl_f64 value); - ZPL_DEF void zpl_adt_set_int(zpl_adt_node *obj, char const *name, zpl_i64 value); +/* extensions */ - ZPL_DEF zpl_adt_node *zpl_adt_inset_obj(zpl_adt_node *parent, char const *name); - ZPL_DEF zpl_adt_node *zpl_adt_inset_arr(zpl_adt_node *parent, char const *name); - ZPL_DEF zpl_adt_node *zpl_adt_inset_str(zpl_adt_node *parent, char const *name, char const *value); - ZPL_DEF zpl_adt_node *zpl_adt_inset_flt(zpl_adt_node *parent, char const *name, zpl_f64 value); - ZPL_DEF zpl_adt_node *zpl_adt_inset_int(zpl_adt_node *parent, char const *name, zpl_i64 value); +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L +#define zpl_adt_inset(parent, name, value) _Generic((value), \ +char*: zpl_adt_inset_str, \ +char const*: zpl_adt_inset_str, \ +zpl_f64: zpl_adt_inset_flt, \ +default: zpl_adt_inset_int)(parent, name, value) +#define zpl_adt_set(obj, name, value) _Generic((value), \ +char*: zpl_adt_set_str, \ +char const*: zpl_adt_set_str, \ +zpl_f64: zpl_adt_set_flt, \ +default: zpl_adt_set_int)(obj, name, value) +#endif - /* parser helpers */ +/* deprecated */ - ZPL_DEF char *zpl_adt_parse_number(zpl_adt_node *node, char* base); - ZPL_DEF void zpl_adt_str_to_number(zpl_adt_node *node); - ZPL_DEF void zpl_adt_print_number(zpl_file *file, zpl_adt_node *node); - ZPL_DEF void zpl_adt_print_string(zpl_file *file, zpl_adt_node *node, char const* escaped_chars, char escape_symbol); +ZPL_DEPRECATED_FOR(13.3.0, zpl_adt_str_to_number) +ZPL_IMPL_INLINE void zpl_adt_str_to_flt(zpl_adt_node *node) { + zpl_adt_str_to_number(node); +} - /* extensions */ +ZPL_END_C_DECLS - #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L - #define zpl_adt_inset(parent, name, value) _Generic((value), \ - char*: zpl_adt_inset_str, \ - char const*: zpl_adt_inset_str, \ - zpl_f64: zpl_adt_inset_flt, \ - default: zpl_adt_inset_int)(parent, name, value) - #define zpl_adt_set(obj, name, value) _Generic((value), \ - char*: zpl_adt_set_str, \ - char const*: zpl_adt_set_str, \ - zpl_f64: zpl_adt_set_flt, \ - default: zpl_adt_set_int)(obj, name, value) - #endif - - /* deprecated */ - - ZPL_DEPRECATED_FOR(13.3.0, zpl_adt_str_to_number) - ZPL_IMPL_INLINE void zpl_adt_str_to_flt(zpl_adt_node *node) { - zpl_adt_str_to_number(node); - } - - ZPL_END_C_DECLS - - /* parsers */ - // file: header/parsers/json.h +/* parsers */ +// file: header/parsers/json.h - ZPL_BEGIN_C_DECLS +ZPL_BEGIN_C_DECLS - typedef enum zpl_json_error { - ZPL_JSON_ERROR_NONE, - ZPL_JSON_ERROR_INTERNAL, - ZPL_JSON_ERROR_INVALID_NAME, - ZPL_JSON_ERROR_INVALID_VALUE, - ZPL_JSON_ERROR_INVALID_ASSIGNMENT, - ZPL_JSON_ERROR_UNKNOWN_KEYWORD, - ZPL_JSON_ERROR_ARRAY_LEFT_OPEN, - ZPL_JSON_ERROR_OBJECT_END_PAIR_MISMATCHED, - } zpl_json_error; +typedef enum zpl_json_error { + ZPL_JSON_ERROR_NONE, + ZPL_JSON_ERROR_INTERNAL, + ZPL_JSON_ERROR_INVALID_NAME, + ZPL_JSON_ERROR_INVALID_VALUE, + ZPL_JSON_ERROR_INVALID_ASSIGNMENT, + ZPL_JSON_ERROR_UNKNOWN_KEYWORD, + ZPL_JSON_ERROR_ARRAY_LEFT_OPEN, + ZPL_JSON_ERROR_OBJECT_END_PAIR_MISMATCHED, +} zpl_json_error; - typedef zpl_adt_node zpl_json_object; +typedef zpl_adt_node zpl_json_object; - ZPL_DEF zpl_u8 zpl_json_parse(zpl_json_object *root, char *text, zpl_allocator allocator); - ZPL_DEF void zpl_json_free(zpl_json_object *obj); - ZPL_DEF void zpl_json_write(zpl_file *file, zpl_json_object *obj, zpl_isize indent); - ZPL_DEF zpl_string zpl_json_write_string(zpl_allocator a, zpl_json_object *obj, zpl_isize indent); +ZPL_DEF zpl_u8 zpl_json_parse(zpl_json_object *root, char *text, zpl_allocator allocator); +ZPL_DEF void zpl_json_free(zpl_json_object *obj); +ZPL_DEF void zpl_json_write(zpl_file *file, zpl_json_object *obj, zpl_isize indent); +ZPL_DEF zpl_string zpl_json_write_string(zpl_allocator a, zpl_json_object *obj, zpl_isize indent); - ZPL_END_C_DECLS - // file: header/parsers/csv.h +ZPL_END_C_DECLS +// file: header/parsers/csv.h - ZPL_BEGIN_C_DECLS +ZPL_BEGIN_C_DECLS - typedef enum zpl_csv_error { - ZPL_CSV_ERROR_NONE, - ZPL_CSV_ERROR_INTERNAL, - ZPL_CSV_ERROR_UNEXPECTED_END_OF_INPUT, - ZPL_CSV_ERROR_MISMATCHED_ROWS, - } zpl_csv_error; +typedef enum zpl_csv_error { + ZPL_CSV_ERROR_NONE, + ZPL_CSV_ERROR_INTERNAL, + ZPL_CSV_ERROR_UNEXPECTED_END_OF_INPUT, + ZPL_CSV_ERROR_MISMATCHED_ROWS, +} zpl_csv_error; - typedef zpl_adt_node zpl_csv_object; +typedef zpl_adt_node zpl_csv_object; - ZPL_DEF_INLINE zpl_u8 zpl_csv_parse(zpl_csv_object *root, char *text, zpl_allocator allocator, zpl_b32 has_header); - ZPL_DEF zpl_u8 zpl_csv_parse_delimiter(zpl_csv_object *root, char *text, zpl_allocator allocator, zpl_b32 has_header, char delim); - ZPL_DEF void zpl_csv_free(zpl_csv_object *obj); +ZPL_DEF_INLINE zpl_u8 zpl_csv_parse(zpl_csv_object *root, char *text, zpl_allocator allocator, zpl_b32 has_header); +ZPL_DEF zpl_u8 zpl_csv_parse_delimiter(zpl_csv_object *root, char *text, zpl_allocator allocator, zpl_b32 has_header, char delim); +ZPL_DEF void zpl_csv_free(zpl_csv_object *obj); - ZPL_DEF_INLINE void zpl_csv_write(zpl_file *file, zpl_csv_object *obj); - ZPL_DEF_INLINE zpl_string zpl_csv_write_string(zpl_allocator a, zpl_csv_object *obj); - ZPL_DEF void zpl_csv_write_delimiter(zpl_file *file, zpl_csv_object *obj, char delim); - ZPL_DEF zpl_string zpl_csv_write_string_delimiter(zpl_allocator a, zpl_csv_object *obj, char delim); +ZPL_DEF_INLINE void zpl_csv_write(zpl_file *file, zpl_csv_object *obj); +ZPL_DEF_INLINE zpl_string zpl_csv_write_string(zpl_allocator a, zpl_csv_object *obj); +ZPL_DEF void zpl_csv_write_delimiter(zpl_file *file, zpl_csv_object *obj, char delim); +ZPL_DEF zpl_string zpl_csv_write_string_delimiter(zpl_allocator a, zpl_csv_object *obj, char delim); - /* inline */ +/* inline */ - ZPL_IMPL_INLINE zpl_u8 zpl_csv_parse(zpl_csv_object *root, char *text, zpl_allocator allocator, zpl_b32 has_header) { - return zpl_csv_parse_delimiter(root, text, allocator, has_header, ','); - } +ZPL_IMPL_INLINE zpl_u8 zpl_csv_parse(zpl_csv_object *root, char *text, zpl_allocator allocator, zpl_b32 has_header) { + return zpl_csv_parse_delimiter(root, text, allocator, has_header, ','); +} - ZPL_IMPL_INLINE void zpl_csv_write(zpl_file *file, zpl_csv_object *obj) { - zpl_csv_write_delimiter(file, obj, ','); - } +ZPL_IMPL_INLINE void zpl_csv_write(zpl_file *file, zpl_csv_object *obj) { + zpl_csv_write_delimiter(file, obj, ','); +} - ZPL_IMPL_INLINE zpl_string zpl_csv_write_string(zpl_allocator a, zpl_csv_object *obj) { - return zpl_csv_write_string_delimiter(a, obj, ','); - } +ZPL_IMPL_INLINE zpl_string zpl_csv_write_string(zpl_allocator a, zpl_csv_object *obj) { + return zpl_csv_write_string_delimiter(a, obj, ','); +} - ZPL_END_C_DECLS +ZPL_END_C_DECLS #endif #if defined(ZPL_MODULE_THREADING) @@ -7325,7 +7323,7 @@ License: # undef WIN32_MEAN_AND_LEAN # undef VC_EXTRALEAN - /* prevent it from including later */ +/* prevent it from including later */ # define ZPL_NO_WINDOWS_H # endif # endif @@ -7342,490 +7340,490 @@ License: # endif # endif - // file: header/threading/atomic.h +// file: header/threading/atomic.h - // Atomics +// Atomics - // TODO: Be specific with memory order? - // e.g. relaxed, acquire, release, acquire_release +// TODO: Be specific with memory order? +// e.g. relaxed, acquire, release, acquire_release - #if !defined(__STDC_NO_ATOMICS__) && !defined(__cplusplus) && !defined(ZPL_COMPILER_MSVC) && !defined(ZPL_COMPILER_TINYC) - # define zpl_atomic(X) volatile _Atomic(X) - #else - // TODO: Fix once C++ guys bother to add C atomics to std. - //# include - # define zpl_atomic(X) volatile X /*std::atomic*/ - #endif +#if !defined(__STDC_NO_ATOMICS__) && !defined(__cplusplus) && !defined(ZPL_COMPILER_MSVC) && !defined(ZPL_COMPILER_TINYC) +# define zpl_atomic(X) volatile _Atomic(X) +#else +// TODO: Fix once C++ guys bother to add C atomics to std. +//# include +# define zpl_atomic(X) volatile X /*std::atomic*/ +#endif - #if defined(__STDC_NO_ATOMICS__) || defined(__cplusplus) || defined(ZPL_COMPILER_MSVC) - #define zpl_atomicarg(X) volatile X - #else - #define zpl_atomicarg(X) X - #endif +#if defined(__STDC_NO_ATOMICS__) || defined(__cplusplus) || defined(ZPL_COMPILER_MSVC) +#define zpl_atomicarg(X) volatile X +#else +#define zpl_atomicarg(X) X +#endif - ZPL_BEGIN_C_DECLS +ZPL_BEGIN_C_DECLS - #if defined(ZPL_COMPILER_MSVC) - typedef struct zpl_atomic32 { zpl_atomic(zpl_i32) value; } zpl_atomic32; - typedef struct zpl_atomic64 { zpl_atomic(zpl_i64) value; } zpl_atomic64; - typedef struct zpl_atomic_ptr { zpl_atomic(void*) value; } zpl_atomic_ptr; - #else - # if defined(ZPL_ARCH_32_BIT) - # define ZPL_ATOMIC_PTR_ALIGNMENT 4 - # elif defined(ZPL_ARCH_64_BIT) - # define ZPL_ATOMIC_PTR_ALIGNMENT 8 - # else - # error Unknown architecture - # endif +#if defined(ZPL_COMPILER_MSVC) +typedef struct zpl_atomic32 { zpl_atomic(zpl_i32) value; } zpl_atomic32; +typedef struct zpl_atomic64 { zpl_atomic(zpl_i64) value; } zpl_atomic64; +typedef struct zpl_atomic_ptr { zpl_atomic(void*) value; } zpl_atomic_ptr; +#else +# if defined(ZPL_ARCH_32_BIT) +# define ZPL_ATOMIC_PTR_ALIGNMENT 4 +# elif defined(ZPL_ARCH_64_BIT) +# define ZPL_ATOMIC_PTR_ALIGNMENT 8 +# else +# error Unknown architecture +# endif - typedef struct zpl_atomic32 { zpl_atomic(zpl_i32) value; } __attribute__ ((aligned(4))) zpl_atomic32; - typedef struct zpl_atomic64 { zpl_atomic(zpl_i64) value; } __attribute__ ((aligned(8))) zpl_atomic64; - typedef struct zpl_atomic_ptr { zpl_atomic(void*) value; } __attribute__ ((aligned(ZPL_ATOMIC_PTR_ALIGNMENT))) zpl_atomic_ptr; - #endif +typedef struct zpl_atomic32 { zpl_atomic(zpl_i32) value; } __attribute__ ((aligned(4))) zpl_atomic32; +typedef struct zpl_atomic64 { zpl_atomic(zpl_i64) value; } __attribute__ ((aligned(8))) zpl_atomic64; +typedef struct zpl_atomic_ptr { zpl_atomic(void*) value; } __attribute__ ((aligned(ZPL_ATOMIC_PTR_ALIGNMENT))) zpl_atomic_ptr; +#endif - ZPL_DEF zpl_i32 zpl_atomic32_load (zpl_atomic32 const *a); - ZPL_DEF void zpl_atomic32_store (zpl_atomic32 *a, zpl_atomicarg(zpl_i32) value); - ZPL_DEF zpl_i32 zpl_atomic32_compare_exchange(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) expected, zpl_atomicarg(zpl_i32) desired); - ZPL_DEF zpl_i32 zpl_atomic32_exchange (zpl_atomic32 *a, zpl_atomicarg(zpl_i32) desired); - ZPL_DEF zpl_i32 zpl_atomic32_fetch_add (zpl_atomic32 *a, zpl_atomicarg(zpl_i32) operand); - ZPL_DEF zpl_i32 zpl_atomic32_fetch_and (zpl_atomic32 *a, zpl_atomicarg(zpl_i32) operand); - ZPL_DEF zpl_i32 zpl_atomic32_fetch_or (zpl_atomic32 *a, zpl_atomicarg(zpl_i32) operand); - ZPL_DEF zpl_b32 zpl_atomic32_spin_lock (zpl_atomic32 *a, zpl_isize time_out); // NOTE: time_out = -1 as default - ZPL_DEF void zpl_atomic32_spin_unlock (zpl_atomic32 *a); - ZPL_DEF zpl_b32 zpl_atomic32_try_acquire_lock(zpl_atomic32 *a); +ZPL_DEF zpl_i32 zpl_atomic32_load (zpl_atomic32 const *a); +ZPL_DEF void zpl_atomic32_store (zpl_atomic32 *a, zpl_atomicarg(zpl_i32) value); +ZPL_DEF zpl_i32 zpl_atomic32_compare_exchange(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) expected, zpl_atomicarg(zpl_i32) desired); +ZPL_DEF zpl_i32 zpl_atomic32_exchange (zpl_atomic32 *a, zpl_atomicarg(zpl_i32) desired); +ZPL_DEF zpl_i32 zpl_atomic32_fetch_add (zpl_atomic32 *a, zpl_atomicarg(zpl_i32) operand); +ZPL_DEF zpl_i32 zpl_atomic32_fetch_and (zpl_atomic32 *a, zpl_atomicarg(zpl_i32) operand); +ZPL_DEF zpl_i32 zpl_atomic32_fetch_or (zpl_atomic32 *a, zpl_atomicarg(zpl_i32) operand); +ZPL_DEF zpl_b32 zpl_atomic32_spin_lock (zpl_atomic32 *a, zpl_isize time_out); // NOTE: time_out = -1 as default +ZPL_DEF void zpl_atomic32_spin_unlock (zpl_atomic32 *a); +ZPL_DEF zpl_b32 zpl_atomic32_try_acquire_lock(zpl_atomic32 *a); - ZPL_DEF zpl_i64 zpl_atomic64_load (zpl_atomic64 const *a); - ZPL_DEF void zpl_atomic64_store (zpl_atomic64 *a, zpl_atomicarg(zpl_i64) value); - ZPL_DEF zpl_i64 zpl_atomic64_compare_exchange(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) expected, zpl_atomicarg(zpl_i64) desired); - ZPL_DEF zpl_i64 zpl_atomic64_exchange (zpl_atomic64 *a, zpl_atomicarg(zpl_i64) desired); - ZPL_DEF zpl_i64 zpl_atomic64_fetch_add (zpl_atomic64 *a, zpl_atomicarg(zpl_i64) operand); - ZPL_DEF zpl_i64 zpl_atomic64_fetch_and (zpl_atomic64 *a, zpl_atomicarg(zpl_i64) operand); - ZPL_DEF zpl_i64 zpl_atomic64_fetch_or (zpl_atomic64 *a, zpl_atomicarg(zpl_i64) operand); - ZPL_DEF zpl_b32 zpl_atomic64_spin_lock (zpl_atomic64 *a, zpl_isize time_out); // NOTE: time_out = -1 as default - ZPL_DEF void zpl_atomic64_spin_unlock (zpl_atomic64 *a); - ZPL_DEF zpl_b32 zpl_atomic64_try_acquire_lock(zpl_atomic64 *a); +ZPL_DEF zpl_i64 zpl_atomic64_load (zpl_atomic64 const *a); +ZPL_DEF void zpl_atomic64_store (zpl_atomic64 *a, zpl_atomicarg(zpl_i64) value); +ZPL_DEF zpl_i64 zpl_atomic64_compare_exchange(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) expected, zpl_atomicarg(zpl_i64) desired); +ZPL_DEF zpl_i64 zpl_atomic64_exchange (zpl_atomic64 *a, zpl_atomicarg(zpl_i64) desired); +ZPL_DEF zpl_i64 zpl_atomic64_fetch_add (zpl_atomic64 *a, zpl_atomicarg(zpl_i64) operand); +ZPL_DEF zpl_i64 zpl_atomic64_fetch_and (zpl_atomic64 *a, zpl_atomicarg(zpl_i64) operand); +ZPL_DEF zpl_i64 zpl_atomic64_fetch_or (zpl_atomic64 *a, zpl_atomicarg(zpl_i64) operand); +ZPL_DEF zpl_b32 zpl_atomic64_spin_lock (zpl_atomic64 *a, zpl_isize time_out); // NOTE: time_out = -1 as default +ZPL_DEF void zpl_atomic64_spin_unlock (zpl_atomic64 *a); +ZPL_DEF zpl_b32 zpl_atomic64_try_acquire_lock(zpl_atomic64 *a); - ZPL_DEF void *zpl_atomic_ptr_load (zpl_atomic_ptr const *a); - ZPL_DEF void zpl_atomic_ptr_store (zpl_atomic_ptr *a, zpl_atomicarg(void *)value); - ZPL_DEF void *zpl_atomic_ptr_compare_exchange(zpl_atomic_ptr *a, zpl_atomicarg(void *)expected, zpl_atomicarg(void *)desired); - ZPL_DEF void *zpl_atomic_ptr_exchange (zpl_atomic_ptr *a, zpl_atomicarg(void *)desired); - ZPL_DEF void *zpl_atomic_ptr_fetch_add (zpl_atomic_ptr *a, zpl_atomicarg(void *)operand); - ZPL_DEF void *zpl_atomic_ptr_fetch_and (zpl_atomic_ptr *a, zpl_atomicarg(void *)operand); - ZPL_DEF void *zpl_atomic_ptr_fetch_or (zpl_atomic_ptr *a, zpl_atomicarg(void *)operand); - ZPL_DEF zpl_b32 zpl_atomic_ptr_spin_lock (zpl_atomic_ptr *a, zpl_isize time_out); // NOTE: time_out = -1 as default - ZPL_DEF void zpl_atomic_ptr_spin_unlock (zpl_atomic_ptr *a); - ZPL_DEF zpl_b32 zpl_atomic_ptr_try_acquire_lock(zpl_atomic_ptr *a); +ZPL_DEF void *zpl_atomic_ptr_load (zpl_atomic_ptr const *a); +ZPL_DEF void zpl_atomic_ptr_store (zpl_atomic_ptr *a, zpl_atomicarg(void *)value); +ZPL_DEF void *zpl_atomic_ptr_compare_exchange(zpl_atomic_ptr *a, zpl_atomicarg(void *)expected, zpl_atomicarg(void *)desired); +ZPL_DEF void *zpl_atomic_ptr_exchange (zpl_atomic_ptr *a, zpl_atomicarg(void *)desired); +ZPL_DEF void *zpl_atomic_ptr_fetch_add (zpl_atomic_ptr *a, zpl_atomicarg(void *)operand); +ZPL_DEF void *zpl_atomic_ptr_fetch_and (zpl_atomic_ptr *a, zpl_atomicarg(void *)operand); +ZPL_DEF void *zpl_atomic_ptr_fetch_or (zpl_atomic_ptr *a, zpl_atomicarg(void *)operand); +ZPL_DEF zpl_b32 zpl_atomic_ptr_spin_lock (zpl_atomic_ptr *a, zpl_isize time_out); // NOTE: time_out = -1 as default +ZPL_DEF void zpl_atomic_ptr_spin_unlock (zpl_atomic_ptr *a); +ZPL_DEF zpl_b32 zpl_atomic_ptr_try_acquire_lock(zpl_atomic_ptr *a); - ZPL_END_C_DECLS - // file: header/threading/fence.h +ZPL_END_C_DECLS +// file: header/threading/fence.h - // Fences +// Fences - ZPL_BEGIN_C_DECLS +ZPL_BEGIN_C_DECLS - ZPL_DEF void zpl_yield_thread(void); - ZPL_DEF void zpl_mfence (void); - ZPL_DEF void zpl_sfence (void); - ZPL_DEF void zpl_lfence (void); +ZPL_DEF void zpl_yield_thread(void); +ZPL_DEF void zpl_mfence (void); +ZPL_DEF void zpl_sfence (void); +ZPL_DEF void zpl_lfence (void); - ZPL_END_C_DECLS - // file: header/threading/sem.h +ZPL_END_C_DECLS +// file: header/threading/sem.h - ZPL_BEGIN_C_DECLS +ZPL_BEGIN_C_DECLS - #if defined(ZPL_SYSTEM_MACOS) - # include - #elif defined(ZPL_SYSTEM_UNIX) - # include - #endif +#if defined(ZPL_SYSTEM_MACOS) +# include +#elif defined(ZPL_SYSTEM_UNIX) +# include +#endif - #if defined(ZPL_SYSTEM_WINDOWS) - typedef struct zpl_semaphore { void *win32_handle; } zpl_semaphore; - #elif defined(ZPL_SYSTEM_MACOS) - typedef struct zpl_semaphore { semaphore_t osx_handle; } zpl_semaphore; - #elif defined(ZPL_SYSTEM_UNIX) - typedef struct zpl_semaphore { sem_t unix_handle; } zpl_semaphore; - #else - # error - #endif +#if defined(ZPL_SYSTEM_WINDOWS) +typedef struct zpl_semaphore { void *win32_handle; } zpl_semaphore; +#elif defined(ZPL_SYSTEM_MACOS) +typedef struct zpl_semaphore { semaphore_t osx_handle; } zpl_semaphore; +#elif defined(ZPL_SYSTEM_UNIX) +typedef struct zpl_semaphore { sem_t unix_handle; } zpl_semaphore; +#else +# error +#endif - ZPL_DEF void zpl_semaphore_init (zpl_semaphore *s); - ZPL_DEF void zpl_semaphore_destroy(zpl_semaphore *s); - ZPL_DEF void zpl_semaphore_post (zpl_semaphore *s, zpl_i32 count); - ZPL_DEF void zpl_semaphore_release(zpl_semaphore *s); // NOTE: zpl_semaphore_post(s, 1) - ZPL_DEF void zpl_semaphore_wait (zpl_semaphore *s); +ZPL_DEF void zpl_semaphore_init (zpl_semaphore *s); +ZPL_DEF void zpl_semaphore_destroy(zpl_semaphore *s); +ZPL_DEF void zpl_semaphore_post (zpl_semaphore *s, zpl_i32 count); +ZPL_DEF void zpl_semaphore_release(zpl_semaphore *s); // NOTE: zpl_semaphore_post(s, 1) +ZPL_DEF void zpl_semaphore_wait (zpl_semaphore *s); - ZPL_END_C_DECLS - // file: header/threading/mutex.h +ZPL_END_C_DECLS +// file: header/threading/mutex.h - ZPL_BEGIN_C_DECLS +ZPL_BEGIN_C_DECLS - typedef struct zpl_mutex { - #if defined(ZPL_SYSTEM_WINDOWS) - zpl_u64 win32_critical_section[sizeof(zpl_usize) / 2 + 1]; - #else - pthread_mutex_t pthread_mutex; - #endif - } zpl_mutex; +typedef struct zpl_mutex { +#if defined(ZPL_SYSTEM_WINDOWS) + zpl_u64 win32_critical_section[sizeof(zpl_usize) / 2 + 1]; +#else + pthread_mutex_t pthread_mutex; +#endif +} zpl_mutex; - ZPL_DEF void zpl_mutex_init (zpl_mutex *m); - ZPL_DEF void zpl_mutex_destroy (zpl_mutex *m); - ZPL_DEF void zpl_mutex_lock (zpl_mutex *m); - ZPL_DEF zpl_b32 zpl_mutex_try_lock(zpl_mutex *m); - ZPL_DEF void zpl_mutex_unlock (zpl_mutex *m); +ZPL_DEF void zpl_mutex_init (zpl_mutex *m); +ZPL_DEF void zpl_mutex_destroy (zpl_mutex *m); +ZPL_DEF void zpl_mutex_lock (zpl_mutex *m); +ZPL_DEF zpl_b32 zpl_mutex_try_lock(zpl_mutex *m); +ZPL_DEF void zpl_mutex_unlock (zpl_mutex *m); - ZPL_END_C_DECLS - // file: header/threading/thread.h +ZPL_END_C_DECLS +// file: header/threading/thread.h - #ifdef ZPL_EDITOR - #include - #else - struct zpl_thread; - #endif +#ifdef ZPL_EDITOR +#include +#else +struct zpl_thread; +#endif - ZPL_BEGIN_C_DECLS +ZPL_BEGIN_C_DECLS - typedef zpl_isize (*zpl_thread_proc)(struct zpl_thread *thread); +typedef zpl_isize (*zpl_thread_proc)(struct zpl_thread *thread); - typedef struct zpl_thread { - #if defined(ZPL_SYSTEM_WINDOWS) - void * win32_handle; - #else - pthread_t posix_handle; - #endif +typedef struct zpl_thread { +#if defined(ZPL_SYSTEM_WINDOWS) + void * win32_handle; +#else + pthread_t posix_handle; +#endif + + zpl_thread_proc proc; + void * user_data; + zpl_isize user_index; + zpl_isize return_value; + + zpl_semaphore semaphore; + zpl_isize stack_size; + zpl_b32 is_running; +} zpl_thread; - zpl_thread_proc proc; - void * user_data; - zpl_isize user_index; - zpl_isize return_value; +ZPL_DEF void zpl_thread_init (zpl_thread *t); +ZPL_DEF void zpl_thread_destroy (zpl_thread *t); +ZPL_DEF void zpl_thread_start (zpl_thread *t, zpl_thread_proc proc, void *data); +ZPL_DEF void zpl_thread_start_with_stack(zpl_thread *t, zpl_thread_proc proc, void *data, zpl_isize stack_size); +ZPL_DEF void zpl_thread_join (zpl_thread *t); +ZPL_DEF zpl_b32 zpl_thread_is_running (zpl_thread const *t); +ZPL_DEF zpl_u32 zpl_thread_current_id (void); +ZPL_DEF void zpl_thread_set_name (zpl_thread *t, char const *name); - zpl_semaphore semaphore; - zpl_isize stack_size; - zpl_b32 is_running; - } zpl_thread; +ZPL_END_C_DECLS +// file: header/threading/sync.h - ZPL_DEF void zpl_thread_init (zpl_thread *t); - ZPL_DEF void zpl_thread_destroy (zpl_thread *t); - ZPL_DEF void zpl_thread_start (zpl_thread *t, zpl_thread_proc proc, void *data); - ZPL_DEF void zpl_thread_start_with_stack(zpl_thread *t, zpl_thread_proc proc, void *data, zpl_isize stack_size); - ZPL_DEF void zpl_thread_join (zpl_thread *t); - ZPL_DEF zpl_b32 zpl_thread_is_running (zpl_thread const *t); - ZPL_DEF zpl_u32 zpl_thread_current_id (void); - ZPL_DEF void zpl_thread_set_name (zpl_thread *t, char const *name); +// NOTE: Thread Merge Operation +// Based on Sean Barrett's stb_sync - ZPL_END_C_DECLS - // file: header/threading/sync.h +ZPL_BEGIN_C_DECLS - // NOTE: Thread Merge Operation - // Based on Sean Barrett's stb_sync +typedef struct zpl_sync { + zpl_i32 target; // Target Number of threads + zpl_i32 current; // Threads to hit + zpl_i32 waiting; // Threads waiting + + zpl_mutex start; + zpl_mutex mutex; + zpl_semaphore release; +} zpl_sync; - ZPL_BEGIN_C_DECLS +ZPL_DEF void zpl_sync_init (zpl_sync *s); +ZPL_DEF void zpl_sync_destroy (zpl_sync *s); +ZPL_DEF void zpl_sync_set_target (zpl_sync *s, zpl_i32 count); +ZPL_DEF void zpl_sync_release (zpl_sync *s); +ZPL_DEF zpl_i32 zpl_sync_reach (zpl_sync *s); +ZPL_DEF void zpl_sync_reach_and_wait(zpl_sync *s); - typedef struct zpl_sync { - zpl_i32 target; // Target Number of threads - zpl_i32 current; // Threads to hit - zpl_i32 waiting; // Threads waiting - - zpl_mutex start; - zpl_mutex mutex; - zpl_semaphore release; - } zpl_sync; - - ZPL_DEF void zpl_sync_init (zpl_sync *s); - ZPL_DEF void zpl_sync_destroy (zpl_sync *s); - ZPL_DEF void zpl_sync_set_target (zpl_sync *s, zpl_i32 count); - ZPL_DEF void zpl_sync_release (zpl_sync *s); - ZPL_DEF zpl_i32 zpl_sync_reach (zpl_sync *s); - ZPL_DEF void zpl_sync_reach_and_wait(zpl_sync *s); - - ZPL_END_C_DECLS - // file: header/threading/affinity.h +ZPL_END_C_DECLS +// file: header/threading/affinity.h - ZPL_BEGIN_C_DECLS +ZPL_BEGIN_C_DECLS - #if defined(ZPL_SYSTEM_WINDOWS) || defined (ZPL_SYSTEM_CYGWIN) +#if defined(ZPL_SYSTEM_WINDOWS) || defined (ZPL_SYSTEM_CYGWIN) - typedef struct zpl_affinity { - zpl_b32 is_accurate; - zpl_isize core_count; - zpl_isize thread_count; +typedef struct zpl_affinity { + zpl_b32 is_accurate; + zpl_isize core_count; + zpl_isize thread_count; + +# define ZPL_WIN32_MAX_THREADS (8 * zpl_size_of(zpl_usize)) + zpl_usize core_masks[ZPL_WIN32_MAX_THREADS]; +} zpl_affinity; - # define ZPL_WIN32_MAX_THREADS (8 * zpl_size_of(zpl_usize)) - zpl_usize core_masks[ZPL_WIN32_MAX_THREADS]; - } zpl_affinity; +#elif defined(ZPL_SYSTEM_OSX) - #elif defined(ZPL_SYSTEM_OSX) +typedef struct zpl_affinity { + zpl_b32 is_accurate; + zpl_isize core_count; + zpl_isize thread_count; + zpl_isize threads_per_core; +} zpl_affinity; - typedef struct zpl_affinity { - zpl_b32 is_accurate; - zpl_isize core_count; - zpl_isize thread_count; - zpl_isize threads_per_core; - } zpl_affinity; +#elif defined(ZPL_SYSTEM_LINUX) || defined(ZPL_SYSTEM_FREEBSD) || defined(ZPL_SYSTEM_EMSCRIPTEN) || defined(ZPL_SYSTEM_OPENBSD) - #elif defined(ZPL_SYSTEM_LINUX) || defined(ZPL_SYSTEM_FREEBSD) || defined(ZPL_SYSTEM_EMSCRIPTEN) || defined(ZPL_SYSTEM_OPENBSD) +typedef struct zpl_affinity { + zpl_b32 is_accurate; + zpl_isize core_count; + zpl_isize thread_count; + zpl_isize threads_per_core; +} zpl_affinity; - typedef struct zpl_affinity { - zpl_b32 is_accurate; - zpl_isize core_count; - zpl_isize thread_count; - zpl_isize threads_per_core; - } zpl_affinity; +#else +# error TODO: Unknown system +#endif - #else - # error TODO: Unknown system - #endif +ZPL_DEF void zpl_affinity_init (zpl_affinity *a); +ZPL_DEF void zpl_affinity_destroy(zpl_affinity *a); +ZPL_DEF zpl_b32 zpl_affinity_set (zpl_affinity *a, zpl_isize core, zpl_isize thread); +ZPL_DEF zpl_isize zpl_affinity_thread_count_for_core(zpl_affinity *a, zpl_isize core); - ZPL_DEF void zpl_affinity_init (zpl_affinity *a); - ZPL_DEF void zpl_affinity_destroy(zpl_affinity *a); - ZPL_DEF zpl_b32 zpl_affinity_set (zpl_affinity *a, zpl_isize core, zpl_isize thread); - ZPL_DEF zpl_isize zpl_affinity_thread_count_for_core(zpl_affinity *a, zpl_isize core); - - ZPL_END_C_DECLS +ZPL_END_C_DECLS # if defined(ZPL_MODULE_JOBS) - // file: header/jobs.h +// file: header/jobs.h - /** @file threadpool.c - @brief Job system - @defgroup jobs Job system +/** @file threadpool.c +@brief Job system +@defgroup jobs Job system - This job system follows thread pool pattern to minimize the costs of thread initialization. - It reuses fixed number of threads to process variable number of jobs. + This job system follows thread pool pattern to minimize the costs of thread initialization. + It reuses fixed number of threads to process variable number of jobs. - @{ - */ + @{ + */ - ZPL_BEGIN_C_DECLS +ZPL_BEGIN_C_DECLS - typedef void (*zpl_jobs_proc)(void *data); +typedef void (*zpl_jobs_proc)(void *data); - #define ZPL_INVALID_JOB ZPL_U32_MAX +#define ZPL_INVALID_JOB ZPL_U32_MAX - #ifndef ZPL_JOBS_MAX_QUEUE - #define ZPL_JOBS_MAX_QUEUE 100 - #endif +#ifndef ZPL_JOBS_MAX_QUEUE +#define ZPL_JOBS_MAX_QUEUE 100 +#endif - #ifdef ZPL_JOBS_ENABLE_DEBUG - #define ZPL_JOBS_DEBUG - #endif +#ifdef ZPL_JOBS_ENABLE_DEBUG +#define ZPL_JOBS_DEBUG +#endif - typedef enum { - ZPL_JOBS_STATUS_READY, - ZPL_JOBS_STATUS_BUSY, - ZPL_JOBS_STATUS_WAITING, - ZPL_JOBS_STATUS_TERM, - } zpl_jobs_status; +typedef enum { + ZPL_JOBS_STATUS_READY, + ZPL_JOBS_STATUS_BUSY, + ZPL_JOBS_STATUS_WAITING, + ZPL_JOBS_STATUS_TERM, +} zpl_jobs_status; - typedef enum { - ZPL_JOBS_PRIORITY_REALTIME, - ZPL_JOBS_PRIORITY_HIGH, - ZPL_JOBS_PRIORITY_NORMAL, - ZPL_JOBS_PRIORITY_LOW, - ZPL_JOBS_PRIORITY_IDLE, - ZPL_JOBS_MAX_PRIORITIES, - } zpl_jobs_priority; +typedef enum { + ZPL_JOBS_PRIORITY_REALTIME, + ZPL_JOBS_PRIORITY_HIGH, + ZPL_JOBS_PRIORITY_NORMAL, + ZPL_JOBS_PRIORITY_LOW, + ZPL_JOBS_PRIORITY_IDLE, + ZPL_JOBS_MAX_PRIORITIES, +} zpl_jobs_priority; - typedef struct { - zpl_jobs_proc proc; - void *data; - } zpl_thread_job; +typedef struct { + zpl_jobs_proc proc; + void *data; +} zpl_thread_job; - ZPL_RING_DECLARE(zpl__jobs_ring_, zpl_thread_job); +ZPL_RING_DECLARE(zpl__jobs_ring_, zpl_thread_job); - typedef struct { - zpl_thread thread; - zpl_atomic32 status; - zpl_thread_job job; - #ifdef ZPL_JOBS_DEBUG - zpl_u32 hits; - zpl_u32 idle; - #endif - } zpl_thread_worker; +typedef struct { + zpl_thread thread; + zpl_atomic32 status; + zpl_thread_job job; +#ifdef ZPL_JOBS_DEBUG + zpl_u32 hits; + zpl_u32 idle; +#endif +} zpl_thread_worker; - typedef struct { - zpl__jobs_ring_zpl_thread_job jobs; ///< zpl_ring - zpl_u32 chance; - #ifdef ZPL_JOBS_DEBUG - zpl_u32 hits; - #endif - } zpl_thread_queue; +typedef struct { + zpl__jobs_ring_zpl_thread_job jobs; ///< zpl_ring + zpl_u32 chance; +#ifdef ZPL_JOBS_DEBUG + zpl_u32 hits; +#endif +} zpl_thread_queue; - typedef struct { - zpl_allocator alloc; - zpl_u32 max_threads, max_jobs, counter; - zpl_thread_worker *workers; ///< zpl_buffer - zpl_thread_queue queues[ZPL_JOBS_MAX_PRIORITIES]; - } zpl_jobs_system; +typedef struct { + zpl_allocator alloc; + zpl_u32 max_threads, max_jobs, counter; + zpl_thread_worker *workers; ///< zpl_buffer + zpl_thread_queue queues[ZPL_JOBS_MAX_PRIORITIES]; +} zpl_jobs_system; - //! Initialize thread pool with specified amount of fixed threads. - ZPL_DEF void zpl_jobs_init(zpl_jobs_system *pool, zpl_allocator a, zpl_u32 max_threads); +//! Initialize thread pool with specified amount of fixed threads. +ZPL_DEF void zpl_jobs_init(zpl_jobs_system *pool, zpl_allocator a, zpl_u32 max_threads); - //! Initialize thread pool with specified amount of fixed threads and custom job limit. - ZPL_DEF void zpl_jobs_init_with_limit(zpl_jobs_system *pool, zpl_allocator a, zpl_u32 max_threads, zpl_u32 max_jobs); +//! Initialize thread pool with specified amount of fixed threads and custom job limit. +ZPL_DEF void zpl_jobs_init_with_limit(zpl_jobs_system *pool, zpl_allocator a, zpl_u32 max_threads, zpl_u32 max_jobs); - //! Release the resources use by thread pool. - ZPL_DEF void zpl_jobs_free(zpl_jobs_system *pool); +//! Release the resources use by thread pool. +ZPL_DEF void zpl_jobs_free(zpl_jobs_system *pool); - //! Enqueue a job with specified data and custom priority. - ZPL_DEF zpl_b32 zpl_jobs_enqueue_with_priority(zpl_jobs_system *pool, zpl_jobs_proc proc, void *data, zpl_jobs_priority priority); +//! Enqueue a job with specified data and custom priority. +ZPL_DEF zpl_b32 zpl_jobs_enqueue_with_priority(zpl_jobs_system *pool, zpl_jobs_proc proc, void *data, zpl_jobs_priority priority); - //! Enqueue a job with specified data. - ZPL_DEF zpl_b32 zpl_jobs_enqueue(zpl_jobs_system *pool, zpl_jobs_proc proc, void *data); +//! Enqueue a job with specified data. +ZPL_DEF zpl_b32 zpl_jobs_enqueue(zpl_jobs_system *pool, zpl_jobs_proc proc, void *data); - //! Check if the work queue is empty. - ZPL_DEF zpl_b32 zpl_jobs_empty(zpl_jobs_system *pool, zpl_jobs_priority priority); +//! Check if the work queue is empty. +ZPL_DEF zpl_b32 zpl_jobs_empty(zpl_jobs_system *pool, zpl_jobs_priority priority); - ZPL_DEF zpl_b32 zpl_jobs_empty_all(zpl_jobs_system *pool); - ZPL_DEF zpl_b32 zpl_jobs_full_all(zpl_jobs_system *pool); +ZPL_DEF zpl_b32 zpl_jobs_empty_all(zpl_jobs_system *pool); +ZPL_DEF zpl_b32 zpl_jobs_full_all(zpl_jobs_system *pool); - //! Check if the work queue is full. - ZPL_DEF zpl_b32 zpl_jobs_full(zpl_jobs_system *pool, zpl_jobs_priority priority); +//! Check if the work queue is full. +ZPL_DEF zpl_b32 zpl_jobs_full(zpl_jobs_system *pool, zpl_jobs_priority priority); - //! Check if all workers are done. - ZPL_DEF zpl_b32 zpl_jobs_done(zpl_jobs_system *pool); +//! Check if all workers are done. +ZPL_DEF zpl_b32 zpl_jobs_done(zpl_jobs_system *pool); - //! Process all jobs and check all threads. Should be called by Main Thread in a tight loop. - ZPL_DEF zpl_b32 zpl_jobs_process(zpl_jobs_system *pool); +//! Process all jobs and check all threads. Should be called by Main Thread in a tight loop. +ZPL_DEF zpl_b32 zpl_jobs_process(zpl_jobs_system *pool); - ZPL_END_C_DECLS +ZPL_END_C_DECLS # endif # if defined(ZPL_MODULE_COROUTINES) - // file: header/coroutines.h +// file: header/coroutines.h - /** @file coroutines.c - @brief Coroutines module - @defgroup misc Coroutines module +/** @file coroutines.c +@brief Coroutines module +@defgroup misc Coroutines module - This module implements co-routines feature for C99. + This module implements co-routines feature for C99. - @{ - */ - /* - See test/coroutines.c for an example usage - */ + @{ + */ +/* + See test/coroutines.c for an example usage + */ - ZPL_BEGIN_C_DECLS +ZPL_BEGIN_C_DECLS - #ifndef ZPL_CO_ARG_STACK_CAPACITY - #define ZPL_CO_ARG_STACK_CAPACITY 128 - #endif +#ifndef ZPL_CO_ARG_STACK_CAPACITY +#define ZPL_CO_ARG_STACK_CAPACITY 128 +#endif - typedef enum { - ZPL_CO_READY, - ZPL_CO_ENQUEUED, - ZPL_CO_RUNNING, - ZPL_CO_WAITING, - ZPL_CO_DEAD, - } zpl_co_status; +typedef enum { + ZPL_CO_READY, + ZPL_CO_ENQUEUED, + ZPL_CO_RUNNING, + ZPL_CO_WAITING, + ZPL_CO_DEAD, +} zpl_co_status; - struct zpl_co; +struct zpl_co; - typedef void (*zpl_co_proc)(struct zpl_co *co); +typedef void (*zpl_co_proc)(struct zpl_co *co); - typedef struct zpl_co { - zpl_atomic32 status; - zpl_co_proc f; - void *data; // overwritten internally, use inside of co-routines - void *data_stack[ZPL_CO_ARG_STACK_CAPACITY]; - zpl_i32 data_read_idx, data_write_idx; - zpl_atomic32 resume, push_arg; - } zpl_co; +typedef struct zpl_co { + zpl_atomic32 status; + zpl_co_proc f; + void *data; // overwritten internally, use inside of co-routines + void *data_stack[ZPL_CO_ARG_STACK_CAPACITY]; + zpl_i32 data_read_idx, data_write_idx; + zpl_atomic32 resume, push_arg; +} zpl_co; - // These methods are used to initialize the co-routine subsystem +// These methods are used to initialize the co-routine subsystem - /** - * Initializes the coroutines subsystem - * @param a Memory allocator to be used - * @param max_threads Maximum amount of threads to use for coroutines execution - */ - ZPL_DEF void zpl_co_init(zpl_allocator a, zpl_u32 max_threads); +/** + * Initializes the coroutines subsystem + * @param a Memory allocator to be used + * @param max_threads Maximum amount of threads to use for coroutines execution + */ +ZPL_DEF void zpl_co_init(zpl_allocator a, zpl_u32 max_threads); - /** - * Destroys the coroutines subsystem - * - * IMPORTANT: This is a blocking method that waits until all the coroutines are finished. - * Please, make sure your coroutines are correctly designed, so that you - * won't end up in an infinite loop. - */ - ZPL_DEF void zpl_co_destroy(void); +/** + * Destroys the coroutines subsystem + * + * IMPORTANT: This is a blocking method that waits until all the coroutines are finished. + * Please, make sure your coroutines are correctly designed, so that you + * won't end up in an infinite loop. + */ +ZPL_DEF void zpl_co_destroy(void); - // These methods are used by the host to create and run/resume co-routines - // Make sure the co-routine subsystem is initialized first! +// These methods are used by the host to create and run/resume co-routines +// Make sure the co-routine subsystem is initialized first! - /** - * Create a paused coroutine - * @param co Coroutine reference - * @param f Coroutine method - */ - ZPL_DEF void zpl_co_make(zpl_co *co, zpl_co_proc f); +/** + * Create a paused coroutine + * @param co Coroutine reference + * @param f Coroutine method + */ +ZPL_DEF void zpl_co_make(zpl_co *co, zpl_co_proc f); - /** - * Starts/Resumes a coroutine execution. - * - * IMPORTANT: Data you pass is stored in a stack of up to ZPL_CO_ARG_STACK_CAPACITY. - * This means that you can cause stack corruption if you - * call 'zpl_co_resume' with data passed (ZPL_CO_ARG_STACK_CAPACITY+1) times. - * Raise the number by defining ZPL_CO_ARG_STACK_CAPACITY if required. - * - * @param co Coroutine - * @param data Data we want to pass (or NULL) - */ - ZPL_DEF void zpl_co_resume(zpl_co *co, void *data); +/** + * Starts/Resumes a coroutine execution. + * + * IMPORTANT: Data you pass is stored in a stack of up to ZPL_CO_ARG_STACK_CAPACITY. + * This means that you can cause stack corruption if you + * call 'zpl_co_resume' with data passed (ZPL_CO_ARG_STACK_CAPACITY+1) times. + * Raise the number by defining ZPL_CO_ARG_STACK_CAPACITY if required. + * + * @param co Coroutine + * @param data Data we want to pass (or NULL) + */ +ZPL_DEF void zpl_co_resume(zpl_co *co, void *data); - /** - * Is a coroutine running at the moment? - * @param co Coroutine - * @return - */ - ZPL_DEF_INLINE zpl_b32 zpl_co_running(zpl_co *co); +/** + * Is a coroutine running at the moment? + * @param co Coroutine + * @return + */ +ZPL_DEF_INLINE zpl_b32 zpl_co_running(zpl_co *co); - /** - * Is a coroutine already finished? - * @param co Coroutine - * @return - */ - ZPL_DEF_INLINE zpl_b32 zpl_co_finished(zpl_co *co); +/** + * Is a coroutine already finished? + * @param co Coroutine + * @return + */ +ZPL_DEF_INLINE zpl_b32 zpl_co_finished(zpl_co *co); - /** - * Is coroutine waiting? (in yield state) - * @param co Coroutine - * @return - */ - ZPL_DEF_INLINE zpl_b32 zpl_co_waiting(zpl_co *co); +/** + * Is coroutine waiting? (in yield state) + * @param co Coroutine + * @return + */ +ZPL_DEF_INLINE zpl_b32 zpl_co_waiting(zpl_co *co); - // This method is used by the co-routine to await execution - // +// This method is used by the co-routine to await execution +// - /** - * Yield the coroutine. - * - * IMPORTANT: Only to be used by the coroutine!! - * @param co Coroutine - */ - ZPL_DEF void zpl_co_yield(zpl_co *co); +/** + * Yield the coroutine. + * + * IMPORTANT: Only to be used by the coroutine!! + * @param co Coroutine + */ +ZPL_DEF void zpl_co_yield(zpl_co *co); - //! @} +//! @} - ZPL_IMPL_INLINE zpl_b32 zpl_co_running(zpl_co *co) { - return zpl_atomic32_load(&co->status) == ZPL_CO_RUNNING; - } +ZPL_IMPL_INLINE zpl_b32 zpl_co_running(zpl_co *co) { + return zpl_atomic32_load(&co->status) == ZPL_CO_RUNNING; +} - ZPL_IMPL_INLINE zpl_b32 zpl_co_finished(zpl_co *co) { - return zpl_atomic32_load(&co->status) == ZPL_CO_DEAD; - } +ZPL_IMPL_INLINE zpl_b32 zpl_co_finished(zpl_co *co) { + return zpl_atomic32_load(&co->status) == ZPL_CO_DEAD; +} - ZPL_IMPL_INLINE zpl_b32 zpl_co_waiting(zpl_co *co) { - return zpl_atomic32_load(&co->resume) == 0; - } +ZPL_IMPL_INLINE zpl_b32 zpl_co_waiting(zpl_co *co) { + return zpl_atomic32_load(&co->resume) == 0; +} - ZPL_END_C_DECLS +ZPL_END_C_DECLS # endif #else # if !defined(zpl_thread_local) @@ -7910,10139 +7908,10139 @@ License: #endif #if defined(ZPL_MODULE_ESSENTIALS) - // file: source/essentials/debug.c - - - ZPL_BEGIN_C_DECLS - - void zpl_assert_handler(char const *condition, char const *file, zpl_i32 line, char const *msg, ...) { - zpl__printf_err("%s:(%d): Assert Failure: ", file, line); - - if (condition) zpl__printf_err("`%s` ", condition); - - if (msg) { - va_list va; - va_start(va, msg); - zpl__printf_err_va(msg, va); - va_end(va); - } - - zpl__printf_err("%s", "\n"); - } - - zpl_i32 zpl_assert_crash(char const *condition) { - ZPL_PANIC(condition); - return 0; - } - - #if defined(ZPL_SYSTEM_UNIX) || defined(ZPL_SYSTEM_MACOS) - # include - #endif - - #if defined(ZPL_SYSTEM_WINDOWS) - void zpl_exit(zpl_u32 code) { ExitProcess(code); } - #else - # include - void zpl_exit(zpl_u32 code) { exit(code); } - #endif - - ZPL_END_C_DECLS - // file: source/essentials/memory.c - - - #include - - ZPL_BEGIN_C_DECLS - - - void zpl_memswap(void *i, void *j, zpl_isize size) { - if (i == j) return; - - if (size == 4) { - zpl_swap(zpl_u32, *cast(zpl_u32 *) i, *cast(zpl_u32 *) j); - } else if (size == 8) { - zpl_swap(zpl_u64, *cast(zpl_u64 *) i, *cast(zpl_u64 *) j); - } else if (size < 8) { - zpl_u8 *a = cast(zpl_u8 *) i; - zpl_u8 *b = cast(zpl_u8 *) j; - if (a != b) { - while (size--) { zpl_swap(zpl_u8, *a++, *b++); } - } - } else { - char buffer[256]; - - while (size > zpl_size_of(buffer)) { - zpl_memswap(i, j, zpl_size_of(buffer)); - i = zpl_pointer_add(i, zpl_size_of(buffer)); - j = zpl_pointer_add(j, zpl_size_of(buffer)); - size -= zpl_size_of(buffer); - } - - zpl_memcopy(buffer, i, size); - zpl_memcopy(i, j, size); - zpl_memcopy(j, buffer, size); - } - } - - void const *zpl_memchr(void const *data, zpl_u8 c, zpl_isize n) { - zpl_u8 const *s = cast(zpl_u8 const *) data; - while ((cast(zpl_uintptr) s & (sizeof(zpl_usize) - 1)) && n && *s != c) { - s++; - n--; - } - if (n && *s != c) { - zpl_isize const *w; - zpl_isize k = ZPL__ONES * c; - w = cast(zpl_isize const *) s; - while (n >= zpl_size_of(zpl_isize) && !ZPL__HAS_ZERO(*w ^ k)) { - w++; - n -= zpl_size_of(zpl_isize); - } - s = cast(zpl_u8 const *) w; - while (n && *s != c) { - s++; - n--; - } - } - - return n ? cast(void const *) s : NULL; - } - - void const *zpl_memrchr(void const *data, zpl_u8 c, zpl_isize n) { - zpl_u8 const *s = cast(zpl_u8 const *) data; - while (n--) { - if (s[n] == c) return cast(void const *)(s + n); - } - return NULL; - } - - void *zpl_memcopy(void *dest, void const *source, zpl_isize n) { - if (dest == NULL) { return NULL; } - - return memcpy(dest, source, n); - - // TODO: Re-work the whole method - #if 0 - #if defined(_MSC_VER) - __movsb(cast(zpl_u8 *) dest, cast(zpl_u8 *) source, n); - #elif defined(ZPL_CPU_X86) && !defined(ZPL_SYSTEM_EMSCRIPTEN) - zpl_u8 *__dest8 = cast(zpl_u8 *) dest; - zpl_u8 *__source8 = cast(zpl_u8 *) source; - __asm__ __volatile__("rep movsb" : "+D"(__dest8), "+S"(__source8), "+c"(n) : : "memory"); - #elif defined(ZPL_CPU_ARM) - return memcpy(dest, source, n); - #else - zpl_u8 *d = cast(zpl_u8 *) dest; - zpl_u8 const *s = cast(zpl_u8 const *) source; - zpl_u32 w, x; - - for (; cast(zpl_uintptr) s % 4 && n; n--) *d++ = *s++; - - if (cast(zpl_uintptr) d % 4 == 0) { - for (; n >= 16; s += 16, d += 16, n -= 16) { - *cast(zpl_u32 *)(d + 0) = *cast(zpl_u32 *)(s + 0); - *cast(zpl_u32 *)(d + 4) = *cast(zpl_u32 *)(s + 4); - *cast(zpl_u32 *)(d + 8) = *cast(zpl_u32 *)(s + 8); - *cast(zpl_u32 *)(d + 12) = *cast(zpl_u32 *)(s + 12); - } - if (n & 8) { - *cast(zpl_u32 *)(d + 0) = *cast(zpl_u32 *)(s + 0); - *cast(zpl_u32 *)(d + 4) = *cast(zpl_u32 *)(s + 4); - d += 8; - s += 8; - } - if (n & 4) { - *cast(zpl_u32 *)(d + 0) = *cast(zpl_u32 *)(s + 0); - d += 4; - s += 4; - } - if (n & 2) { - *d++ = *s++; - *d++ = *s++; - } - if (n & 1) { *d = *s; } - return dest; - } - - if (n >= 32) { - #if __BYTE_ORDER == __BIG_ENDIAN - #define LS << - #define RS >> - #else - #define LS >> - #define RS << - #endif - switch (cast(zpl_uintptr) d % 4) { - case 1: { - w = *cast(zpl_u32 *) s; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - n -= 3; - while (n > 16) { - x = *cast(zpl_u32 *)(s + 1); - *cast(zpl_u32 *)(d + 0) = (w LS 24) | (x RS 8); - w = *cast(zpl_u32 *)(s + 5); - *cast(zpl_u32 *)(d + 4) = (x LS 24) | (w RS 8); - x = *cast(zpl_u32 *)(s + 9); - *cast(zpl_u32 *)(d + 8) = (w LS 24) | (x RS 8); - w = *cast(zpl_u32 *)(s + 13); - *cast(zpl_u32 *)(d + 12) = (x LS 24) | (w RS 8); - - s += 16; - d += 16; - n -= 16; - } - } break; - case 2: { - w = *cast(zpl_u32 *) s; - *d++ = *s++; - *d++ = *s++; - n -= 2; - while (n > 17) { - x = *cast(zpl_u32 *)(s + 2); - *cast(zpl_u32 *)(d + 0) = (w LS 16) | (x RS 16); - w = *cast(zpl_u32 *)(s + 6); - *cast(zpl_u32 *)(d + 4) = (x LS 16) | (w RS 16); - x = *cast(zpl_u32 *)(s + 10); - *cast(zpl_u32 *)(d + 8) = (w LS 16) | (x RS 16); - w = *cast(zpl_u32 *)(s + 14); - *cast(zpl_u32 *)(d + 12) = (x LS 16) | (w RS 16); - - s += 16; - d += 16; - n -= 16; - } - } break; - case 3: { - w = *cast(zpl_u32 *) s; - *d++ = *s++; - n -= 1; - while (n > 18) { - x = *cast(zpl_u32 *)(s + 3); - *cast(zpl_u32 *)(d + 0) = (w LS 8) | (x RS 24); - w = *cast(zpl_u32 *)(s + 7); - *cast(zpl_u32 *)(d + 4) = (x LS 8) | (w RS 24); - x = *cast(zpl_u32 *)(s + 11); - *cast(zpl_u32 *)(d + 8) = (w LS 8) | (x RS 24); - w = *cast(zpl_u32 *)(s + 15); - *cast(zpl_u32 *)(d + 12) = (x LS 8) | (w RS 24); - - s += 16; - d += 16; - n -= 16; - } - } break; - default: break; // NOTE: Do nowt! - } - #undef LS - #undef RS - if (n & 16) { - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - } - if (n & 8) { - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - } - if (n & 4) { - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - } - if (n & 2) { - *d++ = *s++; - *d++ = *s++; - } - if (n & 1) { *d = *s; } - } - - #endif - #endif - - return dest; - } - - ZPL_END_C_DECLS - // file: source/essentials/memory_custom.c - - - #ifndef _IOSC11_SOURCE - #define _IOSC11_SOURCE - #endif - - #include - - #if defined(ZPL_SYSTEM_WINDOWS) - # include - #endif - - // include errno.h for MinGW - #if defined(ZPL_COMPILER_GCC) || (defined(ZPL_COMPILER_TINYC) && defined(ZPL_SYSTEM_WINDOWS)) - # include - #endif - - #if defined(ZPL_COMPILER_MINGW) - # ifdef __MINGW32__ - # define _aligned_malloc __mingw_aligned_malloc - # define _aligned_free __mingw_aligned_free - # endif //MINGW - #endif - - ZPL_BEGIN_C_DECLS - - char *zpl_alloc_str(zpl_allocator a, char const *str) { - return zpl_alloc_str_len(a, str, zpl__strlen(str)); - } - - //////////////////////////////////////////////////////////////// - // - // Custom Allocation - // - // - - // - // Heap Allocator - // - - #define ZPL_HEAP_STATS_MAGIC 0xDEADC0DE - - typedef struct zpl__heap_stats { - zpl_u32 magic; - zpl_isize used_memory; - zpl_isize alloc_count; - } zpl__heap_stats; - - zpl_global zpl__heap_stats zpl__heap_stats_info; - - void zpl_heap_stats_init(void) { - zpl_zero_item(&zpl__heap_stats_info); - zpl__heap_stats_info.magic = ZPL_HEAP_STATS_MAGIC; - } - zpl_isize zpl_heap_stats_used_memory(void) { - ZPL_ASSERT_MSG(zpl__heap_stats_info.magic == ZPL_HEAP_STATS_MAGIC, "zpl_heap_stats is not initialised yet, call zpl_heap_stats_init first!"); - return zpl__heap_stats_info.used_memory; - } - zpl_isize zpl_heap_stats_alloc_count(void) { - ZPL_ASSERT_MSG(zpl__heap_stats_info.magic == ZPL_HEAP_STATS_MAGIC, "zpl_heap_stats is not initialised yet, call zpl_heap_stats_init first!"); - return zpl__heap_stats_info.alloc_count; - } - void zpl_heap_stats_check(void) { - ZPL_ASSERT_MSG(zpl__heap_stats_info.magic == ZPL_HEAP_STATS_MAGIC, "zpl_heap_stats is not initialised yet, call zpl_heap_stats_init first!"); - ZPL_ASSERT(zpl__heap_stats_info.used_memory == 0); - ZPL_ASSERT(zpl__heap_stats_info.alloc_count == 0); - } - - typedef struct zpl__heap_alloc_info { - zpl_isize size; - void *physical_start; - } zpl__heap_alloc_info; - - ZPL_ALLOCATOR_PROC(zpl_heap_allocator_proc) { - void *ptr = NULL; - zpl_unused(allocator_data); - zpl_unused(old_size); - if (!alignment) alignment = ZPL_DEFAULT_MEMORY_ALIGNMENT; - - # ifdef ZPL_HEAP_ANALYSIS - zpl_isize alloc_info_size = zpl_size_of(zpl__heap_alloc_info); - zpl_isize alloc_info_remainder = (alloc_info_size % alignment); - zpl_isize track_size = zpl_max(alloc_info_size, alignment) + alloc_info_remainder; - switch (type) { - case ZPL_ALLOCATION_FREE: { - if (!old_memory) break; - zpl__heap_alloc_info *alloc_info = cast(zpl__heap_alloc_info *)old_memory - 1; - zpl__heap_stats_info.used_memory -= alloc_info->size; - zpl__heap_stats_info.alloc_count--; - old_memory = alloc_info->physical_start; - } break; - case ZPL_ALLOCATION_ALLOC: { - size += track_size; - } break; - default: break; - } - # endif - - switch (type) { - #if defined(ZPL_COMPILER_MSVC) || (defined(ZPL_COMPILER_GCC) && defined(ZPL_SYSTEM_WINDOWS)) || (defined(ZPL_COMPILER_TINYC) && defined(ZPL_SYSTEM_WINDOWS)) - case ZPL_ALLOCATION_ALLOC: - ptr = _aligned_malloc(size, alignment); - if (flags & ZPL_ALLOCATOR_FLAG_CLEAR_TO_ZERO) zpl_zero_size(ptr, size); - break; - case ZPL_ALLOCATION_FREE: _aligned_free(old_memory); break; - case ZPL_ALLOCATION_RESIZE: { - zpl_allocator a = zpl_heap_allocator(); - ptr = zpl_default_resize_align(a, old_memory, old_size, size, alignment); - } break; - - #elif defined(ZPL_SYSTEM_LINUX) && !defined(ZPL_CPU_ARM) && !defined(ZPL_COMPILER_TINYC) - case ZPL_ALLOCATION_ALLOC: { - ptr = aligned_alloc(alignment, (size + alignment - 1) & ~(alignment - 1)); - - if (flags & ZPL_ALLOCATOR_FLAG_CLEAR_TO_ZERO) { zpl_zero_size(ptr, size); } - } break; - - case ZPL_ALLOCATION_FREE: { - free(old_memory); - } break; - - case ZPL_ALLOCATION_RESIZE: { - zpl_allocator a = zpl_heap_allocator(); - ptr = zpl_default_resize_align(a, old_memory, old_size, size, alignment); - } break; - #else - case ZPL_ALLOCATION_ALLOC: { - posix_memalign(&ptr, alignment, size); - - if (flags & ZPL_ALLOCATOR_FLAG_CLEAR_TO_ZERO) { zpl_zero_size(ptr, size); } - } break; - - case ZPL_ALLOCATION_FREE: { - free(old_memory); - } break; - - case ZPL_ALLOCATION_RESIZE: { - zpl_allocator a = zpl_heap_allocator( ); - ptr = zpl_default_resize_align(a, old_memory, old_size, size, alignment); - } break; - #endif - - case ZPL_ALLOCATION_FREE_ALL: break; - } - - # ifdef ZPL_HEAP_ANALYSIS - if (type == ZPL_ALLOCATION_ALLOC) { - zpl__heap_alloc_info *alloc_info = cast(zpl__heap_alloc_info *)(cast(char *)ptr + alloc_info_remainder); - zpl_zero_item(alloc_info); - alloc_info->size = size - track_size; - alloc_info->physical_start = ptr; - ptr = cast(void*)(alloc_info + 1); - zpl__heap_stats_info.used_memory += alloc_info->size; - zpl__heap_stats_info.alloc_count++; - } - # endif - - return ptr; - } - - // - // Arena Allocator - // - - ZPL_ALLOCATOR_PROC(zpl_arena_allocator_proc) { - zpl_arena *arena = cast(zpl_arena *) allocator_data; - void *ptr = NULL; - - zpl_unused(old_size); - - switch (type) { - case ZPL_ALLOCATION_ALLOC: { - void *end = zpl_pointer_add(arena->physical_start, arena->total_allocated); - zpl_isize total_size = size + alignment; - - // NOTE: Out of memory - if (arena->total_allocated + total_size > cast(zpl_isize) arena->total_size) { - zpl__printf_err("%s", "Arena out of memory\n"); - return NULL; - } - - ptr = zpl_align_forward(end, alignment); - arena->total_allocated += total_size; - if (flags & ZPL_ALLOCATOR_FLAG_CLEAR_TO_ZERO) zpl_zero_size(ptr, size); - } break; - - case ZPL_ALLOCATION_FREE: - // NOTE: Free all at once - // Use Temp_Arena_Memory if you want to free a block - break; - - case ZPL_ALLOCATION_FREE_ALL: arena->total_allocated = 0; break; - - case ZPL_ALLOCATION_RESIZE: { - // TODO: Check if ptr is on top of stack and just extend - zpl_allocator a = zpl_arena_allocator(arena); - ptr = zpl_default_resize_align(a, old_memory, old_size, size, alignment); - } break; - } - return ptr; - } - - // - // Pool Allocator - // - - void zpl_pool_init_align(zpl_pool *pool, zpl_allocator backing, zpl_isize num_blocks, zpl_isize block_size, zpl_isize block_align) { - zpl_isize actual_block_size, pool_size, block_index; - void *data, *curr; - zpl_uintptr *end; - - zpl_zero_item(pool); - - pool->backing = backing; - pool->block_size = block_size; - pool->block_align = block_align; - pool->num_blocks = num_blocks; - - actual_block_size = block_size + block_align; - pool_size = num_blocks * actual_block_size; - - data = zpl_alloc_align(backing, pool_size, block_align); - - // NOTE: Init intrusive freelist - curr = data; - for (block_index = 0; block_index < num_blocks - 1; block_index++) { - zpl_uintptr *next = cast(zpl_uintptr *) curr; - *next = cast(zpl_uintptr) curr + actual_block_size; - curr = zpl_pointer_add(curr, actual_block_size); - } - - end = cast(zpl_uintptr *) curr; - *end = cast(zpl_uintptr) NULL; - - pool->physical_start = data; - pool->free_list = data; - } - - ZPL_ALLOCATOR_PROC(zpl_pool_allocator_proc) { - zpl_pool *pool = cast(zpl_pool *) allocator_data; - void *ptr = NULL; - - zpl_unused(old_size); - - switch (type) { - case ZPL_ALLOCATION_ALLOC: { - zpl_uintptr next_free; - ZPL_ASSERT(size == pool->block_size); - ZPL_ASSERT(alignment == pool->block_align); - ZPL_ASSERT(pool->free_list != NULL); - - next_free = *cast(zpl_uintptr *) pool->free_list; - ptr = pool->free_list; - pool->free_list = cast(void *) next_free; - pool->total_size += pool->block_size; - if (flags & ZPL_ALLOCATOR_FLAG_CLEAR_TO_ZERO) zpl_zero_size(ptr, size); - } break; - - case ZPL_ALLOCATION_FREE: { - zpl_uintptr *next; - if (old_memory == NULL) return NULL; - - next = cast(zpl_uintptr *) old_memory; - *next = cast(zpl_uintptr) pool->free_list; - pool->free_list = old_memory; - pool->total_size -= pool->block_size; - } break; - - case ZPL_ALLOCATION_FREE_ALL: { - zpl_isize actual_block_size, block_index; - void *curr; - zpl_uintptr *end; - - actual_block_size = pool->block_size + pool->block_align; - pool->total_size = 0; - - // NOTE: Init intrusive freelist - curr = pool->physical_start; - for (block_index = 0; block_index < pool->num_blocks - 1; block_index++) { - zpl_uintptr *next = cast(zpl_uintptr *) curr; - *next = cast(zpl_uintptr) curr + actual_block_size; - curr = zpl_pointer_add(curr, actual_block_size); - } - - end = cast(zpl_uintptr *) curr; - *end = cast(zpl_uintptr) NULL; - pool->free_list = pool->physical_start; - } break; - - case ZPL_ALLOCATION_RESIZE: - // NOTE: Cannot resize - ZPL_PANIC("You cannot resize something allocated by with a pool."); - break; - } - - return ptr; - } - - - // - // Scratch Memory Allocator - // - - void zpl_scratch_memory_init(zpl_scratch_memory *s, void *start, zpl_isize size) { - s->physical_start = start; - s->total_size = size; - s->alloc_point = start; - s->free_point = start; - } - - zpl_b32 zpl_scratch_memory_is_in_use(zpl_scratch_memory *s, void *ptr) { - if (s->free_point == s->alloc_point) return false; - if (s->alloc_point > s->free_point) return ptr >= s->free_point && ptr < s->alloc_point; - return ptr >= s->free_point || ptr < s->alloc_point; - } - - zpl_allocator zpl_scratch_allocator(zpl_scratch_memory *s) { - zpl_allocator a; - a.proc = zpl_scratch_allocator_proc; - a.data = s; - return a; - } - - ZPL_ALLOCATOR_PROC(zpl_scratch_allocator_proc) { - zpl_scratch_memory *s = cast(zpl_scratch_memory *) allocator_data; - void *ptr = NULL; - ZPL_ASSERT_NOT_NULL(s); - - switch (type) { - case ZPL_ALLOCATION_ALLOC: { - void *pt = s->alloc_point; - zpl_allocation_header_ev *header = cast(zpl_allocation_header_ev *) pt; - void *data = zpl_align_forward(header + 1, alignment); - void *end = zpl_pointer_add(s->physical_start, s->total_size); - - ZPL_ASSERT(alignment % 4 == 0); - size = ((size + 3) / 4) * 4; - pt = zpl_pointer_add(pt, size); - - // NOTE: Wrap around - if (pt > end) { - header->size = zpl_pointer_diff(header, end) | ZPL_ISIZE_HIGH_BIT; - pt = s->physical_start; - header = cast(zpl_allocation_header_ev *) pt; - data = zpl_align_forward(header + 1, alignment); - pt = zpl_pointer_add(pt, size); - } - - if (!zpl_scratch_memory_is_in_use(s, pt)) { - zpl_allocation_header_fill(header, pt, zpl_pointer_diff(header, pt)); - s->alloc_point = cast(zpl_u8 *) pt; - ptr = data; - } - - if (flags & ZPL_ALLOCATOR_FLAG_CLEAR_TO_ZERO) zpl_zero_size(ptr, size); - } break; - - case ZPL_ALLOCATION_FREE: { - if (old_memory) { - void *end = zpl_pointer_add(s->physical_start, s->total_size); - if (old_memory < s->physical_start || old_memory >= end) { - ZPL_ASSERT(false); - } else { - // NOTE: Mark as free - zpl_allocation_header_ev *h = zpl_allocation_header(old_memory); - ZPL_ASSERT((h->size & ZPL_ISIZE_HIGH_BIT) == 0); - h->size = h->size | ZPL_ISIZE_HIGH_BIT; - - while (s->free_point != s->alloc_point) { - zpl_allocation_header_ev *header = cast(zpl_allocation_header_ev *) s->free_point; - if ((header->size & ZPL_ISIZE_HIGH_BIT) == 0) break; - - s->free_point = zpl_pointer_add(s->free_point, h->size & (~ZPL_ISIZE_HIGH_BIT)); - if (s->free_point == end) s->free_point = s->physical_start; - } - } - } - } break; - - case ZPL_ALLOCATION_FREE_ALL: - s->alloc_point = s->physical_start; - s->free_point = s->physical_start; - break; - - case ZPL_ALLOCATION_RESIZE: - ptr = zpl_default_resize_align(zpl_scratch_allocator(s), old_memory, old_size, size, alignment); - break; - } - - return ptr; - } - - // - // Stack Memory Allocator - // - ZPL_ALLOCATOR_PROC(zpl_stack_allocator_proc) { - zpl_stack_memory *s = cast(zpl_stack_memory *) allocator_data; - void *ptr = NULL; - ZPL_ASSERT_NOT_NULL(s); - zpl_unused(old_size); - zpl_unused(flags); - - switch (type) { - case ZPL_ALLOCATION_ALLOC: { - size += ZPL_STACK_ALLOC_OFFSET; - zpl_u64 alloc_offset = s->allocated; - - void *curr = - cast(zpl_u64 *) zpl_align_forward(cast(zpl_u64 *) zpl_pointer_add(s->physical_start, s->allocated), alignment); - - if (cast(zpl_u64 *) zpl_pointer_add(curr, size) > cast(zpl_u64 *) zpl_pointer_add(s->physical_start, s->total_size)) { - if (s->backing.proc) { - void *old_start = s->physical_start; - s->physical_start = - zpl_resize_align(s->backing, s->physical_start, s->total_size, s->total_size + size, alignment); - curr = cast(zpl_u64 *) - zpl_align_forward(cast(zpl_u64 *) zpl_pointer_add(s->physical_start, s->allocated), alignment); - s->total_size = zpl_pointer_diff(old_start, s->physical_start); - } else { - ZPL_PANIC("Can not resize stack's memory! Allocator not defined!"); - } - } - - s->allocated = zpl_pointer_diff(s->physical_start, curr) + size; - - *(zpl_u64 *)curr = alloc_offset; - curr = zpl_pointer_add(curr, ZPL_STACK_ALLOC_OFFSET); - - ptr = curr; - } break; - - case ZPL_ALLOCATION_FREE: { - if (old_memory) { - void *curr = old_memory; - curr = zpl_pointer_sub(curr, ZPL_STACK_ALLOC_OFFSET); - - zpl_u64 alloc_offset = *(zpl_u64 *)curr; - s->allocated = (zpl_usize)alloc_offset; - } - } break; - - case ZPL_ALLOCATION_FREE_ALL: { - s->allocated = 0; - } break; - - case ZPL_ALLOCATION_RESIZE: { - ZPL_PANIC("You cannot resize something allocated by a stack."); - } break; - } - return ptr; - } - - ZPL_END_C_DECLS - // file: source/essentials/array.c - - - ZPL_BEGIN_C_DECLS - - ZPL_NEVER_INLINE void *zpl__array_set_capacity(void *array, zpl_isize capacity, zpl_isize element_size) { - zpl_array_header *h = ZPL_ARRAY_HEADER(array); - - ZPL_ASSERT(element_size > 0); - - if (capacity == h->capacity) return array; - - if (capacity < h->count) { - if (h->capacity < capacity) { - zpl_isize new_capacity = ZPL_ARRAY_GROW_FORMULA(h->capacity); - if (new_capacity < capacity) new_capacity = capacity; - zpl__array_set_capacity(array, new_capacity, element_size); - } - h->count = capacity; - } - - { - zpl_isize size = zpl_size_of(zpl_array_header) + element_size * capacity; - zpl_array_header *nh = cast(zpl_array_header *) zpl_alloc(h->allocator, size); - zpl_memmove(nh, h, zpl_size_of(zpl_array_header) + element_size * h->count); - nh->allocator = h->allocator; - nh->count = h->count; - nh->data = (char *)nh + 1; - nh->capacity = capacity; - zpl_free(h->allocator, h); - return nh + 1; - } - } - - ZPL_END_C_DECLS +// file: source/essentials/debug.c + + +ZPL_BEGIN_C_DECLS + +void zpl_assert_handler(char const *condition, char const *file, zpl_i32 line, char const *msg, ...) { + zpl__printf_err("%s:(%d): Assert Failure: ", file, line); + + if (condition) zpl__printf_err("`%s` ", condition); + + if (msg) { + va_list va; + va_start(va, msg); + zpl__printf_err_va(msg, va); + va_end(va); + } + + zpl__printf_err("%s", "\n"); +} + +zpl_i32 zpl_assert_crash(char const *condition) { + ZPL_PANIC(condition); + return 0; +} + +#if defined(ZPL_SYSTEM_UNIX) || defined(ZPL_SYSTEM_MACOS) +# include +#endif + +#if defined(ZPL_SYSTEM_WINDOWS) +void zpl_exit(zpl_u32 code) { ExitProcess(code); } +#else +# include +void zpl_exit(zpl_u32 code) { exit(code); } +#endif + +ZPL_END_C_DECLS +// file: source/essentials/memory.c + + +#include + +ZPL_BEGIN_C_DECLS + + +void zpl_memswap(void *i, void *j, zpl_isize size) { + if (i == j) return; + + if (size == 4) { + zpl_swap(zpl_u32, *cast(zpl_u32 *) i, *cast(zpl_u32 *) j); + } else if (size == 8) { + zpl_swap(zpl_u64, *cast(zpl_u64 *) i, *cast(zpl_u64 *) j); + } else if (size < 8) { + zpl_u8 *a = cast(zpl_u8 *) i; + zpl_u8 *b = cast(zpl_u8 *) j; + if (a != b) { + while (size--) { zpl_swap(zpl_u8, *a++, *b++); } + } + } else { + char buffer[256]; + + while (size > zpl_size_of(buffer)) { + zpl_memswap(i, j, zpl_size_of(buffer)); + i = zpl_pointer_add(i, zpl_size_of(buffer)); + j = zpl_pointer_add(j, zpl_size_of(buffer)); + size -= zpl_size_of(buffer); + } + + zpl_memcopy(buffer, i, size); + zpl_memcopy(i, j, size); + zpl_memcopy(j, buffer, size); + } +} + +void const *zpl_memchr(void const *data, zpl_u8 c, zpl_isize n) { + zpl_u8 const *s = cast(zpl_u8 const *) data; + while ((cast(zpl_uintptr) s & (sizeof(zpl_usize) - 1)) && n && *s != c) { + s++; + n--; + } + if (n && *s != c) { + zpl_isize const *w; + zpl_isize k = ZPL__ONES * c; + w = cast(zpl_isize const *) s; + while (n >= zpl_size_of(zpl_isize) && !ZPL__HAS_ZERO(*w ^ k)) { + w++; + n -= zpl_size_of(zpl_isize); + } + s = cast(zpl_u8 const *) w; + while (n && *s != c) { + s++; + n--; + } + } + + return n ? cast(void const *) s : NULL; +} + +void const *zpl_memrchr(void const *data, zpl_u8 c, zpl_isize n) { + zpl_u8 const *s = cast(zpl_u8 const *) data; + while (n--) { + if (s[n] == c) return cast(void const *)(s + n); + } + return NULL; +} + +void *zpl_memcopy(void *dest, void const *source, zpl_isize n) { + if (dest == NULL) { return NULL; } + + return memcpy(dest, source, n); + + // TODO: Re-work the whole method +#if 0 +#if defined(_MSC_VER) + __movsb(cast(zpl_u8 *) dest, cast(zpl_u8 *) source, n); +#elif defined(ZPL_CPU_X86) && !defined(ZPL_SYSTEM_EMSCRIPTEN) + zpl_u8 *__dest8 = cast(zpl_u8 *) dest; + zpl_u8 *__source8 = cast(zpl_u8 *) source; + __asm__ __volatile__("rep movsb" : "+D"(__dest8), "+S"(__source8), "+c"(n) : : "memory"); +#elif defined(ZPL_CPU_ARM) + return memcpy(dest, source, n); +#else + zpl_u8 *d = cast(zpl_u8 *) dest; + zpl_u8 const *s = cast(zpl_u8 const *) source; + zpl_u32 w, x; + + for (; cast(zpl_uintptr) s % 4 && n; n--) *d++ = *s++; + + if (cast(zpl_uintptr) d % 4 == 0) { + for (; n >= 16; s += 16, d += 16, n -= 16) { + *cast(zpl_u32 *)(d + 0) = *cast(zpl_u32 *)(s + 0); + *cast(zpl_u32 *)(d + 4) = *cast(zpl_u32 *)(s + 4); + *cast(zpl_u32 *)(d + 8) = *cast(zpl_u32 *)(s + 8); + *cast(zpl_u32 *)(d + 12) = *cast(zpl_u32 *)(s + 12); + } + if (n & 8) { + *cast(zpl_u32 *)(d + 0) = *cast(zpl_u32 *)(s + 0); + *cast(zpl_u32 *)(d + 4) = *cast(zpl_u32 *)(s + 4); + d += 8; + s += 8; + } + if (n & 4) { + *cast(zpl_u32 *)(d + 0) = *cast(zpl_u32 *)(s + 0); + d += 4; + s += 4; + } + if (n & 2) { + *d++ = *s++; + *d++ = *s++; + } + if (n & 1) { *d = *s; } + return dest; + } + + if (n >= 32) { +#if __BYTE_ORDER == __BIG_ENDIAN +#define LS << +#define RS >> +#else +#define LS >> +#define RS << +#endif + switch (cast(zpl_uintptr) d % 4) { + case 1: { + w = *cast(zpl_u32 *) s; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + n -= 3; + while (n > 16) { + x = *cast(zpl_u32 *)(s + 1); + *cast(zpl_u32 *)(d + 0) = (w LS 24) | (x RS 8); + w = *cast(zpl_u32 *)(s + 5); + *cast(zpl_u32 *)(d + 4) = (x LS 24) | (w RS 8); + x = *cast(zpl_u32 *)(s + 9); + *cast(zpl_u32 *)(d + 8) = (w LS 24) | (x RS 8); + w = *cast(zpl_u32 *)(s + 13); + *cast(zpl_u32 *)(d + 12) = (x LS 24) | (w RS 8); + + s += 16; + d += 16; + n -= 16; + } + } break; + case 2: { + w = *cast(zpl_u32 *) s; + *d++ = *s++; + *d++ = *s++; + n -= 2; + while (n > 17) { + x = *cast(zpl_u32 *)(s + 2); + *cast(zpl_u32 *)(d + 0) = (w LS 16) | (x RS 16); + w = *cast(zpl_u32 *)(s + 6); + *cast(zpl_u32 *)(d + 4) = (x LS 16) | (w RS 16); + x = *cast(zpl_u32 *)(s + 10); + *cast(zpl_u32 *)(d + 8) = (w LS 16) | (x RS 16); + w = *cast(zpl_u32 *)(s + 14); + *cast(zpl_u32 *)(d + 12) = (x LS 16) | (w RS 16); + + s += 16; + d += 16; + n -= 16; + } + } break; + case 3: { + w = *cast(zpl_u32 *) s; + *d++ = *s++; + n -= 1; + while (n > 18) { + x = *cast(zpl_u32 *)(s + 3); + *cast(zpl_u32 *)(d + 0) = (w LS 8) | (x RS 24); + w = *cast(zpl_u32 *)(s + 7); + *cast(zpl_u32 *)(d + 4) = (x LS 8) | (w RS 24); + x = *cast(zpl_u32 *)(s + 11); + *cast(zpl_u32 *)(d + 8) = (w LS 8) | (x RS 24); + w = *cast(zpl_u32 *)(s + 15); + *cast(zpl_u32 *)(d + 12) = (x LS 8) | (w RS 24); + + s += 16; + d += 16; + n -= 16; + } + } break; + default: break; // NOTE: Do nowt! + } +#undef LS +#undef RS + if (n & 16) { + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + } + if (n & 8) { + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + } + if (n & 4) { + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + } + if (n & 2) { + *d++ = *s++; + *d++ = *s++; + } + if (n & 1) { *d = *s; } + } + +#endif +#endif + + return dest; +} + +ZPL_END_C_DECLS +// file: source/essentials/memory_custom.c + + +#ifndef _IOSC11_SOURCE +#define _IOSC11_SOURCE +#endif + +#include + +#if defined(ZPL_SYSTEM_WINDOWS) +# include +#endif + +// include errno.h for MinGW +#if defined(ZPL_COMPILER_GCC) || (defined(ZPL_COMPILER_TINYC) && defined(ZPL_SYSTEM_WINDOWS)) +# include +#endif + +#if defined(ZPL_COMPILER_MINGW) +# ifdef __MINGW32__ +# define _aligned_malloc __mingw_aligned_malloc +# define _aligned_free __mingw_aligned_free +# endif //MINGW +#endif + +ZPL_BEGIN_C_DECLS + +char *zpl_alloc_str(zpl_allocator a, char const *str) { + return zpl_alloc_str_len(a, str, zpl__strlen(str)); +} + +//////////////////////////////////////////////////////////////// +// +// Custom Allocation +// +// + +// +// Heap Allocator +// + +#define ZPL_HEAP_STATS_MAGIC 0xDEADC0DE + +typedef struct zpl__heap_stats { + zpl_u32 magic; + zpl_isize used_memory; + zpl_isize alloc_count; +} zpl__heap_stats; + +zpl_global zpl__heap_stats zpl__heap_stats_info; + +void zpl_heap_stats_init(void) { + zpl_zero_item(&zpl__heap_stats_info); + zpl__heap_stats_info.magic = ZPL_HEAP_STATS_MAGIC; +} +zpl_isize zpl_heap_stats_used_memory(void) { + ZPL_ASSERT_MSG(zpl__heap_stats_info.magic == ZPL_HEAP_STATS_MAGIC, "zpl_heap_stats is not initialised yet, call zpl_heap_stats_init first!"); + return zpl__heap_stats_info.used_memory; +} +zpl_isize zpl_heap_stats_alloc_count(void) { + ZPL_ASSERT_MSG(zpl__heap_stats_info.magic == ZPL_HEAP_STATS_MAGIC, "zpl_heap_stats is not initialised yet, call zpl_heap_stats_init first!"); + return zpl__heap_stats_info.alloc_count; +} +void zpl_heap_stats_check(void) { + ZPL_ASSERT_MSG(zpl__heap_stats_info.magic == ZPL_HEAP_STATS_MAGIC, "zpl_heap_stats is not initialised yet, call zpl_heap_stats_init first!"); + ZPL_ASSERT(zpl__heap_stats_info.used_memory == 0); + ZPL_ASSERT(zpl__heap_stats_info.alloc_count == 0); +} + +typedef struct zpl__heap_alloc_info { + zpl_isize size; + void *physical_start; +} zpl__heap_alloc_info; + +ZPL_ALLOCATOR_PROC(zpl_heap_allocator_proc) { + void *ptr = NULL; + zpl_unused(allocator_data); + zpl_unused(old_size); + if (!alignment) alignment = ZPL_DEFAULT_MEMORY_ALIGNMENT; + +# ifdef ZPL_HEAP_ANALYSIS + zpl_isize alloc_info_size = zpl_size_of(zpl__heap_alloc_info); + zpl_isize alloc_info_remainder = (alloc_info_size % alignment); + zpl_isize track_size = zpl_max(alloc_info_size, alignment) + alloc_info_remainder; + switch (type) { + case ZPL_ALLOCATION_FREE: { + if (!old_memory) break; + zpl__heap_alloc_info *alloc_info = cast(zpl__heap_alloc_info *)old_memory - 1; + zpl__heap_stats_info.used_memory -= alloc_info->size; + zpl__heap_stats_info.alloc_count--; + old_memory = alloc_info->physical_start; + } break; + case ZPL_ALLOCATION_ALLOC: { + size += track_size; + } break; + default: break; + } +# endif + + switch (type) { +#if defined(ZPL_COMPILER_MSVC) || (defined(ZPL_COMPILER_GCC) && defined(ZPL_SYSTEM_WINDOWS)) || (defined(ZPL_COMPILER_TINYC) && defined(ZPL_SYSTEM_WINDOWS)) + case ZPL_ALLOCATION_ALLOC: + ptr = _aligned_malloc(size, alignment); + if (flags & ZPL_ALLOCATOR_FLAG_CLEAR_TO_ZERO) zpl_zero_size(ptr, size); + break; + case ZPL_ALLOCATION_FREE: _aligned_free(old_memory); break; + case ZPL_ALLOCATION_RESIZE: { + zpl_allocator a = zpl_heap_allocator(); + ptr = zpl_default_resize_align(a, old_memory, old_size, size, alignment); + } break; + +#elif defined(ZPL_SYSTEM_LINUX) && !defined(ZPL_CPU_ARM) && !defined(ZPL_COMPILER_TINYC) + case ZPL_ALLOCATION_ALLOC: { + ptr = aligned_alloc(alignment, (size + alignment - 1) & ~(alignment - 1)); + + if (flags & ZPL_ALLOCATOR_FLAG_CLEAR_TO_ZERO) { zpl_zero_size(ptr, size); } + } break; + + case ZPL_ALLOCATION_FREE: { + free(old_memory); + } break; + + case ZPL_ALLOCATION_RESIZE: { + zpl_allocator a = zpl_heap_allocator(); + ptr = zpl_default_resize_align(a, old_memory, old_size, size, alignment); + } break; +#else + case ZPL_ALLOCATION_ALLOC: { + posix_memalign(&ptr, alignment, size); + + if (flags & ZPL_ALLOCATOR_FLAG_CLEAR_TO_ZERO) { zpl_zero_size(ptr, size); } + } break; + + case ZPL_ALLOCATION_FREE: { + free(old_memory); + } break; + + case ZPL_ALLOCATION_RESIZE: { + zpl_allocator a = zpl_heap_allocator( ); + ptr = zpl_default_resize_align(a, old_memory, old_size, size, alignment); + } break; +#endif + + case ZPL_ALLOCATION_FREE_ALL: break; + } + +# ifdef ZPL_HEAP_ANALYSIS + if (type == ZPL_ALLOCATION_ALLOC) { + zpl__heap_alloc_info *alloc_info = cast(zpl__heap_alloc_info *)(cast(char *)ptr + alloc_info_remainder); + zpl_zero_item(alloc_info); + alloc_info->size = size - track_size; + alloc_info->physical_start = ptr; + ptr = cast(void*)(alloc_info + 1); + zpl__heap_stats_info.used_memory += alloc_info->size; + zpl__heap_stats_info.alloc_count++; + } +# endif + + return ptr; +} + +// +// Arena Allocator +// + +ZPL_ALLOCATOR_PROC(zpl_arena_allocator_proc) { + zpl_arena *arena = cast(zpl_arena *) allocator_data; + void *ptr = NULL; + + zpl_unused(old_size); + + switch (type) { + case ZPL_ALLOCATION_ALLOC: { + void *end = zpl_pointer_add(arena->physical_start, arena->total_allocated); + zpl_isize total_size = size + alignment; + + // NOTE: Out of memory + if (arena->total_allocated + total_size > cast(zpl_isize) arena->total_size) { + zpl__printf_err("%s", "Arena out of memory\n"); + return NULL; + } + + ptr = zpl_align_forward(end, alignment); + arena->total_allocated += total_size; + if (flags & ZPL_ALLOCATOR_FLAG_CLEAR_TO_ZERO) zpl_zero_size(ptr, size); + } break; + + case ZPL_ALLOCATION_FREE: + // NOTE: Free all at once + // Use Temp_Arena_Memory if you want to free a block + break; + + case ZPL_ALLOCATION_FREE_ALL: arena->total_allocated = 0; break; + + case ZPL_ALLOCATION_RESIZE: { + // TODO: Check if ptr is on top of stack and just extend + zpl_allocator a = zpl_arena_allocator(arena); + ptr = zpl_default_resize_align(a, old_memory, old_size, size, alignment); + } break; + } + return ptr; +} + +// +// Pool Allocator +// + +void zpl_pool_init_align(zpl_pool *pool, zpl_allocator backing, zpl_isize num_blocks, zpl_isize block_size, zpl_isize block_align) { + zpl_isize actual_block_size, pool_size, block_index; + void *data, *curr; + zpl_uintptr *end; + + zpl_zero_item(pool); + + pool->backing = backing; + pool->block_size = block_size; + pool->block_align = block_align; + pool->num_blocks = num_blocks; + + actual_block_size = block_size + block_align; + pool_size = num_blocks * actual_block_size; + + data = zpl_alloc_align(backing, pool_size, block_align); + + // NOTE: Init intrusive freelist + curr = data; + for (block_index = 0; block_index < num_blocks - 1; block_index++) { + zpl_uintptr *next = cast(zpl_uintptr *) curr; + *next = cast(zpl_uintptr) curr + actual_block_size; + curr = zpl_pointer_add(curr, actual_block_size); + } + + end = cast(zpl_uintptr *) curr; + *end = cast(zpl_uintptr) NULL; + + pool->physical_start = data; + pool->free_list = data; +} + +ZPL_ALLOCATOR_PROC(zpl_pool_allocator_proc) { + zpl_pool *pool = cast(zpl_pool *) allocator_data; + void *ptr = NULL; + + zpl_unused(old_size); + + switch (type) { + case ZPL_ALLOCATION_ALLOC: { + zpl_uintptr next_free; + ZPL_ASSERT(size == pool->block_size); + ZPL_ASSERT(alignment == pool->block_align); + ZPL_ASSERT(pool->free_list != NULL); + + next_free = *cast(zpl_uintptr *) pool->free_list; + ptr = pool->free_list; + pool->free_list = cast(void *) next_free; + pool->total_size += pool->block_size; + if (flags & ZPL_ALLOCATOR_FLAG_CLEAR_TO_ZERO) zpl_zero_size(ptr, size); + } break; + + case ZPL_ALLOCATION_FREE: { + zpl_uintptr *next; + if (old_memory == NULL) return NULL; + + next = cast(zpl_uintptr *) old_memory; + *next = cast(zpl_uintptr) pool->free_list; + pool->free_list = old_memory; + pool->total_size -= pool->block_size; + } break; + + case ZPL_ALLOCATION_FREE_ALL: { + zpl_isize actual_block_size, block_index; + void *curr; + zpl_uintptr *end; + + actual_block_size = pool->block_size + pool->block_align; + pool->total_size = 0; + + // NOTE: Init intrusive freelist + curr = pool->physical_start; + for (block_index = 0; block_index < pool->num_blocks - 1; block_index++) { + zpl_uintptr *next = cast(zpl_uintptr *) curr; + *next = cast(zpl_uintptr) curr + actual_block_size; + curr = zpl_pointer_add(curr, actual_block_size); + } + + end = cast(zpl_uintptr *) curr; + *end = cast(zpl_uintptr) NULL; + pool->free_list = pool->physical_start; + } break; + + case ZPL_ALLOCATION_RESIZE: + // NOTE: Cannot resize + ZPL_PANIC("You cannot resize something allocated by with a pool."); + break; + } + + return ptr; +} + + +// +// Scratch Memory Allocator +// + +void zpl_scratch_memory_init(zpl_scratch_memory *s, void *start, zpl_isize size) { + s->physical_start = start; + s->total_size = size; + s->alloc_point = start; + s->free_point = start; +} + +zpl_b32 zpl_scratch_memory_is_in_use(zpl_scratch_memory *s, void *ptr) { + if (s->free_point == s->alloc_point) return false; + if (s->alloc_point > s->free_point) return ptr >= s->free_point && ptr < s->alloc_point; + return ptr >= s->free_point || ptr < s->alloc_point; +} + +zpl_allocator zpl_scratch_allocator(zpl_scratch_memory *s) { + zpl_allocator a; + a.proc = zpl_scratch_allocator_proc; + a.data = s; + return a; +} + +ZPL_ALLOCATOR_PROC(zpl_scratch_allocator_proc) { + zpl_scratch_memory *s = cast(zpl_scratch_memory *) allocator_data; + void *ptr = NULL; + ZPL_ASSERT_NOT_NULL(s); + + switch (type) { + case ZPL_ALLOCATION_ALLOC: { + void *pt = s->alloc_point; + zpl_allocation_header_ev *header = cast(zpl_allocation_header_ev *) pt; + void *data = zpl_align_forward(header + 1, alignment); + void *end = zpl_pointer_add(s->physical_start, s->total_size); + + ZPL_ASSERT(alignment % 4 == 0); + size = ((size + 3) / 4) * 4; + pt = zpl_pointer_add(pt, size); + + // NOTE: Wrap around + if (pt > end) { + header->size = zpl_pointer_diff(header, end) | ZPL_ISIZE_HIGH_BIT; + pt = s->physical_start; + header = cast(zpl_allocation_header_ev *) pt; + data = zpl_align_forward(header + 1, alignment); + pt = zpl_pointer_add(pt, size); + } + + if (!zpl_scratch_memory_is_in_use(s, pt)) { + zpl_allocation_header_fill(header, pt, zpl_pointer_diff(header, pt)); + s->alloc_point = cast(zpl_u8 *) pt; + ptr = data; + } + + if (flags & ZPL_ALLOCATOR_FLAG_CLEAR_TO_ZERO) zpl_zero_size(ptr, size); + } break; + + case ZPL_ALLOCATION_FREE: { + if (old_memory) { + void *end = zpl_pointer_add(s->physical_start, s->total_size); + if (old_memory < s->physical_start || old_memory >= end) { + ZPL_ASSERT(false); + } else { + // NOTE: Mark as free + zpl_allocation_header_ev *h = zpl_allocation_header(old_memory); + ZPL_ASSERT((h->size & ZPL_ISIZE_HIGH_BIT) == 0); + h->size = h->size | ZPL_ISIZE_HIGH_BIT; + + while (s->free_point != s->alloc_point) { + zpl_allocation_header_ev *header = cast(zpl_allocation_header_ev *) s->free_point; + if ((header->size & ZPL_ISIZE_HIGH_BIT) == 0) break; + + s->free_point = zpl_pointer_add(s->free_point, h->size & (~ZPL_ISIZE_HIGH_BIT)); + if (s->free_point == end) s->free_point = s->physical_start; + } + } + } + } break; + + case ZPL_ALLOCATION_FREE_ALL: + s->alloc_point = s->physical_start; + s->free_point = s->physical_start; + break; + + case ZPL_ALLOCATION_RESIZE: + ptr = zpl_default_resize_align(zpl_scratch_allocator(s), old_memory, old_size, size, alignment); + break; + } + + return ptr; +} + +// +// Stack Memory Allocator +// +ZPL_ALLOCATOR_PROC(zpl_stack_allocator_proc) { + zpl_stack_memory *s = cast(zpl_stack_memory *) allocator_data; + void *ptr = NULL; + ZPL_ASSERT_NOT_NULL(s); + zpl_unused(old_size); + zpl_unused(flags); + + switch (type) { + case ZPL_ALLOCATION_ALLOC: { + size += ZPL_STACK_ALLOC_OFFSET; + zpl_u64 alloc_offset = s->allocated; + + void *curr = + cast(zpl_u64 *) zpl_align_forward(cast(zpl_u64 *) zpl_pointer_add(s->physical_start, s->allocated), alignment); + + if (cast(zpl_u64 *) zpl_pointer_add(curr, size) > cast(zpl_u64 *) zpl_pointer_add(s->physical_start, s->total_size)) { + if (s->backing.proc) { + void *old_start = s->physical_start; + s->physical_start = + zpl_resize_align(s->backing, s->physical_start, s->total_size, s->total_size + size, alignment); + curr = cast(zpl_u64 *) + zpl_align_forward(cast(zpl_u64 *) zpl_pointer_add(s->physical_start, s->allocated), alignment); + s->total_size = zpl_pointer_diff(old_start, s->physical_start); + } else { + ZPL_PANIC("Can not resize stack's memory! Allocator not defined!"); + } + } + + s->allocated = zpl_pointer_diff(s->physical_start, curr) + size; + + *(zpl_u64 *)curr = alloc_offset; + curr = zpl_pointer_add(curr, ZPL_STACK_ALLOC_OFFSET); + + ptr = curr; + } break; + + case ZPL_ALLOCATION_FREE: { + if (old_memory) { + void *curr = old_memory; + curr = zpl_pointer_sub(curr, ZPL_STACK_ALLOC_OFFSET); + + zpl_u64 alloc_offset = *(zpl_u64 *)curr; + s->allocated = (zpl_usize)alloc_offset; + } + } break; + + case ZPL_ALLOCATION_FREE_ALL: { + s->allocated = 0; + } break; + + case ZPL_ALLOCATION_RESIZE: { + ZPL_PANIC("You cannot resize something allocated by a stack."); + } break; + } + return ptr; +} + +ZPL_END_C_DECLS +// file: source/essentials/array.c + + +ZPL_BEGIN_C_DECLS + +ZPL_NEVER_INLINE void *zpl__array_set_capacity(void *array, zpl_isize capacity, zpl_isize element_size) { + zpl_array_header *h = ZPL_ARRAY_HEADER(array); + + ZPL_ASSERT(element_size > 0); + + if (capacity == h->capacity) return array; + + if (capacity < h->count) { + if (h->capacity < capacity) { + zpl_isize new_capacity = ZPL_ARRAY_GROW_FORMULA(h->capacity); + if (new_capacity < capacity) new_capacity = capacity; + zpl__array_set_capacity(array, new_capacity, element_size); + } + h->count = capacity; + } + + { + zpl_isize size = zpl_size_of(zpl_array_header) + element_size * capacity; + zpl_array_header *nh = cast(zpl_array_header *) zpl_alloc(h->allocator, size); + zpl_memmove(nh, h, zpl_size_of(zpl_array_header) + element_size * h->count); + nh->allocator = h->allocator; + nh->count = h->count; + nh->data = (char *)(nh + 1); + nh->capacity = capacity; + zpl_free(h->allocator, h); + return nh + 1; + } +} + +ZPL_END_C_DECLS # if defined(ZPL_MODULE_CORE) - // file: source/core/memory_virtual.c - - //////////////////////////////////////////////////////////////// - // - // Virtual Memory - // - // - - ZPL_BEGIN_C_DECLS - - zpl_virtual_memory zpl_vm(void *data, zpl_isize size) { - zpl_virtual_memory vm; - vm.data = data; - vm.size = size; - return vm; - } - - #if defined(ZPL_SYSTEM_WINDOWS) - zpl_virtual_memory zpl_vm_alloc(void *addr, zpl_isize size) { - zpl_virtual_memory vm; - ZPL_ASSERT(size > 0); - vm.data = VirtualAlloc(addr, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); - vm.size = size; - return vm; - } - - zpl_b32 zpl_vm_free(zpl_virtual_memory vm) { - MEMORY_BASIC_INFORMATION info; - while (vm.size > 0) { - if (VirtualQuery(vm.data, &info, zpl_size_of(info)) == 0) return false; - if (info.BaseAddress != vm.data || info.AllocationBase != vm.data || info.State != MEM_COMMIT || - info.RegionSize > cast(zpl_usize) vm.size) { - return false; - } - if (VirtualFree(vm.data, 0, MEM_RELEASE) == 0) return false; - vm.data = zpl_pointer_add(vm.data, info.RegionSize); - vm.size -= info.RegionSize; - } - return true; - } - - zpl_virtual_memory zpl_vm_trim(zpl_virtual_memory vm, zpl_isize lead_size, zpl_isize size) { - zpl_virtual_memory new_vm = { 0 }; - void *ptr; - ZPL_ASSERT(vm.size >= lead_size + size); - - ptr = zpl_pointer_add(vm.data, lead_size); - - zpl_vm_free(vm); - new_vm = zpl_vm_alloc(ptr, size); - if (new_vm.data == ptr) return new_vm; - if (new_vm.data) zpl_vm_free(new_vm); - return new_vm; - } - - zpl_b32 zpl_vm_purge(zpl_virtual_memory vm) { - VirtualAlloc(vm.data, vm.size, MEM_RESET, PAGE_READWRITE); - // NOTE: Can this really fail? - return true; - } - - zpl_isize zpl_virtual_memory_page_size(zpl_isize *alignment_out) { - SYSTEM_INFO info; - GetSystemInfo(&info); - if (alignment_out) *alignment_out = info.dwAllocationGranularity; - return info.dwPageSize; - } - - #else - # include - - # ifndef MAP_ANONYMOUS - # define MAP_ANONYMOUS MAP_ANON - # endif - - zpl_virtual_memory zpl_vm_alloc(void *addr, zpl_isize size) { - zpl_virtual_memory vm; - ZPL_ASSERT(size > 0); - vm.data = mmap(addr, size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); - vm.size = size; - return vm; - } - - zpl_b32 zpl_vm_free(zpl_virtual_memory vm) { - munmap(vm.data, vm.size); - return true; - } - - zpl_virtual_memory zpl_vm_trim(zpl_virtual_memory vm, zpl_isize lead_size, zpl_isize size) { - void *ptr; - zpl_isize trail_size; - ZPL_ASSERT(vm.size >= lead_size + size); - - ptr = zpl_pointer_add(vm.data, lead_size); - trail_size = vm.size - lead_size - size; - - if (lead_size != 0) zpl_vm_free(zpl_vm(vm.data, lead_size)); - if (trail_size != 0) zpl_vm_free(zpl_vm(ptr, trail_size)); - return zpl_vm(ptr, size); - } - - zpl_b32 zpl_vm_purge(zpl_virtual_memory vm) { - int err = madvise(vm.data, vm.size, MADV_DONTNEED); - return err != 0; - } - - zpl_isize zpl_virtual_memory_page_size(zpl_isize *alignment_out) { - // TODO: Is this always true? - zpl_isize result = cast(zpl_isize) sysconf(_SC_PAGE_SIZE); - if (alignment_out) *alignment_out = result; - return result; - } - - #endif - - ZPL_END_C_DECLS - // file: source/core/string.c - - //////////////////////////////////////////////////////////////// - // - // Char things - // - // - - ZPL_BEGIN_C_DECLS - - zpl_internal zpl_isize zpl__scan_zpl_i64(const char *text, zpl_i32 base, zpl_i64 *value) { - const char *text_begin = text; - zpl_i64 result = 0; - zpl_b32 negative = false; - - if (*text == '-') { - negative = true; - text++; - } - - if (base == 16 && zpl_strncmp(text, "0x", 2) == 0) text += 2; - - for (;;) { - zpl_i64 v; - if (zpl_char_is_digit(*text)) - v = *text - '0'; - else if (base == 16 && zpl_char_is_hex_digit(*text)) - v = zpl_hex_digit_to_int(*text); - else - break; - - result *= base; - result += v; - text++; - } - - if (value) { - if (negative) result = -result; - *value = result; - } - - return (text - text_begin); - } - - zpl_internal zpl_isize zpl__scan_zpl_u64(const char *text, zpl_i32 base, zpl_u64 *value) { - const char *text_begin = text; - zpl_u64 result = 0; - - if (base == 16 && zpl_strncmp(text, "0x", 2) == 0) text += 2; - - for (;;) { - zpl_u64 v; - if (zpl_char_is_digit(*text)) - v = *text - '0'; - else if (base == 16 && zpl_char_is_hex_digit(*text)) - v = zpl_hex_digit_to_int(*text); - else { - break; - } - - result *= base; - result += v; - text++; - } - - if (value) *value = result; - - return (text - text_begin); - } - - // TODO: Make better - zpl_u64 zpl_str_to_u64(const char *str, char **end_ptr, zpl_i32 base) { - zpl_isize len; - zpl_u64 value = 0; - - if (!base) { - if ((zpl_strlen(str) > 2) && (zpl_strncmp(str, "0x", 2) == 0)) - base = 16; - else - base = 10; - } - - len = zpl__scan_zpl_u64(str, base, &value); - if (end_ptr) *end_ptr = (char *)str + len; - return value; - } - - zpl_i64 zpl_str_to_i64(const char *str, char **end_ptr, zpl_i32 base) { - zpl_isize len; - zpl_i64 value; - - if (!base) { - if ((zpl_strlen(str) > 2) && (zpl_strncmp(str, "0x", 2) == 0)) - base = 16; - else - base = 10; - } - - len = zpl__scan_zpl_i64(str, base, &value); - if (end_ptr) *end_ptr = (char *)str + len; - return value; - } - - // TODO: Are these good enough for characters? - zpl_global const char zpl__num_to_char_table[] = "0123456789" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "@$"; - - void zpl_i64_to_str(zpl_i64 value, char *string, zpl_i32 base) { - char *buf = string; - zpl_b32 negative = false; - zpl_u64 v; - - if (value < 0) { - negative = true; - value = -value; - } - - v = cast(zpl_u64) value; - if (v != 0) { - while (v > 0) { - *buf++ = zpl__num_to_char_table[v % base]; - v /= base; - } - } else { - *buf++ = '0'; - } - if (negative) *buf++ = '-'; - *buf = '\0'; - zpl_strrev(string); - } - - void zpl_u64_to_str(zpl_u64 value, char *string, zpl_i32 base) { - char *buf = string; - - if (value) { - while (value > 0) { - *buf++ = zpl__num_to_char_table[value % base]; - value /= base; - } - } else { - *buf++ = '0'; - } - *buf = '\0'; - - zpl_strrev(string); - } - - zpl_f64 zpl_str_to_f64(const char *str, char **end_ptr) { - zpl_f64 result, value, sign, scale; - zpl_i32 frac; - - while (zpl_char_is_space(*str)) { str++; } - - sign = 1.0; - if (*str == '-') { - sign = -1.0; - str++; - } else if (*str == '+') { - str++; - } - - for (value = 0.0; zpl_char_is_digit(*str); str++) { value = value * 10.0 + (*str - '0'); } - - if (*str == '.') { - zpl_f64 pow10 = 10.0; - str++; - while (zpl_char_is_digit(*str)) { - value += (*str - '0') / pow10; - pow10 *= 10.0; - str++; - } - } - - frac = 0; - scale = 1.0; - if ((*str == 'e') || (*str == 'E')) { - zpl_u32 exp; - - str++; - if (*str == '-') { - frac = 1; - str++; - } else if (*str == '+') { - str++; - } - - for (exp = 0; zpl_char_is_digit(*str); str++) { exp = exp * 10 + (*str - '0'); } - if (exp > 308) exp = 308; - - while (exp >= 50) { - scale *= 1e50; - exp -= 50; - } - while (exp >= 8) { - scale *= 1e8; - exp -= 8; - } - while (exp > 0) { - scale *= 10.0; - exp -= 1; - } - } - - result = sign * (frac ? (value / scale) : (value * scale)); - - if (end_ptr) *end_ptr = cast(char *) str; - - return result; - } - - - - //////////////////////////////////////////////////////////////// - // - // Windows UTF-8 Handling - // - // - - zpl_u16 *zpl_utf8_to_ucs2(zpl_u16 *buffer, zpl_isize len, zpl_u8 const *str) { - zpl_rune c; - zpl_isize i = 0; - len--; - while (*str) { - if (i >= len) return NULL; - if (!(*str & 0x80)) { - buffer[i++] = *str++; - } else if ((*str & 0xe0) == 0xc0) { - if (*str < 0xc2) return NULL; - c = (*str++ & 0x1f) << 6; - if ((*str & 0xc0) != 0x80) return NULL; - buffer[i++] = cast(zpl_u16)(c + (*str++ & 0x3f)); - } else if ((*str & 0xf0) == 0xe0) { - if (*str == 0xe0 && (str[1] < 0xa0 || str[1] > 0xbf)) return NULL; - if (*str == 0xed && str[1] > 0x9f) // str[1] < 0x80 is checked below - return NULL; - c = (*str++ & 0x0f) << 12; - if ((*str & 0xc0) != 0x80) return NULL; - c += (*str++ & 0x3f) << 6; - if ((*str & 0xc0) != 0x80) return NULL; - buffer[i++] = cast(zpl_u16)(c + (*str++ & 0x3f)); - } else if ((*str & 0xf8) == 0xf0) { - if (*str > 0xf4) return NULL; - if (*str == 0xf0 && (str[1] < 0x90 || str[1] > 0xbf)) return NULL; - if (*str == 0xf4 && str[1] > 0x8f) // str[1] < 0x80 is checked below - return NULL; - c = (*str++ & 0x07) << 18; - if ((*str & 0xc0) != 0x80) return NULL; - c += (*str++ & 0x3f) << 12; - if ((*str & 0xc0) != 0x80) return NULL; - c += (*str++ & 0x3f) << 6; - if ((*str & 0xc0) != 0x80) return NULL; - c += (*str++ & 0x3f); - // UTF-8 encodings of values used in surrogate pairs are invalid - if ((c & 0xfffff800) == 0xd800) return NULL; - if (c >= 0x10000) { - c -= 0x10000; - if (i + 2 > len) return NULL; - buffer[i++] = 0xd800 | (0x3ff & (c >> 10)); - buffer[i++] = 0xdc00 | (0x3ff & (c)); - } - } else { - return NULL; - } - } - buffer[i] = 0; - return buffer; - } - - zpl_u8 *zpl_ucs2_to_utf8(zpl_u8 *buffer, zpl_isize len, zpl_u16 const *str) { - zpl_isize i = 0; - len--; - while (*str) { - if (*str < 0x80) { - if (i + 1 > len) return NULL; - buffer[i++] = (char)*str++; - } else if (*str < 0x800) { - if (i + 2 > len) return NULL; - buffer[i++] = cast(char)(0xc0 + (*str >> 6)); - buffer[i++] = cast(char)(0x80 + (*str & 0x3f)); - str += 1; - } else if (*str >= 0xd800 && *str < 0xdc00) { - zpl_rune c; - if (i + 4 > len) return NULL; - c = ((str[0] - 0xd800) << 10) + ((str[1]) - 0xdc00) + 0x10000; - buffer[i++] = cast(char)(0xf0 + (c >> 18)); - buffer[i++] = cast(char)(0x80 + ((c >> 12) & 0x3f)); - buffer[i++] = cast(char)(0x80 + ((c >> 6) & 0x3f)); - buffer[i++] = cast(char)(0x80 + ((c)&0x3f)); - str += 2; - } else if (*str >= 0xdc00 && *str < 0xe000) { - return NULL; - } else { - if (i + 3 > len) return NULL; - buffer[i++] = 0xe0 + (*str >> 12); - buffer[i++] = 0x80 + ((*str >> 6) & 0x3f); - buffer[i++] = 0x80 + ((*str) & 0x3f); - str += 1; - } - } - buffer[i] = 0; - return buffer; - } - - zpl_u16 *zpl_utf8_to_ucs2_buf(zpl_u8 const *str) { // NOTE: Uses locally persisting buffer - zpl_local_persist zpl_u16 buf[4096]; - return zpl_utf8_to_ucs2(buf, zpl_count_of(buf), str); - } - - zpl_u8 *zpl_ucs2_to_utf8_buf(zpl_u16 const *str) { // NOTE: Uses locally persisting buffer - zpl_local_persist zpl_u8 buf[4096]; - return zpl_ucs2_to_utf8(buf, zpl_count_of(buf), str); - } - - zpl_global zpl_u8 const zpl__utf8_first[256] = { - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x00-0x0F - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x10-0x1F - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x20-0x2F - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x30-0x3F - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x40-0x4F - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x50-0x5F - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x60-0x6F - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x70-0x7F - 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0x80-0x8F - 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0x90-0x9F - 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xA0-0xAF - 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xB0-0xBF - 0xf1, 0xf1, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, // 0xC0-0xCF - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, // 0xD0-0xDF - 0x13, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x23, 0x03, 0x03, // 0xE0-0xEF - 0x34, 0x04, 0x04, 0x04, 0x44, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xF0-0xFF - }; - - - typedef struct zpl_utf8_accept_range { - zpl_u8 lo, hi; - } zpl_utf8_accept_range; - - zpl_global zpl_utf8_accept_range const zpl__utf8_accept_ranges[] = { - { 0x80, 0xbf }, { 0xa0, 0xbf }, { 0x80, 0x9f }, { 0x90, 0xbf }, { 0x80, 0x8f }, - }; - - zpl_isize zpl_utf8_decode(zpl_u8 const *str, zpl_isize str_len, zpl_rune *codepoint_out) { - - zpl_isize width = 0; - zpl_rune codepoint = ZPL_RUNE_INVALID; - - if (str_len > 0) { - zpl_u8 s0 = str[0]; - zpl_u8 x = zpl__utf8_first[s0], sz; - zpl_u8 b1, b2, b3; - zpl_utf8_accept_range accept; - if (x >= 0xf0) { - zpl_rune mask = (cast(zpl_rune) x << 31) >> 31; - codepoint = (cast(zpl_rune) s0 & (~mask)) | (ZPL_RUNE_INVALID & mask); - width = 1; - goto end; - } - if (s0 < 0x80) { - codepoint = s0; - width = 1; - goto end; - } - - sz = x & 7; - accept = zpl__utf8_accept_ranges[x >> 4]; - if (str_len < sz) goto invalid_codepoint; - - b1 = str[1]; - if (b1 < accept.lo || accept.hi < b1) goto invalid_codepoint; - - if (sz == 2) { - codepoint = (cast(zpl_rune) s0 & 0x1f) << 6 | (cast(zpl_rune) b1 & 0x3f); - width = 2; - goto end; - } - - b2 = str[2]; - if (!zpl_is_between(b2, 0x80, 0xbf)) goto invalid_codepoint; - - if (sz == 3) { - codepoint = (cast(zpl_rune) s0 & 0x1f) << 12 | (cast(zpl_rune) b1 & 0x3f) << 6 | (cast(zpl_rune) b2 & 0x3f); - width = 3; - goto end; - } - - b3 = str[3]; - if (!zpl_is_between(b3, 0x80, 0xbf)) goto invalid_codepoint; - - codepoint = (cast(zpl_rune) s0 & 0x07) << 18 | (cast(zpl_rune) b1 & 0x3f) << 12 | (cast(zpl_rune) b2 & 0x3f) << 6 | - (cast(zpl_rune) b3 & 0x3f); - width = 4; - goto end; - - invalid_codepoint: - codepoint = ZPL_RUNE_INVALID; - width = 1; - } - - end: - if (codepoint_out) *codepoint_out = codepoint; - return width; - } - - zpl_isize zpl_utf8_codepoint_size(zpl_u8 const *str, zpl_isize str_len) { - zpl_isize i = 0; - for (; i < str_len && str[i]; i++) { - if ((str[i] & 0xc0) != 0x80) break; - } - return i + 1; - } - - zpl_isize zpl_utf8_encode_rune(zpl_u8 buf[4], zpl_rune r) { - zpl_u32 i = cast(zpl_u32) r; - zpl_u8 mask = 0x3f; - if (i <= (1 << 7) - 1) { - buf[0] = cast(zpl_u8) r; - return 1; - } - if (i <= (1 << 11) - 1) { - buf[0] = 0xc0 | cast(zpl_u8)(r >> 6); - buf[1] = 0x80 | (cast(zpl_u8)(r) & mask); - return 2; - } - - // Invalid or Surrogate range - if (i > ZPL_RUNE_MAX || zpl_is_between(i, 0xd800, 0xdfff)) { - r = ZPL_RUNE_INVALID; - - buf[0] = 0xe0 | cast(zpl_u8)(r >> 12); - buf[1] = 0x80 | (cast(zpl_u8)(r >> 6) & mask); - buf[2] = 0x80 | (cast(zpl_u8)(r) & mask); - return 3; - } - - if (i <= (1 << 16) - 1) { - buf[0] = 0xe0 | cast(zpl_u8)(r >> 12); - buf[1] = 0x80 | (cast(zpl_u8)(r >> 6) & mask); - buf[2] = 0x80 | (cast(zpl_u8)(r) & mask); - return 3; - } - - buf[0] = 0xf0 | cast(zpl_u8)(r >> 18); - buf[1] = 0x80 | (cast(zpl_u8)(r >> 12) & mask); - buf[2] = 0x80 | (cast(zpl_u8)(r >> 6) & mask); - buf[3] = 0x80 | (cast(zpl_u8)(r) & mask); - return 4; - } - - ZPL_END_C_DECLS - // file: source/core/stringlib.c - - - ZPL_BEGIN_C_DECLS - - zpl_string zpl_string_make_reserve(zpl_allocator a, zpl_isize capacity) { - zpl_isize header_size = zpl_size_of(zpl_string_header); - void *ptr = zpl_alloc(a, header_size + capacity + 1); - - zpl_string str; - zpl_string_header *header; - - if (ptr == NULL) return NULL; - zpl_zero_size(ptr, header_size + capacity + 1); - - str = cast(char *) ptr + header_size; - header = ZPL_STRING_HEADER(str); - header->allocator = a; - header->length = 0; - header->capacity = capacity; - str[capacity] = '\0'; - - return str; - } - - - zpl_string zpl_string_make_length(zpl_allocator a, void const *init_str, zpl_isize num_bytes) { - zpl_isize header_size = zpl_size_of(zpl_string_header); - void *ptr = zpl_alloc(a, header_size + num_bytes + 1); - - zpl_string str; - zpl_string_header *header; - - if (ptr == NULL) return NULL; - if (!init_str) zpl_zero_size(ptr, header_size + num_bytes + 1); - - str = cast(char *) ptr + header_size; - header = ZPL_STRING_HEADER(str); - header->allocator = a; - header->length = num_bytes; - header->capacity = num_bytes; - if (num_bytes && init_str) zpl_memcopy(str, init_str, num_bytes); - str[num_bytes] = '\0'; - - return str; - } - - zpl_string zpl_string_sprintf_buf(zpl_allocator a, const char *fmt, ...) { - zpl_local_persist zpl_thread_local char buf[ZPL_PRINTF_MAXLEN] = { 0 }; - va_list va; - va_start(va, fmt); - zpl_snprintf_va(buf, ZPL_PRINTF_MAXLEN, fmt, va); - va_end(va); - - return zpl_string_make(a, buf); - } - - zpl_string zpl_string_sprintf(zpl_allocator a, char *buf, zpl_isize num_bytes, const char *fmt, ...) { - va_list va; - va_start(va, fmt); - zpl_snprintf_va(buf, num_bytes, fmt, va); - va_end(va); - - return zpl_string_make(a, buf); - } - - zpl_string zpl_string_append_length(zpl_string str, void const *other, zpl_isize other_len) { - if (other_len > 0) { - zpl_isize curr_len = zpl_string_length(str); - - str = zpl_string_make_space_for(str, other_len); - if (str == NULL) return NULL; - - zpl_memcopy(str + curr_len, other, other_len); - str[curr_len + other_len] = '\0'; - zpl__set_string_length(str, curr_len + other_len); - } - return str; - } - - ZPL_ALWAYS_INLINE zpl_string zpl_string_appendc(zpl_string str, const char *other) { - return zpl_string_append_length(str, other, zpl_strlen(other)); - } - - ZPL_ALWAYS_INLINE zpl_string zpl_string_join(zpl_allocator a, const char **parts, zpl_isize count, const char *glue) { - zpl_string ret; - zpl_isize i; - - ret = zpl_string_make(a, NULL); - - for (i=0; i= add_len) { - return str; - } else { - zpl_isize new_len, old_size, new_size; - void *ptr, *new_ptr; - zpl_allocator a = ZPL_STRING_HEADER(str)->allocator; - zpl_string_header *header; - - new_len = zpl_string_length(str) + add_len; - ptr = ZPL_STRING_HEADER(str); - old_size = zpl_size_of(zpl_string_header) + zpl_string_length(str) + 1; - new_size = zpl_size_of(zpl_string_header) + new_len + 1; - - new_ptr = zpl_resize(a, ptr, old_size, new_size); - if (new_ptr == NULL) return NULL; - - header = cast(zpl_string_header *) new_ptr; - header->allocator = a; - - str = cast(zpl_string)(header + 1); - zpl__set_string_capacity(str, new_len); - - return str; - } - } - - zpl_isize zpl_string_allocation_size(zpl_string const str) { - zpl_isize cap = zpl_string_capacity(str); - return zpl_size_of(zpl_string_header) + cap; - } - - zpl_b32 zpl_string_are_equal(zpl_string const lhs, zpl_string const rhs) { - zpl_isize lhs_len, rhs_len, i; - lhs_len = zpl_string_length(lhs); - rhs_len = zpl_string_length(rhs); - if (lhs_len != rhs_len) return false; - - for (i = 0; i < lhs_len; i++) { - if (lhs[i] != rhs[i]) return false; - } - - return true; - } - - zpl_string zpl_string_trim(zpl_string str, const char *cut_set) { - char *start, *end, *start_pos, *end_pos; - zpl_isize len; - - start_pos = start = str; - end_pos = end = str + zpl_string_length(str) - 1; - - while (start_pos <= end && zpl_char_first_occurence(cut_set, *start_pos)) start_pos++; - while (end_pos > start_pos && zpl_char_first_occurence(cut_set, *end_pos)) end_pos--; - - len = cast(zpl_isize)((start_pos > end_pos) ? 0 : ((end_pos - start_pos) + 1)); - - if (str != start_pos) zpl_memmove(str, start_pos, len); - str[len] = '\0'; - - zpl__set_string_length(str, len); - - return str; - } - - zpl_string zpl_string_append_rune(zpl_string str, zpl_rune r) { - if (r >= 0) { - zpl_u8 buf[8] = { 0 }; - zpl_isize len = zpl_utf8_encode_rune(buf, r); - return zpl_string_append_length(str, buf, len); - } - - return str; - } - - zpl_string zpl_string_append_fmt(zpl_string str, const char *fmt, ...) { - zpl_isize res; - char buf[ZPL_PRINTF_MAXLEN] = { 0 }; - va_list va; - va_start(va, fmt); - res = zpl_snprintf_va(buf, zpl_count_of(buf) - 1, fmt, va) - 1; - va_end(va); - return zpl_string_append_length(str, buf, res); - } - - ZPL_END_C_DECLS - // file: source/core/file.c - - - //////////////////////////////////////////////////////////////// - // - // File Handling - // - // - #include - - #ifdef ZPL_SYSTEM_MACOS - # include - #endif - - #ifdef ZPL_SYSTEM_CYGWIN - # include - #endif - - #if defined(ZPL_SYSTEM_WINDOWS) && !defined(ZPL_COMPILER_GCC) - #include - #endif - - ZPL_BEGIN_C_DECLS - - #if defined(ZPL_SYSTEM_WINDOWS) || defined (ZPL_SYSTEM_CYGWIN) - - zpl_internal wchar_t *zpl__alloc_utf8_to_ucs2(zpl_allocator a, char const *text, zpl_isize *w_len_) { - wchar_t *w_text = NULL; - zpl_isize len = 0, w_len = 0, w_len1 = 0; - if (text == NULL) { - if (w_len_) *w_len_ = w_len; - return NULL; - } - len = zpl_strlen(text); - if (len == 0) { - if (w_len_) *w_len_ = w_len; - return NULL; - } - w_len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, text, cast(int) len, NULL, 0); - if (w_len == 0) { - if (w_len_) *w_len_ = w_len; - return NULL; - } - w_text = zpl_alloc_array(a, wchar_t, w_len + 1); - w_len1 = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, text, cast(int) len, w_text, cast(int) w_len); - if (w_len1 == 0) { - zpl_free(a, w_text); - if (w_len_) *w_len_ = 0; - return NULL; - } - w_text[w_len] = 0; - if (w_len_) *w_len_ = w_len; - return w_text; - } - - zpl_internal ZPL_FILE_SEEK_PROC(zpl__win32_file_seek) { - LARGE_INTEGER li_offset; - li_offset.QuadPart = offset; - if (!SetFilePointerEx(fd.p, li_offset, &li_offset, whence)) { return false; } - - if (new_offset) *new_offset = li_offset.QuadPart; - return true; - } - - zpl_internal ZPL_FILE_READ_AT_PROC(zpl__win32_file_read) { - zpl_unused(stop_at_newline); - zpl_b32 result = false; - zpl__win32_file_seek(fd, offset, ZPL_SEEK_WHENCE_BEGIN, NULL); - DWORD size_ = cast(DWORD)(size > ZPL_I32_MAX ? ZPL_I32_MAX : size); - DWORD bytes_read_; - if (ReadFile(fd.p, buffer, size_, &bytes_read_, NULL)) { - if (bytes_read) *bytes_read = bytes_read_; - result = true; - } - - return result; - } - - zpl_internal ZPL_FILE_WRITE_AT_PROC(zpl__win32_file_write) { - DWORD size_ = cast(DWORD)(size > ZPL_I32_MAX ? ZPL_I32_MAX : size); - DWORD bytes_written_; - zpl__win32_file_seek(fd, offset, ZPL_SEEK_WHENCE_BEGIN, NULL); - if (WriteFile(fd.p, buffer, size_, &bytes_written_, NULL)) { - if (bytes_written) *bytes_written = bytes_written_; - return true; - } - return false; - } - - zpl_internal ZPL_FILE_CLOSE_PROC(zpl__win32_file_close) { CloseHandle(fd.p); } - - zpl_file_operations const zpl_default_file_operations = { zpl__win32_file_read, zpl__win32_file_write, - zpl__win32_file_seek, zpl__win32_file_close }; - - ZPL_NEVER_INLINE ZPL_FILE_OPEN_PROC(zpl__win32_file_open) { - DWORD desired_access; - DWORD creation_disposition; - void *handle; - wchar_t *w_text; - - switch (mode & ZPL_FILE_MODES) { - case ZPL_FILE_MODE_READ: - desired_access = GENERIC_READ; - creation_disposition = OPEN_EXISTING; - break; - case ZPL_FILE_MODE_WRITE: - desired_access = GENERIC_WRITE; - creation_disposition = CREATE_ALWAYS; - break; - case ZPL_FILE_MODE_APPEND: - desired_access = GENERIC_WRITE; - creation_disposition = OPEN_ALWAYS; - break; - case ZPL_FILE_MODE_READ | ZPL_FILE_MODE_RW: - desired_access = GENERIC_READ | GENERIC_WRITE; - creation_disposition = OPEN_EXISTING; - break; - case ZPL_FILE_MODE_WRITE | ZPL_FILE_MODE_RW: - desired_access = GENERIC_READ | GENERIC_WRITE; - creation_disposition = CREATE_ALWAYS; - break; - case ZPL_FILE_MODE_APPEND | ZPL_FILE_MODE_RW: - desired_access = GENERIC_READ | GENERIC_WRITE; - creation_disposition = OPEN_ALWAYS; - break; - default: ZPL_PANIC("Invalid file mode"); return ZPL_FILE_ERROR_INVALID; - } - - w_text = zpl__alloc_utf8_to_ucs2(zpl_heap_allocator( ), filename, NULL); - handle = CreateFileW(w_text, desired_access, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, creation_disposition, - FILE_ATTRIBUTE_NORMAL, NULL); - - zpl_free(zpl_heap_allocator( ), w_text); - - if (handle == INVALID_HANDLE_VALUE) { - DWORD err = GetLastError( ); - switch (err) { - case ERROR_FILE_NOT_FOUND: return ZPL_FILE_ERROR_NOT_EXISTS; - case ERROR_FILE_EXISTS: return ZPL_FILE_ERROR_EXISTS; - case ERROR_ALREADY_EXISTS: return ZPL_FILE_ERROR_EXISTS; - case ERROR_ACCESS_DENIED: return ZPL_FILE_ERROR_PERMISSION; - } - return ZPL_FILE_ERROR_INVALID; - } - - if (mode & ZPL_FILE_MODE_APPEND) { - LARGE_INTEGER offset = { 0 }; - if (!SetFilePointerEx(handle, offset, NULL, ZPL_SEEK_WHENCE_END)) { - CloseHandle(handle); - return ZPL_FILE_ERROR_INVALID; - } - } - - fd->p = handle; - *ops = zpl_default_file_operations; - return ZPL_FILE_ERROR_NONE; - } - - #else // POSIX - # include - - zpl_internal ZPL_FILE_SEEK_PROC(zpl__posix_file_seek) { - # if defined(ZPL_SYSTEM_OSX) - zpl_i64 res = lseek(fd.i, offset, whence); - # else // TODO(ZaKlaus): @fixme lseek64 - zpl_i64 res = lseek(fd.i, offset, whence); - # endif - if (res < 0) return false; - if (new_offset) *new_offset = res; - return true; - } - - zpl_internal ZPL_FILE_READ_AT_PROC(zpl__posix_file_read) { - zpl_unused(stop_at_newline); - zpl_isize res = pread(fd.i, buffer, size, offset); - if (res < 0) return false; - if (bytes_read) *bytes_read = res; - return true; - } - - zpl_internal ZPL_FILE_WRITE_AT_PROC(zpl__posix_file_write) { - zpl_isize res; - zpl_i64 curr_offset = 0; - zpl__posix_file_seek(fd, 0, ZPL_SEEK_WHENCE_CURRENT, &curr_offset); - if (curr_offset == offset) { - // NOTE: Writing to stdout et al. doesn't like pwrite for numerous reasons - res = write(cast(int) fd.i, buffer, size); - } else { - res = pwrite(cast(int) fd.i, buffer, size, offset); - } - if (res < 0) return false; - if (bytes_written) *bytes_written = res; - return true; - } - - zpl_internal ZPL_FILE_CLOSE_PROC(zpl__posix_file_close) { close(fd.i); } - - zpl_file_operations const zpl_default_file_operations = { zpl__posix_file_read, zpl__posix_file_write, - zpl__posix_file_seek, zpl__posix_file_close }; - - ZPL_NEVER_INLINE ZPL_FILE_OPEN_PROC(zpl__posix_file_open) { - zpl_i32 os_mode; - switch (mode & ZPL_FILE_MODES) { - case ZPL_FILE_MODE_READ: os_mode = O_RDONLY; break; - case ZPL_FILE_MODE_WRITE: os_mode = O_WRONLY | O_CREAT | O_TRUNC; break; - case ZPL_FILE_MODE_APPEND: os_mode = O_WRONLY | O_APPEND | O_CREAT; break; - case ZPL_FILE_MODE_READ | ZPL_FILE_MODE_RW: os_mode = O_RDWR; break; - case ZPL_FILE_MODE_WRITE | ZPL_FILE_MODE_RW: os_mode = O_RDWR | O_CREAT | O_TRUNC; break; - case ZPL_FILE_MODE_APPEND | ZPL_FILE_MODE_RW: os_mode = O_RDWR | O_APPEND | O_CREAT; break; - default: ZPL_PANIC("Invalid file mode"); return ZPL_FILE_ERROR_INVALID; - } - - fd->i = open(filename, os_mode, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); - if (fd->i < 0) { - // TODO: More file errors - return ZPL_FILE_ERROR_INVALID; - } - - *ops = zpl_default_file_operations; - return ZPL_FILE_ERROR_NONE; - } - - #endif - - zpl_file_error zpl_file_new(zpl_file *f, zpl_file_descriptor fd, zpl_file_operations ops, char const *filename) { - zpl_file_error err = ZPL_FILE_ERROR_NONE; - zpl_isize len = zpl_strlen(filename); - - f->ops = ops; - f->fd = fd; - f->dir = NULL; - f->last_write_time = 0; - f->filename = zpl_alloc_array(zpl_heap_allocator( ), char, len + 1); - zpl_memcopy(cast(char *) f->filename, cast(char *) filename, len + 1); - - return err; - } - - zpl_file_error zpl_file_open_mode(zpl_file *f, zpl_file_mode mode, char const *filename) { - zpl_file file_ = {0}; - *f = file_; - zpl_file_error err; - #if defined(ZPL_SYSTEM_WINDOWS) || defined(ZPL_SYSTEM_CYGWIN) - err = zpl__win32_file_open(&f->fd, &f->ops, mode, filename); - #else - err = zpl__posix_file_open(&f->fd, &f->ops, mode, filename); - #endif - if (err == ZPL_FILE_ERROR_NONE) return zpl_file_new(f, f->fd, f->ops, filename); - return err; - } - - zpl_internal void zpl__dirinfo_free_entry(zpl_dir_entry *entry); - - zpl_file_error zpl_file_close(zpl_file *f) { - if (!f) return ZPL_FILE_ERROR_INVALID; - - if (f->filename) zpl_free(zpl_heap_allocator( ), cast(char *) f->filename); - - #if defined(ZPL_SYSTEM_WINDOWS) - if (f->fd.p == INVALID_HANDLE_VALUE) return ZPL_FILE_ERROR_INVALID; - #else - if (f->fd.i < 0) return ZPL_FILE_ERROR_INVALID; - #endif - - if (f->is_temp) - { - f->ops.close(f->fd); - return ZPL_FILE_ERROR_NONE; - } - - if (!f->ops.read_at) f->ops = zpl_default_file_operations; - f->ops.close(f->fd); - - if (f->dir) { - zpl__dirinfo_free_entry(f->dir); - zpl_mfree(f->dir); - f->dir = NULL; - } - - return ZPL_FILE_ERROR_NONE; - } - - - zpl_file_error zpl_file_create(zpl_file *f, char const *filename) { - return zpl_file_open_mode(f, ZPL_FILE_MODE_WRITE | ZPL_FILE_MODE_RW, filename); - } - - zpl_file_error zpl_file_open(zpl_file *f, char const *filename) { - return zpl_file_open_mode(f, ZPL_FILE_MODE_READ, filename); - } - - char const *zpl_file_name(zpl_file *f) { return f->filename ? f->filename : ""; } - - zpl_b32 zpl_file_has_changed(zpl_file *f) { - if (f->is_temp) - return false; - zpl_b32 result = false; - zpl_file_time last_write_time = zpl_fs_last_write_time(f->filename); - if (f->last_write_time != last_write_time) { - result = true; - f->last_write_time = last_write_time; - } - return result; - } - - // TODO: Is this a bad idea? - zpl_global zpl_b32 zpl__std_file_set = false; - zpl_global zpl_file zpl__std_files[ZPL_FILE_STANDARD_COUNT] = { { 0 } }; - - #if defined(ZPL_SYSTEM_WINDOWS) || defined(ZPL_SYSTEM_CYGWIN) - - zpl_file *zpl_file_get_standard(zpl_file_standard_type std) { - if (!zpl__std_file_set) { - #define ZPL__SET_STD_FILE(type, v) \ - zpl__std_files[type].fd.p = v; \ - zpl__std_files[type].ops = zpl_default_file_operations - ZPL__SET_STD_FILE(ZPL_FILE_STANDARD_INPUT, GetStdHandle(STD_INPUT_HANDLE)); - ZPL__SET_STD_FILE(ZPL_FILE_STANDARD_OUTPUT, GetStdHandle(STD_OUTPUT_HANDLE)); - ZPL__SET_STD_FILE(ZPL_FILE_STANDARD_ERROR, GetStdHandle(STD_ERROR_HANDLE)); - #undef ZPL__SET_STD_FILE - zpl__std_file_set = true; - } - return &zpl__std_files[std]; - } - - void zpl_file_connect_handle(zpl_file *file, void *handle) { - ZPL_ASSERT_NOT_NULL(file); - ZPL_ASSERT_NOT_NULL(handle); - - if (file->is_temp) - return; - - zpl_zero_item(file); - - file->fd.p = handle; - file->ops = zpl_default_file_operations; - } - - zpl_file_error zpl_file_truncate(zpl_file *f, zpl_i64 size) { - zpl_file_error err = ZPL_FILE_ERROR_NONE; - zpl_i64 prev_offset = zpl_file_tell(f); - zpl_file_seek(f, size); - if (!SetEndOfFile(f)) err = ZPL_FILE_ERROR_TRUNCATION_FAILURE; - zpl_file_seek(f, prev_offset); - return err; - } - - zpl_b32 zpl_fs_exists(char const *name) { - WIN32_FIND_DATAW data; - wchar_t *w_text; - void *handle; - zpl_b32 found = false; - zpl_allocator a = zpl_heap_allocator( ); - - w_text = zpl__alloc_utf8_to_ucs2(a, name, NULL); - if (w_text == NULL) { return false; } - handle = FindFirstFileW(w_text, &data); - zpl_free(a, w_text); - found = handle != INVALID_HANDLE_VALUE; - if (found) FindClose(handle); - return found; - } - - #else // POSIX - - zpl_file *zpl_file_get_standard(zpl_file_standard_type std) { - if (!zpl__std_file_set) { - #define ZPL__SET_STD_FILE(type, v) \ - zpl__std_files[type].fd.i = v; \ - zpl__std_files[type].ops = zpl_default_file_operations - ZPL__SET_STD_FILE(ZPL_FILE_STANDARD_INPUT, 0); - ZPL__SET_STD_FILE(ZPL_FILE_STANDARD_OUTPUT, 1); - ZPL__SET_STD_FILE(ZPL_FILE_STANDARD_ERROR, 2); - #undef ZPL__SET_STD_FILE - zpl__std_file_set = true; - } - return &zpl__std_files[std]; - } - - zpl_file_error zpl_file_truncate(zpl_file *f, zpl_i64 size) { - zpl_file_error err = ZPL_FILE_ERROR_NONE; - int i = ftruncate(f->fd.i, size); - if (i != 0) err = ZPL_FILE_ERROR_TRUNCATION_FAILURE; - return err; - } - - zpl_b32 zpl_fs_exists(char const *name) { return access(name, F_OK) != -1; } - - #endif - - zpl_i64 zpl_file_size(zpl_file *f) { - zpl_i64 size = 0; - zpl_i64 prev_offset = zpl_file_tell(f); - zpl_file_seek_to_end(f); - size = zpl_file_tell(f); - zpl_file_seek(f, prev_offset); - return size; - } - - zpl_file_error zpl_file_temp(zpl_file *file) { - zpl_zero_item(file); - FILE *fd = NULL; - - #if (defined(ZPL_SYSTEM_WINDOWS) && !defined(ZPL_SYSTEM_TINYC)) && !defined(ZPL_COMPILER_GCC) - errno_t errcode = tmpfile_s(&fd); - - if (errcode != 0) { - fd = NULL; - } - #else - fd = tmpfile(); - #endif - - if (fd == NULL) { return ZPL_FILE_ERROR_INVALID; } - - #if defined(ZPL_SYSTEM_WINDOWS) && !defined(ZPL_COMPILER_GCC) - file->fd.i = _get_osfhandle(_fileno(fd)); - #else - file->fd.i = fileno(fd); - #endif - file->ops = zpl_default_file_operations; - file->is_temp = true; - return ZPL_FILE_ERROR_NONE; - } - - zpl_file_contents zpl_file_read_contents(zpl_allocator a, zpl_b32 zero_terminate, char const *filepath) { - zpl_file_contents result = { 0 }; - zpl_file file = { 0 }; - - result.allocator = a; - - if (zpl_file_open(&file, filepath) == ZPL_FILE_ERROR_NONE) { - zpl_isize file_size = cast(zpl_isize) zpl_file_size(&file); - if (file_size > 0) { - result.data = zpl_alloc(a, zero_terminate ? file_size + 1 : file_size); - result.size = file_size; - zpl_file_read_at(&file, result.data, result.size, 0); - if (zero_terminate) { - zpl_u8 *str = cast(zpl_u8 *) result.data; - str[file_size] = '\0'; - } - } - zpl_file_close(&file); - } - - return result; - } - - void zpl_file_free_contents(zpl_file_contents *fc) { - ZPL_ASSERT_NOT_NULL(fc->data); - zpl_free(fc->allocator, fc->data); - fc->data = NULL; - fc->size = 0; - } - - zpl_b32 zpl_file_write_contents(char const* filepath, void const* buffer, zpl_isize size, zpl_file_error* err) { - zpl_file f = { 0 }; - zpl_file_error open_err; - zpl_b32 write_ok; - open_err = zpl_file_open_mode(&f, ZPL_FILE_MODE_WRITE, filepath); - - if (open_err != ZPL_FILE_ERROR_NONE) - { - if (err) - *err = open_err; - - return false; - } - - write_ok = zpl_file_write(&f, buffer, size); - zpl_file_close(&f); - return write_ok; - } - - char *zpl_file_read_lines(zpl_allocator alloc, zpl_array(char *)*lines, char const *filename, zpl_b32 strip_whitespace) { - zpl_file f = { 0 }; - zpl_file_open(&f, filename); - zpl_isize fsize = (zpl_isize)zpl_file_size(&f); - - char *contents = (char *)zpl_alloc(alloc, fsize + 1); - zpl_file_read(&f, contents, fsize); - contents[fsize] = 0; - *lines = zpl_str_split_lines(alloc, contents, strip_whitespace); - zpl_file_close(&f); - - return contents; - } - - #if !defined(_WINDOWS_) && defined(ZPL_SYSTEM_WINDOWS) - ZPL_IMPORT DWORD WINAPI GetFullPathNameA(char const *lpFileName, DWORD nBufferLength, char *lpBuffer, char **lpFilePart); - ZPL_IMPORT DWORD WINAPI GetFullPathNameW(wchar_t const *lpFileName, DWORD nBufferLength, wchar_t *lpBuffer, wchar_t **lpFilePart); - #endif - - ZPL_END_C_DECLS - // file: source/core/file_stream.c - - - //////////////////////////////////////////////////////////////// - // - // Memory streaming - // - // - - ZPL_BEGIN_C_DECLS - - typedef struct { - zpl_u8 magic; - zpl_u8 *buf; //< zpl_array OR plain buffer if we can't write - zpl_isize cursor; - zpl_allocator alloc; - - zpl_file_stream_flags flags; - zpl_isize cap; - } zpl__memory_fd; - - #define ZPL__FILE_STREAM_FD_MAGIC 37 - - ZPL_DEF_INLINE zpl_file_descriptor zpl__file_stream_fd_make(zpl__memory_fd* d); - ZPL_DEF_INLINE zpl__memory_fd *zpl__file_stream_from_fd(zpl_file_descriptor fd); - - ZPL_IMPL_INLINE zpl_file_descriptor zpl__file_stream_fd_make(zpl__memory_fd* d) { - zpl_file_descriptor fd = {0}; - fd.p = (void*)d; - return fd; - } - - ZPL_IMPL_INLINE zpl__memory_fd *zpl__file_stream_from_fd(zpl_file_descriptor fd) { - zpl__memory_fd *d = (zpl__memory_fd*)fd.p; - ZPL_ASSERT(d->magic == ZPL__FILE_STREAM_FD_MAGIC); - return d; - } - - void zpl_file_stream_new(zpl_file* file, zpl_allocator allocator) { - ZPL_ASSERT_NOT_NULL(file); - zpl__memory_fd *d = (zpl__memory_fd*)zpl_alloc(allocator, zpl_size_of(zpl__memory_fd)); - zpl_zero_item(file); - d->magic = ZPL__FILE_STREAM_FD_MAGIC; - d->alloc = allocator; - d->flags = ZPL_FILE_STREAM_CLONE_WRITABLE; - d->cap = 0; - zpl_array_init(d->buf, allocator); - file->ops = zpl_memory_file_operations; - file->fd = zpl__file_stream_fd_make(d); - file->dir = NULL; - file->last_write_time = 0; - file->filename = NULL; - file->is_temp = true; - } - void zpl_file_stream_open(zpl_file* file, zpl_allocator allocator, zpl_u8 *buffer, zpl_isize size, zpl_file_stream_flags flags) { - ZPL_ASSERT_NOT_NULL(file); - zpl__memory_fd *d = (zpl__memory_fd*)zpl_alloc(allocator, zpl_size_of(zpl__memory_fd)); - zpl_zero_item(file); - d->magic = ZPL__FILE_STREAM_FD_MAGIC; - d->alloc = allocator; - d->flags = flags; - if (d->flags & ZPL_FILE_STREAM_CLONE_WRITABLE) { - zpl_array_init_reserve(d->buf, allocator, size); - zpl_memcopy(d->buf, buffer, size); - d->cap = zpl_array_count(d->buf) = size; - } else { - d->buf = buffer; - d->cap = size; - } - file->ops = zpl_memory_file_operations; - file->fd = zpl__file_stream_fd_make(d); - file->dir = NULL; - file->last_write_time = 0; - file->filename = NULL; - file->is_temp = true; - } - - zpl_u8 *zpl_file_stream_buf(zpl_file* file, zpl_isize *size) { - ZPL_ASSERT_NOT_NULL(file); - zpl__memory_fd *d = zpl__file_stream_from_fd(file->fd); - if (size) *size = d->cap; - return d->buf; - } - - zpl_internal ZPL_FILE_SEEK_PROC(zpl__memory_file_seek) { - zpl__memory_fd *d = zpl__file_stream_from_fd(fd); - zpl_isize buflen = d->cap; - - if (whence == ZPL_SEEK_WHENCE_BEGIN) - d->cursor = 0; - else if (whence == ZPL_SEEK_WHENCE_END) - d->cursor = buflen; - - d->cursor = zpl_max(0, zpl_clamp(d->cursor + offset, 0, buflen)); - if (new_offset) *new_offset = d->cursor; - return true; - } - - zpl_internal ZPL_FILE_READ_AT_PROC(zpl__memory_file_read) { - zpl_unused(stop_at_newline); - zpl__memory_fd *d = zpl__file_stream_from_fd(fd); - zpl_memcopy(buffer, d->buf + offset, size); - if (bytes_read) *bytes_read = size; - return true; - } - - zpl_internal ZPL_FILE_WRITE_AT_PROC(zpl__memory_file_write) { - zpl__memory_fd *d = zpl__file_stream_from_fd(fd); - if (!(d->flags & (ZPL_FILE_STREAM_CLONE_WRITABLE|ZPL_FILE_STREAM_WRITABLE))) - return false; - zpl_isize buflen = d->cap; - zpl_isize extralen = zpl_max(0, size-(buflen-offset)); - zpl_isize rwlen = size-extralen; - zpl_isize new_cap = buflen+extralen; - if (d->flags & ZPL_FILE_STREAM_CLONE_WRITABLE) { - if(zpl_array_capacity(d->buf) < new_cap) { - zpl_array_grow(d->buf, (zpl_i64)(new_cap)); - } - } - zpl_memcopy(d->buf + offset, buffer, rwlen); - - if ((d->flags & ZPL_FILE_STREAM_CLONE_WRITABLE) && extralen > 0) { - zpl_memcopy(d->buf + offset + rwlen, zpl_ptr_add_const(buffer, rwlen), extralen); - d->cap = zpl_array_count(d->buf) = new_cap; - } else { - extralen = 0; - } - - if (bytes_written) *bytes_written = (rwlen+extralen); - return true; - } - - zpl_internal ZPL_FILE_CLOSE_PROC(zpl__memory_file_close) { - zpl__memory_fd *d = zpl__file_stream_from_fd(fd); - zpl_allocator alloc = d->alloc; - if (d->flags & ZPL_FILE_STREAM_CLONE_WRITABLE) - zpl_array_free(d->buf); - zpl_free(alloc, d); - } - - zpl_file_operations const zpl_memory_file_operations = { zpl__memory_file_read, zpl__memory_file_write, - zpl__memory_file_seek, zpl__memory_file_close }; - - ZPL_END_C_DECLS - // file: source/core/file_misc.c - - - #if defined(ZPL_SYSTEM_UNIX) || defined(ZPL_SYSTEM_MACOS) - # include - #endif - - #if defined(ZPL_SYSTEM_UNIX) && !defined(ZPL_SYSTEM_FREEBSD) && !defined(ZPL_SYSTEM_OPENBSD) && !defined(ZPL_SYSTEM_CYGWIN) - # include - #endif - - #if defined(ZPL_SYSTEM_WINDOWS) - # include - # include - #endif - - #if defined(ZPL_SYSTEM_CYGWIN) - # include - # include - # include - #endif - - ZPL_BEGIN_C_DECLS - - - #if defined(ZPL_SYSTEM_WINDOWS) || defined(ZPL_SYSTEM_CYGWIN) - zpl_file_time zpl_fs_last_write_time(char const *filepath) { - ULARGE_INTEGER li = { 0 }; - FILETIME last_write_time = { 0 }; - WIN32_FILE_ATTRIBUTE_DATA data = { 0 }; - zpl_allocator a = zpl_heap_allocator( ); - - wchar_t *w_text = zpl__alloc_utf8_to_ucs2(a, filepath, NULL); - if (w_text == NULL) { return 0; } - if (GetFileAttributesExW(w_text, GetFileExInfoStandard, &data)) last_write_time = data.ftLastWriteTime; - - zpl_free(a, w_text); - - li.LowPart = last_write_time.dwLowDateTime; - li.HighPart = last_write_time.dwHighDateTime; - return cast(zpl_file_time) li.QuadPart; - } - - zpl_b32 zpl_fs_copy(char const *existing_filename, char const *new_filename, zpl_b32 fail_if_exists) { - zpl_b32 result = false; - zpl_allocator a = zpl_heap_allocator( ); - - wchar_t *w_old = zpl__alloc_utf8_to_ucs2(a, existing_filename, NULL); - if (w_old == NULL) { return false; } - - wchar_t *w_new = zpl__alloc_utf8_to_ucs2(a, new_filename, NULL); - if (w_new != NULL) { result = CopyFileW(w_old, w_new, fail_if_exists); } - - zpl_free(a, w_old); - zpl_free(a, w_new); - return result; - } - - zpl_b32 zpl_fs_move(char const *existing_filename, char const *new_filename) { - zpl_b32 result = false; - zpl_allocator a = zpl_heap_allocator( ); - - wchar_t *w_old = zpl__alloc_utf8_to_ucs2(a, existing_filename, NULL); - if (w_old == NULL) { return false; } - - wchar_t *w_new = zpl__alloc_utf8_to_ucs2(a, new_filename, NULL); - if (w_new != NULL) { result = MoveFileW(w_old, w_new); } - - zpl_free(a, w_old); - zpl_free(a, w_new); - return result; - } - - zpl_b32 zpl_fs_remove(char const *filename) { - zpl_b32 result = false; - zpl_allocator a = zpl_heap_allocator( ); - - wchar_t *w_filename = zpl__alloc_utf8_to_ucs2(a, filename, NULL); - if (w_filename == NULL) { return false; } - - result = DeleteFileW(w_filename); - - zpl_free(a, w_filename); - return result; - } - - #else - - zpl_file_time zpl_fs_last_write_time(char const *filepath) { - time_t result = 0; - struct stat file_stat; - - if (stat(filepath, &file_stat)) result = file_stat.st_mtime; - - return cast(zpl_file_time) result; - } - - # if defined(ZPL_SYSTEM_FREEBSD) - # include - # include - # include - # endif - - - zpl_b32 zpl_fs_copy(char const *existing_filename, char const *new_filename, zpl_b32 fail_if_exists) { - zpl_unused(fail_if_exists); - # if defined(ZPL_SYSTEM_OSX) - return copyfile(existing_filename, new_filename, NULL, COPYFILE_DATA) == 0; - # elif defined(ZPL_SYSTEM_OPENBSD) - ZPL_NOT_IMPLEMENTED; - return 0; - # else - int existing_fd = open(existing_filename, O_RDONLY, 0); - struct stat stat_existing; - fstat(existing_fd, &stat_existing); - - zpl_isize size; - int new_fd = open(new_filename, O_WRONLY | O_CREAT, stat_existing.st_mode); - - # if defined(ZPL_SYSTEM_FREEBSD) - size = sendfile(new_fd, existing_fd, 0, stat_existing.st_size, NULL, 0, 0); - # else - size = sendfile(new_fd, existing_fd, 0, stat_existing.st_size); - # endif - - close(new_fd); - close(existing_fd); - - return size == stat_existing.st_size; - # endif - } - - zpl_b32 zpl_fs_move(char const *existing_filename, char const *new_filename) { - if (link(existing_filename, new_filename) == 0) { return (unlink(existing_filename) != -1); } - return false; - } - - zpl_b32 zpl_fs_remove(char const *filename) { - # if defined(ZPL_SYSTEM_OSX) || defined(ZPL_SYSTEM_EMSCRIPTEN) - return (unlink(filename) != -1); - # else - return (remove(filename) == 0); - # endif - } - - #endif - - char *zpl_path_get_full_name(zpl_allocator a, char const *path) { - #if defined(ZPL_SYSTEM_WINDOWS) - wchar_t *w_path = NULL; - wchar_t *w_fullpath = NULL; - zpl_isize w_len = 0; - zpl_isize new_len = 0; - zpl_isize new_len1 = 0; - char *new_path = 0; - - w_path = zpl__alloc_utf8_to_ucs2(zpl_heap_allocator( ), path, NULL); - if (w_path == NULL) { return NULL; } - - w_len = GetFullPathNameW(w_path, 0, NULL, NULL); - if (w_len == 0) { return NULL; } - - w_fullpath = zpl_alloc_array(zpl_heap_allocator( ), wchar_t, w_len + 1); - GetFullPathNameW(w_path, cast(int) w_len, w_fullpath, NULL); - w_fullpath[w_len] = 0; - - zpl_free(zpl_heap_allocator( ), w_path); - - new_len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, w_fullpath, cast(int) w_len, NULL, 0, NULL, NULL); - - if (new_len == 0) { - zpl_free(zpl_heap_allocator( ), w_fullpath); - return NULL; - } - - new_path = zpl_alloc_array(a, char, new_len); - new_len1 = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, w_fullpath, cast(int) w_len, new_path, - cast(int) new_len, NULL, NULL); - - if (new_len1 == 0) { - zpl_free(zpl_heap_allocator( ), w_fullpath); - zpl_free(a, new_path); - return NULL; - } - - new_path[new_len] = 0; - return new_path; - #else - char *p, *result, *fullpath = NULL; - zpl_isize len; - p = realpath(path, NULL); - fullpath = p; - if (p == NULL) { - // NOTE(bill): File does not exist - fullpath = cast(char *) path; - } - - len = zpl_strlen(fullpath); - - result = zpl_alloc_array(a, char, len + 1); - zpl_memmove(result, fullpath, len); - result[len] = 0; - zpl_free(a, p); - - return result; - #endif - } - - zpl_file_error zpl_path_mkdir(char const *path, zpl_i32 mode) { - zpl_i32 error = 0; - #if defined(ZPL_SYSTEM_WINDOWS) - error = _wmkdir((const wchar_t *)zpl_utf8_to_ucs2_buf((const zpl_u8 *)path)); - #else - error = mkdir(path, (mode_t)mode); - #endif - - if (error == 0) { return ZPL_FILE_ERROR_NONE; } - - switch (errno) { - case EPERM: - case EACCES: return ZPL_FILE_ERROR_PERMISSION; - case EEXIST: return ZPL_FILE_ERROR_EXISTS; - case ENAMETOOLONG: return ZPL_FILE_ERROR_NAME_TOO_LONG; - } - - return ZPL_FILE_ERROR_UNKNOWN; - } - - zpl_isize zpl_path_mkdir_recursive(char const *path, zpl_i32 mode) { - char tmp[ZPL_MAX_PATH] = {0}; - char *p = 0; - zpl_isize len = zpl_strlen(path); - - if (len > zpl_size_of(tmp)-1) { - return -1; - } - zpl_strcpy(tmp, path); - zpl_path_fix_slashes(tmp); - for (p = tmp + 1; *p; p++) { - if (*p == ZPL_PATH_SEPARATOR) { - *p = 0; - zpl_path_mkdir(tmp, mode); - *p = ZPL_PATH_SEPARATOR; - } - } - zpl_path_mkdir(tmp, mode); - return 0; - } - - zpl_file_error zpl_path_rmdir(char const *path) { - zpl_i32 error = 0; - #if defined(ZPL_SYSTEM_WINDOWS) - error = _wrmdir((const wchar_t *)zpl_utf8_to_ucs2_buf((const zpl_u8 *)path)); - #else - error = rmdir(path); - #endif - - if (error == 0) { return ZPL_FILE_ERROR_NONE; } - - switch (errno) { - case EPERM: - case EACCES: return ZPL_FILE_ERROR_PERMISSION; - case ENOENT: return ZPL_FILE_ERROR_NOT_EXISTS; - case ENOTEMPTY: return ZPL_FILE_ERROR_NOT_EMPTY; - case ENAMETOOLONG: return ZPL_FILE_ERROR_NAME_TOO_LONG; - } - - return ZPL_FILE_ERROR_UNKNOWN; - } - - void zpl__file_direntry(zpl_allocator alloc, char const *dirname, zpl_string *output, zpl_b32 recurse) { - #if defined(ZPL_SYSTEM_UNIX) || defined(ZPL_SYSTEM_OSX) - DIR *d, *cd; - struct dirent *dir; - d = opendir(dirname); - - if (d) { - while ((dir = readdir(d))) { - if (dir == 0) break; - if (!zpl_strncmp(dir->d_name, "..", 2)) continue; - if (dir->d_name[0] == '.' && dir->d_name[1] == 0) continue; - - zpl_string dirpath = zpl_string_make(alloc, dirname); - dirpath = zpl_string_appendc(dirpath, "/"); - dirpath = zpl_string_appendc(dirpath, dir->d_name); - - *output = zpl_string_appendc(*output, dirpath); - *output = zpl_string_appendc(*output, "\n"); - - if (recurse && (cd = opendir(dirpath)) != NULL && dir->d_type == DT_DIR) { zpl__file_direntry(alloc, dirpath, output, recurse); } - zpl_string_free(dirpath); - } - } - #elif defined(ZPL_SYSTEM_WINDOWS) - zpl_usize length = zpl_strlen(dirname); - struct _wfinddata_t data; - zpl_intptr findhandle; - - char directory[MAX_PATH] = { 0 }; - zpl_strncpy(directory, dirname, length); - - // keeping it native - for (zpl_usize i = 0; i < length; i++) { - if (directory[i] == '/') directory[i] = '\\'; - } - - // remove trailing slashses - if (directory[length - 1] == '\\') { directory[length - 1] = '\0'; } - - // attach search pattern - zpl_string findpath = zpl_string_make(alloc, directory); - findpath = zpl_string_appendc(findpath, "\\"); - findpath = zpl_string_appendc(findpath, "*"); - - findhandle = _wfindfirst((const wchar_t *)zpl_utf8_to_ucs2_buf((const zpl_u8 *)findpath), &data); - zpl_string_free(findpath); - - if (findhandle != -1) { - do { - char *filename = (char *)zpl_ucs2_to_utf8_buf((const zpl_u16 *)data.name); - if (!zpl_strncmp(filename, "..", 2)) continue; - if (filename[0] == '.' && filename[1] == 0) continue; - - zpl_string dirpath = zpl_string_make(alloc, directory); - dirpath = zpl_string_appendc(dirpath, "\\"); - dirpath = zpl_string_appendc(dirpath, filename); - DWORD attrs = GetFileAttributesW((const wchar_t *)zpl_utf8_to_ucs2_buf((const zpl_u8 *)dirpath)); - - *output = zpl_string_appendc(*output, dirpath); - *output = zpl_string_appendc(*output, "\n"); - - if (recurse && (data.attrib & _A_SUBDIR) && !(attrs & FILE_ATTRIBUTE_REPARSE_POINT)) { zpl__file_direntry(alloc, dirpath, output, recurse); } - - zpl_string_free(dirpath); - } while (_wfindnext(findhandle, &data) != -1); - _findclose(findhandle); - } - #else - // TODO: Implement other OSes - #endif - } - - zpl_string zpl_path_dirlist(zpl_allocator alloc, char const *dirname, zpl_b32 recurse) { - zpl_string buf = zpl_string_make_reserve(alloc, 4); - zpl__file_direntry(alloc, dirname, &buf, recurse); - return buf; - } - - void zpl_dirinfo_init(zpl_dir_info *dir, char const *path) { - ZPL_ASSERT_NOT_NULL(dir); - - zpl_dir_info dir_ = {0}; - *dir = dir_; - dir->fullpath = (char const*)zpl_malloc(zpl_strlen(path)); - zpl_strcpy((char *)dir->fullpath, path); - - - zpl_string dirlist = zpl_path_dirlist(zpl_heap(), path, false); - char **files=zpl_str_split_lines(zpl_heap(), dirlist, false); - dir->filenames = files; - dir->buf = dirlist; - - zpl_array_init(dir->entries, zpl_heap()); - - for (zpl_i32 i=0; ientries, entry); - } - } - - zpl_internal void zpl__dirinfo_free_entry(zpl_dir_entry *entry) { - if (entry->dir_info) { - zpl_dirinfo_free(entry->dir_info); - zpl_mfree(entry->dir_info); - entry->dir_info = NULL; - } - } - - void zpl_dirinfo_free(zpl_dir_info *dir) { - ZPL_ASSERT_NOT_NULL(dir); - - for (zpl_isize i = 0; i < zpl_array_count(dir->entries); ++i) { - zpl__dirinfo_free_entry(dir->entries + i); - } - - zpl_array_free(dir->entries); - zpl_array_free(dir->filenames); - zpl_string_free(dir->buf); - zpl_mfree((void *)dir->fullpath); - } - - - zpl_u8 zpl_fs_get_type(char const *path) { - #ifdef ZPL_SYSTEM_WINDOWS - DWORD attrs = GetFileAttributesW((const wchar_t *)zpl_utf8_to_ucs2_buf((const zpl_u8 *)path)); - - if (attrs == INVALID_FILE_ATTRIBUTES) { - return ZPL_DIR_TYPE_UNKNOWN; - } - - if (attrs & FILE_ATTRIBUTE_DIRECTORY) - return ZPL_DIR_TYPE_FOLDER; - else - return ZPL_DIR_TYPE_FILE; - - #else - struct stat s; - if( stat(path,&s) == 0 ) - { - if(s.st_mode & S_IFDIR) - return ZPL_DIR_TYPE_FOLDER; - else - return ZPL_DIR_TYPE_FILE; - } - #endif - - return ZPL_DIR_TYPE_UNKNOWN; - } - - void zpl_dirinfo_step(zpl_dir_entry *entry) { - if (entry->dir_info) { - zpl__dirinfo_free_entry(entry); - } - - entry->dir_info = (zpl_dir_info *)zpl_malloc(sizeof(zpl_dir_info)); - zpl_dir_info dir_ = {0}; - *entry->dir_info = dir_; - - zpl_local_persist char buf[128] = {0}; - char const *path = entry->filename; - - if (entry->type != ZPL_DIR_TYPE_FOLDER) { - zpl_path_fix_slashes((char *)path); - char const* slash = zpl_char_last_occurence(path, ZPL_PATH_SEPARATOR); - zpl_strncpy(buf, path, slash-path); - path = buf; - } - - zpl_dirinfo_init(entry->dir_info, path); - } - - void zpl_file_dirinfo_refresh(zpl_file *file) { - if (file->is_temp) - return; - - if (file->dir) { - zpl__dirinfo_free_entry(file->dir); - zpl_mfree(file->dir); - file->dir = NULL; - } - - file->dir = (zpl_dir_entry *)zpl_malloc(sizeof(zpl_dir_entry)); - zpl_dir_entry dir_ = {0}; - *file->dir = dir_; - file->dir->filename = file->filename; - file->dir->type = ZPL_DIR_TYPE_FILE; - - zpl_dirinfo_step(file->dir); - } - - void zpl_path_fix_slashes(char *path) { - #ifdef ZPL_SYSTEM_WINDOWS - char *p = path; - - while (*p != '\0') { - if (*p == '/') - *p = '\\'; - - ++p; - } - #endif - } - - ZPL_END_C_DECLS - // file: source/core/file_tar.c - - - typedef struct { - char name[100]; - char mode[8]; - char owner[8]; - char group[8]; - char size[12]; - char mtime[12]; - char checksum[8]; - char type; - char linkname[100]; - char _padding[255]; - } zpl__tar_header; - - zpl_internal zpl_usize zpl__tar_checksum(zpl__tar_header *hr) { - zpl_usize i; - zpl_usize res = 256; - zpl_u8 *p = cast(zpl_u8*)(hr); - for (i = 0; i < cast(zpl_usize)zpl_offset_of(zpl__tar_header, checksum); i++) - res += p[i]; - for (i = cast(zpl_usize)zpl_offset_of(zpl__tar_header, type); i < cast(zpl_usize)zpl_size_of(zpl__tar_header); i++) - res += p[i]; - return res; - } - - zpl_internal zpl_b32 zpl__tar_write_null(zpl_file *archive, zpl_isize cnt) { - char *out = zpl_bprintf("%*r", cnt, '\0'); - if (!zpl_file_write(archive, out, cnt)) - return 0; - return 1; - } - - zpl_isize zpl_tar_pack(zpl_file *archive, char const **paths, zpl_isize paths_len) { - ZPL_ASSERT_NOT_NULL(archive); - ZPL_ASSERT_NOT_NULL(paths); - - for (zpl_isize i = 0; i < paths_len; i++) { - ZPL_ASSERT_NOT_NULL(paths[i]); - zpl__tar_header hr = {0}; - zpl_file file; - zpl_file_error ferr = zpl_file_open_mode(&file, ZPL_FILE_MODE_READ, paths[i]); - if (ferr == ZPL_FILE_ERROR_NOT_EXISTS) { - return -(ZPL_TAR_ERROR_FILE_NOT_FOUND); - } else if (ferr != ZPL_FILE_ERROR_NONE) { - return -(ZPL_TAR_ERROR_IO_ERROR); - } - - zpl_i64 file_size = zpl_file_size(&file); - zpl_snprintf(hr.name, 12, "%s", paths[i]); - zpl_snprintf(hr.size, 12, "%o", file_size); - zpl_snprintf(hr.mode, 8, "%o", 0664); - zpl_snprintf(hr.mtime, 12, "%o", zpl_fs_last_write_time(paths[i])); - hr.type = ZPL_TAR_TYPE_REGULAR; - zpl_snprintf(hr.checksum, 8, "%o", zpl__tar_checksum(&hr)); - - zpl_file_write(archive, cast(void*)(&hr), zpl_size_of(zpl__tar_header)); - - // write data - { - zpl_i64 remaining_data = file_size; - zpl_i64 total_data = zpl_align_forward_i64(remaining_data, 512); - zpl_i64 padding = (total_data-file_size); - char buf[4096] = {0}; - zpl_i64 pos = 0; - zpl_isize bytes_read = 0; - do { - if (!zpl_file_read_at_check(&file, buf, 4096, pos, &bytes_read)) { - zpl_file_close(&file); - return -(ZPL_TAR_ERROR_IO_ERROR); - } else if (bytes_read == 0) { - break; - } - - zpl_file_write(archive, buf, bytes_read); - pos += bytes_read; - remaining_data -= bytes_read; - } - while (remaining_data > 0); - - if (padding > 0) { - if (!zpl__tar_write_null(archive, padding)) { - zpl_file_close(&file); - return -(ZPL_TAR_ERROR_IO_ERROR); - } - } - } - - zpl_file_close(&file); - } - - if (!zpl__tar_write_null(archive, zpl_size_of(zpl__tar_header) * 2)) { - return -(ZPL_TAR_ERROR_IO_ERROR); - } - - return 0; - } - - zpl_isize zpl_tar_pack_dir(zpl_file *archive, char const *path, zpl_allocator alloc) { - zpl_string filelst = zpl_path_dirlist(alloc, path, true); - char const **files = cast(char const**)zpl_str_split_lines(alloc, filelst, false); - zpl_isize err = zpl_tar_pack(archive, files, zpl_array_count(files)); - zpl_string_free(filelst); - zpl_array_free(files); - return err; - } - - zpl_isize zpl_tar_unpack(zpl_file *archive, zpl_tar_unpack_proc *unpack_proc, void *user_data) { - ZPL_ASSERT_NOT_NULL(archive); - ZPL_ASSERT_NOT_NULL(unpack_proc); - - zpl_i64 pos = zpl_file_tell(archive); - zpl__tar_header hr = {0}; - zpl_isize err = ZPL_TAR_ERROR_NONE; - - do { - if (!zpl_file_read(archive, cast(void*)&hr, zpl_size_of(hr))) { - err = ZPL_TAR_ERROR_IO_ERROR; - break; - } - else if (*hr.checksum == 0) { - break; - } - pos = zpl_file_tell(archive); - - zpl_tar_record rec = {0}; - rec.type = hr.type; - rec.path = hr.name; - rec.offset = pos; - rec.length = zpl_str_to_i64(hr.size, 0, 8); - rec.error = ZPL_TAR_ERROR_NONE; - - zpl_usize checksum1 = cast(zpl_usize)(zpl_str_to_i64(hr.checksum, 0, 8)); - zpl_usize checksum2 = zpl__tar_checksum(&hr); - rec.error = (checksum1 != checksum2) ? cast(zpl_isize)ZPL_TAR_ERROR_BAD_CHECKSUM : rec.error; - - rec.error = unpack_proc(archive, &rec, user_data); - - if (rec.error > 0) { - err = ZPL_TAR_ERROR_INTERRUPTED; - break; - } - - /* tar rounds files to 512 byte boundary */ - zpl_file_seek(archive, pos + zpl_align_forward_i64(rec.length, 512)); - } - while(err == ZPL_TAR_ERROR_NONE); - - return -(err); - } - - ZPL_TAR_UNPACK_PROC(zpl_tar_default_list_file) { - (void)archive; - (void)user_data; - if (file->error != ZPL_TAR_ERROR_NONE) - return 0; /* skip file */ - - if (file->type != ZPL_TAR_TYPE_REGULAR) - return 0; /* we only care about regular files */ - - /* proceed as usual */ - zpl_printf("name: %s, offset: %d, length: %d\n", file->path, file->offset, file->length); - return 0; - } - - ZPL_TAR_UNPACK_PROC(zpl_tar_default_unpack_file) { - if (file->error != ZPL_TAR_ERROR_NONE) - return 0; /* skip file */ - - if (file->type != ZPL_TAR_TYPE_REGULAR) - return 0; /* we only care about regular files */ - - if (!zpl_strncmp(file->path, "..", 2)) - return 0; - - char tmp[ZPL_MAX_PATH] = {0}; - char *base_path = cast(char*)user_data; - zpl_isize base_len = zpl_strlen(base_path); - zpl_isize len = zpl_strlen(file->path); - ZPL_ASSERT(base_len+len-2 < ZPL_MAX_PATH); /* todo: account for missing leading path sep */ - - zpl_strcpy(tmp, base_path); - zpl_path_fix_slashes(tmp); /* todo: need to do twice as base_path is checked before concat */ - - if (*tmp && tmp[base_len-1] != ZPL_PATH_SEPARATOR) { - char sep[2] = {ZPL_PATH_SEPARATOR, 0}; - zpl_strcat(tmp, sep); - } - zpl_strcat(tmp, file->path); - zpl_path_fix_slashes(tmp); - - const char *last_slash = zpl_char_last_occurence(tmp, ZPL_PATH_SEPARATOR); - - if (last_slash) { - zpl_isize i = cast(zpl_isize)(last_slash-tmp); - tmp[i] = 0; - zpl_path_mkdir_recursive(tmp, 0755); - tmp[i] = ZPL_PATH_SEPARATOR; - } - - zpl_file f; - zpl_file_create(&f, tmp); - { - char buf[4096] = {0}; - zpl_isize remaining_data = file->length; - zpl_isize bytes_read = 0; - zpl_i64 pos = file->offset; - do { - if (!zpl_file_read_at_check(archive, buf, zpl_min(4096, remaining_data), pos, &bytes_read)) { - zpl_file_close(&f); - return 1; - } else if (bytes_read == 0) { - break; - } - - zpl_file_write(&f, buf, bytes_read); - pos += bytes_read; - remaining_data -= bytes_read; - } - while (remaining_data > 0); - } - zpl_file_close(&f); - return 0; - } - // file: source/core/print.c - - - ZPL_BEGIN_C_DECLS - - zpl_isize zpl_printf_va(char const *fmt, va_list va) { - return zpl_fprintf_va(zpl_file_get_standard(ZPL_FILE_STANDARD_OUTPUT), fmt, va); - } - - zpl_isize zpl_printf_err_va(char const *fmt, va_list va) { - return zpl_fprintf_va(zpl_file_get_standard(ZPL_FILE_STANDARD_ERROR), fmt, va); - } - - zpl_isize zpl_fprintf_va(struct zpl_file *f, char const *fmt, va_list va) { - zpl_local_persist zpl_thread_local char buf[ZPL_PRINTF_MAXLEN]; - zpl_isize len = zpl_snprintf_va(buf, zpl_size_of(buf), fmt, va); - zpl_file_write(f, buf, len - 1); // NOTE: prevent extra whitespace - return len; - } - - char *zpl_bprintf_va(char const *fmt, va_list va) { - zpl_local_persist zpl_thread_local char buffer[ZPL_PRINTF_MAXLEN]; - zpl_snprintf_va(buffer, zpl_size_of(buffer), fmt, va); - return buffer; - } - - zpl_isize zpl_asprintf_va(zpl_allocator allocator, char **buffer, char const *fmt, va_list va) { - zpl_local_persist zpl_thread_local char tmp[ZPL_PRINTF_MAXLEN]; - ZPL_ASSERT_NOT_NULL(buffer); - zpl_isize res; - res = zpl_snprintf_va(tmp, zpl_size_of(tmp), fmt, va); - *buffer = zpl_alloc_str(allocator, tmp); - return res; - } - - zpl_isize zpl_printf(char const *fmt, ...) { - zpl_isize res; - va_list va; - va_start(va, fmt); - res = zpl_printf_va(fmt, va); - va_end(va); - return res; - } - - zpl_isize zpl_printf_err(char const *fmt, ...) { - zpl_isize res; - va_list va; - va_start(va, fmt); - res = zpl_printf_err_va(fmt, va); - va_end(va); - return res; - } - - zpl_isize zpl_fprintf(struct zpl_file *f, char const *fmt, ...) { - zpl_isize res; - va_list va; - va_start(va, fmt); - res = zpl_fprintf_va(f, fmt, va); - va_end(va); - return res; - } - - char *zpl_bprintf(char const *fmt, ...) { - va_list va; - char *str; - va_start(va, fmt); - str = zpl_bprintf_va(fmt, va); - va_end(va); - return str; - } - - zpl_isize zpl_asprintf(zpl_allocator allocator, char **buffer, char const *fmt, ...) { - zpl_isize res; - va_list va; - va_start(va, fmt); - res = zpl_asprintf_va(allocator, buffer, fmt, va); - va_end(va); - return res; - } - - zpl_isize zpl_snprintf(char *str, zpl_isize n, char const *fmt, ...) { - zpl_isize res; - va_list va; - va_start(va, fmt); - res = zpl_snprintf_va(str, n, fmt, va); - va_end(va); - return res; - } - - - enum { - ZPL_FMT_MINUS = ZPL_BIT(0), - ZPL_FMT_PLUS = ZPL_BIT(1), - ZPL_FMT_ALT = ZPL_BIT(2), - ZPL_FMT_SPACE = ZPL_BIT(3), - ZPL_FMT_ZERO = ZPL_BIT(4), - - ZPL_FMT_CHAR = ZPL_BIT(5), - ZPL_FMT_SHORT = ZPL_BIT(6), - ZPL_FMT_INT = ZPL_BIT(7), - ZPL_FMT_LONG = ZPL_BIT(8), - ZPL_FMT_LLONG = ZPL_BIT(9), - ZPL_FMT_SIZE = ZPL_BIT(10), - ZPL_FMT_INTPTR = ZPL_BIT(11), - - ZPL_FMT_UNSIGNED = ZPL_BIT(12), - ZPL_FMT_LOWER = ZPL_BIT(13), - ZPL_FMT_UPPER = ZPL_BIT(14), - ZPL_FMT_WIDTH = ZPL_BIT(15), - - ZPL_FMT_DONE = ZPL_BIT(30), - - ZPL_FMT_INTS = - ZPL_FMT_CHAR | ZPL_FMT_SHORT | ZPL_FMT_INT | - ZPL_FMT_LONG | ZPL_FMT_LLONG | ZPL_FMT_SIZE | ZPL_FMT_INTPTR - }; - - typedef struct { - zpl_i32 base; - zpl_i32 flags; - zpl_i32 width; - zpl_i32 precision; - } zpl__format_info; - - zpl_internal zpl_isize zpl__print_string(char *text, zpl_isize max_len, zpl__format_info *info, char const *str) { - zpl_isize res = 0, len = 0; - zpl_isize remaining = max_len; - char *begin = text; - - if (str == NULL && max_len >= 6) { - res += zpl_strlcpy(text, "(null)", 6); - return res; - } - - if (info && info->precision >= 0) - len = zpl_strnlen(str, info->precision); - else - len = zpl_strlen(str); - - if (info && (info->width == 0 && info->flags & ZPL_FMT_WIDTH)) { - return res; - } - - if (info && (info->width == 0 || info->flags & ZPL_FMT_MINUS)) { - if (info->precision > 0) len = info->precision < len ? info->precision : len; - res += zpl_strlcpy(text, str, len); - text += res; - - if (info->width > res) { - zpl_isize padding = info->width - len; - - char pad = (info->flags & ZPL_FMT_ZERO) ? '0' : ' '; - while (padding-- > 0 && remaining-- > 0) *text++ = pad, res++; - } - } else { - if (info && (info->width > res)) { - zpl_isize padding = info->width - len; - char pad = (info->flags & ZPL_FMT_ZERO) ? '0' : ' '; - while (padding-- > 0 && remaining-- > 0) *text++ = pad, res++; - } - - res += zpl_strlcpy(text, str, len); - } - - if (info) { - if (info->flags & ZPL_FMT_UPPER) - zpl_str_to_upper(begin); - else if (info->flags & ZPL_FMT_LOWER) - zpl_str_to_lower(begin); - } - - return res; - } - - zpl_internal zpl_isize zpl__print_char(char *text, zpl_isize max_len, zpl__format_info *info, char arg) { - char str[2] = ""; - str[0] = arg; - return zpl__print_string(text, max_len, info, str); - } - - zpl_internal zpl_isize zpl__print_repeated_char(char *text, zpl_isize max_len, zpl__format_info *info, char arg) { - zpl_isize res = 0; - zpl_i32 rem = (info) ? (info->width > 0) ? info->width : 1 : 1; - res = rem; - while (rem-- > 0) *text++ = arg; - - return res; - } - - zpl_internal zpl_isize zpl__print_i64(char *text, zpl_isize max_len, zpl__format_info *info, zpl_i64 value) { - char num[130]; - zpl_i64_to_str(value, num, info ? info->base : 10); - return zpl__print_string(text, max_len, info, num); - } - - zpl_internal zpl_isize zpl__print_u64(char *text, zpl_isize max_len, zpl__format_info *info, zpl_u64 value) { - char num[130]; - zpl_u64_to_str(value, num, info ? info->base : 10); - return zpl__print_string(text, max_len, info, num); - } - - zpl_internal zpl_isize zpl__print_f64(char *text, zpl_isize max_len, zpl__format_info *info, zpl_f64 arg) { - // TODO: Handle exponent notation - zpl_isize width, len, remaining = max_len; - char *text_begin = text; - - if (arg) { - zpl_u64 value; - if (arg < 0) { - if (remaining > 1) *text = '-', remaining--; - text++; - arg = -arg; - } else if (info->flags & ZPL_FMT_MINUS) { - if (remaining > 1) *text = '+', remaining--; - text++; - } - - value = cast(zpl_u64) arg; - len = zpl__print_u64(text, remaining, NULL, value); - text += len; - - if (len >= remaining) - remaining = zpl_min(remaining, 1); - else - remaining -= len; - arg -= value; - - if (info->precision < 0) info->precision = 6; - - if ((info->flags & ZPL_FMT_ALT) || info->precision > 0) { - zpl_i64 mult = 10; - if (remaining > 1) *text = '.', remaining--; - text++; - while (info->precision-- > 0) { - value = cast(zpl_u64)(arg * mult); - len = zpl__print_u64(text, remaining, NULL, value); - text += len; - if (len >= remaining) - remaining = zpl_min(remaining, 1); - else - remaining -= len; - arg -= cast(zpl_f64) value / mult; - mult *= 10; - } - } - } else { - if (remaining > 1) *text = '0', remaining--; - text++; - if (info->flags & ZPL_FMT_ALT) { - if (remaining > 1) *text = '.', remaining--; - text++; - } - } - - width = info->width - (text - text_begin); - if (width > 0) { - char fill = (info->flags & ZPL_FMT_ZERO) ? '0' : ' '; - char *end = text + remaining - 1; - len = (text - text_begin); - - for (len = (text - text_begin); len--;) { - if ((text_begin + len + width) < end) *(text_begin + len + width) = *(text_begin + len); - } - - len = width; - text += len; - if (len >= remaining) - remaining = zpl_min(remaining, 1); - else - remaining -= len; - - while (len--) { - if (text_begin + len < end) text_begin[len] = fill; - } - } - - return (text - text_begin); - } - - ZPL_NEVER_INLINE zpl_isize zpl_snprintf_va(char *text, zpl_isize max_len, char const *fmt, va_list va) { - char const *text_begin = text; - zpl_isize remaining = max_len, res; - - while (*fmt) { - zpl__format_info info = { 0 }; - zpl_isize len = 0; - info.precision = -1; - - while (*fmt && *fmt != '%' && remaining) *text++ = *fmt++; - - if (*fmt == '%') { - do { - switch (*++fmt) { - case '-': {info.flags |= ZPL_FMT_MINUS; break;} - case '+': {info.flags |= ZPL_FMT_PLUS; break;} - case '#': {info.flags |= ZPL_FMT_ALT; break;} - case ' ': {info.flags |= ZPL_FMT_SPACE; break;} - case '0': {info.flags |= (ZPL_FMT_ZERO|ZPL_FMT_WIDTH); break;} - default: {info.flags |= ZPL_FMT_DONE; break;} - } - } while (!(info.flags & ZPL_FMT_DONE)); - } - - // NOTE: Optional Width - if (*fmt == '*') { - int width = va_arg(va, int); - if (width < 0) { - info.flags |= ZPL_FMT_MINUS; - info.width = -width; - } else { - info.width = width; - } - info.flags |= ZPL_FMT_WIDTH; - fmt++; - } else { - info.width = cast(zpl_i32) zpl_str_to_i64(fmt, cast(char **) & fmt, 10); - if (info.width != 0) { - info.flags |= ZPL_FMT_WIDTH; - } - } - - // NOTE: Optional Precision - if (*fmt == '.') { - fmt++; - if (*fmt == '*') { - info.precision = va_arg(va, int); - fmt++; - } else { - info.precision = cast(zpl_i32) zpl_str_to_i64(fmt, cast(char **) & fmt, 10); - } - info.flags &= ~ZPL_FMT_ZERO; - } - - switch (*fmt++) { - case 'h': - if (*fmt == 'h') { // hh => char - info.flags |= ZPL_FMT_CHAR; - fmt++; - } else { // h => short - info.flags |= ZPL_FMT_SHORT; - } - break; - - case 'l': - if (*fmt == 'l') { // ll => long long - info.flags |= ZPL_FMT_LLONG; - fmt++; - } else { // l => long - info.flags |= ZPL_FMT_LONG; - } - break; - - break; - - case 'z': // NOTE: zpl_usize - info.flags |= ZPL_FMT_UNSIGNED; - // fallthrough - case 't': // NOTE: zpl_isize - info.flags |= ZPL_FMT_SIZE; - break; - - default: fmt--; break; - } - - switch (*fmt) { - case 'u': - info.flags |= ZPL_FMT_UNSIGNED; - // fallthrough - case 'd': - case 'i': info.base = 10; break; - - case 'o': info.base = 8; break; - - case 'x': - info.base = 16; - info.flags |= (ZPL_FMT_UNSIGNED | ZPL_FMT_LOWER); - break; - - case 'X': - info.base = 16; - info.flags |= (ZPL_FMT_UNSIGNED | ZPL_FMT_UPPER); - break; - - case 'f': - case 'F': - case 'g': - case 'G': len = zpl__print_f64(text, remaining, &info, va_arg(va, zpl_f64)); break; - - case 'a': - case 'A': - // TODO: - break; - - case 'c': len = zpl__print_char(text, remaining, &info, cast(char) va_arg(va, int)); break; - - case 's': len = zpl__print_string(text, remaining, &info, va_arg(va, char *)); break; - - case 'r': len = zpl__print_repeated_char(text, remaining, &info, va_arg(va, int)); break; - - case 'p': - info.base = 16; - info.flags |= (ZPL_FMT_LOWER | ZPL_FMT_UNSIGNED | ZPL_FMT_ALT | ZPL_FMT_INTPTR); - break; - - case '%': len = zpl__print_char(text, remaining, &info, '%'); break; - - default: fmt--; break; - } - - fmt++; - - if (info.base != 0) { - if (info.flags & ZPL_FMT_UNSIGNED) { - zpl_u64 value = 0; - switch (info.flags & ZPL_FMT_INTS) { - case ZPL_FMT_CHAR: value = cast(zpl_u64) cast(zpl_u8) va_arg(va, int); break; - case ZPL_FMT_SHORT: value = cast(zpl_u64) cast(zpl_u16) va_arg(va, int); break; - case ZPL_FMT_LONG: value = cast(zpl_u64) va_arg(va, unsigned long); break; - case ZPL_FMT_LLONG: value = cast(zpl_u64) va_arg(va, unsigned long long); break; - case ZPL_FMT_SIZE: value = cast(zpl_u64) va_arg(va, zpl_usize); break; - case ZPL_FMT_INTPTR: value = cast(zpl_u64) va_arg(va, zpl_uintptr); break; - default: value = cast(zpl_u64) va_arg(va, unsigned int); break; - } - - len = zpl__print_u64(text, remaining, &info, value); - - } else { - zpl_i64 value = 0; - switch (info.flags & ZPL_FMT_INTS) { - case ZPL_FMT_CHAR: value = cast(zpl_i64) cast(zpl_i8) va_arg(va, int); break; - case ZPL_FMT_SHORT: value = cast(zpl_i64) cast(zpl_i16) va_arg(va, int); break; - case ZPL_FMT_LONG: value = cast(zpl_i64) va_arg(va, long); break; - case ZPL_FMT_LLONG: value = cast(zpl_i64) va_arg(va, long long); break; - case ZPL_FMT_SIZE: value = cast(zpl_i64) va_arg(va, zpl_usize); break; - case ZPL_FMT_INTPTR: value = cast(zpl_i64) va_arg(va, zpl_uintptr); break; - default: value = cast(zpl_i64) va_arg(va, int); break; - } - - len = zpl__print_i64(text, remaining, &info, value); - } - } - - text += len; - if (len >= remaining) - remaining = zpl_min(remaining, 1); - else - remaining -= len; - } - - *text++ = '\0'; - res = (text - text_begin); - return (res >= max_len || res < 0) ? -1 : res; - } - - ZPL_END_C_DECLS - // file: source/core/time.c - - - #if defined(ZPL_SYSTEM_MACOS) || ZPL_SYSTEM_UNIX - # include - # include - #endif - - #if defined(ZPL_SYSTEM_MACOS) - # include - # include - # include - #endif - - #if defined(ZPL_SYSTEM_EMSCRIPTEN) - # include - #endif - - #if defined(ZPL_SYSTEM_WINDOWS) - # include - #endif - - ZPL_BEGIN_C_DECLS - - //! @} - //$$ - //////////////////////////////////////////////////////////////// - // - // Time - // - // - - #if defined(ZPL_COMPILER_MSVC) && !defined(__clang__) - zpl_u64 zpl_rdtsc(void) { return __rdtsc( ); } - #elif defined(__i386__) - zpl_u64 zpl_rdtsc(void) { - zpl_u64 x; - __asm__ volatile(".byte 0x0f, 0x31" : "=A"(x)); - return x; - } - #elif defined(__x86_64__) - zpl_u64 zpl_rdtsc(void) { - zpl_u32 hi, lo; - __asm__ __volatile__("rdtsc" : "=a"(lo), "=d"(hi)); - return (cast(zpl_u64) lo) | ((cast(zpl_u64) hi) << 32); - } - #elif defined(__powerpc__) - zpl_u64 zpl_rdtsc(void) { - zpl_u64 result = 0; - zpl_u32 upper, lower, tmp; - __asm__ volatile("0: \n" - "\tmftbu %0 \n" - "\tmftb %1 \n" - "\tmftbu %2 \n" - "\tcmpw %2,%0 \n" - "\tbne 0b \n" - : "=r"(upper), "=r"(lower), "=r"(tmp)); - result = upper; - result = result << 32; - result = result | lower; - - return result; - } - #elif defined(ZPL_SYSTEM_EMSCRIPTEN) - zpl_u64 zpl_rdtsc(void) { - return (zpl_u64)(emscripten_get_now() * 1e+6); - } - #elif defined(ZPL_CPU_ARM) && !defined(ZPL_COMPILER_TINYC) - zpl_u64 zpl_rdtsc(void) { - # if defined(__aarch64__) - int64_t r = 0; - asm volatile("mrs %0, cntvct_el0" : "=r"(r)); - # elif (__ARM_ARCH >= 6) - uint32_t r = 0; - uint32_t pmccntr; - uint32_t pmuseren; - uint32_t pmcntenset; - - // Read the user mode perf monitor counter access permissions. - asm volatile("mrc p15, 0, %0, c9, c14, 0" : "=r"(pmuseren)); - if (pmuseren & 1) { // Allows reading perfmon counters for user mode code. - asm volatile("mrc p15, 0, %0, c9, c12, 1" : "=r"(pmcntenset)); - if (pmcntenset & 0x80000000ul) { // Is it counting? - asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r"(pmccntr)); - // The counter is set up to count every 64th cycle - return ((int64_t)pmccntr) * 64; // Should optimize to << 6 - } - } - # else - # error "No suitable method for zpl_rdtsc for this cpu type" - # endif - - return r; - } - #else - zpl_u64 zpl_rdtsc(void) { - ZPL_PANIC("zpl_rdtsc is not supported on this particular setup"); - return -0; - } - #endif - - #if defined(ZPL_SYSTEM_WINDOWS) || defined(ZPL_SYSTEM_CYGWIN) - - zpl_u64 zpl_time_rel_ms(void) { - zpl_local_persist LARGE_INTEGER win32_perf_count_freq = { 0 }; - zpl_u64 result; - LARGE_INTEGER counter; - zpl_local_persist LARGE_INTEGER win32_perf_counter = { 0 }; - if (!win32_perf_count_freq.QuadPart) { - QueryPerformanceFrequency(&win32_perf_count_freq); - ZPL_ASSERT(win32_perf_count_freq.QuadPart != 0); - QueryPerformanceCounter(&win32_perf_counter); - } - - QueryPerformanceCounter(&counter); - - result = (counter.QuadPart - win32_perf_counter.QuadPart) * 1000 / (win32_perf_count_freq.QuadPart); - return result; - } - - zpl_u64 zpl_time_utc_ms(void) { - FILETIME ft; - ULARGE_INTEGER li; - - GetSystemTimeAsFileTime(&ft); - li.LowPart = ft.dwLowDateTime; - li.HighPart = ft.dwHighDateTime; - - return li.QuadPart / 1000; - } - - zpl_u64 zpl_time_tz_ms(void) { - FILETIME ft; - SYSTEMTIME st, lst; - ULARGE_INTEGER li; - - GetSystemTime(&st); - SystemTimeToTzSpecificLocalTime(NULL, &st, &lst); - SystemTimeToFileTime(&lst, &ft); - li.LowPart = ft.dwLowDateTime; - li.HighPart = ft.dwHighDateTime; - - return li.QuadPart / 1000; - } - - void zpl_sleep_ms(zpl_u32 ms) { Sleep(ms); } - - #else - - # if defined(ZPL_SYSTEM_LINUX) || defined(ZPL_SYSTEM_FREEBSD) || defined(ZPL_SYSTEM_OPENBSD) || defined(ZPL_SYSTEM_EMSCRIPTEN) - zpl_u64 zpl__unix_gettime(void) { - struct timespec t; - zpl_u64 result; - - clock_gettime(1 /*CLOCK_MONOTONIC*/, &t); - result = 1000 * t.tv_sec + 1.0e-6 * t.tv_nsec; - return result; - } - # endif - - zpl_u64 zpl_time_rel_ms(void) { - # if defined(ZPL_SYSTEM_OSX) - zpl_u64 result; - - zpl_local_persist zpl_u64 timebase = 0; - zpl_local_persist zpl_u64 timestart = 0; - - if (!timestart) { - mach_timebase_info_data_t tb = { 0 }; - mach_timebase_info(&tb); - timebase = tb.numer; - timebase /= tb.denom; - timestart = mach_absolute_time(); - } - - // NOTE: mach_absolute_time() returns things in nanoseconds - result = 1.0e-6 * (mach_absolute_time() - timestart) * timebase; - return result; - # else - zpl_local_persist zpl_u64 unix_timestart = 0.0; - - if (!unix_timestart) { unix_timestart = zpl__unix_gettime( ); } - - zpl_u64 now = zpl__unix_gettime( ); - - return (now - unix_timestart); - # endif - } - - zpl_u64 zpl_time_utc_ms(void) { - struct timespec t; - # if defined(ZPL_SYSTEM_OSX) - clock_serv_t cclock; - mach_timespec_t mts; - host_get_clock_service(mach_host_self( ), CALENDAR_CLOCK, &cclock); - clock_get_time(cclock, &mts); - mach_port_deallocate(mach_task_self( ), cclock); - t.tv_sec = mts.tv_sec; - t.tv_nsec = mts.tv_nsec; - # else - clock_gettime(0 /*CLOCK_REALTIME*/, &t); - # endif - return ((zpl_u64)t.tv_sec * 1000 + t.tv_nsec * 1e-6 + ZPL__UNIX_TO_WIN32_EPOCH); - } - - void zpl_sleep_ms(zpl_u32 ms) { - struct timespec req = { cast(time_t)(ms * 1e-3), cast(long)((ms % 1000) * 1e6) }; - struct timespec rem = { 0, 0 }; - nanosleep(&req, &rem); - } - - zpl_u64 zpl_time_tz_ms(void) { - struct tm t; - zpl_u64 result = zpl_time_utc_ms() - ZPL__UNIX_TO_WIN32_EPOCH; - zpl_u16 ms = result % 1000; - result *= 1e-3; - localtime_r((const time_t*)&result, &t); - result = (zpl_u64)mktime(&t); - return (result - timezone + t.tm_isdst * 3600) * 1000 + ms + ZPL__UNIX_TO_WIN32_EPOCH; - } - #endif - - zpl_f64 zpl_time_rel(void) { - return (zpl_f64)(zpl_time_rel_ms() * 1e-3); - } - - zpl_f64 zpl_time_utc(void) { - return (zpl_f64)(zpl_time_utc_ms() * 1e-3); - } - - zpl_f64 zpl_time_tz(void) { - return (zpl_f64)(zpl_time_tz_ms() * 1e-3); - } - - - - ZPL_END_C_DECLS - // file: source/core/random.c - - - ZPL_BEGIN_C_DECLS - - #if defined(ZPL_MODULE_THREADING) - zpl_global zpl_atomic32 zpl__random_shared_counter = {0}; - #else - zpl_global zpl_i32 zpl__random_shared_counter = 0; - #endif - - zpl_internal zpl_u32 zpl__get_noise_from_time(void) { - zpl_u32 accum = 0; - zpl_f64 start, remaining, end, curr = 0; - zpl_u64 interval = 100000ll; - - start = zpl_time_rel(); - remaining = (interval - cast(zpl_u64)(interval*start)%interval) / cast(zpl_f64)interval; - end = start + remaining; - - do { - curr = zpl_time_rel(); - accum += cast(zpl_u32)curr; - } while (curr >= end); - return accum; - } - - // NOTE: Partly from http://preshing.com/20121224/how-to-generate-a-sequence-of-unique-random-integers/ - // But the generation is even more random-er-est - - zpl_internal ZPL_ALWAYS_INLINE zpl_u32 zpl__permute_qpr(zpl_u32 x) { - zpl_local_persist zpl_u32 const prime = 4294967291; // 2^32 - 5 - if (x >= prime) { - return x; - } else { - zpl_u32 residue = cast(zpl_u32)(cast(zpl_u64) x * x) % prime; - if (x <= prime / 2) - return residue; - else - return prime - residue; - } - } - - zpl_internal ZPL_ALWAYS_INLINE zpl_u32 zpl__permute_with_offset(zpl_u32 x, zpl_u32 offset) { - return (zpl__permute_qpr(x) + offset) ^ 0x5bf03635; - } - - - void zpl_random_init(zpl_random *r) { - zpl_u64 time, tick; - zpl_isize i, j; - zpl_u32 x = 0; - r->value = 0; - - r->offsets[0] = zpl__get_noise_from_time(); - #ifdef ZPL_MODULE_THREADING - r->offsets[1] = zpl_atomic32_fetch_add(&zpl__random_shared_counter, 1); - r->offsets[2] = zpl_thread_current_id(); - r->offsets[3] = zpl_thread_current_id() * 3 + 1; - #else - r->offsets[1] = zpl__random_shared_counter++; - r->offsets[2] = 0; - r->offsets[3] = 1; - #endif - time = zpl_time_tz_ms(); - r->offsets[4] = cast(zpl_u32)(time >> 32); - r->offsets[5] = cast(zpl_u32)time; - r->offsets[6] = zpl__get_noise_from_time(); - tick = zpl_rdtsc(); - r->offsets[7] = cast(zpl_u32)(tick ^ (tick >> 32)); - - for (j = 0; j < 4; j++) { - for (i = 0; i < zpl_count_of(r->offsets); i++) { - r->offsets[i] = x = zpl__permute_with_offset(x, r->offsets[i]); - } - } - } - - zpl_u32 zpl_random_gen_u32(zpl_random *r) { - zpl_u32 x = r->value; - zpl_u32 carry = 1; - zpl_isize i; - for (i = 0; i < zpl_count_of(r->offsets); i++) { - x = zpl__permute_with_offset(x, r->offsets[i]); - if (carry > 0) { - carry = ++r->offsets[i] ? 0 : 1; - } - } - - r->value = x; - return x; - } - - zpl_u32 zpl_random_gen_u32_unique(zpl_random *r) { - zpl_u32 x = r->value; - zpl_isize i; - r->value++; - for (i = 0; i < zpl_count_of(r->offsets); i++) { - x = zpl__permute_with_offset(x, r->offsets[i]); - } - - return x; - } - - zpl_u64 zpl_random_gen_u64(zpl_random *r) { - return ((cast(zpl_u64)zpl_random_gen_u32(r)) << 32) | zpl_random_gen_u32(r); - } - - - zpl_isize zpl_random_gen_isize(zpl_random *r) { - zpl_u64 u = zpl_random_gen_u64(r); - zpl_isize i; - zpl_memcopy(&i, &u, zpl_size_of(u)); - return i; - } - - - zpl_i64 zpl_random_range_i64(zpl_random *r, zpl_i64 lower_inc, zpl_i64 higher_inc) { - zpl_u64 u = zpl_random_gen_u64(r); - zpl_i64 i = *cast(zpl_i64 *)&u; - zpl_i64 diff = higher_inc-lower_inc+1; - i %= diff; - i += lower_inc; - return i; - } - - zpl_isize zpl_random_range_isize(zpl_random *r, zpl_isize lower_inc, zpl_isize higher_inc) { - zpl_u64 u = zpl_random_gen_u64(r); - zpl_isize i; - zpl_memcopy(&i, &u, zpl_size_of(u)); - zpl_isize diff = higher_inc-lower_inc+1; - i %= diff; - i += lower_inc; - return i; - } - - ZPL_ALWAYS_INLINE zpl_f64 zpl__random_copy_sign64(zpl_f64 x, zpl_f64 y) { - zpl_i64 ix=0, iy=0; - zpl_memcopy(&ix, &x, zpl_size_of(zpl_i64)); - zpl_memcopy(&iy, &y, zpl_size_of(zpl_i64)); - - ix &= 0x7fffffffffffffff; - ix |= iy & 0x8000000000000000; - - zpl_f64 r = 0.0; - zpl_memcopy(&r, &ix, zpl_size_of(zpl_f64)); - return r; - } - - zpl_f64 zpl_random_range_f64(zpl_random *r, zpl_f64 lower_inc, zpl_f64 higher_inc) { - zpl_f64 f = cast(zpl_f64)zpl_random_gen_u64(r) / cast(zpl_f64)ZPL_U64_MAX; - zpl_f64 diff = higher_inc-lower_inc; - - f *= diff; - f += lower_inc; - return f; - } - - ZPL_END_C_DECLS - // file: source/core/misc.c - - - ZPL_BEGIN_C_DECLS - - void zpl_yield(void) { - # if defined(ZPL_SYSTEM_WINDOWS) - Sleep(0); - # else - sched_yield(); - # endif - } - - const char *zpl_get_env(const char *name) { - char *buffer = NULL; - const char *ptr = zpl_get_env_buf(name); - - if (ptr == NULL) { - return NULL; - } - - zpl_isize ptr_size = zpl_strlen(ptr); - buffer = (char *)zpl_malloc(ptr_size * sizeof(char)+1); - zpl_memcopy((char *)buffer, ptr, ptr_size+1); - return buffer; - } - - const char *zpl_get_env_buf(const char *name) { - # ifdef ZPL_SYSTEM_WINDOWS - zpl_local_persist wchar_t wbuffer[32767] = {0}; - zpl_local_persist char buffer[32767] = {0}; - - if (!GetEnvironmentVariableW( - cast(LPCWSTR)zpl_utf8_to_ucs2_buf(cast(const zpl_u8 *)name), - cast(LPWSTR)wbuffer, 32767)) { - return NULL; - } - - zpl_ucs2_to_utf8(cast(zpl_u8*)buffer, 32767, cast(const zpl_u16*)wbuffer); - - return (const char *)buffer; - # else - return (const char *)getenv(name); - # endif - } - - zpl_string zpl_get_env_str(const char *name) { - const char *buf = zpl_get_env_buf(name); - - if (buf == NULL) { - return NULL; - } - - zpl_string str = zpl_string_make(zpl_heap(), buf); - return str; - } - - void zpl_set_env(const char *name, const char *value) { - # if defined(ZPL_SYSTEM_WINDOWS) - SetEnvironmentVariableA(name, value); - # else - setenv(name, value, 1); - # endif - } - - void zpl_unset_env(const char *name) { - # if defined(ZPL_SYSTEM_WINDOWS) - SetEnvironmentVariableA(name, NULL); - # else - unsetenv(name); - # endif - } - - #if !defined(ZPL_SYSTEM_WINDOWS) - extern char **environ; - #endif - - zpl_u32 zpl_system_command(const char *command, zpl_usize buffer_len, char *buffer) { - # if defined(ZPL_SYSTEM_EMSCRIPTEN) - ZPL_PANIC("zpl_system_command not supported"); - # else - - # if defined(ZPL_SYSTEM_WINDOWS) - FILE *handle = _popen(command, "r"); - # else - FILE *handle = popen(command, "r"); - # endif - - if(!handle) return 0; - - int c; - zpl_usize i=0; - while ((c = getc(handle)) != EOF && i++ < buffer_len) { - *buffer++ = c; - } - - # if defined(ZPL_SYSTEM_WINDOWS) - _pclose(handle); - # else - pclose(handle); - # endif - - # endif - - return 1; - } - - zpl_string zpl_system_command_str(const char *command, zpl_allocator backing) { - # if defined(ZPL_SYSTEM_EMSCRIPTEN) - ZPL_PANIC("zpl_system_command not supported"); - # else - - # if defined(ZPL_SYSTEM_WINDOWS) - FILE *handle = _popen(command, "r"); - # else - FILE *handle = popen(command, "r"); - # endif - - if(!handle) return NULL; - - zpl_string output = zpl_string_make_reserve(backing, 4); - - int c; - while ((c = getc(handle)) != EOF) { - char ins[2] = {(char)c,0}; - output = zpl_string_appendc(output, ins); - } - - # if defined(ZPL_SYSTEM_WINDOWS) - _pclose(handle); - # else - pclose(handle); - # endif - return output; - # endif - return NULL; - } - - ZPL_END_C_DECLS - // file: source/core/sort.c - - - ZPL_BEGIN_C_DECLS - - #define ZPL__COMPARE_PROC(Type) \ - zpl_global zpl_isize Type##__cmp_offset; \ - ZPL_COMPARE_PROC(Type##__cmp) { \ - Type const p = *cast(Type const *) zpl_pointer_add_const(a, Type##__cmp_offset); \ - Type const q = *cast(Type const *) zpl_pointer_add_const(b, Type##__cmp_offset); \ - return p < q ? -1 : p > q; \ - } \ - ZPL_COMPARE_PROC_PTR(Type##_cmp(zpl_isize offset)) { \ - Type##__cmp_offset = offset; \ - return &Type##__cmp; \ - } - - ZPL__COMPARE_PROC(zpl_u8); - ZPL__COMPARE_PROC(zpl_i16); - ZPL__COMPARE_PROC(zpl_i32); - ZPL__COMPARE_PROC(zpl_i64); - ZPL__COMPARE_PROC(zpl_isize); - ZPL__COMPARE_PROC(zpl_f32); - ZPL__COMPARE_PROC(zpl_f64); - - // NOTE: str_cmp is special as it requires a funny type and funny comparison - zpl_global zpl_isize zpl__str_cmp_offset; - ZPL_COMPARE_PROC(zpl__str_cmp) { - char const *p = *cast(char const **) zpl_pointer_add_const(a, zpl__str_cmp_offset); - char const *q = *cast(char const **) zpl_pointer_add_const(b, zpl__str_cmp_offset); - return zpl_strcmp(p, q); - } - ZPL_COMPARE_PROC_PTR(zpl_str_cmp(zpl_isize offset)) { - zpl__str_cmp_offset = offset; - return &zpl__str_cmp; - } - - #undef ZPL__COMPARE_PROC - - // TODO: Make user definable? - #define ZPL__SORT_STACK_SIZE 64 - #define zpl__SORT_INSERT_SORT_TRESHOLD 8 - - #define ZPL__SORT_PUSH(_base, _limit) \ - do { \ - stack_ptr[0] = (_base); \ - stack_ptr[1] = (_limit); \ - stack_ptr += 2; \ - } while (0) - - #define ZPL__SORT_POP(_base, _limit) \ - do { \ - stack_ptr -= 2; \ - (_base) = stack_ptr[0]; \ - (_limit) = stack_ptr[1]; \ - } while (0) - - void zpl_sort(void *base_, zpl_isize count, zpl_isize size, zpl_compare_proc cmp) { - zpl_u8 *i, *j; - zpl_u8 *base = cast(zpl_u8 *) base_; - zpl_u8 *limit = base + count * size; - zpl_isize threshold = zpl__SORT_INSERT_SORT_TRESHOLD * size; - - // NOTE: Prepare the stack - zpl_u8 *stack[ZPL__SORT_STACK_SIZE] = { 0 }; - zpl_u8 **stack_ptr = stack; - - for (;;) { - if ((limit - base) > threshold) { - // NOTE: Quick sort - i = base + size; - j = limit - size; - - zpl_memswap(((limit - base) / size / 2) * size + base, base, size); - if (cmp(i, j) > 0) zpl_memswap(i, j, size); - if (cmp(base, j) > 0) zpl_memswap(base, j, size); - if (cmp(i, base) > 0) zpl_memswap(i, base, size); - - for (;;) { - do - i += size; - while (cmp(i, base) < 0); - do - j -= size; - while (cmp(j, base) > 0); - if (i > j) break; - zpl_memswap(i, j, size); - } - - zpl_memswap(base, j, size); - - if (j - base > limit - i) { - ZPL__SORT_PUSH(base, j); - base = i; - } else { - ZPL__SORT_PUSH(i, limit); - limit = j; - } - } else { - // NOTE: Insertion sort - for (j = base, i = j + size; i < limit; j = i, i += size) { - for (; cmp(j, j + size) > 0; j -= size) { - zpl_memswap(j, j + size, size); - if (j == base) break; - } - } - - if (stack_ptr == stack) break; // NOTE: Sorting is done! - ZPL__SORT_POP(base, limit); - } - } - } - - #undef ZPL__SORT_PUSH - #undef ZPL__SORT_POP - - #define ZPL_RADIX_SORT_PROC_GEN(Type) \ - ZPL_RADIX_SORT_PROC(Type) { \ - zpl_##Type *source = items; \ - zpl_##Type *dest = temp; \ - zpl_isize byte_index, i, byte_max = 8 * zpl_size_of(zpl_##Type); \ - for (byte_index = 0; byte_index < byte_max; byte_index += 8) { \ - zpl_isize offsets[256] = { 0 }; \ - zpl_isize total = 0; \ - /* NOTE: First pass - count how many of each key */ \ - for (i = 0; i < count; i++) { \ - zpl_##Type radix_value = source[i]; \ - zpl_##Type radix_piece = (radix_value >> byte_index) & 0xff; \ - offsets[radix_piece]++; \ - } \ - /* NOTE: Change counts to offsets */ \ - for (i = 0; i < zpl_count_of(offsets); i++) { \ - zpl_isize skcount = offsets[i]; \ - offsets[i] = total; \ - total += skcount; \ - } \ - /* NOTE: Second pass - place elements into the right location */ \ - for (i = 0; i < count; i++) { \ - zpl_##Type radix_value = source[i]; \ - zpl_##Type radix_piece = (radix_value >> byte_index) & 0xff; \ - dest[offsets[radix_piece]++] = source[i]; \ - } \ - zpl_swap(zpl_##Type *, source, dest); \ - } \ - } - - ZPL_RADIX_SORT_PROC_GEN(u8); - ZPL_RADIX_SORT_PROC_GEN(u16); - ZPL_RADIX_SORT_PROC_GEN(u32); - ZPL_RADIX_SORT_PROC_GEN(u64); - - void zpl_shuffle(void *base, zpl_isize count, zpl_isize size) { - zpl_u8 *a; - zpl_isize i, j; - zpl_random random; - zpl_random_init(&random); - - a = cast(zpl_u8 *) base + (count - 1) * size; - for (i = count; i > 1; i--) { - j = zpl_random_gen_isize(&random) % i; - zpl_memswap(a, cast(zpl_u8 *) base + j * size, size); - a -= size; - } - } - - void zpl_reverse(void *base, zpl_isize count, zpl_isize size) { - zpl_isize i, j = count - 1; - for (i = 0; i < j; i++, j++) zpl_memswap(cast(zpl_u8 *) base + i * size, cast(zpl_u8 *) base + j * size, size); - } - - ZPL_END_C_DECLS +// file: source/core/memory_virtual.c + +//////////////////////////////////////////////////////////////// +// +// Virtual Memory +// +// + +ZPL_BEGIN_C_DECLS + +zpl_virtual_memory zpl_vm(void *data, zpl_isize size) { + zpl_virtual_memory vm; + vm.data = data; + vm.size = size; + return vm; +} + +#if defined(ZPL_SYSTEM_WINDOWS) +zpl_virtual_memory zpl_vm_alloc(void *addr, zpl_isize size) { + zpl_virtual_memory vm; + ZPL_ASSERT(size > 0); + vm.data = VirtualAlloc(addr, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + vm.size = size; + return vm; +} + +zpl_b32 zpl_vm_free(zpl_virtual_memory vm) { + MEMORY_BASIC_INFORMATION info; + while (vm.size > 0) { + if (VirtualQuery(vm.data, &info, zpl_size_of(info)) == 0) return false; + if (info.BaseAddress != vm.data || info.AllocationBase != vm.data || info.State != MEM_COMMIT || + info.RegionSize > cast(zpl_usize) vm.size) { + return false; + } + if (VirtualFree(vm.data, 0, MEM_RELEASE) == 0) return false; + vm.data = zpl_pointer_add(vm.data, info.RegionSize); + vm.size -= info.RegionSize; + } + return true; +} + +zpl_virtual_memory zpl_vm_trim(zpl_virtual_memory vm, zpl_isize lead_size, zpl_isize size) { + zpl_virtual_memory new_vm = { 0 }; + void *ptr; + ZPL_ASSERT(vm.size >= lead_size + size); + + ptr = zpl_pointer_add(vm.data, lead_size); + + zpl_vm_free(vm); + new_vm = zpl_vm_alloc(ptr, size); + if (new_vm.data == ptr) return new_vm; + if (new_vm.data) zpl_vm_free(new_vm); + return new_vm; +} + +zpl_b32 zpl_vm_purge(zpl_virtual_memory vm) { + VirtualAlloc(vm.data, vm.size, MEM_RESET, PAGE_READWRITE); + // NOTE: Can this really fail? + return true; +} + +zpl_isize zpl_virtual_memory_page_size(zpl_isize *alignment_out) { + SYSTEM_INFO info; + GetSystemInfo(&info); + if (alignment_out) *alignment_out = info.dwAllocationGranularity; + return info.dwPageSize; +} + +#else +# include + +# ifndef MAP_ANONYMOUS +# define MAP_ANONYMOUS MAP_ANON +# endif + +zpl_virtual_memory zpl_vm_alloc(void *addr, zpl_isize size) { + zpl_virtual_memory vm; + ZPL_ASSERT(size > 0); + vm.data = mmap(addr, size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + vm.size = size; + return vm; +} + +zpl_b32 zpl_vm_free(zpl_virtual_memory vm) { + munmap(vm.data, vm.size); + return true; +} + +zpl_virtual_memory zpl_vm_trim(zpl_virtual_memory vm, zpl_isize lead_size, zpl_isize size) { + void *ptr; + zpl_isize trail_size; + ZPL_ASSERT(vm.size >= lead_size + size); + + ptr = zpl_pointer_add(vm.data, lead_size); + trail_size = vm.size - lead_size - size; + + if (lead_size != 0) zpl_vm_free(zpl_vm(vm.data, lead_size)); + if (trail_size != 0) zpl_vm_free(zpl_vm(ptr, trail_size)); + return zpl_vm(ptr, size); +} + +zpl_b32 zpl_vm_purge(zpl_virtual_memory vm) { + int err = madvise(vm.data, vm.size, MADV_DONTNEED); + return err != 0; +} + +zpl_isize zpl_virtual_memory_page_size(zpl_isize *alignment_out) { + // TODO: Is this always true? + zpl_isize result = cast(zpl_isize) sysconf(_SC_PAGE_SIZE); + if (alignment_out) *alignment_out = result; + return result; +} + +#endif + +ZPL_END_C_DECLS +// file: source/core/string.c + +//////////////////////////////////////////////////////////////// +// +// Char things +// +// + +ZPL_BEGIN_C_DECLS + +zpl_internal zpl_isize zpl__scan_zpl_i64(const char *text, zpl_i32 base, zpl_i64 *value) { + const char *text_begin = text; + zpl_i64 result = 0; + zpl_b32 negative = false; + + if (*text == '-') { + negative = true; + text++; + } + + if (base == 16 && zpl_strncmp(text, "0x", 2) == 0) text += 2; + + for (;;) { + zpl_i64 v; + if (zpl_char_is_digit(*text)) + v = *text - '0'; + else if (base == 16 && zpl_char_is_hex_digit(*text)) + v = zpl_hex_digit_to_int(*text); + else + break; + + result *= base; + result += v; + text++; + } + + if (value) { + if (negative) result = -result; + *value = result; + } + + return (text - text_begin); +} + +zpl_internal zpl_isize zpl__scan_zpl_u64(const char *text, zpl_i32 base, zpl_u64 *value) { + const char *text_begin = text; + zpl_u64 result = 0; + + if (base == 16 && zpl_strncmp(text, "0x", 2) == 0) text += 2; + + for (;;) { + zpl_u64 v; + if (zpl_char_is_digit(*text)) + v = *text - '0'; + else if (base == 16 && zpl_char_is_hex_digit(*text)) + v = zpl_hex_digit_to_int(*text); + else { + break; + } + + result *= base; + result += v; + text++; + } + + if (value) *value = result; + + return (text - text_begin); +} + +// TODO: Make better +zpl_u64 zpl_str_to_u64(const char *str, char **end_ptr, zpl_i32 base) { + zpl_isize len; + zpl_u64 value = 0; + + if (!base) { + if ((zpl_strlen(str) > 2) && (zpl_strncmp(str, "0x", 2) == 0)) + base = 16; + else + base = 10; + } + + len = zpl__scan_zpl_u64(str, base, &value); + if (end_ptr) *end_ptr = (char *)str + len; + return value; +} + +zpl_i64 zpl_str_to_i64(const char *str, char **end_ptr, zpl_i32 base) { + zpl_isize len; + zpl_i64 value; + + if (!base) { + if ((zpl_strlen(str) > 2) && (zpl_strncmp(str, "0x", 2) == 0)) + base = 16; + else + base = 10; + } + + len = zpl__scan_zpl_i64(str, base, &value); + if (end_ptr) *end_ptr = (char *)str + len; + return value; +} + +// TODO: Are these good enough for characters? +zpl_global const char zpl__num_to_char_table[] = "0123456789" +"ABCDEFGHIJKLMNOPQRSTUVWXYZ" +"abcdefghijklmnopqrstuvwxyz" +"@$"; + +void zpl_i64_to_str(zpl_i64 value, char *string, zpl_i32 base) { + char *buf = string; + zpl_b32 negative = false; + zpl_u64 v; + + if (value < 0) { + negative = true; + value = -value; + } + + v = cast(zpl_u64) value; + if (v != 0) { + while (v > 0) { + *buf++ = zpl__num_to_char_table[v % base]; + v /= base; + } + } else { + *buf++ = '0'; + } + if (negative) *buf++ = '-'; + *buf = '\0'; + zpl_strrev(string); +} + +void zpl_u64_to_str(zpl_u64 value, char *string, zpl_i32 base) { + char *buf = string; + + if (value) { + while (value > 0) { + *buf++ = zpl__num_to_char_table[value % base]; + value /= base; + } + } else { + *buf++ = '0'; + } + *buf = '\0'; + + zpl_strrev(string); +} + +zpl_f64 zpl_str_to_f64(const char *str, char **end_ptr) { + zpl_f64 result, value, sign, scale; + zpl_i32 frac; + + while (zpl_char_is_space(*str)) { str++; } + + sign = 1.0; + if (*str == '-') { + sign = -1.0; + str++; + } else if (*str == '+') { + str++; + } + + for (value = 0.0; zpl_char_is_digit(*str); str++) { value = value * 10.0 + (*str - '0'); } + + if (*str == '.') { + zpl_f64 pow10 = 10.0; + str++; + while (zpl_char_is_digit(*str)) { + value += (*str - '0') / pow10; + pow10 *= 10.0; + str++; + } + } + + frac = 0; + scale = 1.0; + if ((*str == 'e') || (*str == 'E')) { + zpl_u32 exp; + + str++; + if (*str == '-') { + frac = 1; + str++; + } else if (*str == '+') { + str++; + } + + for (exp = 0; zpl_char_is_digit(*str); str++) { exp = exp * 10 + (*str - '0'); } + if (exp > 308) exp = 308; + + while (exp >= 50) { + scale *= 1e50; + exp -= 50; + } + while (exp >= 8) { + scale *= 1e8; + exp -= 8; + } + while (exp > 0) { + scale *= 10.0; + exp -= 1; + } + } + + result = sign * (frac ? (value / scale) : (value * scale)); + + if (end_ptr) *end_ptr = cast(char *) str; + + return result; +} + + + +//////////////////////////////////////////////////////////////// +// +// Windows UTF-8 Handling +// +// + +zpl_u16 *zpl_utf8_to_ucs2(zpl_u16 *buffer, zpl_isize len, zpl_u8 const *str) { + zpl_rune c; + zpl_isize i = 0; + len--; + while (*str) { + if (i >= len) return NULL; + if (!(*str & 0x80)) { + buffer[i++] = *str++; + } else if ((*str & 0xe0) == 0xc0) { + if (*str < 0xc2) return NULL; + c = (*str++ & 0x1f) << 6; + if ((*str & 0xc0) != 0x80) return NULL; + buffer[i++] = cast(zpl_u16)(c + (*str++ & 0x3f)); + } else if ((*str & 0xf0) == 0xe0) { + if (*str == 0xe0 && (str[1] < 0xa0 || str[1] > 0xbf)) return NULL; + if (*str == 0xed && str[1] > 0x9f) // str[1] < 0x80 is checked below + return NULL; + c = (*str++ & 0x0f) << 12; + if ((*str & 0xc0) != 0x80) return NULL; + c += (*str++ & 0x3f) << 6; + if ((*str & 0xc0) != 0x80) return NULL; + buffer[i++] = cast(zpl_u16)(c + (*str++ & 0x3f)); + } else if ((*str & 0xf8) == 0xf0) { + if (*str > 0xf4) return NULL; + if (*str == 0xf0 && (str[1] < 0x90 || str[1] > 0xbf)) return NULL; + if (*str == 0xf4 && str[1] > 0x8f) // str[1] < 0x80 is checked below + return NULL; + c = (*str++ & 0x07) << 18; + if ((*str & 0xc0) != 0x80) return NULL; + c += (*str++ & 0x3f) << 12; + if ((*str & 0xc0) != 0x80) return NULL; + c += (*str++ & 0x3f) << 6; + if ((*str & 0xc0) != 0x80) return NULL; + c += (*str++ & 0x3f); + // UTF-8 encodings of values used in surrogate pairs are invalid + if ((c & 0xfffff800) == 0xd800) return NULL; + if (c >= 0x10000) { + c -= 0x10000; + if (i + 2 > len) return NULL; + buffer[i++] = 0xd800 | (0x3ff & (c >> 10)); + buffer[i++] = 0xdc00 | (0x3ff & (c)); + } + } else { + return NULL; + } + } + buffer[i] = 0; + return buffer; +} + +zpl_u8 *zpl_ucs2_to_utf8(zpl_u8 *buffer, zpl_isize len, zpl_u16 const *str) { + zpl_isize i = 0; + len--; + while (*str) { + if (*str < 0x80) { + if (i + 1 > len) return NULL; + buffer[i++] = (char)*str++; + } else if (*str < 0x800) { + if (i + 2 > len) return NULL; + buffer[i++] = cast(char)(0xc0 + (*str >> 6)); + buffer[i++] = cast(char)(0x80 + (*str & 0x3f)); + str += 1; + } else if (*str >= 0xd800 && *str < 0xdc00) { + zpl_rune c; + if (i + 4 > len) return NULL; + c = ((str[0] - 0xd800) << 10) + ((str[1]) - 0xdc00) + 0x10000; + buffer[i++] = cast(char)(0xf0 + (c >> 18)); + buffer[i++] = cast(char)(0x80 + ((c >> 12) & 0x3f)); + buffer[i++] = cast(char)(0x80 + ((c >> 6) & 0x3f)); + buffer[i++] = cast(char)(0x80 + ((c)&0x3f)); + str += 2; + } else if (*str >= 0xdc00 && *str < 0xe000) { + return NULL; + } else { + if (i + 3 > len) return NULL; + buffer[i++] = 0xe0 + (*str >> 12); + buffer[i++] = 0x80 + ((*str >> 6) & 0x3f); + buffer[i++] = 0x80 + ((*str) & 0x3f); + str += 1; + } + } + buffer[i] = 0; + return buffer; +} + +zpl_u16 *zpl_utf8_to_ucs2_buf(zpl_u8 const *str) { // NOTE: Uses locally persisting buffer + zpl_local_persist zpl_u16 buf[4096]; + return zpl_utf8_to_ucs2(buf, zpl_count_of(buf), str); +} + +zpl_u8 *zpl_ucs2_to_utf8_buf(zpl_u16 const *str) { // NOTE: Uses locally persisting buffer + zpl_local_persist zpl_u8 buf[4096]; + return zpl_ucs2_to_utf8(buf, zpl_count_of(buf), str); +} + +zpl_global zpl_u8 const zpl__utf8_first[256] = { + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x00-0x0F + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x10-0x1F + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x20-0x2F + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x30-0x3F + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x40-0x4F + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x50-0x5F + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x60-0x6F + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x70-0x7F + 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0x80-0x8F + 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0x90-0x9F + 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xA0-0xAF + 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xB0-0xBF + 0xf1, 0xf1, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, // 0xC0-0xCF + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, // 0xD0-0xDF + 0x13, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x23, 0x03, 0x03, // 0xE0-0xEF + 0x34, 0x04, 0x04, 0x04, 0x44, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xF0-0xFF +}; + + +typedef struct zpl_utf8_accept_range { + zpl_u8 lo, hi; +} zpl_utf8_accept_range; + +zpl_global zpl_utf8_accept_range const zpl__utf8_accept_ranges[] = { + { 0x80, 0xbf }, { 0xa0, 0xbf }, { 0x80, 0x9f }, { 0x90, 0xbf }, { 0x80, 0x8f }, +}; + +zpl_isize zpl_utf8_decode(zpl_u8 const *str, zpl_isize str_len, zpl_rune *codepoint_out) { + + zpl_isize width = 0; + zpl_rune codepoint = ZPL_RUNE_INVALID; + + if (str_len > 0) { + zpl_u8 s0 = str[0]; + zpl_u8 x = zpl__utf8_first[s0], sz; + zpl_u8 b1, b2, b3; + zpl_utf8_accept_range accept; + if (x >= 0xf0) { + zpl_rune mask = (cast(zpl_rune) x << 31) >> 31; + codepoint = (cast(zpl_rune) s0 & (~mask)) | (ZPL_RUNE_INVALID & mask); + width = 1; + goto end; + } + if (s0 < 0x80) { + codepoint = s0; + width = 1; + goto end; + } + + sz = x & 7; + accept = zpl__utf8_accept_ranges[x >> 4]; + if (str_len < sz) goto invalid_codepoint; + + b1 = str[1]; + if (b1 < accept.lo || accept.hi < b1) goto invalid_codepoint; + + if (sz == 2) { + codepoint = (cast(zpl_rune) s0 & 0x1f) << 6 | (cast(zpl_rune) b1 & 0x3f); + width = 2; + goto end; + } + + b2 = str[2]; + if (!zpl_is_between(b2, 0x80, 0xbf)) goto invalid_codepoint; + + if (sz == 3) { + codepoint = (cast(zpl_rune) s0 & 0x1f) << 12 | (cast(zpl_rune) b1 & 0x3f) << 6 | (cast(zpl_rune) b2 & 0x3f); + width = 3; + goto end; + } + + b3 = str[3]; + if (!zpl_is_between(b3, 0x80, 0xbf)) goto invalid_codepoint; + + codepoint = (cast(zpl_rune) s0 & 0x07) << 18 | (cast(zpl_rune) b1 & 0x3f) << 12 | (cast(zpl_rune) b2 & 0x3f) << 6 | + (cast(zpl_rune) b3 & 0x3f); + width = 4; + goto end; + + invalid_codepoint: + codepoint = ZPL_RUNE_INVALID; + width = 1; + } + + end: + if (codepoint_out) *codepoint_out = codepoint; + return width; +} + +zpl_isize zpl_utf8_codepoint_size(zpl_u8 const *str, zpl_isize str_len) { + zpl_isize i = 0; + for (; i < str_len && str[i]; i++) { + if ((str[i] & 0xc0) != 0x80) break; + } + return i + 1; +} + +zpl_isize zpl_utf8_encode_rune(zpl_u8 buf[4], zpl_rune r) { + zpl_u32 i = cast(zpl_u32) r; + zpl_u8 mask = 0x3f; + if (i <= (1 << 7) - 1) { + buf[0] = cast(zpl_u8) r; + return 1; + } + if (i <= (1 << 11) - 1) { + buf[0] = 0xc0 | cast(zpl_u8)(r >> 6); + buf[1] = 0x80 | (cast(zpl_u8)(r) & mask); + return 2; + } + + // Invalid or Surrogate range + if (i > ZPL_RUNE_MAX || zpl_is_between(i, 0xd800, 0xdfff)) { + r = ZPL_RUNE_INVALID; + + buf[0] = 0xe0 | cast(zpl_u8)(r >> 12); + buf[1] = 0x80 | (cast(zpl_u8)(r >> 6) & mask); + buf[2] = 0x80 | (cast(zpl_u8)(r) & mask); + return 3; + } + + if (i <= (1 << 16) - 1) { + buf[0] = 0xe0 | cast(zpl_u8)(r >> 12); + buf[1] = 0x80 | (cast(zpl_u8)(r >> 6) & mask); + buf[2] = 0x80 | (cast(zpl_u8)(r) & mask); + return 3; + } + + buf[0] = 0xf0 | cast(zpl_u8)(r >> 18); + buf[1] = 0x80 | (cast(zpl_u8)(r >> 12) & mask); + buf[2] = 0x80 | (cast(zpl_u8)(r >> 6) & mask); + buf[3] = 0x80 | (cast(zpl_u8)(r) & mask); + return 4; +} + +ZPL_END_C_DECLS +// file: source/core/stringlib.c + + +ZPL_BEGIN_C_DECLS + +zpl_string zpl_string_make_reserve(zpl_allocator a, zpl_isize capacity) { + zpl_isize header_size = zpl_size_of(zpl_string_header); + void *ptr = zpl_alloc(a, header_size + capacity + 1); + + zpl_string str; + zpl_string_header *header; + + if (ptr == NULL) return NULL; + zpl_zero_size(ptr, header_size + capacity + 1); + + str = cast(char *) ptr + header_size; + header = ZPL_STRING_HEADER(str); + header->allocator = a; + header->length = 0; + header->capacity = capacity; + str[capacity] = '\0'; + + return str; +} + + +zpl_string zpl_string_make_length(zpl_allocator a, void const *init_str, zpl_isize num_bytes) { + zpl_isize header_size = zpl_size_of(zpl_string_header); + void *ptr = zpl_alloc(a, header_size + num_bytes + 1); + + zpl_string str; + zpl_string_header *header; + + if (ptr == NULL) return NULL; + if (!init_str) zpl_zero_size(ptr, header_size + num_bytes + 1); + + str = cast(char *) ptr + header_size; + header = ZPL_STRING_HEADER(str); + header->allocator = a; + header->length = num_bytes; + header->capacity = num_bytes; + if (num_bytes && init_str) zpl_memcopy(str, init_str, num_bytes); + str[num_bytes] = '\0'; + + return str; +} + +zpl_string zpl_string_sprintf_buf(zpl_allocator a, const char *fmt, ...) { + zpl_local_persist zpl_thread_local char buf[ZPL_PRINTF_MAXLEN] = { 0 }; + va_list va; + va_start(va, fmt); + zpl_snprintf_va(buf, ZPL_PRINTF_MAXLEN, fmt, va); + va_end(va); + + return zpl_string_make(a, buf); +} + +zpl_string zpl_string_sprintf(zpl_allocator a, char *buf, zpl_isize num_bytes, const char *fmt, ...) { + va_list va; + va_start(va, fmt); + zpl_snprintf_va(buf, num_bytes, fmt, va); + va_end(va); + + return zpl_string_make(a, buf); +} + +zpl_string zpl_string_append_length(zpl_string str, void const *other, zpl_isize other_len) { + if (other_len > 0) { + zpl_isize curr_len = zpl_string_length(str); + + str = zpl_string_make_space_for(str, other_len); + if (str == NULL) return NULL; + + zpl_memcopy(str + curr_len, other, other_len); + str[curr_len + other_len] = '\0'; + zpl__set_string_length(str, curr_len + other_len); + } + return str; +} + +ZPL_ALWAYS_INLINE zpl_string zpl_string_appendc(zpl_string str, const char *other) { + return zpl_string_append_length(str, other, zpl_strlen(other)); +} + +ZPL_ALWAYS_INLINE zpl_string zpl_string_join(zpl_allocator a, const char **parts, zpl_isize count, const char *glue) { + zpl_string ret; + zpl_isize i; + + ret = zpl_string_make(a, NULL); + + for (i=0; i= add_len) { + return str; + } else { + zpl_isize new_len, old_size, new_size; + void *ptr, *new_ptr; + zpl_allocator a = ZPL_STRING_HEADER(str)->allocator; + zpl_string_header *header; + + new_len = zpl_string_length(str) + add_len; + ptr = ZPL_STRING_HEADER(str); + old_size = zpl_size_of(zpl_string_header) + zpl_string_length(str) + 1; + new_size = zpl_size_of(zpl_string_header) + new_len + 1; + + new_ptr = zpl_resize(a, ptr, old_size, new_size); + if (new_ptr == NULL) return NULL; + + header = cast(zpl_string_header *) new_ptr; + header->allocator = a; + + str = cast(zpl_string)(header + 1); + zpl__set_string_capacity(str, new_len); + + return str; + } +} + +zpl_isize zpl_string_allocation_size(zpl_string const str) { + zpl_isize cap = zpl_string_capacity(str); + return zpl_size_of(zpl_string_header) + cap; +} + +zpl_b32 zpl_string_are_equal(zpl_string const lhs, zpl_string const rhs) { + zpl_isize lhs_len, rhs_len, i; + lhs_len = zpl_string_length(lhs); + rhs_len = zpl_string_length(rhs); + if (lhs_len != rhs_len) return false; + + for (i = 0; i < lhs_len; i++) { + if (lhs[i] != rhs[i]) return false; + } + + return true; +} + +zpl_string zpl_string_trim(zpl_string str, const char *cut_set) { + char *start, *end, *start_pos, *end_pos; + zpl_isize len; + + start_pos = start = str; + end_pos = end = str + zpl_string_length(str) - 1; + + while (start_pos <= end && zpl_char_first_occurence(cut_set, *start_pos)) start_pos++; + while (end_pos > start_pos && zpl_char_first_occurence(cut_set, *end_pos)) end_pos--; + + len = cast(zpl_isize)((start_pos > end_pos) ? 0 : ((end_pos - start_pos) + 1)); + + if (str != start_pos) zpl_memmove(str, start_pos, len); + str[len] = '\0'; + + zpl__set_string_length(str, len); + + return str; +} + +zpl_string zpl_string_append_rune(zpl_string str, zpl_rune r) { + if (r >= 0) { + zpl_u8 buf[8] = { 0 }; + zpl_isize len = zpl_utf8_encode_rune(buf, r); + return zpl_string_append_length(str, buf, len); + } + + return str; +} + +zpl_string zpl_string_append_fmt(zpl_string str, const char *fmt, ...) { + zpl_isize res; + char buf[ZPL_PRINTF_MAXLEN] = { 0 }; + va_list va; + va_start(va, fmt); + res = zpl_snprintf_va(buf, zpl_count_of(buf) - 1, fmt, va) - 1; + va_end(va); + return zpl_string_append_length(str, buf, res); +} + +ZPL_END_C_DECLS +// file: source/core/file.c + + +//////////////////////////////////////////////////////////////// +// +// File Handling +// +// +#include + +#ifdef ZPL_SYSTEM_MACOS +# include +#endif + +#ifdef ZPL_SYSTEM_CYGWIN +# include +#endif + +#if defined(ZPL_SYSTEM_WINDOWS) && !defined(ZPL_COMPILER_GCC) +#include +#endif + +ZPL_BEGIN_C_DECLS + +#if defined(ZPL_SYSTEM_WINDOWS) || defined (ZPL_SYSTEM_CYGWIN) + +zpl_internal wchar_t *zpl__alloc_utf8_to_ucs2(zpl_allocator a, char const *text, zpl_isize *w_len_) { + wchar_t *w_text = NULL; + zpl_isize len = 0, w_len = 0, w_len1 = 0; + if (text == NULL) { + if (w_len_) *w_len_ = w_len; + return NULL; + } + len = zpl_strlen(text); + if (len == 0) { + if (w_len_) *w_len_ = w_len; + return NULL; + } + w_len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, text, cast(int) len, NULL, 0); + if (w_len == 0) { + if (w_len_) *w_len_ = w_len; + return NULL; + } + w_text = zpl_alloc_array(a, wchar_t, w_len + 1); + w_len1 = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, text, cast(int) len, w_text, cast(int) w_len); + if (w_len1 == 0) { + zpl_free(a, w_text); + if (w_len_) *w_len_ = 0; + return NULL; + } + w_text[w_len] = 0; + if (w_len_) *w_len_ = w_len; + return w_text; +} + +zpl_internal ZPL_FILE_SEEK_PROC(zpl__win32_file_seek) { + LARGE_INTEGER li_offset; + li_offset.QuadPart = offset; + if (!SetFilePointerEx(fd.p, li_offset, &li_offset, whence)) { return false; } + + if (new_offset) *new_offset = li_offset.QuadPart; + return true; +} + +zpl_internal ZPL_FILE_READ_AT_PROC(zpl__win32_file_read) { + zpl_unused(stop_at_newline); + zpl_b32 result = false; + zpl__win32_file_seek(fd, offset, ZPL_SEEK_WHENCE_BEGIN, NULL); + DWORD size_ = cast(DWORD)(size > ZPL_I32_MAX ? ZPL_I32_MAX : size); + DWORD bytes_read_; + if (ReadFile(fd.p, buffer, size_, &bytes_read_, NULL)) { + if (bytes_read) *bytes_read = bytes_read_; + result = true; + } + + return result; +} + +zpl_internal ZPL_FILE_WRITE_AT_PROC(zpl__win32_file_write) { + DWORD size_ = cast(DWORD)(size > ZPL_I32_MAX ? ZPL_I32_MAX : size); + DWORD bytes_written_; + zpl__win32_file_seek(fd, offset, ZPL_SEEK_WHENCE_BEGIN, NULL); + if (WriteFile(fd.p, buffer, size_, &bytes_written_, NULL)) { + if (bytes_written) *bytes_written = bytes_written_; + return true; + } + return false; +} + +zpl_internal ZPL_FILE_CLOSE_PROC(zpl__win32_file_close) { CloseHandle(fd.p); } + +zpl_file_operations const zpl_default_file_operations = { zpl__win32_file_read, zpl__win32_file_write, + zpl__win32_file_seek, zpl__win32_file_close }; + +ZPL_NEVER_INLINE ZPL_FILE_OPEN_PROC(zpl__win32_file_open) { + DWORD desired_access; + DWORD creation_disposition; + void *handle; + wchar_t *w_text; + + switch (mode & ZPL_FILE_MODES) { + case ZPL_FILE_MODE_READ: + desired_access = GENERIC_READ; + creation_disposition = OPEN_EXISTING; + break; + case ZPL_FILE_MODE_WRITE: + desired_access = GENERIC_WRITE; + creation_disposition = CREATE_ALWAYS; + break; + case ZPL_FILE_MODE_APPEND: + desired_access = GENERIC_WRITE; + creation_disposition = OPEN_ALWAYS; + break; + case ZPL_FILE_MODE_READ | ZPL_FILE_MODE_RW: + desired_access = GENERIC_READ | GENERIC_WRITE; + creation_disposition = OPEN_EXISTING; + break; + case ZPL_FILE_MODE_WRITE | ZPL_FILE_MODE_RW: + desired_access = GENERIC_READ | GENERIC_WRITE; + creation_disposition = CREATE_ALWAYS; + break; + case ZPL_FILE_MODE_APPEND | ZPL_FILE_MODE_RW: + desired_access = GENERIC_READ | GENERIC_WRITE; + creation_disposition = OPEN_ALWAYS; + break; + default: ZPL_PANIC("Invalid file mode"); return ZPL_FILE_ERROR_INVALID; + } + + w_text = zpl__alloc_utf8_to_ucs2(zpl_heap_allocator( ), filename, NULL); + handle = CreateFileW(w_text, desired_access, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, creation_disposition, + FILE_ATTRIBUTE_NORMAL, NULL); + + zpl_free(zpl_heap_allocator( ), w_text); + + if (handle == INVALID_HANDLE_VALUE) { + DWORD err = GetLastError( ); + switch (err) { + case ERROR_FILE_NOT_FOUND: return ZPL_FILE_ERROR_NOT_EXISTS; + case ERROR_FILE_EXISTS: return ZPL_FILE_ERROR_EXISTS; + case ERROR_ALREADY_EXISTS: return ZPL_FILE_ERROR_EXISTS; + case ERROR_ACCESS_DENIED: return ZPL_FILE_ERROR_PERMISSION; + } + return ZPL_FILE_ERROR_INVALID; + } + + if (mode & ZPL_FILE_MODE_APPEND) { + LARGE_INTEGER offset = { 0 }; + if (!SetFilePointerEx(handle, offset, NULL, ZPL_SEEK_WHENCE_END)) { + CloseHandle(handle); + return ZPL_FILE_ERROR_INVALID; + } + } + + fd->p = handle; + *ops = zpl_default_file_operations; + return ZPL_FILE_ERROR_NONE; +} + +#else // POSIX +# include + +zpl_internal ZPL_FILE_SEEK_PROC(zpl__posix_file_seek) { +# if defined(ZPL_SYSTEM_OSX) + zpl_i64 res = lseek(fd.i, offset, whence); +# else // TODO(ZaKlaus): @fixme lseek64 + zpl_i64 res = lseek(fd.i, offset, whence); +# endif + if (res < 0) return false; + if (new_offset) *new_offset = res; + return true; +} + +zpl_internal ZPL_FILE_READ_AT_PROC(zpl__posix_file_read) { + zpl_unused(stop_at_newline); + zpl_isize res = pread(fd.i, buffer, size, offset); + if (res < 0) return false; + if (bytes_read) *bytes_read = res; + return true; +} + +zpl_internal ZPL_FILE_WRITE_AT_PROC(zpl__posix_file_write) { + zpl_isize res; + zpl_i64 curr_offset = 0; + zpl__posix_file_seek(fd, 0, ZPL_SEEK_WHENCE_CURRENT, &curr_offset); + if (curr_offset == offset) { + // NOTE: Writing to stdout et al. doesn't like pwrite for numerous reasons + res = write(cast(int) fd.i, buffer, size); + } else { + res = pwrite(cast(int) fd.i, buffer, size, offset); + } + if (res < 0) return false; + if (bytes_written) *bytes_written = res; + return true; +} + +zpl_internal ZPL_FILE_CLOSE_PROC(zpl__posix_file_close) { close(fd.i); } + +zpl_file_operations const zpl_default_file_operations = { zpl__posix_file_read, zpl__posix_file_write, + zpl__posix_file_seek, zpl__posix_file_close }; + +ZPL_NEVER_INLINE ZPL_FILE_OPEN_PROC(zpl__posix_file_open) { + zpl_i32 os_mode; + switch (mode & ZPL_FILE_MODES) { + case ZPL_FILE_MODE_READ: os_mode = O_RDONLY; break; + case ZPL_FILE_MODE_WRITE: os_mode = O_WRONLY | O_CREAT | O_TRUNC; break; + case ZPL_FILE_MODE_APPEND: os_mode = O_WRONLY | O_APPEND | O_CREAT; break; + case ZPL_FILE_MODE_READ | ZPL_FILE_MODE_RW: os_mode = O_RDWR; break; + case ZPL_FILE_MODE_WRITE | ZPL_FILE_MODE_RW: os_mode = O_RDWR | O_CREAT | O_TRUNC; break; + case ZPL_FILE_MODE_APPEND | ZPL_FILE_MODE_RW: os_mode = O_RDWR | O_APPEND | O_CREAT; break; + default: ZPL_PANIC("Invalid file mode"); return ZPL_FILE_ERROR_INVALID; + } + + fd->i = open(filename, os_mode, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); + if (fd->i < 0) { + // TODO: More file errors + return ZPL_FILE_ERROR_INVALID; + } + + *ops = zpl_default_file_operations; + return ZPL_FILE_ERROR_NONE; +} + +#endif + +zpl_file_error zpl_file_new(zpl_file *f, zpl_file_descriptor fd, zpl_file_operations ops, char const *filename) { + zpl_file_error err = ZPL_FILE_ERROR_NONE; + zpl_isize len = zpl_strlen(filename); + + f->ops = ops; + f->fd = fd; + f->dir = NULL; + f->last_write_time = 0; + f->filename = zpl_alloc_array(zpl_heap_allocator( ), char, len + 1); + zpl_memcopy(cast(char *) f->filename, cast(char *) filename, len + 1); + + return err; +} + +zpl_file_error zpl_file_open_mode(zpl_file *f, zpl_file_mode mode, char const *filename) { + zpl_file file_ = {0}; + *f = file_; + zpl_file_error err; +#if defined(ZPL_SYSTEM_WINDOWS) || defined(ZPL_SYSTEM_CYGWIN) + err = zpl__win32_file_open(&f->fd, &f->ops, mode, filename); +#else + err = zpl__posix_file_open(&f->fd, &f->ops, mode, filename); +#endif + if (err == ZPL_FILE_ERROR_NONE) return zpl_file_new(f, f->fd, f->ops, filename); + return err; +} + +zpl_internal void zpl__dirinfo_free_entry(zpl_dir_entry *entry); + +zpl_file_error zpl_file_close(zpl_file *f) { + if (!f) return ZPL_FILE_ERROR_INVALID; + + if (f->filename) zpl_free(zpl_heap_allocator( ), cast(char *) f->filename); + +#if defined(ZPL_SYSTEM_WINDOWS) + if (f->fd.p == INVALID_HANDLE_VALUE) return ZPL_FILE_ERROR_INVALID; +#else + if (f->fd.i < 0) return ZPL_FILE_ERROR_INVALID; +#endif + + if (f->is_temp) + { + f->ops.close(f->fd); + return ZPL_FILE_ERROR_NONE; + } + + if (!f->ops.read_at) f->ops = zpl_default_file_operations; + f->ops.close(f->fd); + + if (f->dir) { + zpl__dirinfo_free_entry(f->dir); + zpl_mfree(f->dir); + f->dir = NULL; + } + + return ZPL_FILE_ERROR_NONE; +} + + +zpl_file_error zpl_file_create(zpl_file *f, char const *filename) { + return zpl_file_open_mode(f, ZPL_FILE_MODE_WRITE | ZPL_FILE_MODE_RW, filename); +} + +zpl_file_error zpl_file_open(zpl_file *f, char const *filename) { + return zpl_file_open_mode(f, ZPL_FILE_MODE_READ, filename); +} + +char const *zpl_file_name(zpl_file *f) { return f->filename ? f->filename : ""; } + +zpl_b32 zpl_file_has_changed(zpl_file *f) { + if (f->is_temp) + return false; + zpl_b32 result = false; + zpl_file_time last_write_time = zpl_fs_last_write_time(f->filename); + if (f->last_write_time != last_write_time) { + result = true; + f->last_write_time = last_write_time; + } + return result; +} + +// TODO: Is this a bad idea? +zpl_global zpl_b32 zpl__std_file_set = false; +zpl_global zpl_file zpl__std_files[ZPL_FILE_STANDARD_COUNT] = { { 0 } }; + +#if defined(ZPL_SYSTEM_WINDOWS) || defined(ZPL_SYSTEM_CYGWIN) + +zpl_file *zpl_file_get_standard(zpl_file_standard_type std) { + if (!zpl__std_file_set) { +#define ZPL__SET_STD_FILE(type, v) \ +zpl__std_files[type].fd.p = v; \ +zpl__std_files[type].ops = zpl_default_file_operations + ZPL__SET_STD_FILE(ZPL_FILE_STANDARD_INPUT, GetStdHandle(STD_INPUT_HANDLE)); + ZPL__SET_STD_FILE(ZPL_FILE_STANDARD_OUTPUT, GetStdHandle(STD_OUTPUT_HANDLE)); + ZPL__SET_STD_FILE(ZPL_FILE_STANDARD_ERROR, GetStdHandle(STD_ERROR_HANDLE)); +#undef ZPL__SET_STD_FILE + zpl__std_file_set = true; + } + return &zpl__std_files[std]; +} + +void zpl_file_connect_handle(zpl_file *file, void *handle) { + ZPL_ASSERT_NOT_NULL(file); + ZPL_ASSERT_NOT_NULL(handle); + + if (file->is_temp) + return; + + zpl_zero_item(file); + + file->fd.p = handle; + file->ops = zpl_default_file_operations; +} + +zpl_file_error zpl_file_truncate(zpl_file *f, zpl_i64 size) { + zpl_file_error err = ZPL_FILE_ERROR_NONE; + zpl_i64 prev_offset = zpl_file_tell(f); + zpl_file_seek(f, size); + if (!SetEndOfFile(f)) err = ZPL_FILE_ERROR_TRUNCATION_FAILURE; + zpl_file_seek(f, prev_offset); + return err; +} + +zpl_b32 zpl_fs_exists(char const *name) { + WIN32_FIND_DATAW data; + wchar_t *w_text; + void *handle; + zpl_b32 found = false; + zpl_allocator a = zpl_heap_allocator( ); + + w_text = zpl__alloc_utf8_to_ucs2(a, name, NULL); + if (w_text == NULL) { return false; } + handle = FindFirstFileW(w_text, &data); + zpl_free(a, w_text); + found = handle != INVALID_HANDLE_VALUE; + if (found) FindClose(handle); + return found; +} + +#else // POSIX + +zpl_file *zpl_file_get_standard(zpl_file_standard_type std) { + if (!zpl__std_file_set) { +#define ZPL__SET_STD_FILE(type, v) \ +zpl__std_files[type].fd.i = v; \ +zpl__std_files[type].ops = zpl_default_file_operations + ZPL__SET_STD_FILE(ZPL_FILE_STANDARD_INPUT, 0); + ZPL__SET_STD_FILE(ZPL_FILE_STANDARD_OUTPUT, 1); + ZPL__SET_STD_FILE(ZPL_FILE_STANDARD_ERROR, 2); +#undef ZPL__SET_STD_FILE + zpl__std_file_set = true; + } + return &zpl__std_files[std]; +} + +zpl_file_error zpl_file_truncate(zpl_file *f, zpl_i64 size) { + zpl_file_error err = ZPL_FILE_ERROR_NONE; + int i = ftruncate(f->fd.i, size); + if (i != 0) err = ZPL_FILE_ERROR_TRUNCATION_FAILURE; + return err; +} + +zpl_b32 zpl_fs_exists(char const *name) { return access(name, F_OK) != -1; } + +#endif + +zpl_i64 zpl_file_size(zpl_file *f) { + zpl_i64 size = 0; + zpl_i64 prev_offset = zpl_file_tell(f); + zpl_file_seek_to_end(f); + size = zpl_file_tell(f); + zpl_file_seek(f, prev_offset); + return size; +} + +zpl_file_error zpl_file_temp(zpl_file *file) { + zpl_zero_item(file); + FILE *fd = NULL; + +#if (defined(ZPL_SYSTEM_WINDOWS) && !defined(ZPL_SYSTEM_TINYC)) && !defined(ZPL_COMPILER_GCC) + errno_t errcode = tmpfile_s(&fd); + + if (errcode != 0) { + fd = NULL; + } +#else + fd = tmpfile(); +#endif + + if (fd == NULL) { return ZPL_FILE_ERROR_INVALID; } + +#if defined(ZPL_SYSTEM_WINDOWS) && !defined(ZPL_COMPILER_GCC) + file->fd.i = _get_osfhandle(_fileno(fd)); +#else + file->fd.i = fileno(fd); +#endif + file->ops = zpl_default_file_operations; + file->is_temp = true; + return ZPL_FILE_ERROR_NONE; +} + +zpl_file_contents zpl_file_read_contents(zpl_allocator a, zpl_b32 zero_terminate, char const *filepath) { + zpl_file_contents result = { 0 }; + zpl_file file = { 0 }; + + result.allocator = a; + + if (zpl_file_open(&file, filepath) == ZPL_FILE_ERROR_NONE) { + zpl_isize file_size = cast(zpl_isize) zpl_file_size(&file); + if (file_size > 0) { + result.data = zpl_alloc(a, zero_terminate ? file_size + 1 : file_size); + result.size = file_size; + zpl_file_read_at(&file, result.data, result.size, 0); + if (zero_terminate) { + zpl_u8 *str = cast(zpl_u8 *) result.data; + str[file_size] = '\0'; + } + } + zpl_file_close(&file); + } + + return result; +} + +void zpl_file_free_contents(zpl_file_contents *fc) { + ZPL_ASSERT_NOT_NULL(fc->data); + zpl_free(fc->allocator, fc->data); + fc->data = NULL; + fc->size = 0; +} + +zpl_b32 zpl_file_write_contents(char const* filepath, void const* buffer, zpl_isize size, zpl_file_error* err) { + zpl_file f = { 0 }; + zpl_file_error open_err; + zpl_b32 write_ok; + open_err = zpl_file_open_mode(&f, ZPL_FILE_MODE_WRITE, filepath); + + if (open_err != ZPL_FILE_ERROR_NONE) + { + if (err) + *err = open_err; + + return false; + } + + write_ok = zpl_file_write(&f, buffer, size); + zpl_file_close(&f); + return write_ok; +} + +char *zpl_file_read_lines(zpl_allocator alloc, zpl_array(char *)*lines, char const *filename, zpl_b32 strip_whitespace) { + zpl_file f = { 0 }; + zpl_file_open(&f, filename); + zpl_isize fsize = (zpl_isize)zpl_file_size(&f); + + char *contents = (char *)zpl_alloc(alloc, fsize + 1); + zpl_file_read(&f, contents, fsize); + contents[fsize] = 0; + *lines = zpl_str_split_lines(alloc, contents, strip_whitespace); + zpl_file_close(&f); + + return contents; +} + +#if !defined(_WINDOWS_) && defined(ZPL_SYSTEM_WINDOWS) +ZPL_IMPORT DWORD WINAPI GetFullPathNameA(char const *lpFileName, DWORD nBufferLength, char *lpBuffer, char **lpFilePart); +ZPL_IMPORT DWORD WINAPI GetFullPathNameW(wchar_t const *lpFileName, DWORD nBufferLength, wchar_t *lpBuffer, wchar_t **lpFilePart); +#endif + +ZPL_END_C_DECLS +// file: source/core/file_stream.c + + +//////////////////////////////////////////////////////////////// +// +// Memory streaming +// +// + +ZPL_BEGIN_C_DECLS + +typedef struct { + zpl_u8 magic; + zpl_u8 *buf; //< zpl_array OR plain buffer if we can't write + zpl_isize cursor; + zpl_allocator alloc; + + zpl_file_stream_flags flags; + zpl_isize cap; +} zpl__memory_fd; + +#define ZPL__FILE_STREAM_FD_MAGIC 37 + +ZPL_DEF_INLINE zpl_file_descriptor zpl__file_stream_fd_make(zpl__memory_fd* d); +ZPL_DEF_INLINE zpl__memory_fd *zpl__file_stream_from_fd(zpl_file_descriptor fd); + +ZPL_IMPL_INLINE zpl_file_descriptor zpl__file_stream_fd_make(zpl__memory_fd* d) { + zpl_file_descriptor fd = {0}; + fd.p = (void*)d; + return fd; +} + +ZPL_IMPL_INLINE zpl__memory_fd *zpl__file_stream_from_fd(zpl_file_descriptor fd) { + zpl__memory_fd *d = (zpl__memory_fd*)fd.p; + ZPL_ASSERT(d->magic == ZPL__FILE_STREAM_FD_MAGIC); + return d; +} + +void zpl_file_stream_new(zpl_file* file, zpl_allocator allocator) { + ZPL_ASSERT_NOT_NULL(file); + zpl__memory_fd *d = (zpl__memory_fd*)zpl_alloc(allocator, zpl_size_of(zpl__memory_fd)); + zpl_zero_item(file); + d->magic = ZPL__FILE_STREAM_FD_MAGIC; + d->alloc = allocator; + d->flags = ZPL_FILE_STREAM_CLONE_WRITABLE; + d->cap = 0; + zpl_array_init(d->buf, allocator); + file->ops = zpl_memory_file_operations; + file->fd = zpl__file_stream_fd_make(d); + file->dir = NULL; + file->last_write_time = 0; + file->filename = NULL; + file->is_temp = true; +} +void zpl_file_stream_open(zpl_file* file, zpl_allocator allocator, zpl_u8 *buffer, zpl_isize size, zpl_file_stream_flags flags) { + ZPL_ASSERT_NOT_NULL(file); + zpl__memory_fd *d = (zpl__memory_fd*)zpl_alloc(allocator, zpl_size_of(zpl__memory_fd)); + zpl_zero_item(file); + d->magic = ZPL__FILE_STREAM_FD_MAGIC; + d->alloc = allocator; + d->flags = flags; + if (d->flags & ZPL_FILE_STREAM_CLONE_WRITABLE) { + zpl_array_init_reserve(d->buf, allocator, size); + zpl_memcopy(d->buf, buffer, size); + d->cap = zpl_array_count(d->buf) = size; + } else { + d->buf = buffer; + d->cap = size; + } + file->ops = zpl_memory_file_operations; + file->fd = zpl__file_stream_fd_make(d); + file->dir = NULL; + file->last_write_time = 0; + file->filename = NULL; + file->is_temp = true; +} + +zpl_u8 *zpl_file_stream_buf(zpl_file* file, zpl_isize *size) { + ZPL_ASSERT_NOT_NULL(file); + zpl__memory_fd *d = zpl__file_stream_from_fd(file->fd); + if (size) *size = d->cap; + return d->buf; +} + +zpl_internal ZPL_FILE_SEEK_PROC(zpl__memory_file_seek) { + zpl__memory_fd *d = zpl__file_stream_from_fd(fd); + zpl_isize buflen = d->cap; + + if (whence == ZPL_SEEK_WHENCE_BEGIN) + d->cursor = 0; + else if (whence == ZPL_SEEK_WHENCE_END) + d->cursor = buflen; + + d->cursor = zpl_max(0, zpl_clamp(d->cursor + offset, 0, buflen)); + if (new_offset) *new_offset = d->cursor; + return true; +} + +zpl_internal ZPL_FILE_READ_AT_PROC(zpl__memory_file_read) { + zpl_unused(stop_at_newline); + zpl__memory_fd *d = zpl__file_stream_from_fd(fd); + zpl_memcopy(buffer, d->buf + offset, size); + if (bytes_read) *bytes_read = size; + return true; +} + +zpl_internal ZPL_FILE_WRITE_AT_PROC(zpl__memory_file_write) { + zpl__memory_fd *d = zpl__file_stream_from_fd(fd); + if (!(d->flags & (ZPL_FILE_STREAM_CLONE_WRITABLE|ZPL_FILE_STREAM_WRITABLE))) + return false; + zpl_isize buflen = d->cap; + zpl_isize extralen = zpl_max(0, size-(buflen-offset)); + zpl_isize rwlen = size-extralen; + zpl_isize new_cap = buflen+extralen; + if (d->flags & ZPL_FILE_STREAM_CLONE_WRITABLE) { + if(zpl_array_capacity(d->buf) < new_cap) { + zpl_array_grow(d->buf, (zpl_i64)(new_cap)); + } + } + zpl_memcopy(d->buf + offset, buffer, rwlen); + + if ((d->flags & ZPL_FILE_STREAM_CLONE_WRITABLE) && extralen > 0) { + zpl_memcopy(d->buf + offset + rwlen, zpl_ptr_add_const(buffer, rwlen), extralen); + d->cap = zpl_array_count(d->buf) = new_cap; + } else { + extralen = 0; + } + + if (bytes_written) *bytes_written = (rwlen+extralen); + return true; +} + +zpl_internal ZPL_FILE_CLOSE_PROC(zpl__memory_file_close) { + zpl__memory_fd *d = zpl__file_stream_from_fd(fd); + zpl_allocator alloc = d->alloc; + if (d->flags & ZPL_FILE_STREAM_CLONE_WRITABLE) + zpl_array_free(d->buf); + zpl_free(alloc, d); +} + +zpl_file_operations const zpl_memory_file_operations = { zpl__memory_file_read, zpl__memory_file_write, + zpl__memory_file_seek, zpl__memory_file_close }; + +ZPL_END_C_DECLS +// file: source/core/file_misc.c + + +#if defined(ZPL_SYSTEM_UNIX) || defined(ZPL_SYSTEM_MACOS) +# include +#endif + +#if defined(ZPL_SYSTEM_UNIX) && !defined(ZPL_SYSTEM_FREEBSD) && !defined(ZPL_SYSTEM_OPENBSD) && !defined(ZPL_SYSTEM_CYGWIN) +# include +#endif + +#if defined(ZPL_SYSTEM_WINDOWS) +# include +# include +#endif + +#if defined(ZPL_SYSTEM_CYGWIN) +# include +# include +# include +#endif + +ZPL_BEGIN_C_DECLS + + +#if defined(ZPL_SYSTEM_WINDOWS) || defined(ZPL_SYSTEM_CYGWIN) +zpl_file_time zpl_fs_last_write_time(char const *filepath) { + ULARGE_INTEGER li = { 0 }; + FILETIME last_write_time = { 0 }; + WIN32_FILE_ATTRIBUTE_DATA data = { 0 }; + zpl_allocator a = zpl_heap_allocator( ); + + wchar_t *w_text = zpl__alloc_utf8_to_ucs2(a, filepath, NULL); + if (w_text == NULL) { return 0; } + if (GetFileAttributesExW(w_text, GetFileExInfoStandard, &data)) last_write_time = data.ftLastWriteTime; + + zpl_free(a, w_text); + + li.LowPart = last_write_time.dwLowDateTime; + li.HighPart = last_write_time.dwHighDateTime; + return cast(zpl_file_time) li.QuadPart; +} + +zpl_b32 zpl_fs_copy(char const *existing_filename, char const *new_filename, zpl_b32 fail_if_exists) { + zpl_b32 result = false; + zpl_allocator a = zpl_heap_allocator( ); + + wchar_t *w_old = zpl__alloc_utf8_to_ucs2(a, existing_filename, NULL); + if (w_old == NULL) { return false; } + + wchar_t *w_new = zpl__alloc_utf8_to_ucs2(a, new_filename, NULL); + if (w_new != NULL) { result = CopyFileW(w_old, w_new, fail_if_exists); } + + zpl_free(a, w_old); + zpl_free(a, w_new); + return result; +} + +zpl_b32 zpl_fs_move(char const *existing_filename, char const *new_filename) { + zpl_b32 result = false; + zpl_allocator a = zpl_heap_allocator( ); + + wchar_t *w_old = zpl__alloc_utf8_to_ucs2(a, existing_filename, NULL); + if (w_old == NULL) { return false; } + + wchar_t *w_new = zpl__alloc_utf8_to_ucs2(a, new_filename, NULL); + if (w_new != NULL) { result = MoveFileW(w_old, w_new); } + + zpl_free(a, w_old); + zpl_free(a, w_new); + return result; +} + +zpl_b32 zpl_fs_remove(char const *filename) { + zpl_b32 result = false; + zpl_allocator a = zpl_heap_allocator( ); + + wchar_t *w_filename = zpl__alloc_utf8_to_ucs2(a, filename, NULL); + if (w_filename == NULL) { return false; } + + result = DeleteFileW(w_filename); + + zpl_free(a, w_filename); + return result; +} + +#else + +zpl_file_time zpl_fs_last_write_time(char const *filepath) { + time_t result = 0; + struct stat file_stat; + + if (stat(filepath, &file_stat)) result = file_stat.st_mtime; + + return cast(zpl_file_time) result; +} + +# if defined(ZPL_SYSTEM_FREEBSD) +# include +# include +# include +# endif + + +zpl_b32 zpl_fs_copy(char const *existing_filename, char const *new_filename, zpl_b32 fail_if_exists) { + zpl_unused(fail_if_exists); +# if defined(ZPL_SYSTEM_OSX) + return copyfile(existing_filename, new_filename, NULL, COPYFILE_DATA) == 0; +# elif defined(ZPL_SYSTEM_OPENBSD) + ZPL_NOT_IMPLEMENTED; + return 0; +# else + int existing_fd = open(existing_filename, O_RDONLY, 0); + struct stat stat_existing; + fstat(existing_fd, &stat_existing); + + zpl_isize size; + int new_fd = open(new_filename, O_WRONLY | O_CREAT, stat_existing.st_mode); + +# if defined(ZPL_SYSTEM_FREEBSD) + size = sendfile(new_fd, existing_fd, 0, stat_existing.st_size, NULL, 0, 0); +# else + size = sendfile(new_fd, existing_fd, 0, stat_existing.st_size); +# endif + + close(new_fd); + close(existing_fd); + + return size == stat_existing.st_size; +# endif +} + +zpl_b32 zpl_fs_move(char const *existing_filename, char const *new_filename) { + if (link(existing_filename, new_filename) == 0) { return (unlink(existing_filename) != -1); } + return false; +} + +zpl_b32 zpl_fs_remove(char const *filename) { +# if defined(ZPL_SYSTEM_OSX) || defined(ZPL_SYSTEM_EMSCRIPTEN) + return (unlink(filename) != -1); +# else + return (remove(filename) == 0); +# endif +} + +#endif + +char *zpl_path_get_full_name(zpl_allocator a, char const *path) { +#if defined(ZPL_SYSTEM_WINDOWS) + wchar_t *w_path = NULL; + wchar_t *w_fullpath = NULL; + zpl_isize w_len = 0; + zpl_isize new_len = 0; + zpl_isize new_len1 = 0; + char *new_path = 0; + + w_path = zpl__alloc_utf8_to_ucs2(zpl_heap_allocator( ), path, NULL); + if (w_path == NULL) { return NULL; } + + w_len = GetFullPathNameW(w_path, 0, NULL, NULL); + if (w_len == 0) { return NULL; } + + w_fullpath = zpl_alloc_array(zpl_heap_allocator( ), wchar_t, w_len + 1); + GetFullPathNameW(w_path, cast(int) w_len, w_fullpath, NULL); + w_fullpath[w_len] = 0; + + zpl_free(zpl_heap_allocator( ), w_path); + + new_len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, w_fullpath, cast(int) w_len, NULL, 0, NULL, NULL); + + if (new_len == 0) { + zpl_free(zpl_heap_allocator( ), w_fullpath); + return NULL; + } + + new_path = zpl_alloc_array(a, char, new_len); + new_len1 = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, w_fullpath, cast(int) w_len, new_path, + cast(int) new_len, NULL, NULL); + + if (new_len1 == 0) { + zpl_free(zpl_heap_allocator( ), w_fullpath); + zpl_free(a, new_path); + return NULL; + } + + new_path[new_len] = 0; + return new_path; +#else + char *p, *result, *fullpath = NULL; + zpl_isize len; + p = realpath(path, NULL); + fullpath = p; + if (p == NULL) { + // NOTE(bill): File does not exist + fullpath = cast(char *) path; + } + + len = zpl_strlen(fullpath); + + result = zpl_alloc_array(a, char, len + 1); + zpl_memmove(result, fullpath, len); + result[len] = 0; + zpl_free(a, p); + + return result; +#endif +} + +zpl_file_error zpl_path_mkdir(char const *path, zpl_i32 mode) { + zpl_i32 error = 0; +#if defined(ZPL_SYSTEM_WINDOWS) + error = _wmkdir((const wchar_t *)zpl_utf8_to_ucs2_buf((const zpl_u8 *)path)); +#else + error = mkdir(path, (mode_t)mode); +#endif + + if (error == 0) { return ZPL_FILE_ERROR_NONE; } + + switch (errno) { + case EPERM: + case EACCES: return ZPL_FILE_ERROR_PERMISSION; + case EEXIST: return ZPL_FILE_ERROR_EXISTS; + case ENAMETOOLONG: return ZPL_FILE_ERROR_NAME_TOO_LONG; + } + + return ZPL_FILE_ERROR_UNKNOWN; +} + +zpl_isize zpl_path_mkdir_recursive(char const *path, zpl_i32 mode) { + char tmp[ZPL_MAX_PATH] = {0}; + char *p = 0; + zpl_isize len = zpl_strlen(path); + + if (len > zpl_size_of(tmp)-1) { + return -1; + } + zpl_strcpy(tmp, path); + zpl_path_fix_slashes(tmp); + for (p = tmp + 1; *p; p++) { + if (*p == ZPL_PATH_SEPARATOR) { + *p = 0; + zpl_path_mkdir(tmp, mode); + *p = ZPL_PATH_SEPARATOR; + } + } + zpl_path_mkdir(tmp, mode); + return 0; +} + +zpl_file_error zpl_path_rmdir(char const *path) { + zpl_i32 error = 0; +#if defined(ZPL_SYSTEM_WINDOWS) + error = _wrmdir((const wchar_t *)zpl_utf8_to_ucs2_buf((const zpl_u8 *)path)); +#else + error = rmdir(path); +#endif + + if (error == 0) { return ZPL_FILE_ERROR_NONE; } + + switch (errno) { + case EPERM: + case EACCES: return ZPL_FILE_ERROR_PERMISSION; + case ENOENT: return ZPL_FILE_ERROR_NOT_EXISTS; + case ENOTEMPTY: return ZPL_FILE_ERROR_NOT_EMPTY; + case ENAMETOOLONG: return ZPL_FILE_ERROR_NAME_TOO_LONG; + } + + return ZPL_FILE_ERROR_UNKNOWN; +} + +void zpl__file_direntry(zpl_allocator alloc, char const *dirname, zpl_string *output, zpl_b32 recurse) { +#if defined(ZPL_SYSTEM_UNIX) || defined(ZPL_SYSTEM_OSX) + DIR *d, *cd; + struct dirent *dir; + d = opendir(dirname); + + if (d) { + while ((dir = readdir(d))) { + if (dir == 0) break; + if (!zpl_strncmp(dir->d_name, "..", 2)) continue; + if (dir->d_name[0] == '.' && dir->d_name[1] == 0) continue; + + zpl_string dirpath = zpl_string_make(alloc, dirname); + dirpath = zpl_string_appendc(dirpath, "/"); + dirpath = zpl_string_appendc(dirpath, dir->d_name); + + *output = zpl_string_appendc(*output, dirpath); + *output = zpl_string_appendc(*output, "\n"); + + if (recurse && (cd = opendir(dirpath)) != NULL && dir->d_type == DT_DIR) { zpl__file_direntry(alloc, dirpath, output, recurse); } + zpl_string_free(dirpath); + } + } +#elif defined(ZPL_SYSTEM_WINDOWS) + zpl_usize length = zpl_strlen(dirname); + struct _wfinddata_t data; + zpl_intptr findhandle; + + char directory[MAX_PATH] = { 0 }; + zpl_strncpy(directory, dirname, length); + + // keeping it native + for (zpl_usize i = 0; i < length; i++) { + if (directory[i] == '/') directory[i] = '\\'; + } + + // remove trailing slashses + if (directory[length - 1] == '\\') { directory[length - 1] = '\0'; } + + // attach search pattern + zpl_string findpath = zpl_string_make(alloc, directory); + findpath = zpl_string_appendc(findpath, "\\"); + findpath = zpl_string_appendc(findpath, "*"); + + findhandle = _wfindfirst((const wchar_t *)zpl_utf8_to_ucs2_buf((const zpl_u8 *)findpath), &data); + zpl_string_free(findpath); + + if (findhandle != -1) { + do { + char *filename = (char *)zpl_ucs2_to_utf8_buf((const zpl_u16 *)data.name); + if (!zpl_strncmp(filename, "..", 2)) continue; + if (filename[0] == '.' && filename[1] == 0) continue; + + zpl_string dirpath = zpl_string_make(alloc, directory); + dirpath = zpl_string_appendc(dirpath, "\\"); + dirpath = zpl_string_appendc(dirpath, filename); + DWORD attrs = GetFileAttributesW((const wchar_t *)zpl_utf8_to_ucs2_buf((const zpl_u8 *)dirpath)); + + *output = zpl_string_appendc(*output, dirpath); + *output = zpl_string_appendc(*output, "\n"); + + if (recurse && (data.attrib & _A_SUBDIR) && !(attrs & FILE_ATTRIBUTE_REPARSE_POINT)) { zpl__file_direntry(alloc, dirpath, output, recurse); } + + zpl_string_free(dirpath); + } while (_wfindnext(findhandle, &data) != -1); + _findclose(findhandle); + } +#else + // TODO: Implement other OSes +#endif +} + +zpl_string zpl_path_dirlist(zpl_allocator alloc, char const *dirname, zpl_b32 recurse) { + zpl_string buf = zpl_string_make_reserve(alloc, 4); + zpl__file_direntry(alloc, dirname, &buf, recurse); + return buf; +} + +void zpl_dirinfo_init(zpl_dir_info *dir, char const *path) { + ZPL_ASSERT_NOT_NULL(dir); + + zpl_dir_info dir_ = {0}; + *dir = dir_; + dir->fullpath = (char const*)zpl_malloc(zpl_strlen(path)); + zpl_strcpy((char *)dir->fullpath, path); + + + zpl_string dirlist = zpl_path_dirlist(zpl_heap(), path, false); + char **files=zpl_str_split_lines(zpl_heap(), dirlist, false); + dir->filenames = files; + dir->buf = dirlist; + + zpl_array_init(dir->entries, zpl_heap()); + + for (zpl_i32 i=0; ientries, entry); + } +} + +zpl_internal void zpl__dirinfo_free_entry(zpl_dir_entry *entry) { + if (entry->dir_info) { + zpl_dirinfo_free(entry->dir_info); + zpl_mfree(entry->dir_info); + entry->dir_info = NULL; + } +} + +void zpl_dirinfo_free(zpl_dir_info *dir) { + ZPL_ASSERT_NOT_NULL(dir); + + for (zpl_isize i = 0; i < zpl_array_count(dir->entries); ++i) { + zpl__dirinfo_free_entry(dir->entries + i); + } + + zpl_array_free(dir->entries); + zpl_array_free(dir->filenames); + zpl_string_free(dir->buf); + zpl_mfree((void *)dir->fullpath); +} + + +zpl_u8 zpl_fs_get_type(char const *path) { +#ifdef ZPL_SYSTEM_WINDOWS + DWORD attrs = GetFileAttributesW((const wchar_t *)zpl_utf8_to_ucs2_buf((const zpl_u8 *)path)); + + if (attrs == INVALID_FILE_ATTRIBUTES) { + return ZPL_DIR_TYPE_UNKNOWN; + } + + if (attrs & FILE_ATTRIBUTE_DIRECTORY) + return ZPL_DIR_TYPE_FOLDER; + else + return ZPL_DIR_TYPE_FILE; + +#else + struct stat s; + if( stat(path,&s) == 0 ) + { + if(s.st_mode & S_IFDIR) + return ZPL_DIR_TYPE_FOLDER; + else + return ZPL_DIR_TYPE_FILE; + } +#endif + + return ZPL_DIR_TYPE_UNKNOWN; +} + +void zpl_dirinfo_step(zpl_dir_entry *entry) { + if (entry->dir_info) { + zpl__dirinfo_free_entry(entry); + } + + entry->dir_info = (zpl_dir_info *)zpl_malloc(sizeof(zpl_dir_info)); + zpl_dir_info dir_ = {0}; + *entry->dir_info = dir_; + + zpl_local_persist char buf[128] = {0}; + char const *path = entry->filename; + + if (entry->type != ZPL_DIR_TYPE_FOLDER) { + zpl_path_fix_slashes((char *)path); + char const* slash = zpl_char_last_occurence(path, ZPL_PATH_SEPARATOR); + zpl_strncpy(buf, path, slash-path); + path = buf; + } + + zpl_dirinfo_init(entry->dir_info, path); +} + +void zpl_file_dirinfo_refresh(zpl_file *file) { + if (file->is_temp) + return; + + if (file->dir) { + zpl__dirinfo_free_entry(file->dir); + zpl_mfree(file->dir); + file->dir = NULL; + } + + file->dir = (zpl_dir_entry *)zpl_malloc(sizeof(zpl_dir_entry)); + zpl_dir_entry dir_ = {0}; + *file->dir = dir_; + file->dir->filename = file->filename; + file->dir->type = ZPL_DIR_TYPE_FILE; + + zpl_dirinfo_step(file->dir); +} + +void zpl_path_fix_slashes(char *path) { +#ifdef ZPL_SYSTEM_WINDOWS + char *p = path; + + while (*p != '\0') { + if (*p == '/') + *p = '\\'; + + ++p; + } +#endif +} + +ZPL_END_C_DECLS +// file: source/core/file_tar.c + + +typedef struct { + char name[100]; + char mode[8]; + char owner[8]; + char group[8]; + char size[12]; + char mtime[12]; + char checksum[8]; + char type; + char linkname[100]; + char _padding[255]; +} zpl__tar_header; + +zpl_internal zpl_usize zpl__tar_checksum(zpl__tar_header *hr) { + zpl_usize i; + zpl_usize res = 256; + zpl_u8 *p = cast(zpl_u8*)(hr); + for (i = 0; i < cast(zpl_usize)zpl_offset_of(zpl__tar_header, checksum); i++) + res += p[i]; + for (i = cast(zpl_usize)zpl_offset_of(zpl__tar_header, type); i < cast(zpl_usize)zpl_size_of(zpl__tar_header); i++) + res += p[i]; + return res; +} + +zpl_internal zpl_b32 zpl__tar_write_null(zpl_file *archive, zpl_isize cnt) { + char *out = zpl_bprintf("%*r", cnt, '\0'); + if (!zpl_file_write(archive, out, cnt)) + return 0; + return 1; +} + +zpl_isize zpl_tar_pack(zpl_file *archive, char const **paths, zpl_isize paths_len) { + ZPL_ASSERT_NOT_NULL(archive); + ZPL_ASSERT_NOT_NULL(paths); + + for (zpl_isize i = 0; i < paths_len; i++) { + ZPL_ASSERT_NOT_NULL(paths[i]); + zpl__tar_header hr = {0}; + zpl_file file; + zpl_file_error ferr = zpl_file_open_mode(&file, ZPL_FILE_MODE_READ, paths[i]); + if (ferr == ZPL_FILE_ERROR_NOT_EXISTS) { + return -(ZPL_TAR_ERROR_FILE_NOT_FOUND); + } else if (ferr != ZPL_FILE_ERROR_NONE) { + return -(ZPL_TAR_ERROR_IO_ERROR); + } + + zpl_i64 file_size = zpl_file_size(&file); + zpl_snprintf(hr.name, 12, "%s", paths[i]); + zpl_snprintf(hr.size, 12, "%o", file_size); + zpl_snprintf(hr.mode, 8, "%o", 0664); + zpl_snprintf(hr.mtime, 12, "%o", zpl_fs_last_write_time(paths[i])); + hr.type = ZPL_TAR_TYPE_REGULAR; + zpl_snprintf(hr.checksum, 8, "%o", zpl__tar_checksum(&hr)); + + zpl_file_write(archive, cast(void*)(&hr), zpl_size_of(zpl__tar_header)); + + // write data + { + zpl_i64 remaining_data = file_size; + zpl_i64 total_data = zpl_align_forward_i64(remaining_data, 512); + zpl_i64 padding = (total_data-file_size); + char buf[4096] = {0}; + zpl_i64 pos = 0; + zpl_isize bytes_read = 0; + do { + if (!zpl_file_read_at_check(&file, buf, 4096, pos, &bytes_read)) { + zpl_file_close(&file); + return -(ZPL_TAR_ERROR_IO_ERROR); + } else if (bytes_read == 0) { + break; + } + + zpl_file_write(archive, buf, bytes_read); + pos += bytes_read; + remaining_data -= bytes_read; + } + while (remaining_data > 0); + + if (padding > 0) { + if (!zpl__tar_write_null(archive, padding)) { + zpl_file_close(&file); + return -(ZPL_TAR_ERROR_IO_ERROR); + } + } + } + + zpl_file_close(&file); + } + + if (!zpl__tar_write_null(archive, zpl_size_of(zpl__tar_header) * 2)) { + return -(ZPL_TAR_ERROR_IO_ERROR); + } + + return 0; +} + +zpl_isize zpl_tar_pack_dir(zpl_file *archive, char const *path, zpl_allocator alloc) { + zpl_string filelst = zpl_path_dirlist(alloc, path, true); + char const **files = cast(char const**)zpl_str_split_lines(alloc, filelst, false); + zpl_isize err = zpl_tar_pack(archive, files, zpl_array_count(files)); + zpl_string_free(filelst); + zpl_array_free(files); + return err; +} + +zpl_isize zpl_tar_unpack(zpl_file *archive, zpl_tar_unpack_proc *unpack_proc, void *user_data) { + ZPL_ASSERT_NOT_NULL(archive); + ZPL_ASSERT_NOT_NULL(unpack_proc); + + zpl_i64 pos = zpl_file_tell(archive); + zpl__tar_header hr = {0}; + zpl_isize err = ZPL_TAR_ERROR_NONE; + + do { + if (!zpl_file_read(archive, cast(void*)&hr, zpl_size_of(hr))) { + err = ZPL_TAR_ERROR_IO_ERROR; + break; + } + else if (*hr.checksum == 0) { + break; + } + pos = zpl_file_tell(archive); + + zpl_tar_record rec = {0}; + rec.type = hr.type; + rec.path = hr.name; + rec.offset = pos; + rec.length = zpl_str_to_i64(hr.size, 0, 8); + rec.error = ZPL_TAR_ERROR_NONE; + + zpl_usize checksum1 = cast(zpl_usize)(zpl_str_to_i64(hr.checksum, 0, 8)); + zpl_usize checksum2 = zpl__tar_checksum(&hr); + rec.error = (checksum1 != checksum2) ? cast(zpl_isize)ZPL_TAR_ERROR_BAD_CHECKSUM : rec.error; + + rec.error = unpack_proc(archive, &rec, user_data); + + if (rec.error > 0) { + err = ZPL_TAR_ERROR_INTERRUPTED; + break; + } + + /* tar rounds files to 512 byte boundary */ + zpl_file_seek(archive, pos + zpl_align_forward_i64(rec.length, 512)); + } + while(err == ZPL_TAR_ERROR_NONE); + + return -(err); +} + +ZPL_TAR_UNPACK_PROC(zpl_tar_default_list_file) { + (void)archive; + (void)user_data; + if (file->error != ZPL_TAR_ERROR_NONE) + return 0; /* skip file */ + + if (file->type != ZPL_TAR_TYPE_REGULAR) + return 0; /* we only care about regular files */ + + /* proceed as usual */ + zpl_printf("name: %s, offset: %d, length: %d\n", file->path, file->offset, file->length); + return 0; +} + +ZPL_TAR_UNPACK_PROC(zpl_tar_default_unpack_file) { + if (file->error != ZPL_TAR_ERROR_NONE) + return 0; /* skip file */ + + if (file->type != ZPL_TAR_TYPE_REGULAR) + return 0; /* we only care about regular files */ + + if (!zpl_strncmp(file->path, "..", 2)) + return 0; + + char tmp[ZPL_MAX_PATH] = {0}; + char *base_path = cast(char*)user_data; + zpl_isize base_len = zpl_strlen(base_path); + zpl_isize len = zpl_strlen(file->path); + ZPL_ASSERT(base_len+len-2 < ZPL_MAX_PATH); /* todo: account for missing leading path sep */ + + zpl_strcpy(tmp, base_path); + zpl_path_fix_slashes(tmp); /* todo: need to do twice as base_path is checked before concat */ + + if (*tmp && tmp[base_len-1] != ZPL_PATH_SEPARATOR) { + char sep[2] = {ZPL_PATH_SEPARATOR, 0}; + zpl_strcat(tmp, sep); + } + zpl_strcat(tmp, file->path); + zpl_path_fix_slashes(tmp); + + const char *last_slash = zpl_char_last_occurence(tmp, ZPL_PATH_SEPARATOR); + + if (last_slash) { + zpl_isize i = cast(zpl_isize)(last_slash-tmp); + tmp[i] = 0; + zpl_path_mkdir_recursive(tmp, 0755); + tmp[i] = ZPL_PATH_SEPARATOR; + } + + zpl_file f; + zpl_file_create(&f, tmp); + { + char buf[4096] = {0}; + zpl_isize remaining_data = file->length; + zpl_isize bytes_read = 0; + zpl_i64 pos = file->offset; + do { + if (!zpl_file_read_at_check(archive, buf, zpl_min(4096, remaining_data), pos, &bytes_read)) { + zpl_file_close(&f); + return 1; + } else if (bytes_read == 0) { + break; + } + + zpl_file_write(&f, buf, bytes_read); + pos += bytes_read; + remaining_data -= bytes_read; + } + while (remaining_data > 0); + } + zpl_file_close(&f); + return 0; +} +// file: source/core/print.c + + +ZPL_BEGIN_C_DECLS + +zpl_isize zpl_printf_va(char const *fmt, va_list va) { + return zpl_fprintf_va(zpl_file_get_standard(ZPL_FILE_STANDARD_OUTPUT), fmt, va); +} + +zpl_isize zpl_printf_err_va(char const *fmt, va_list va) { + return zpl_fprintf_va(zpl_file_get_standard(ZPL_FILE_STANDARD_ERROR), fmt, va); +} + +zpl_isize zpl_fprintf_va(struct zpl_file *f, char const *fmt, va_list va) { + zpl_local_persist zpl_thread_local char buf[ZPL_PRINTF_MAXLEN]; + zpl_isize len = zpl_snprintf_va(buf, zpl_size_of(buf), fmt, va); + zpl_file_write(f, buf, len - 1); // NOTE: prevent extra whitespace + return len; +} + +char *zpl_bprintf_va(char const *fmt, va_list va) { + zpl_local_persist zpl_thread_local char buffer[ZPL_PRINTF_MAXLEN]; + zpl_snprintf_va(buffer, zpl_size_of(buffer), fmt, va); + return buffer; +} + +zpl_isize zpl_asprintf_va(zpl_allocator allocator, char **buffer, char const *fmt, va_list va) { + zpl_local_persist zpl_thread_local char tmp[ZPL_PRINTF_MAXLEN]; + ZPL_ASSERT_NOT_NULL(buffer); + zpl_isize res; + res = zpl_snprintf_va(tmp, zpl_size_of(tmp), fmt, va); + *buffer = zpl_alloc_str(allocator, tmp); + return res; +} + +zpl_isize zpl_printf(char const *fmt, ...) { + zpl_isize res; + va_list va; + va_start(va, fmt); + res = zpl_printf_va(fmt, va); + va_end(va); + return res; +} + +zpl_isize zpl_printf_err(char const *fmt, ...) { + zpl_isize res; + va_list va; + va_start(va, fmt); + res = zpl_printf_err_va(fmt, va); + va_end(va); + return res; +} + +zpl_isize zpl_fprintf(struct zpl_file *f, char const *fmt, ...) { + zpl_isize res; + va_list va; + va_start(va, fmt); + res = zpl_fprintf_va(f, fmt, va); + va_end(va); + return res; +} + +char *zpl_bprintf(char const *fmt, ...) { + va_list va; + char *str; + va_start(va, fmt); + str = zpl_bprintf_va(fmt, va); + va_end(va); + return str; +} + +zpl_isize zpl_asprintf(zpl_allocator allocator, char **buffer, char const *fmt, ...) { + zpl_isize res; + va_list va; + va_start(va, fmt); + res = zpl_asprintf_va(allocator, buffer, fmt, va); + va_end(va); + return res; +} + +zpl_isize zpl_snprintf(char *str, zpl_isize n, char const *fmt, ...) { + zpl_isize res; + va_list va; + va_start(va, fmt); + res = zpl_snprintf_va(str, n, fmt, va); + va_end(va); + return res; +} + + +enum { + ZPL_FMT_MINUS = ZPL_BIT(0), + ZPL_FMT_PLUS = ZPL_BIT(1), + ZPL_FMT_ALT = ZPL_BIT(2), + ZPL_FMT_SPACE = ZPL_BIT(3), + ZPL_FMT_ZERO = ZPL_BIT(4), + + ZPL_FMT_CHAR = ZPL_BIT(5), + ZPL_FMT_SHORT = ZPL_BIT(6), + ZPL_FMT_INT = ZPL_BIT(7), + ZPL_FMT_LONG = ZPL_BIT(8), + ZPL_FMT_LLONG = ZPL_BIT(9), + ZPL_FMT_SIZE = ZPL_BIT(10), + ZPL_FMT_INTPTR = ZPL_BIT(11), + + ZPL_FMT_UNSIGNED = ZPL_BIT(12), + ZPL_FMT_LOWER = ZPL_BIT(13), + ZPL_FMT_UPPER = ZPL_BIT(14), + ZPL_FMT_WIDTH = ZPL_BIT(15), + + ZPL_FMT_DONE = ZPL_BIT(30), + + ZPL_FMT_INTS = + ZPL_FMT_CHAR | ZPL_FMT_SHORT | ZPL_FMT_INT | + ZPL_FMT_LONG | ZPL_FMT_LLONG | ZPL_FMT_SIZE | ZPL_FMT_INTPTR +}; + +typedef struct { + zpl_i32 base; + zpl_i32 flags; + zpl_i32 width; + zpl_i32 precision; +} zpl__format_info; + +zpl_internal zpl_isize zpl__print_string(char *text, zpl_isize max_len, zpl__format_info *info, char const *str) { + zpl_isize res = 0, len = 0; + zpl_isize remaining = max_len; + char *begin = text; + + if (str == NULL && max_len >= 6) { + res += zpl_strlcpy(text, "(null)", 6); + return res; + } + + if (info && info->precision >= 0) + len = zpl_strnlen(str, info->precision); + else + len = zpl_strlen(str); + + if (info && (info->width == 0 && info->flags & ZPL_FMT_WIDTH)) { + return res; + } + + if (info && (info->width == 0 || info->flags & ZPL_FMT_MINUS)) { + if (info->precision > 0) len = info->precision < len ? info->precision : len; + res += zpl_strlcpy(text, str, len); + text += res; + + if (info->width > res) { + zpl_isize padding = info->width - len; + + char pad = (info->flags & ZPL_FMT_ZERO) ? '0' : ' '; + while (padding-- > 0 && remaining-- > 0) *text++ = pad, res++; + } + } else { + if (info && (info->width > res)) { + zpl_isize padding = info->width - len; + char pad = (info->flags & ZPL_FMT_ZERO) ? '0' : ' '; + while (padding-- > 0 && remaining-- > 0) *text++ = pad, res++; + } + + res += zpl_strlcpy(text, str, len); + } + + if (info) { + if (info->flags & ZPL_FMT_UPPER) + zpl_str_to_upper(begin); + else if (info->flags & ZPL_FMT_LOWER) + zpl_str_to_lower(begin); + } + + return res; +} + +zpl_internal zpl_isize zpl__print_char(char *text, zpl_isize max_len, zpl__format_info *info, char arg) { + char str[2] = ""; + str[0] = arg; + return zpl__print_string(text, max_len, info, str); +} + +zpl_internal zpl_isize zpl__print_repeated_char(char *text, zpl_isize max_len, zpl__format_info *info, char arg) { + zpl_isize res = 0; + zpl_i32 rem = (info) ? (info->width > 0) ? info->width : 1 : 1; + res = rem; + while (rem-- > 0) *text++ = arg; + + return res; +} + +zpl_internal zpl_isize zpl__print_i64(char *text, zpl_isize max_len, zpl__format_info *info, zpl_i64 value) { + char num[130]; + zpl_i64_to_str(value, num, info ? info->base : 10); + return zpl__print_string(text, max_len, info, num); +} + +zpl_internal zpl_isize zpl__print_u64(char *text, zpl_isize max_len, zpl__format_info *info, zpl_u64 value) { + char num[130]; + zpl_u64_to_str(value, num, info ? info->base : 10); + return zpl__print_string(text, max_len, info, num); +} + +zpl_internal zpl_isize zpl__print_f64(char *text, zpl_isize max_len, zpl__format_info *info, zpl_f64 arg) { + // TODO: Handle exponent notation + zpl_isize width, len, remaining = max_len; + char *text_begin = text; + + if (arg) { + zpl_u64 value; + if (arg < 0) { + if (remaining > 1) *text = '-', remaining--; + text++; + arg = -arg; + } else if (info->flags & ZPL_FMT_MINUS) { + if (remaining > 1) *text = '+', remaining--; + text++; + } + + value = cast(zpl_u64) arg; + len = zpl__print_u64(text, remaining, NULL, value); + text += len; + + if (len >= remaining) + remaining = zpl_min(remaining, 1); + else + remaining -= len; + arg -= value; + + if (info->precision < 0) info->precision = 6; + + if ((info->flags & ZPL_FMT_ALT) || info->precision > 0) { + zpl_i64 mult = 10; + if (remaining > 1) *text = '.', remaining--; + text++; + while (info->precision-- > 0) { + value = cast(zpl_u64)(arg * mult); + len = zpl__print_u64(text, remaining, NULL, value); + text += len; + if (len >= remaining) + remaining = zpl_min(remaining, 1); + else + remaining -= len; + arg -= cast(zpl_f64) value / mult; + mult *= 10; + } + } + } else { + if (remaining > 1) *text = '0', remaining--; + text++; + if (info->flags & ZPL_FMT_ALT) { + if (remaining > 1) *text = '.', remaining--; + text++; + } + } + + width = info->width - (text - text_begin); + if (width > 0) { + char fill = (info->flags & ZPL_FMT_ZERO) ? '0' : ' '; + char *end = text + remaining - 1; + len = (text - text_begin); + + for (len = (text - text_begin); len--;) { + if ((text_begin + len + width) < end) *(text_begin + len + width) = *(text_begin + len); + } + + len = width; + text += len; + if (len >= remaining) + remaining = zpl_min(remaining, 1); + else + remaining -= len; + + while (len--) { + if (text_begin + len < end) text_begin[len] = fill; + } + } + + return (text - text_begin); +} + +ZPL_NEVER_INLINE zpl_isize zpl_snprintf_va(char *text, zpl_isize max_len, char const *fmt, va_list va) { + char const *text_begin = text; + zpl_isize remaining = max_len, res; + + while (*fmt) { + zpl__format_info info = { 0 }; + zpl_isize len = 0; + info.precision = -1; + + while (*fmt && *fmt != '%' && remaining) *text++ = *fmt++; + + if (*fmt == '%') { + do { + switch (*++fmt) { + case '-': {info.flags |= ZPL_FMT_MINUS; break;} + case '+': {info.flags |= ZPL_FMT_PLUS; break;} + case '#': {info.flags |= ZPL_FMT_ALT; break;} + case ' ': {info.flags |= ZPL_FMT_SPACE; break;} + case '0': {info.flags |= (ZPL_FMT_ZERO|ZPL_FMT_WIDTH); break;} + default: {info.flags |= ZPL_FMT_DONE; break;} + } + } while (!(info.flags & ZPL_FMT_DONE)); + } + + // NOTE: Optional Width + if (*fmt == '*') { + int width = va_arg(va, int); + if (width < 0) { + info.flags |= ZPL_FMT_MINUS; + info.width = -width; + } else { + info.width = width; + } + info.flags |= ZPL_FMT_WIDTH; + fmt++; + } else { + info.width = cast(zpl_i32) zpl_str_to_i64(fmt, cast(char **) & fmt, 10); + if (info.width != 0) { + info.flags |= ZPL_FMT_WIDTH; + } + } + + // NOTE: Optional Precision + if (*fmt == '.') { + fmt++; + if (*fmt == '*') { + info.precision = va_arg(va, int); + fmt++; + } else { + info.precision = cast(zpl_i32) zpl_str_to_i64(fmt, cast(char **) & fmt, 10); + } + info.flags &= ~ZPL_FMT_ZERO; + } + + switch (*fmt++) { + case 'h': + if (*fmt == 'h') { // hh => char + info.flags |= ZPL_FMT_CHAR; + fmt++; + } else { // h => short + info.flags |= ZPL_FMT_SHORT; + } + break; + + case 'l': + if (*fmt == 'l') { // ll => long long + info.flags |= ZPL_FMT_LLONG; + fmt++; + } else { // l => long + info.flags |= ZPL_FMT_LONG; + } + break; + + break; + + case 'z': // NOTE: zpl_usize + info.flags |= ZPL_FMT_UNSIGNED; + // fallthrough + case 't': // NOTE: zpl_isize + info.flags |= ZPL_FMT_SIZE; + break; + + default: fmt--; break; + } + + switch (*fmt) { + case 'u': + info.flags |= ZPL_FMT_UNSIGNED; + // fallthrough + case 'd': + case 'i': info.base = 10; break; + + case 'o': info.base = 8; break; + + case 'x': + info.base = 16; + info.flags |= (ZPL_FMT_UNSIGNED | ZPL_FMT_LOWER); + break; + + case 'X': + info.base = 16; + info.flags |= (ZPL_FMT_UNSIGNED | ZPL_FMT_UPPER); + break; + + case 'f': + case 'F': + case 'g': + case 'G': len = zpl__print_f64(text, remaining, &info, va_arg(va, zpl_f64)); break; + + case 'a': + case 'A': + // TODO: + break; + + case 'c': len = zpl__print_char(text, remaining, &info, cast(char) va_arg(va, int)); break; + + case 's': len = zpl__print_string(text, remaining, &info, va_arg(va, char *)); break; + + case 'r': len = zpl__print_repeated_char(text, remaining, &info, va_arg(va, int)); break; + + case 'p': + info.base = 16; + info.flags |= (ZPL_FMT_LOWER | ZPL_FMT_UNSIGNED | ZPL_FMT_ALT | ZPL_FMT_INTPTR); + break; + + case '%': len = zpl__print_char(text, remaining, &info, '%'); break; + + default: fmt--; break; + } + + fmt++; + + if (info.base != 0) { + if (info.flags & ZPL_FMT_UNSIGNED) { + zpl_u64 value = 0; + switch (info.flags & ZPL_FMT_INTS) { + case ZPL_FMT_CHAR: value = cast(zpl_u64) cast(zpl_u8) va_arg(va, int); break; + case ZPL_FMT_SHORT: value = cast(zpl_u64) cast(zpl_u16) va_arg(va, int); break; + case ZPL_FMT_LONG: value = cast(zpl_u64) va_arg(va, unsigned long); break; + case ZPL_FMT_LLONG: value = cast(zpl_u64) va_arg(va, unsigned long long); break; + case ZPL_FMT_SIZE: value = cast(zpl_u64) va_arg(va, zpl_usize); break; + case ZPL_FMT_INTPTR: value = cast(zpl_u64) va_arg(va, zpl_uintptr); break; + default: value = cast(zpl_u64) va_arg(va, unsigned int); break; + } + + len = zpl__print_u64(text, remaining, &info, value); + + } else { + zpl_i64 value = 0; + switch (info.flags & ZPL_FMT_INTS) { + case ZPL_FMT_CHAR: value = cast(zpl_i64) cast(zpl_i8) va_arg(va, int); break; + case ZPL_FMT_SHORT: value = cast(zpl_i64) cast(zpl_i16) va_arg(va, int); break; + case ZPL_FMT_LONG: value = cast(zpl_i64) va_arg(va, long); break; + case ZPL_FMT_LLONG: value = cast(zpl_i64) va_arg(va, long long); break; + case ZPL_FMT_SIZE: value = cast(zpl_i64) va_arg(va, zpl_usize); break; + case ZPL_FMT_INTPTR: value = cast(zpl_i64) va_arg(va, zpl_uintptr); break; + default: value = cast(zpl_i64) va_arg(va, int); break; + } + + len = zpl__print_i64(text, remaining, &info, value); + } + } + + text += len; + if (len >= remaining) + remaining = zpl_min(remaining, 1); + else + remaining -= len; + } + + *text++ = '\0'; + res = (text - text_begin); + return (res >= max_len || res < 0) ? -1 : res; +} + +ZPL_END_C_DECLS +// file: source/core/time.c + + +#if defined(ZPL_SYSTEM_MACOS) || ZPL_SYSTEM_UNIX +# include +# include +#endif + +#if defined(ZPL_SYSTEM_MACOS) +# include +# include +# include +#endif + +#if defined(ZPL_SYSTEM_EMSCRIPTEN) +# include +#endif + +#if defined(ZPL_SYSTEM_WINDOWS) +# include +#endif + +ZPL_BEGIN_C_DECLS + +//! @} +//$$ +//////////////////////////////////////////////////////////////// +// +// Time +// +// + +#if defined(ZPL_COMPILER_MSVC) && !defined(__clang__) +zpl_u64 zpl_rdtsc(void) { return __rdtsc( ); } +#elif defined(__i386__) +zpl_u64 zpl_rdtsc(void) { + zpl_u64 x; + __asm__ volatile(".byte 0x0f, 0x31" : "=A"(x)); + return x; +} +#elif defined(__x86_64__) +zpl_u64 zpl_rdtsc(void) { + zpl_u32 hi, lo; + __asm__ __volatile__("rdtsc" : "=a"(lo), "=d"(hi)); + return (cast(zpl_u64) lo) | ((cast(zpl_u64) hi) << 32); +} +#elif defined(__powerpc__) +zpl_u64 zpl_rdtsc(void) { + zpl_u64 result = 0; + zpl_u32 upper, lower, tmp; + __asm__ volatile("0: \n" + "\tmftbu %0 \n" + "\tmftb %1 \n" + "\tmftbu %2 \n" + "\tcmpw %2,%0 \n" + "\tbne 0b \n" + : "=r"(upper), "=r"(lower), "=r"(tmp)); + result = upper; + result = result << 32; + result = result | lower; + + return result; +} +#elif defined(ZPL_SYSTEM_EMSCRIPTEN) +zpl_u64 zpl_rdtsc(void) { + return (zpl_u64)(emscripten_get_now() * 1e+6); +} +#elif defined(ZPL_CPU_ARM) && !defined(ZPL_COMPILER_TINYC) +zpl_u64 zpl_rdtsc(void) { +# if defined(__aarch64__) + int64_t r = 0; + asm volatile("mrs %0, cntvct_el0" : "=r"(r)); +# elif (__ARM_ARCH >= 6) + uint32_t r = 0; + uint32_t pmccntr; + uint32_t pmuseren; + uint32_t pmcntenset; + + // Read the user mode perf monitor counter access permissions. + asm volatile("mrc p15, 0, %0, c9, c14, 0" : "=r"(pmuseren)); + if (pmuseren & 1) { // Allows reading perfmon counters for user mode code. + asm volatile("mrc p15, 0, %0, c9, c12, 1" : "=r"(pmcntenset)); + if (pmcntenset & 0x80000000ul) { // Is it counting? + asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r"(pmccntr)); + // The counter is set up to count every 64th cycle + return ((int64_t)pmccntr) * 64; // Should optimize to << 6 + } + } +# else +# error "No suitable method for zpl_rdtsc for this cpu type" +# endif + + return r; +} +#else +zpl_u64 zpl_rdtsc(void) { + ZPL_PANIC("zpl_rdtsc is not supported on this particular setup"); + return -0; +} +#endif + +#if defined(ZPL_SYSTEM_WINDOWS) || defined(ZPL_SYSTEM_CYGWIN) + +zpl_u64 zpl_time_rel_ms(void) { + zpl_local_persist LARGE_INTEGER win32_perf_count_freq = { 0 }; + zpl_u64 result; + LARGE_INTEGER counter; + zpl_local_persist LARGE_INTEGER win32_perf_counter = { 0 }; + if (!win32_perf_count_freq.QuadPart) { + QueryPerformanceFrequency(&win32_perf_count_freq); + ZPL_ASSERT(win32_perf_count_freq.QuadPart != 0); + QueryPerformanceCounter(&win32_perf_counter); + } + + QueryPerformanceCounter(&counter); + + result = (counter.QuadPart - win32_perf_counter.QuadPart) * 1000 / (win32_perf_count_freq.QuadPart); + return result; +} + +zpl_u64 zpl_time_utc_ms(void) { + FILETIME ft; + ULARGE_INTEGER li; + + GetSystemTimeAsFileTime(&ft); + li.LowPart = ft.dwLowDateTime; + li.HighPart = ft.dwHighDateTime; + + return li.QuadPart / 1000; +} + +zpl_u64 zpl_time_tz_ms(void) { + FILETIME ft; + SYSTEMTIME st, lst; + ULARGE_INTEGER li; + + GetSystemTime(&st); + SystemTimeToTzSpecificLocalTime(NULL, &st, &lst); + SystemTimeToFileTime(&lst, &ft); + li.LowPart = ft.dwLowDateTime; + li.HighPart = ft.dwHighDateTime; + + return li.QuadPart / 1000; +} + +void zpl_sleep_ms(zpl_u32 ms) { Sleep(ms); } + +#else + +# if defined(ZPL_SYSTEM_LINUX) || defined(ZPL_SYSTEM_FREEBSD) || defined(ZPL_SYSTEM_OPENBSD) || defined(ZPL_SYSTEM_EMSCRIPTEN) +zpl_u64 zpl__unix_gettime(void) { + struct timespec t; + zpl_u64 result; + + clock_gettime(1 /*CLOCK_MONOTONIC*/, &t); + result = 1000 * t.tv_sec + 1.0e-6 * t.tv_nsec; + return result; +} +# endif + +zpl_u64 zpl_time_rel_ms(void) { +# if defined(ZPL_SYSTEM_OSX) + zpl_u64 result; + + zpl_local_persist zpl_u64 timebase = 0; + zpl_local_persist zpl_u64 timestart = 0; + + if (!timestart) { + mach_timebase_info_data_t tb = { 0 }; + mach_timebase_info(&tb); + timebase = tb.numer; + timebase /= tb.denom; + timestart = mach_absolute_time(); + } + + // NOTE: mach_absolute_time() returns things in nanoseconds + result = 1.0e-6 * (mach_absolute_time() - timestart) * timebase; + return result; +# else + zpl_local_persist zpl_u64 unix_timestart = 0.0; + + if (!unix_timestart) { unix_timestart = zpl__unix_gettime( ); } + + zpl_u64 now = zpl__unix_gettime( ); + + return (now - unix_timestart); +# endif +} + +zpl_u64 zpl_time_utc_ms(void) { + struct timespec t; +# if defined(ZPL_SYSTEM_OSX) + clock_serv_t cclock; + mach_timespec_t mts; + host_get_clock_service(mach_host_self( ), CALENDAR_CLOCK, &cclock); + clock_get_time(cclock, &mts); + mach_port_deallocate(mach_task_self( ), cclock); + t.tv_sec = mts.tv_sec; + t.tv_nsec = mts.tv_nsec; +# else + clock_gettime(0 /*CLOCK_REALTIME*/, &t); +# endif + return ((zpl_u64)t.tv_sec * 1000 + t.tv_nsec * 1e-6 + ZPL__UNIX_TO_WIN32_EPOCH); +} + +void zpl_sleep_ms(zpl_u32 ms) { + struct timespec req = { cast(time_t)(ms * 1e-3), cast(long)((ms % 1000) * 1e6) }; + struct timespec rem = { 0, 0 }; + nanosleep(&req, &rem); +} + +zpl_u64 zpl_time_tz_ms(void) { + struct tm t; + zpl_u64 result = zpl_time_utc_ms() - ZPL__UNIX_TO_WIN32_EPOCH; + zpl_u16 ms = result % 1000; + result *= 1e-3; + localtime_r((const time_t*)&result, &t); + result = (zpl_u64)mktime(&t); + return (result - timezone + t.tm_isdst * 3600) * 1000 + ms + ZPL__UNIX_TO_WIN32_EPOCH; +} +#endif + +zpl_f64 zpl_time_rel(void) { + return (zpl_f64)(zpl_time_rel_ms() * 1e-3); +} + +zpl_f64 zpl_time_utc(void) { + return (zpl_f64)(zpl_time_utc_ms() * 1e-3); +} + +zpl_f64 zpl_time_tz(void) { + return (zpl_f64)(zpl_time_tz_ms() * 1e-3); +} + + + +ZPL_END_C_DECLS +// file: source/core/random.c + + +ZPL_BEGIN_C_DECLS + +#if defined(ZPL_MODULE_THREADING) +zpl_global zpl_atomic32 zpl__random_shared_counter = {0}; +#else +zpl_global zpl_i32 zpl__random_shared_counter = 0; +#endif + +zpl_internal zpl_u32 zpl__get_noise_from_time(void) { + zpl_u32 accum = 0; + zpl_f64 start, remaining, end, curr = 0; + zpl_u64 interval = 100000ll; + + start = zpl_time_rel(); + remaining = (interval - cast(zpl_u64)(interval*start)%interval) / cast(zpl_f64)interval; + end = start + remaining; + + do { + curr = zpl_time_rel(); + accum += cast(zpl_u32)curr; + } while (curr >= end); + return accum; +} + +// NOTE: Partly from http://preshing.com/20121224/how-to-generate-a-sequence-of-unique-random-integers/ +// But the generation is even more random-er-est + +zpl_internal ZPL_ALWAYS_INLINE zpl_u32 zpl__permute_qpr(zpl_u32 x) { + zpl_local_persist zpl_u32 const prime = 4294967291; // 2^32 - 5 + if (x >= prime) { + return x; + } else { + zpl_u32 residue = cast(zpl_u32)(cast(zpl_u64) x * x) % prime; + if (x <= prime / 2) + return residue; + else + return prime - residue; + } +} + +zpl_internal ZPL_ALWAYS_INLINE zpl_u32 zpl__permute_with_offset(zpl_u32 x, zpl_u32 offset) { + return (zpl__permute_qpr(x) + offset) ^ 0x5bf03635; +} + + +void zpl_random_init(zpl_random *r) { + zpl_u64 time, tick; + zpl_isize i, j; + zpl_u32 x = 0; + r->value = 0; + + r->offsets[0] = zpl__get_noise_from_time(); +#ifdef ZPL_MODULE_THREADING + r->offsets[1] = zpl_atomic32_fetch_add(&zpl__random_shared_counter, 1); + r->offsets[2] = zpl_thread_current_id(); + r->offsets[3] = zpl_thread_current_id() * 3 + 1; +#else + r->offsets[1] = zpl__random_shared_counter++; + r->offsets[2] = 0; + r->offsets[3] = 1; +#endif + time = zpl_time_tz_ms(); + r->offsets[4] = cast(zpl_u32)(time >> 32); + r->offsets[5] = cast(zpl_u32)time; + r->offsets[6] = zpl__get_noise_from_time(); + tick = zpl_rdtsc(); + r->offsets[7] = cast(zpl_u32)(tick ^ (tick >> 32)); + + for (j = 0; j < 4; j++) { + for (i = 0; i < zpl_count_of(r->offsets); i++) { + r->offsets[i] = x = zpl__permute_with_offset(x, r->offsets[i]); + } + } +} + +zpl_u32 zpl_random_gen_u32(zpl_random *r) { + zpl_u32 x = r->value; + zpl_u32 carry = 1; + zpl_isize i; + for (i = 0; i < zpl_count_of(r->offsets); i++) { + x = zpl__permute_with_offset(x, r->offsets[i]); + if (carry > 0) { + carry = ++r->offsets[i] ? 0 : 1; + } + } + + r->value = x; + return x; +} + +zpl_u32 zpl_random_gen_u32_unique(zpl_random *r) { + zpl_u32 x = r->value; + zpl_isize i; + r->value++; + for (i = 0; i < zpl_count_of(r->offsets); i++) { + x = zpl__permute_with_offset(x, r->offsets[i]); + } + + return x; +} + +zpl_u64 zpl_random_gen_u64(zpl_random *r) { + return ((cast(zpl_u64)zpl_random_gen_u32(r)) << 32) | zpl_random_gen_u32(r); +} + + +zpl_isize zpl_random_gen_isize(zpl_random *r) { + zpl_u64 u = zpl_random_gen_u64(r); + zpl_isize i; + zpl_memcopy(&i, &u, zpl_size_of(u)); + return i; +} + + +zpl_i64 zpl_random_range_i64(zpl_random *r, zpl_i64 lower_inc, zpl_i64 higher_inc) { + zpl_u64 u = zpl_random_gen_u64(r); + zpl_i64 i = *cast(zpl_i64 *)&u; + zpl_i64 diff = higher_inc-lower_inc+1; + i %= diff; + i += lower_inc; + return i; +} + +zpl_isize zpl_random_range_isize(zpl_random *r, zpl_isize lower_inc, zpl_isize higher_inc) { + zpl_u64 u = zpl_random_gen_u64(r); + zpl_isize i; + zpl_memcopy(&i, &u, zpl_size_of(u)); + zpl_isize diff = higher_inc-lower_inc+1; + i %= diff; + i += lower_inc; + return i; +} + +ZPL_ALWAYS_INLINE zpl_f64 zpl__random_copy_sign64(zpl_f64 x, zpl_f64 y) { + zpl_i64 ix=0, iy=0; + zpl_memcopy(&ix, &x, zpl_size_of(zpl_i64)); + zpl_memcopy(&iy, &y, zpl_size_of(zpl_i64)); + + ix &= 0x7fffffffffffffff; + ix |= iy & 0x8000000000000000; + + zpl_f64 r = 0.0; + zpl_memcopy(&r, &ix, zpl_size_of(zpl_f64)); + return r; +} + +zpl_f64 zpl_random_range_f64(zpl_random *r, zpl_f64 lower_inc, zpl_f64 higher_inc) { + zpl_f64 f = cast(zpl_f64)zpl_random_gen_u64(r) / cast(zpl_f64)ZPL_U64_MAX; + zpl_f64 diff = higher_inc-lower_inc; + + f *= diff; + f += lower_inc; + return f; +} + +ZPL_END_C_DECLS +// file: source/core/misc.c + + +ZPL_BEGIN_C_DECLS + +void zpl_yield(void) { +# if defined(ZPL_SYSTEM_WINDOWS) + Sleep(0); +# else + sched_yield(); +# endif +} + +const char *zpl_get_env(const char *name) { + char *buffer = NULL; + const char *ptr = zpl_get_env_buf(name); + + if (ptr == NULL) { + return NULL; + } + + zpl_isize ptr_size = zpl_strlen(ptr); + buffer = (char *)zpl_malloc(ptr_size * sizeof(char)+1); + zpl_memcopy((char *)buffer, ptr, ptr_size+1); + return buffer; +} + +const char *zpl_get_env_buf(const char *name) { +# ifdef ZPL_SYSTEM_WINDOWS + zpl_local_persist wchar_t wbuffer[32767] = {0}; + zpl_local_persist char buffer[32767] = {0}; + + if (!GetEnvironmentVariableW( + cast(LPCWSTR)zpl_utf8_to_ucs2_buf(cast(const zpl_u8 *)name), + cast(LPWSTR)wbuffer, 32767)) { + return NULL; + } + + zpl_ucs2_to_utf8(cast(zpl_u8*)buffer, 32767, cast(const zpl_u16*)wbuffer); + + return (const char *)buffer; +# else + return (const char *)getenv(name); +# endif +} + +zpl_string zpl_get_env_str(const char *name) { + const char *buf = zpl_get_env_buf(name); + + if (buf == NULL) { + return NULL; + } + + zpl_string str = zpl_string_make(zpl_heap(), buf); + return str; +} + +void zpl_set_env(const char *name, const char *value) { +# if defined(ZPL_SYSTEM_WINDOWS) + SetEnvironmentVariableA(name, value); +# else + setenv(name, value, 1); +# endif +} + +void zpl_unset_env(const char *name) { +# if defined(ZPL_SYSTEM_WINDOWS) + SetEnvironmentVariableA(name, NULL); +# else + unsetenv(name); +# endif +} + +#if !defined(ZPL_SYSTEM_WINDOWS) +extern char **environ; +#endif + +zpl_u32 zpl_system_command(const char *command, zpl_usize buffer_len, char *buffer) { +# if defined(ZPL_SYSTEM_EMSCRIPTEN) + ZPL_PANIC("zpl_system_command not supported"); +# else + +# if defined(ZPL_SYSTEM_WINDOWS) + FILE *handle = _popen(command, "r"); +# else + FILE *handle = popen(command, "r"); +# endif + + if(!handle) return 0; + + int c; + zpl_usize i=0; + while ((c = getc(handle)) != EOF && i++ < buffer_len) { + *buffer++ = c; + } + +# if defined(ZPL_SYSTEM_WINDOWS) + _pclose(handle); +# else + pclose(handle); +# endif + +# endif + + return 1; +} + +zpl_string zpl_system_command_str(const char *command, zpl_allocator backing) { +# if defined(ZPL_SYSTEM_EMSCRIPTEN) + ZPL_PANIC("zpl_system_command not supported"); +# else + +# if defined(ZPL_SYSTEM_WINDOWS) + FILE *handle = _popen(command, "r"); +# else + FILE *handle = popen(command, "r"); +# endif + + if(!handle) return NULL; + + zpl_string output = zpl_string_make_reserve(backing, 4); + + int c; + while ((c = getc(handle)) != EOF) { + char ins[2] = {(char)c,0}; + output = zpl_string_appendc(output, ins); + } + +# if defined(ZPL_SYSTEM_WINDOWS) + _pclose(handle); +# else + pclose(handle); +# endif + return output; +# endif + return NULL; +} + +ZPL_END_C_DECLS +// file: source/core/sort.c + + +ZPL_BEGIN_C_DECLS + +#define ZPL__COMPARE_PROC(Type) \ +zpl_global zpl_isize Type##__cmp_offset; \ +ZPL_COMPARE_PROC(Type##__cmp) { \ +Type const p = *cast(Type const *) zpl_pointer_add_const(a, Type##__cmp_offset); \ +Type const q = *cast(Type const *) zpl_pointer_add_const(b, Type##__cmp_offset); \ +return p < q ? -1 : p > q; \ +} \ +ZPL_COMPARE_PROC_PTR(Type##_cmp(zpl_isize offset)) { \ +Type##__cmp_offset = offset; \ +return &Type##__cmp; \ +} + +ZPL__COMPARE_PROC(zpl_u8); +ZPL__COMPARE_PROC(zpl_i16); +ZPL__COMPARE_PROC(zpl_i32); +ZPL__COMPARE_PROC(zpl_i64); +ZPL__COMPARE_PROC(zpl_isize); +ZPL__COMPARE_PROC(zpl_f32); +ZPL__COMPARE_PROC(zpl_f64); + +// NOTE: str_cmp is special as it requires a funny type and funny comparison +zpl_global zpl_isize zpl__str_cmp_offset; +ZPL_COMPARE_PROC(zpl__str_cmp) { + char const *p = *cast(char const **) zpl_pointer_add_const(a, zpl__str_cmp_offset); + char const *q = *cast(char const **) zpl_pointer_add_const(b, zpl__str_cmp_offset); + return zpl_strcmp(p, q); +} +ZPL_COMPARE_PROC_PTR(zpl_str_cmp(zpl_isize offset)) { + zpl__str_cmp_offset = offset; + return &zpl__str_cmp; +} + +#undef ZPL__COMPARE_PROC + +// TODO: Make user definable? +#define ZPL__SORT_STACK_SIZE 64 +#define zpl__SORT_INSERT_SORT_TRESHOLD 8 + +#define ZPL__SORT_PUSH(_base, _limit) \ +do { \ +stack_ptr[0] = (_base); \ +stack_ptr[1] = (_limit); \ +stack_ptr += 2; \ +} while (0) + +#define ZPL__SORT_POP(_base, _limit) \ +do { \ +stack_ptr -= 2; \ +(_base) = stack_ptr[0]; \ +(_limit) = stack_ptr[1]; \ +} while (0) + +void zpl_sort(void *base_, zpl_isize count, zpl_isize size, zpl_compare_proc cmp) { + zpl_u8 *i, *j; + zpl_u8 *base = cast(zpl_u8 *) base_; + zpl_u8 *limit = base + count * size; + zpl_isize threshold = zpl__SORT_INSERT_SORT_TRESHOLD * size; + + // NOTE: Prepare the stack + zpl_u8 *stack[ZPL__SORT_STACK_SIZE] = { 0 }; + zpl_u8 **stack_ptr = stack; + + for (;;) { + if ((limit - base) > threshold) { + // NOTE: Quick sort + i = base + size; + j = limit - size; + + zpl_memswap(((limit - base) / size / 2) * size + base, base, size); + if (cmp(i, j) > 0) zpl_memswap(i, j, size); + if (cmp(base, j) > 0) zpl_memswap(base, j, size); + if (cmp(i, base) > 0) zpl_memswap(i, base, size); + + for (;;) { + do + i += size; + while (cmp(i, base) < 0); + do + j -= size; + while (cmp(j, base) > 0); + if (i > j) break; + zpl_memswap(i, j, size); + } + + zpl_memswap(base, j, size); + + if (j - base > limit - i) { + ZPL__SORT_PUSH(base, j); + base = i; + } else { + ZPL__SORT_PUSH(i, limit); + limit = j; + } + } else { + // NOTE: Insertion sort + for (j = base, i = j + size; i < limit; j = i, i += size) { + for (; cmp(j, j + size) > 0; j -= size) { + zpl_memswap(j, j + size, size); + if (j == base) break; + } + } + + if (stack_ptr == stack) break; // NOTE: Sorting is done! + ZPL__SORT_POP(base, limit); + } + } +} + +#undef ZPL__SORT_PUSH +#undef ZPL__SORT_POP + +#define ZPL_RADIX_SORT_PROC_GEN(Type) \ +ZPL_RADIX_SORT_PROC(Type) { \ +zpl_##Type *source = items; \ +zpl_##Type *dest = temp; \ +zpl_isize byte_index, i, byte_max = 8 * zpl_size_of(zpl_##Type); \ +for (byte_index = 0; byte_index < byte_max; byte_index += 8) { \ +zpl_isize offsets[256] = { 0 }; \ +zpl_isize total = 0; \ +/* NOTE: First pass - count how many of each key */ \ +for (i = 0; i < count; i++) { \ +zpl_##Type radix_value = source[i]; \ +zpl_##Type radix_piece = (radix_value >> byte_index) & 0xff; \ +offsets[radix_piece]++; \ +} \ +/* NOTE: Change counts to offsets */ \ +for (i = 0; i < zpl_count_of(offsets); i++) { \ +zpl_isize skcount = offsets[i]; \ +offsets[i] = total; \ +total += skcount; \ +} \ +/* NOTE: Second pass - place elements into the right location */ \ +for (i = 0; i < count; i++) { \ +zpl_##Type radix_value = source[i]; \ +zpl_##Type radix_piece = (radix_value >> byte_index) & 0xff; \ +dest[offsets[radix_piece]++] = source[i]; \ +} \ +zpl_swap(zpl_##Type *, source, dest); \ +} \ +} + +ZPL_RADIX_SORT_PROC_GEN(u8); +ZPL_RADIX_SORT_PROC_GEN(u16); +ZPL_RADIX_SORT_PROC_GEN(u32); +ZPL_RADIX_SORT_PROC_GEN(u64); + +void zpl_shuffle(void *base, zpl_isize count, zpl_isize size) { + zpl_u8 *a; + zpl_isize i, j; + zpl_random random; + zpl_random_init(&random); + + a = cast(zpl_u8 *) base + (count - 1) * size; + for (i = count; i > 1; i--) { + j = zpl_random_gen_isize(&random) % i; + zpl_memswap(a, cast(zpl_u8 *) base + j * size, size); + a -= size; + } +} + +void zpl_reverse(void *base, zpl_isize count, zpl_isize size) { + zpl_isize i, j = count - 1; + for (i = 0; i < j; i++, j++) zpl_memswap(cast(zpl_u8 *) base + i * size, cast(zpl_u8 *) base + j * size, size); +} + +ZPL_END_C_DECLS # endif #endif #if defined(ZPL_MODULE_TIMER) - // file: source/timer.c +// file: source/timer.c - //////////////////////////////////////////////////////////////// - // - // Timer - // - // +//////////////////////////////////////////////////////////////// +// +// Timer +// +// - ZPL_BEGIN_C_DECLS +ZPL_BEGIN_C_DECLS - zpl_timer *zpl_timer_add(zpl_timer_pool pool) { - ZPL_ASSERT(pool); +zpl_timer *zpl_timer_add(zpl_timer_pool pool) { + ZPL_ASSERT(pool); + + zpl_timer t = { 0 }; + zpl_array_append(pool, t); + return pool + (zpl_array_count(pool) - 1); +} - zpl_timer t = { 0 }; - zpl_array_append(pool, t); - return pool + (zpl_array_count(pool) - 1); - } +void zpl_timer_set(zpl_timer *t, zpl_f64 duration, zpl_i32 count, zpl_timer_cb cb) { + ZPL_ASSERT(t); + + t->duration = duration; + t->remaining_calls = t->initial_calls = count; + t->callback = cb; + t->enabled = false; +} - void zpl_timer_set(zpl_timer *t, zpl_f64 duration, zpl_i32 count, zpl_timer_cb cb) { - ZPL_ASSERT(t); +void zpl_timer_start(zpl_timer *t, zpl_f64 delay_start) { + ZPL_ASSERT(t && !t->enabled); + + t->enabled = true; + t->remaining_calls = t->initial_calls; + t->next_call_ts = zpl_time_rel( ) + delay_start; +} - t->duration = duration; - t->remaining_calls = t->initial_calls = count; - t->callback = cb; - t->enabled = false; - } +void zpl_timer_stop(zpl_timer *t) { + ZPL_ASSERT(t && t->enabled); + + t->enabled = false; +} - void zpl_timer_start(zpl_timer *t, zpl_f64 delay_start) { - ZPL_ASSERT(t && !t->enabled); +void zpl_timer_update(zpl_timer *timer) { + zpl_f64 now = zpl_time_rel(); + if (timer->enabled) { + if (timer->remaining_calls > 0 || timer->initial_calls == -1) { + if (timer->next_call_ts <= now) { + if (timer->initial_calls != -1) { --timer->remaining_calls; } + + if (timer->remaining_calls == 0) { + timer->enabled = false; + } else { + timer->next_call_ts = now + timer->duration; + } + + timer->callback(timer->user_data); + } + } + } +} - t->enabled = true; - t->remaining_calls = t->initial_calls; - t->next_call_ts = zpl_time_rel( ) + delay_start; - } +void zpl_timer_update_array(zpl_timer_pool pool) { + ZPL_ASSERT(pool); + + for (zpl_isize i = 0; i < zpl_array_count(pool); ++i) { + zpl_timer *t = pool + i; + + zpl_timer_update(t); + } +} - void zpl_timer_stop(zpl_timer *t) { - ZPL_ASSERT(t && t->enabled); - - t->enabled = false; - } - - void zpl_timer_update(zpl_timer *timer) { - zpl_f64 now = zpl_time_rel(); - if (timer->enabled) { - if (timer->remaining_calls > 0 || timer->initial_calls == -1) { - if (timer->next_call_ts <= now) { - if (timer->initial_calls != -1) { --timer->remaining_calls; } - - if (timer->remaining_calls == 0) { - timer->enabled = false; - } else { - timer->next_call_ts = now + timer->duration; - } - - timer->callback(timer->user_data); - } - } - } - } - - void zpl_timer_update_array(zpl_timer_pool pool) { - ZPL_ASSERT(pool); - - for (zpl_isize i = 0; i < zpl_array_count(pool); ++i) { - zpl_timer *t = pool + i; - - zpl_timer_update(t); - } - } - - ZPL_END_C_DECLS +ZPL_END_C_DECLS #endif #if defined(ZPL_MODULE_HASHING) - // file: source/hashing.c - - //////////////////////////////////////////////////////////////// - // - // Hashing functions - // - // - - ZPL_BEGIN_C_DECLS - - zpl_u32 zpl_adler32(void const *data, zpl_isize len) { - zpl_u32 const MOD_ALDER = 65521; - zpl_u32 a = 1, b = 0; - zpl_isize i, block_len; - zpl_u8 const *bytes = cast(zpl_u8 const *) data; - - block_len = len % 5552; - - while (len) { - for (i = 0; i + 7 < block_len; i += 8) { - a += bytes[0], b += a; - a += bytes[1], b += a; - a += bytes[2], b += a; - a += bytes[3], b += a; - a += bytes[4], b += a; - a += bytes[5], b += a; - a += bytes[6], b += a; - a += bytes[7], b += a; - - bytes += 8; - } - for (; i < block_len; i++) a += *bytes++, b += a; - - a %= MOD_ALDER, b %= MOD_ALDER; - len -= block_len; - block_len = 5552; - } - - return (b << 16) | a; - } - - zpl_global zpl_u32 const zpl__crc32_table[256] = { - 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, - 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, - 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, - 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, - 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, - 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, - 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, - 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, - 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, - 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, - 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, - 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, - 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, - 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, - 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, - 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, - 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, - 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, - 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, - 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, - 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, - 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, - 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, - 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, - 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, - 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, - 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, - 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, - 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, - }; - - zpl_global zpl_u64 const zpl__crc64_table[256] = { - 0x0000000000000000ull, 0x7ad870c830358979ull, 0xf5b0e190606b12f2ull, 0x8f689158505e9b8bull, 0xc038e5739841b68full, 0xbae095bba8743ff6ull, - 0x358804e3f82aa47dull, 0x4f50742bc81f2d04ull, 0xab28ecb46814fe75ull, 0xd1f09c7c5821770cull, 0x5e980d24087fec87ull, 0x24407dec384a65feull, - 0x6b1009c7f05548faull, 0x11c8790fc060c183ull, 0x9ea0e857903e5a08ull, 0xe478989fa00bd371ull, 0x7d08ff3b88be6f81ull, 0x07d08ff3b88be6f8ull, - 0x88b81eabe8d57d73ull, 0xf2606e63d8e0f40aull, 0xbd301a4810ffd90eull, 0xc7e86a8020ca5077ull, 0x4880fbd87094cbfcull, 0x32588b1040a14285ull, - 0xd620138fe0aa91f4ull, 0xacf86347d09f188dull, 0x2390f21f80c18306ull, 0x594882d7b0f40a7full, 0x1618f6fc78eb277bull, 0x6cc0863448deae02ull, - 0xe3a8176c18803589ull, 0x997067a428b5bcf0ull, 0xfa11fe77117cdf02ull, 0x80c98ebf2149567bull, - 0x0fa11fe77117cdf0ull, 0x75796f2f41224489ull, 0x3a291b04893d698dull, 0x40f16bccb908e0f4ull, 0xcf99fa94e9567b7full, 0xb5418a5cd963f206ull, - 0x513912c379682177ull, 0x2be1620b495da80eull, 0xa489f35319033385ull, 0xde51839b2936bafcull, 0x9101f7b0e12997f8ull, 0xebd98778d11c1e81ull, - 0x64b116208142850aull, 0x1e6966e8b1770c73ull, 0x8719014c99c2b083ull, 0xfdc17184a9f739faull, 0x72a9e0dcf9a9a271ull, 0x08719014c99c2b08ull, - 0x4721e43f0183060cull, 0x3df994f731b68f75ull, 0xb29105af61e814feull, 0xc849756751dd9d87ull, 0x2c31edf8f1d64ef6ull, 0x56e99d30c1e3c78full, - 0xd9810c6891bd5c04ull, 0xa3597ca0a188d57dull, 0xec09088b6997f879ull, 0x96d1784359a27100ull, 0x19b9e91b09fcea8bull, 0x636199d339c963f2ull, - 0xdf7adabd7a6e2d6full, 0xa5a2aa754a5ba416ull, 0x2aca3b2d1a053f9dull, 0x50124be52a30b6e4ull, 0x1f423fcee22f9be0ull, 0x659a4f06d21a1299ull, - 0xeaf2de5e82448912ull, 0x902aae96b271006bull, 0x74523609127ad31aull, 0x0e8a46c1224f5a63ull, 0x81e2d7997211c1e8ull, 0xfb3aa75142244891ull, - 0xb46ad37a8a3b6595ull, 0xceb2a3b2ba0eececull, 0x41da32eaea507767ull, 0x3b024222da65fe1eull, 0xa2722586f2d042eeull, 0xd8aa554ec2e5cb97ull, - 0x57c2c41692bb501cull, 0x2d1ab4dea28ed965ull, 0x624ac0f56a91f461ull, 0x1892b03d5aa47d18ull, 0x97fa21650afae693ull, 0xed2251ad3acf6feaull, - 0x095ac9329ac4bc9bull, 0x7382b9faaaf135e2ull, 0xfcea28a2faafae69ull, 0x8632586aca9a2710ull, 0xc9622c4102850a14ull, 0xb3ba5c8932b0836dull, - 0x3cd2cdd162ee18e6ull, 0x460abd1952db919full, 0x256b24ca6b12f26dull, 0x5fb354025b277b14ull, 0xd0dbc55a0b79e09full, 0xaa03b5923b4c69e6ull, - 0xe553c1b9f35344e2ull, 0x9f8bb171c366cd9bull, 0x10e3202993385610ull, 0x6a3b50e1a30ddf69ull, 0x8e43c87e03060c18ull, 0xf49bb8b633338561ull, - 0x7bf329ee636d1eeaull, 0x012b592653589793ull, 0x4e7b2d0d9b47ba97ull, 0x34a35dc5ab7233eeull, 0xbbcbcc9dfb2ca865ull, 0xc113bc55cb19211cull, - 0x5863dbf1e3ac9decull, 0x22bbab39d3991495ull, 0xadd33a6183c78f1eull, 0xd70b4aa9b3f20667ull, 0x985b3e827bed2b63ull, 0xe2834e4a4bd8a21aull, - 0x6debdf121b863991ull, 0x1733afda2bb3b0e8ull, 0xf34b37458bb86399ull, 0x8993478dbb8deae0ull, 0x06fbd6d5ebd3716bull, 0x7c23a61ddbe6f812ull, - 0x3373d23613f9d516ull, 0x49aba2fe23cc5c6full, 0xc6c333a67392c7e4ull, 0xbc1b436e43a74e9dull, 0x95ac9329ac4bc9b5ull, 0xef74e3e19c7e40ccull, - 0x601c72b9cc20db47ull, 0x1ac40271fc15523eull, 0x5594765a340a7f3aull, 0x2f4c0692043ff643ull, 0xa02497ca54616dc8ull, 0xdafce7026454e4b1ull, - 0x3e847f9dc45f37c0ull, 0x445c0f55f46abeb9ull, 0xcb349e0da4342532ull, 0xb1eceec59401ac4bull, 0xfebc9aee5c1e814full, 0x8464ea266c2b0836ull, - 0x0b0c7b7e3c7593bdull, 0x71d40bb60c401ac4ull, 0xe8a46c1224f5a634ull, 0x927c1cda14c02f4dull, 0x1d148d82449eb4c6ull, 0x67ccfd4a74ab3dbfull, - 0x289c8961bcb410bbull, 0x5244f9a98c8199c2ull, 0xdd2c68f1dcdf0249ull, 0xa7f41839ecea8b30ull, 0x438c80a64ce15841ull, 0x3954f06e7cd4d138ull, - 0xb63c61362c8a4ab3ull, 0xcce411fe1cbfc3caull, 0x83b465d5d4a0eeceull, 0xf96c151de49567b7ull, 0x76048445b4cbfc3cull, 0x0cdcf48d84fe7545ull, - 0x6fbd6d5ebd3716b7ull, 0x15651d968d029fceull, 0x9a0d8ccedd5c0445ull, 0xe0d5fc06ed698d3cull, 0xaf85882d2576a038ull, 0xd55df8e515432941ull, - 0x5a3569bd451db2caull, 0x20ed197575283bb3ull, 0xc49581ead523e8c2ull, 0xbe4df122e51661bbull, 0x3125607ab548fa30ull, 0x4bfd10b2857d7349ull, - 0x04ad64994d625e4dull, 0x7e7514517d57d734ull, 0xf11d85092d094cbfull, 0x8bc5f5c11d3cc5c6ull, 0x12b5926535897936ull, 0x686de2ad05bcf04full, - 0xe70573f555e26bc4ull, 0x9ddd033d65d7e2bdull, 0xd28d7716adc8cfb9ull, 0xa85507de9dfd46c0ull, 0x273d9686cda3dd4bull, 0x5de5e64efd965432ull, - 0xb99d7ed15d9d8743ull, 0xc3450e196da80e3aull, 0x4c2d9f413df695b1ull, 0x36f5ef890dc31cc8ull, 0x79a59ba2c5dc31ccull, 0x037deb6af5e9b8b5ull, - 0x8c157a32a5b7233eull, 0xf6cd0afa9582aa47ull, 0x4ad64994d625e4daull, 0x300e395ce6106da3ull, 0xbf66a804b64ef628ull, 0xc5bed8cc867b7f51ull, - 0x8aeeace74e645255ull, 0xf036dc2f7e51db2cull, 0x7f5e4d772e0f40a7ull, 0x05863dbf1e3ac9deull, 0xe1fea520be311aafull, 0x9b26d5e88e0493d6ull, - 0x144e44b0de5a085dull, 0x6e963478ee6f8124ull, 0x21c640532670ac20ull, 0x5b1e309b16452559ull, 0xd476a1c3461bbed2ull, 0xaeaed10b762e37abull, - 0x37deb6af5e9b8b5bull, 0x4d06c6676eae0222ull, 0xc26e573f3ef099a9ull, 0xb8b627f70ec510d0ull, 0xf7e653dcc6da3dd4ull, 0x8d3e2314f6efb4adull, - 0x0256b24ca6b12f26ull, 0x788ec2849684a65full, 0x9cf65a1b368f752eull, 0xe62e2ad306bafc57ull, 0x6946bb8b56e467dcull, 0x139ecb4366d1eea5ull, - 0x5ccebf68aecec3a1ull, 0x2616cfa09efb4ad8ull, 0xa97e5ef8cea5d153ull, 0xd3a62e30fe90582aull, 0xb0c7b7e3c7593bd8ull, 0xca1fc72bf76cb2a1ull, - 0x45775673a732292aull, 0x3faf26bb9707a053ull, 0x70ff52905f188d57ull, 0x0a2722586f2d042eull, 0x854fb3003f739fa5ull, 0xff97c3c80f4616dcull, - 0x1bef5b57af4dc5adull, 0x61372b9f9f784cd4ull, 0xee5fbac7cf26d75full, 0x9487ca0fff135e26ull, 0xdbd7be24370c7322ull, 0xa10fceec0739fa5bull, - 0x2e675fb4576761d0ull, 0x54bf2f7c6752e8a9ull, 0xcdcf48d84fe75459ull, 0xb71738107fd2dd20ull, 0x387fa9482f8c46abull, 0x42a7d9801fb9cfd2ull, - 0x0df7adabd7a6e2d6ull, 0x772fdd63e7936bafull, 0xf8474c3bb7cdf024ull, 0x829f3cf387f8795dull, 0x66e7a46c27f3aa2cull, 0x1c3fd4a417c62355ull, - 0x935745fc4798b8deull, 0xe98f353477ad31a7ull, 0xa6df411fbfb21ca3ull, 0xdc0731d78f8795daull, 0x536fa08fdfd90e51ull, 0x29b7d047efec8728ull, - }; - - zpl_u32 zpl_crc32(void const *data, zpl_isize len) { - zpl_isize remaining; - zpl_u32 result = ~(cast(zpl_u32) 0); - zpl_u8 const *c = cast(zpl_u8 const *) data; - for (remaining = len; remaining--; c++) result = (result >> 8) ^ (zpl__crc32_table[(result ^ *c) & 0xff]); - return ~result; - } - - zpl_u64 zpl_crc64(void const *data, zpl_isize len) { - zpl_isize remaining; - zpl_u64 result = (cast(zpl_u64)0); - zpl_u8 const *c = cast(zpl_u8 const *) data; - for (remaining = len; remaining--; c++) result = (result >> 8) ^ (zpl__crc64_table[(result ^ *c) & 0xff]); - return result; - } - - zpl_u32 zpl_fnv32(void const *data, zpl_isize len) { - zpl_isize i; - zpl_u32 h = 0x811c9dc5; - zpl_u8 const *c = cast(zpl_u8 const *) data; - - for (i = 0; i < len; i++) h = (h * 0x01000193) ^ c[i]; - - return h; - } - - zpl_u64 zpl_fnv64(void const *data, zpl_isize len) { - zpl_isize i; - zpl_u64 h = 0xcbf29ce484222325ull; - zpl_u8 const *c = cast(zpl_u8 const *) data; - - for (i = 0; i < len; i++) h = (h * 0x100000001b3ll) ^ c[i]; - - return h; - } - - zpl_u32 zpl_fnv32a(void const *data, zpl_isize len) { - zpl_isize i; - zpl_u32 h = 0x811c9dc5; - zpl_u8 const *c = cast(zpl_u8 const *) data; - - for (i = 0; i < len; i++) h = (h ^ c[i]) * 0x01000193; - - return h; - } - - zpl_u64 zpl_fnv64a(void const *data, zpl_isize len) { - zpl_isize i; - zpl_u64 h = 0xcbf29ce484222325ull; - zpl_u8 const *c = cast(zpl_u8 const *) data; - - for (i = 0; i < len; i++) h = (h ^ c[i]) * 0x100000001b3ll; - - return h; - } - - // base64 implementation based on https://nachtimwald.com/2017/11/18/base64-encode-and-decode-in-c/ - // - zpl_global zpl_u8 zpl__base64_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - - - /* generated table based on: */ - #if 0 - void zpl__base64_decode_table() { - zpl_i32 inv[80]; - zpl_isize i; - - zpl_memset(inv, -1, zpl_size_of(inv)); - - for (i=0; i < zpl_size_of(zpl__base64_chars)-1; i++) { - inv[zpl__base64_chars[i]-43] = i; - } - } - #endif - /* === */ - zpl_global zpl_i32 zpl__base64_dec_table[] = { - 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, - 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, - 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, - 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, - 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, - 43, 44, 45, 46, 47, 48, 49, 50, 51 }; - - zpl_isize zpl__base64_encoded_size(zpl_isize len) { - zpl_isize ret = len; - - if (len % 3 != 0) { - ret += 3 - (len % 3); - } - - ret /= 3; - ret *= 4; - - return ret; - } - - zpl_isize zpl__base64_decoded_size(void const *data) { - zpl_isize len, ret, i; - const zpl_u8 *s = cast(const zpl_u8 *)data; - - if (s == NULL) { - return 0; - } - - len = zpl_strlen(cast(const char*)s); - ret = len / 4 * 3; - - for (i=len; i-- > 0;) { - if (s[i] == '=') { - ret--; - } else { - break; - } - } - - return ret; - } - - zpl_b32 zpl__base64_valid_char(zpl_u8 c) { - if (c >= '0' && c <= '9') - return true; - if (c >= 'A' && c <= 'Z') - return true; - if (c >= 'a' && c <= 'z') - return true; - if (c == '+' || c == '/' || c == '=') - return true; - - return false; - } - - zpl_u8 *zpl_base64_encode(zpl_allocator a, void const *data, zpl_isize len) { - const zpl_u8 *s = cast(const zpl_u8*)data; - zpl_u8 *ret = NULL; - zpl_isize enc_len, i, j, v; - - if (data == NULL || len == 0) { - return NULL; - } - - enc_len = zpl__base64_encoded_size(len); - ret = cast(zpl_u8 *)zpl_alloc(a, enc_len+1); - ret[enc_len] = 0; - - for (i=0, j=0; i < len; i+=3, j+=4) { - v = s[i]; - v = (i+1 < len) ? (v << 8 | s[i+1]) : (v << 8); - v = (i+2 < len) ? (v << 8 | s[i+2]) : (v << 8); - - ret[j] = zpl__base64_chars[(v >> 18) & 0x3F]; - ret[j+1] = zpl__base64_chars[(v >> 12) & 0x3F]; - - if (i+1 < len) - ret[j+2] = zpl__base64_chars[(v >> 6) & 0x3F]; - - else ret[j+2] = '='; - - if (i+2 < len) - ret[j+3] = zpl__base64_chars[v & 0x3F]; - - else ret[j+3] = '='; - - } - - return ret; - } - - zpl_u8 *zpl_base64_decode(zpl_allocator a, void const *data, zpl_isize len) { - const zpl_u8 *s = cast(const zpl_u8*)data; - zpl_u8 *ret = NULL; - zpl_isize alen, i, j, v; - - if (data == NULL) { - return NULL; - } - - alen = zpl__base64_decoded_size(s); - ret = cast(zpl_u8 *)zpl_alloc(a, alen+1); - - ZPL_ASSERT_NOT_NULL(ret); - - ret[alen] = 0; - - for (i=0; i> 16) & 0xFF; - - if (s[i+2] != '=') - ret[j+1] = (v >> 8) & 0xFF; - - if (s[i+3] != '=') - ret[j+2] = v & 0xFF; - } - - return ret; - } - - zpl_u32 zpl_murmur32_seed(void const *data, zpl_isize len, zpl_u32 seed) { - zpl_u32 const c1 = 0xcc9e2d51; - zpl_u32 const c2 = 0x1b873593; - zpl_u32 const r1 = 15; - zpl_u32 const r2 = 13; - zpl_u32 const m = 5; - zpl_u32 const n = 0xe6546b64; - - zpl_isize i, nblocks = len / 4; - zpl_u32 hash = seed, k1 = 0; - zpl_u32 const *blocks = cast(zpl_u32 const *) data; - zpl_u8 const *tail = cast(zpl_u8 const *)(data) + nblocks * 4; - - for (i = 0; i < nblocks; i++) { - zpl_u32 k = blocks[i]; - k *= c1; - k = (k << r1) | (k >> (32 - r1)); - k *= c2; - - hash ^= k; - hash = ((hash << r2) | (hash >> (32 - r2))) * m + n; - } - - switch (len & 3) { - case 3: k1 ^= tail[2] << 16; - case 2: k1 ^= tail[1] << 8; - case 1: - k1 ^= tail[0]; - - k1 *= c1; - k1 = (k1 << r1) | (k1 >> (32 - r1)); - k1 *= c2; - hash ^= k1; - } - - hash ^= len; - hash ^= (hash >> 16); - hash *= 0x85ebca6b; - hash ^= (hash >> 13); - hash *= 0xc2b2ae35; - hash ^= (hash >> 16); - - return hash; - } - - zpl_u64 zpl_murmur64_seed(void const *data_, zpl_isize len, zpl_u64 seed) { - zpl_u64 const m = 0xc6a4a7935bd1e995ULL; - zpl_i32 const r = 47; - - zpl_u64 h = seed ^ (len * m); - - zpl_u64 const *data = cast(zpl_u64 const *) data_; - zpl_u8 const *data2 = cast(zpl_u8 const *) data_; - zpl_u64 const *end = data + (len / 8); - - while (data != end) { - zpl_u64 k = *data++; - - k *= m; - k ^= k >> r; - k *= m; - - h ^= k; - h *= m; - } - - switch (len & 7) { - case 7: h ^= cast(zpl_u64)(data2[6]) << 48; - case 6: h ^= cast(zpl_u64)(data2[5]) << 40; - case 5: h ^= cast(zpl_u64)(data2[4]) << 32; - case 4: h ^= cast(zpl_u64)(data2[3]) << 24; - case 3: h ^= cast(zpl_u64)(data2[2]) << 16; - case 2: h ^= cast(zpl_u64)(data2[1]) << 8; - case 1: h ^= cast(zpl_u64)(data2[0]); - h *= m; - }; - - h ^= h >> r; - h *= m; - h ^= h >> r; - - return h; - } - - ZPL_END_C_DECLS +// file: source/hashing.c + +//////////////////////////////////////////////////////////////// +// +// Hashing functions +// +// + +ZPL_BEGIN_C_DECLS + +zpl_u32 zpl_adler32(void const *data, zpl_isize len) { + zpl_u32 const MOD_ALDER = 65521; + zpl_u32 a = 1, b = 0; + zpl_isize i, block_len; + zpl_u8 const *bytes = cast(zpl_u8 const *) data; + + block_len = len % 5552; + + while (len) { + for (i = 0; i + 7 < block_len; i += 8) { + a += bytes[0], b += a; + a += bytes[1], b += a; + a += bytes[2], b += a; + a += bytes[3], b += a; + a += bytes[4], b += a; + a += bytes[5], b += a; + a += bytes[6], b += a; + a += bytes[7], b += a; + + bytes += 8; + } + for (; i < block_len; i++) a += *bytes++, b += a; + + a %= MOD_ALDER, b %= MOD_ALDER; + len -= block_len; + block_len = 5552; + } + + return (b << 16) | a; +} + +zpl_global zpl_u32 const zpl__crc32_table[256] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, + 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, + 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, + 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, + 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, + 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, + 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, + 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, + 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, + 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, + 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, + 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, + 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, + 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, + 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, +}; + +zpl_global zpl_u64 const zpl__crc64_table[256] = { + 0x0000000000000000ull, 0x7ad870c830358979ull, 0xf5b0e190606b12f2ull, 0x8f689158505e9b8bull, 0xc038e5739841b68full, 0xbae095bba8743ff6ull, + 0x358804e3f82aa47dull, 0x4f50742bc81f2d04ull, 0xab28ecb46814fe75ull, 0xd1f09c7c5821770cull, 0x5e980d24087fec87ull, 0x24407dec384a65feull, + 0x6b1009c7f05548faull, 0x11c8790fc060c183ull, 0x9ea0e857903e5a08ull, 0xe478989fa00bd371ull, 0x7d08ff3b88be6f81ull, 0x07d08ff3b88be6f8ull, + 0x88b81eabe8d57d73ull, 0xf2606e63d8e0f40aull, 0xbd301a4810ffd90eull, 0xc7e86a8020ca5077ull, 0x4880fbd87094cbfcull, 0x32588b1040a14285ull, + 0xd620138fe0aa91f4ull, 0xacf86347d09f188dull, 0x2390f21f80c18306ull, 0x594882d7b0f40a7full, 0x1618f6fc78eb277bull, 0x6cc0863448deae02ull, + 0xe3a8176c18803589ull, 0x997067a428b5bcf0ull, 0xfa11fe77117cdf02ull, 0x80c98ebf2149567bull, + 0x0fa11fe77117cdf0ull, 0x75796f2f41224489ull, 0x3a291b04893d698dull, 0x40f16bccb908e0f4ull, 0xcf99fa94e9567b7full, 0xb5418a5cd963f206ull, + 0x513912c379682177ull, 0x2be1620b495da80eull, 0xa489f35319033385ull, 0xde51839b2936bafcull, 0x9101f7b0e12997f8ull, 0xebd98778d11c1e81ull, + 0x64b116208142850aull, 0x1e6966e8b1770c73ull, 0x8719014c99c2b083ull, 0xfdc17184a9f739faull, 0x72a9e0dcf9a9a271ull, 0x08719014c99c2b08ull, + 0x4721e43f0183060cull, 0x3df994f731b68f75ull, 0xb29105af61e814feull, 0xc849756751dd9d87ull, 0x2c31edf8f1d64ef6ull, 0x56e99d30c1e3c78full, + 0xd9810c6891bd5c04ull, 0xa3597ca0a188d57dull, 0xec09088b6997f879ull, 0x96d1784359a27100ull, 0x19b9e91b09fcea8bull, 0x636199d339c963f2ull, + 0xdf7adabd7a6e2d6full, 0xa5a2aa754a5ba416ull, 0x2aca3b2d1a053f9dull, 0x50124be52a30b6e4ull, 0x1f423fcee22f9be0ull, 0x659a4f06d21a1299ull, + 0xeaf2de5e82448912ull, 0x902aae96b271006bull, 0x74523609127ad31aull, 0x0e8a46c1224f5a63ull, 0x81e2d7997211c1e8ull, 0xfb3aa75142244891ull, + 0xb46ad37a8a3b6595ull, 0xceb2a3b2ba0eececull, 0x41da32eaea507767ull, 0x3b024222da65fe1eull, 0xa2722586f2d042eeull, 0xd8aa554ec2e5cb97ull, + 0x57c2c41692bb501cull, 0x2d1ab4dea28ed965ull, 0x624ac0f56a91f461ull, 0x1892b03d5aa47d18ull, 0x97fa21650afae693ull, 0xed2251ad3acf6feaull, + 0x095ac9329ac4bc9bull, 0x7382b9faaaf135e2ull, 0xfcea28a2faafae69ull, 0x8632586aca9a2710ull, 0xc9622c4102850a14ull, 0xb3ba5c8932b0836dull, + 0x3cd2cdd162ee18e6ull, 0x460abd1952db919full, 0x256b24ca6b12f26dull, 0x5fb354025b277b14ull, 0xd0dbc55a0b79e09full, 0xaa03b5923b4c69e6ull, + 0xe553c1b9f35344e2ull, 0x9f8bb171c366cd9bull, 0x10e3202993385610ull, 0x6a3b50e1a30ddf69ull, 0x8e43c87e03060c18ull, 0xf49bb8b633338561ull, + 0x7bf329ee636d1eeaull, 0x012b592653589793ull, 0x4e7b2d0d9b47ba97ull, 0x34a35dc5ab7233eeull, 0xbbcbcc9dfb2ca865ull, 0xc113bc55cb19211cull, + 0x5863dbf1e3ac9decull, 0x22bbab39d3991495ull, 0xadd33a6183c78f1eull, 0xd70b4aa9b3f20667ull, 0x985b3e827bed2b63ull, 0xe2834e4a4bd8a21aull, + 0x6debdf121b863991ull, 0x1733afda2bb3b0e8ull, 0xf34b37458bb86399ull, 0x8993478dbb8deae0ull, 0x06fbd6d5ebd3716bull, 0x7c23a61ddbe6f812ull, + 0x3373d23613f9d516ull, 0x49aba2fe23cc5c6full, 0xc6c333a67392c7e4ull, 0xbc1b436e43a74e9dull, 0x95ac9329ac4bc9b5ull, 0xef74e3e19c7e40ccull, + 0x601c72b9cc20db47ull, 0x1ac40271fc15523eull, 0x5594765a340a7f3aull, 0x2f4c0692043ff643ull, 0xa02497ca54616dc8ull, 0xdafce7026454e4b1ull, + 0x3e847f9dc45f37c0ull, 0x445c0f55f46abeb9ull, 0xcb349e0da4342532ull, 0xb1eceec59401ac4bull, 0xfebc9aee5c1e814full, 0x8464ea266c2b0836ull, + 0x0b0c7b7e3c7593bdull, 0x71d40bb60c401ac4ull, 0xe8a46c1224f5a634ull, 0x927c1cda14c02f4dull, 0x1d148d82449eb4c6ull, 0x67ccfd4a74ab3dbfull, + 0x289c8961bcb410bbull, 0x5244f9a98c8199c2ull, 0xdd2c68f1dcdf0249ull, 0xa7f41839ecea8b30ull, 0x438c80a64ce15841ull, 0x3954f06e7cd4d138ull, + 0xb63c61362c8a4ab3ull, 0xcce411fe1cbfc3caull, 0x83b465d5d4a0eeceull, 0xf96c151de49567b7ull, 0x76048445b4cbfc3cull, 0x0cdcf48d84fe7545ull, + 0x6fbd6d5ebd3716b7ull, 0x15651d968d029fceull, 0x9a0d8ccedd5c0445ull, 0xe0d5fc06ed698d3cull, 0xaf85882d2576a038ull, 0xd55df8e515432941ull, + 0x5a3569bd451db2caull, 0x20ed197575283bb3ull, 0xc49581ead523e8c2ull, 0xbe4df122e51661bbull, 0x3125607ab548fa30ull, 0x4bfd10b2857d7349ull, + 0x04ad64994d625e4dull, 0x7e7514517d57d734ull, 0xf11d85092d094cbfull, 0x8bc5f5c11d3cc5c6ull, 0x12b5926535897936ull, 0x686de2ad05bcf04full, + 0xe70573f555e26bc4ull, 0x9ddd033d65d7e2bdull, 0xd28d7716adc8cfb9ull, 0xa85507de9dfd46c0ull, 0x273d9686cda3dd4bull, 0x5de5e64efd965432ull, + 0xb99d7ed15d9d8743ull, 0xc3450e196da80e3aull, 0x4c2d9f413df695b1ull, 0x36f5ef890dc31cc8ull, 0x79a59ba2c5dc31ccull, 0x037deb6af5e9b8b5ull, + 0x8c157a32a5b7233eull, 0xf6cd0afa9582aa47ull, 0x4ad64994d625e4daull, 0x300e395ce6106da3ull, 0xbf66a804b64ef628ull, 0xc5bed8cc867b7f51ull, + 0x8aeeace74e645255ull, 0xf036dc2f7e51db2cull, 0x7f5e4d772e0f40a7ull, 0x05863dbf1e3ac9deull, 0xe1fea520be311aafull, 0x9b26d5e88e0493d6ull, + 0x144e44b0de5a085dull, 0x6e963478ee6f8124ull, 0x21c640532670ac20ull, 0x5b1e309b16452559ull, 0xd476a1c3461bbed2ull, 0xaeaed10b762e37abull, + 0x37deb6af5e9b8b5bull, 0x4d06c6676eae0222ull, 0xc26e573f3ef099a9ull, 0xb8b627f70ec510d0ull, 0xf7e653dcc6da3dd4ull, 0x8d3e2314f6efb4adull, + 0x0256b24ca6b12f26ull, 0x788ec2849684a65full, 0x9cf65a1b368f752eull, 0xe62e2ad306bafc57ull, 0x6946bb8b56e467dcull, 0x139ecb4366d1eea5ull, + 0x5ccebf68aecec3a1ull, 0x2616cfa09efb4ad8ull, 0xa97e5ef8cea5d153ull, 0xd3a62e30fe90582aull, 0xb0c7b7e3c7593bd8ull, 0xca1fc72bf76cb2a1ull, + 0x45775673a732292aull, 0x3faf26bb9707a053ull, 0x70ff52905f188d57ull, 0x0a2722586f2d042eull, 0x854fb3003f739fa5ull, 0xff97c3c80f4616dcull, + 0x1bef5b57af4dc5adull, 0x61372b9f9f784cd4ull, 0xee5fbac7cf26d75full, 0x9487ca0fff135e26ull, 0xdbd7be24370c7322ull, 0xa10fceec0739fa5bull, + 0x2e675fb4576761d0ull, 0x54bf2f7c6752e8a9ull, 0xcdcf48d84fe75459ull, 0xb71738107fd2dd20ull, 0x387fa9482f8c46abull, 0x42a7d9801fb9cfd2ull, + 0x0df7adabd7a6e2d6ull, 0x772fdd63e7936bafull, 0xf8474c3bb7cdf024ull, 0x829f3cf387f8795dull, 0x66e7a46c27f3aa2cull, 0x1c3fd4a417c62355ull, + 0x935745fc4798b8deull, 0xe98f353477ad31a7ull, 0xa6df411fbfb21ca3ull, 0xdc0731d78f8795daull, 0x536fa08fdfd90e51ull, 0x29b7d047efec8728ull, +}; + +zpl_u32 zpl_crc32(void const *data, zpl_isize len) { + zpl_isize remaining; + zpl_u32 result = ~(cast(zpl_u32) 0); + zpl_u8 const *c = cast(zpl_u8 const *) data; + for (remaining = len; remaining--; c++) result = (result >> 8) ^ (zpl__crc32_table[(result ^ *c) & 0xff]); + return ~result; +} + +zpl_u64 zpl_crc64(void const *data, zpl_isize len) { + zpl_isize remaining; + zpl_u64 result = (cast(zpl_u64)0); + zpl_u8 const *c = cast(zpl_u8 const *) data; + for (remaining = len; remaining--; c++) result = (result >> 8) ^ (zpl__crc64_table[(result ^ *c) & 0xff]); + return result; +} + +zpl_u32 zpl_fnv32(void const *data, zpl_isize len) { + zpl_isize i; + zpl_u32 h = 0x811c9dc5; + zpl_u8 const *c = cast(zpl_u8 const *) data; + + for (i = 0; i < len; i++) h = (h * 0x01000193) ^ c[i]; + + return h; +} + +zpl_u64 zpl_fnv64(void const *data, zpl_isize len) { + zpl_isize i; + zpl_u64 h = 0xcbf29ce484222325ull; + zpl_u8 const *c = cast(zpl_u8 const *) data; + + for (i = 0; i < len; i++) h = (h * 0x100000001b3ll) ^ c[i]; + + return h; +} + +zpl_u32 zpl_fnv32a(void const *data, zpl_isize len) { + zpl_isize i; + zpl_u32 h = 0x811c9dc5; + zpl_u8 const *c = cast(zpl_u8 const *) data; + + for (i = 0; i < len; i++) h = (h ^ c[i]) * 0x01000193; + + return h; +} + +zpl_u64 zpl_fnv64a(void const *data, zpl_isize len) { + zpl_isize i; + zpl_u64 h = 0xcbf29ce484222325ull; + zpl_u8 const *c = cast(zpl_u8 const *) data; + + for (i = 0; i < len; i++) h = (h ^ c[i]) * 0x100000001b3ll; + + return h; +} + +// base64 implementation based on https://nachtimwald.com/2017/11/18/base64-encode-and-decode-in-c/ +// +zpl_global zpl_u8 zpl__base64_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + +/* generated table based on: */ +#if 0 +void zpl__base64_decode_table() { + zpl_i32 inv[80]; + zpl_isize i; + + zpl_memset(inv, -1, zpl_size_of(inv)); + + for (i=0; i < zpl_size_of(zpl__base64_chars)-1; i++) { + inv[zpl__base64_chars[i]-43] = i; + } +} +#endif +/* === */ +zpl_global zpl_i32 zpl__base64_dec_table[] = { + 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51 }; + +zpl_isize zpl__base64_encoded_size(zpl_isize len) { + zpl_isize ret = len; + + if (len % 3 != 0) { + ret += 3 - (len % 3); + } + + ret /= 3; + ret *= 4; + + return ret; +} + +zpl_isize zpl__base64_decoded_size(void const *data) { + zpl_isize len, ret, i; + const zpl_u8 *s = cast(const zpl_u8 *)data; + + if (s == NULL) { + return 0; + } + + len = zpl_strlen(cast(const char*)s); + ret = len / 4 * 3; + + for (i=len; i-- > 0;) { + if (s[i] == '=') { + ret--; + } else { + break; + } + } + + return ret; +} + +zpl_b32 zpl__base64_valid_char(zpl_u8 c) { + if (c >= '0' && c <= '9') + return true; + if (c >= 'A' && c <= 'Z') + return true; + if (c >= 'a' && c <= 'z') + return true; + if (c == '+' || c == '/' || c == '=') + return true; + + return false; +} + +zpl_u8 *zpl_base64_encode(zpl_allocator a, void const *data, zpl_isize len) { + const zpl_u8 *s = cast(const zpl_u8*)data; + zpl_u8 *ret = NULL; + zpl_isize enc_len, i, j, v; + + if (data == NULL || len == 0) { + return NULL; + } + + enc_len = zpl__base64_encoded_size(len); + ret = cast(zpl_u8 *)zpl_alloc(a, enc_len+1); + ret[enc_len] = 0; + + for (i=0, j=0; i < len; i+=3, j+=4) { + v = s[i]; + v = (i+1 < len) ? (v << 8 | s[i+1]) : (v << 8); + v = (i+2 < len) ? (v << 8 | s[i+2]) : (v << 8); + + ret[j] = zpl__base64_chars[(v >> 18) & 0x3F]; + ret[j+1] = zpl__base64_chars[(v >> 12) & 0x3F]; + + if (i+1 < len) + ret[j+2] = zpl__base64_chars[(v >> 6) & 0x3F]; + + else ret[j+2] = '='; + + if (i+2 < len) + ret[j+3] = zpl__base64_chars[v & 0x3F]; + + else ret[j+3] = '='; + + } + + return ret; +} + +zpl_u8 *zpl_base64_decode(zpl_allocator a, void const *data, zpl_isize len) { + const zpl_u8 *s = cast(const zpl_u8*)data; + zpl_u8 *ret = NULL; + zpl_isize alen, i, j, v; + + if (data == NULL) { + return NULL; + } + + alen = zpl__base64_decoded_size(s); + ret = cast(zpl_u8 *)zpl_alloc(a, alen+1); + + ZPL_ASSERT_NOT_NULL(ret); + + ret[alen] = 0; + + for (i=0; i> 16) & 0xFF; + + if (s[i+2] != '=') + ret[j+1] = (v >> 8) & 0xFF; + + if (s[i+3] != '=') + ret[j+2] = v & 0xFF; + } + + return ret; +} + +zpl_u32 zpl_murmur32_seed(void const *data, zpl_isize len, zpl_u32 seed) { + zpl_u32 const c1 = 0xcc9e2d51; + zpl_u32 const c2 = 0x1b873593; + zpl_u32 const r1 = 15; + zpl_u32 const r2 = 13; + zpl_u32 const m = 5; + zpl_u32 const n = 0xe6546b64; + + zpl_isize i, nblocks = len / 4; + zpl_u32 hash = seed, k1 = 0; + zpl_u32 const *blocks = cast(zpl_u32 const *) data; + zpl_u8 const *tail = cast(zpl_u8 const *)(data) + nblocks * 4; + + for (i = 0; i < nblocks; i++) { + zpl_u32 k = blocks[i]; + k *= c1; + k = (k << r1) | (k >> (32 - r1)); + k *= c2; + + hash ^= k; + hash = ((hash << r2) | (hash >> (32 - r2))) * m + n; + } + + switch (len & 3) { + case 3: k1 ^= tail[2] << 16; + case 2: k1 ^= tail[1] << 8; + case 1: + k1 ^= tail[0]; + + k1 *= c1; + k1 = (k1 << r1) | (k1 >> (32 - r1)); + k1 *= c2; + hash ^= k1; + } + + hash ^= len; + hash ^= (hash >> 16); + hash *= 0x85ebca6b; + hash ^= (hash >> 13); + hash *= 0xc2b2ae35; + hash ^= (hash >> 16); + + return hash; +} + +zpl_u64 zpl_murmur64_seed(void const *data_, zpl_isize len, zpl_u64 seed) { + zpl_u64 const m = 0xc6a4a7935bd1e995ULL; + zpl_i32 const r = 47; + + zpl_u64 h = seed ^ (len * m); + + zpl_u64 const *data = cast(zpl_u64 const *) data_; + zpl_u8 const *data2 = cast(zpl_u8 const *) data_; + zpl_u64 const *end = data + (len / 8); + + while (data != end) { + zpl_u64 k = *data++; + + k *= m; + k ^= k >> r; + k *= m; + + h ^= k; + h *= m; + } + + switch (len & 7) { + case 7: h ^= cast(zpl_u64)(data2[6]) << 48; + case 6: h ^= cast(zpl_u64)(data2[5]) << 40; + case 5: h ^= cast(zpl_u64)(data2[4]) << 32; + case 4: h ^= cast(zpl_u64)(data2[3]) << 24; + case 3: h ^= cast(zpl_u64)(data2[2]) << 16; + case 2: h ^= cast(zpl_u64)(data2[1]) << 8; + case 1: h ^= cast(zpl_u64)(data2[0]); + h *= m; + }; + + h ^= h >> r; + h *= m; + h ^= h >> r; + + return h; +} + +ZPL_END_C_DECLS #endif #if defined(ZPL_MODULE_REGEX) - // file: source/regex.c - - - ZPL_BEGIN_C_DECLS - - typedef enum zplreOp { - ZPL_RE_OP_BEGIN_CAPTURE, - ZPL_RE_OP_END_CAPTURE, - - ZPL_RE_OP_BEGINNING_OF_LINE, - ZPL_RE_OP_END_OF_LINE, - - ZPL_RE_OP_EXACT_MATCH, - ZPL_RE_OP_META_MATCH, - - ZPL_RE_OP_ANY, - ZPL_RE_OP_ANY_OF, - ZPL_RE_OP_ANY_BUT, - - ZPL_RE_OP_ZERO_OR_MORE, - ZPL_RE_OP_ONE_OR_MORE, - ZPL_RE_OP_ZERO_OR_MORE_SHORTEST, - ZPL_RE_OP_ONE_OR_MORE_SHORTEST, - ZPL_RE_OP_ZERO_OR_ONE, - - ZPL_RE_OP_BRANCH_START, - ZPL_RE_OP_BRANCH_END - } zplreOp; - - typedef enum zplreCode { - ZPL_RE_CODE_NULL = 0x0000, - ZPL_RE_CODE_WHITESPACE = 0x0100, - ZPL_RE_CODE_NOT_WHITESPACE = 0x0200, - ZPL_RE_CODE_DIGIT = 0x0300, - ZPL_RE_CODE_NOT_DIGIT = 0x0400, - ZPL_RE_CODE_ALPHA = 0x0500, - ZPL_RE_CODE_LOWER = 0x0600, - ZPL_RE_CODE_UPPER = 0x0700, - ZPL_RE_CODE_WORD = 0x0800, - ZPL_RE_CODE_NOT_WORD = 0x0900, - - ZPL_RE_CODE_XDIGIT = 0x0a00, - ZPL_RE_CODE_PRINTABLE = 0x0b00, - } zplreCode; - - typedef struct { - zpl_isize op, offset; - } zpl_re_ctx; - - enum { - ZPL_RE__NO_MATCH = -1, - ZPL_RE__INTERNAL_FAILURE = -2, - }; - - static char const ZPL_RE__META_CHARS[] = "^$()[].*+?|\\"; - static char const ZPL_RE__WHITESPACE[] = " \r\t\n\v\f"; - #define ZPL_RE__LITERAL(str) (str), zpl_size_of(str)-1 - - static zpl_re_ctx zpl_re__exec_single(zpl_re *re, zpl_isize op, char const *str, zpl_isize str_len, zpl_isize offset, zpl_re_capture *captures, zpl_isize max_capture_count); - static zpl_re_ctx zpl_re__exec(zpl_re *re, zpl_isize op, char const *str, zpl_isize str_len, zpl_isize offset, zpl_re_capture *captures, zpl_isize max_capture_count); - - static zpl_re_ctx zpl_re__ctx_no_match(zpl_isize op) { - zpl_re_ctx c; - c.op = op; - c.offset = ZPL_RE__NO_MATCH; - return c; - } - - static zpl_re_ctx zpl_re__ctx_internal_failure(zpl_isize op) { - zpl_re_ctx c; - c.op = op; - c.offset = ZPL_RE__INTERNAL_FAILURE; - return c; - } - - static zpl_u8 zpl_re__hex(char const *s) { - return ((zpl_char_to_hex_digit(*s) << 4) & 0xf0) | (zpl_char_to_hex_digit(*(s+1)) & 0x0f); - } - - static zpl_isize zpl_re__strfind(char const *s, zpl_isize len, char c, zpl_isize offset) { - if (offset < len) { - char const *found = (char const *)zpl_memchr(s+offset, c, len-offset); - if (found) - return found - s; - } - - return -1; - } - - static zpl_b32 zpl_re__match_escape(char c, int code) { - switch (code) { - case ZPL_RE_CODE_NULL: return c == 0; - case ZPL_RE_CODE_WHITESPACE: return zpl_re__strfind(ZPL_RE__LITERAL(ZPL_RE__WHITESPACE), c, 0) >= 0; - case ZPL_RE_CODE_NOT_WHITESPACE: return zpl_re__strfind(ZPL_RE__LITERAL(ZPL_RE__WHITESPACE), c, 0) < 0; - case ZPL_RE_CODE_DIGIT: return (c >= '0' && c <= '9'); - case ZPL_RE_CODE_NOT_DIGIT: return !(c >= '0' && c <= '9'); - case ZPL_RE_CODE_ALPHA: return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); - case ZPL_RE_CODE_LOWER: return (c >= 'a' && c <= 'z'); - case ZPL_RE_CODE_UPPER: return (c >= 'A' && c <= 'Z'); - - /* TODO(bill): Make better? */ - case ZPL_RE_CODE_WORD: return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_'; - case ZPL_RE_CODE_NOT_WORD: return !((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_'); - - /* TODO(bill): Maybe replace with between tests? */ - case ZPL_RE_CODE_XDIGIT: return zpl_re__strfind(ZPL_RE__LITERAL("0123456789ABCDEFabcdef"), c, 0) >= 0; - case ZPL_RE_CODE_PRINTABLE: return c >= 0x20 && c <= 0x7e; - default: break; - } - - return 0; - } - - static zpl_re_ctx zpl_re__consume(zpl_re *re, zpl_isize op, char const *str, zpl_isize str_len, zpl_isize offset, zpl_re_capture *captures, zpl_isize max_capture_count, zpl_b32 is_greedy) - { - zpl_re_ctx c, best_c, next_c; - - c.op = op; - c.offset = offset; - - best_c.op = ZPL_RE__NO_MATCH; - best_c.offset = offset; - - for (;;) { - c = zpl_re__exec_single(re, op, str, str_len, c.offset, 0, 0); - if (c.offset > str_len || c.offset == -1) break; - if (c.op >= re->buf_len) return c; - - next_c = zpl_re__exec(re, c.op, str, str_len, c.offset, captures, max_capture_count); - if (next_c.offset <= str_len) { - if (captures) - zpl_re__exec(re, c.op, str, str_len, c.offset, captures, max_capture_count); - - best_c = next_c; - if (!is_greedy) break; - } - - if (best_c.op > re->buf_len) - best_c.op = c.op; - - } - - return best_c; - } - - static zpl_re_ctx zpl_re__exec_single(zpl_re *re, zpl_isize op, char const *str, zpl_isize str_len, zpl_isize offset, zpl_re_capture *captures, zpl_isize max_capture_count) { - zpl_re_ctx ctx; - zpl_isize buffer_len; - zpl_isize match_len; - zpl_isize next_op; - zpl_isize skip; - - switch (re->buf[op++]) { - case ZPL_RE_OP_BEGIN_CAPTURE: { - zpl_u8 capture = re->buf[op++]; - if (captures && (capture < max_capture_count)) - captures[capture].str = str + offset; - } break; - - case ZPL_RE_OP_END_CAPTURE: { - zpl_u8 capture = re->buf[op++]; - if (captures && (capture < max_capture_count)) - captures[capture].len = (str + offset) - captures[capture].str; - } break; - - case ZPL_RE_OP_BEGINNING_OF_LINE: { - if (offset != 0) - return zpl_re__ctx_no_match(op); - } break; - - case ZPL_RE_OP_END_OF_LINE: { - if (offset != str_len) - return zpl_re__ctx_no_match(op); - } break; - - case ZPL_RE_OP_BRANCH_START: { - skip = re->buf[op++]; - ctx = zpl_re__exec(re, op, str, str_len, offset, captures, max_capture_count); - if (ctx.offset <= str_len) { - offset = ctx.offset; - op = ctx.op; - } else { - ctx = zpl_re__exec(re, op + skip, str, str_len, offset, captures, max_capture_count); - offset = ctx.offset; - op = ctx.op; - } - } break; - - case ZPL_RE_OP_BRANCH_END: { - skip = re->buf[op++]; - op += skip; - } break; - - case ZPL_RE_OP_ANY: { - if (offset < str_len) { - offset++; - break; - } - return zpl_re__ctx_no_match(op); - } break; - - case ZPL_RE_OP_ANY_OF: { - zpl_isize i; - char cin = str[offset]; - buffer_len = re->buf[op++]; - - if (offset >= str_len) - return zpl_re__ctx_no_match(op + buffer_len); - - for (i = 0; i < buffer_len; i++) { - char cmatch = (char)re->buf[op+i]; - if (!cmatch) { - i++; - if (zpl_re__match_escape(cin, re->buf[op+i] << 8)) - break; - } else if (cin == cmatch) { - break; - } - } - - if (i == buffer_len) - return zpl_re__ctx_no_match(op + buffer_len); - - offset++; - op += buffer_len; - } break; - - case ZPL_RE_OP_ANY_BUT: { - zpl_isize i; - char cin = str[offset]; - buffer_len = re->buf[op++]; - - if (offset >= str_len) - return zpl_re__ctx_no_match(op + buffer_len); - - for (i = 0; i < buffer_len; i++) { - char cmatch = (char)re->buf[op + i]; - if (!cmatch) { - i++; - if (zpl_re__match_escape(cin, re->buf[op+i] << 8)) - return zpl_re__ctx_no_match(op + buffer_len); - } else if (cin == cmatch) { - return zpl_re__ctx_no_match(op + buffer_len); - } - } - - offset++; - op += buffer_len; - } break; - - case ZPL_RE_OP_EXACT_MATCH: { - match_len = re->buf[op++]; - - if ((match_len > (str_len - offset)) || - zpl_strncmp(str+offset, (const char*)re->buf + op, match_len) != 0) - return zpl_re__ctx_no_match(op + match_len); - - op += match_len; - offset += match_len; - } break; - - case ZPL_RE_OP_META_MATCH: { - char cin = (char)re->buf[op++]; - char cmatch = str[offset++]; - - if (!cin) { - if (zpl_re__match_escape(cmatch, re->buf[op++] << 8)) - break; - } - else if (cin == cmatch) break; - - return zpl_re__ctx_no_match(op); - } break; - - case ZPL_RE_OP_ZERO_OR_MORE: { - ctx = zpl_re__consume(re, op, str, str_len, offset, captures, max_capture_count, 1); - offset = ctx.offset; - op = ctx.op; - } break; - - case ZPL_RE_OP_ONE_OR_MORE: { - ctx = zpl_re__exec_single(re, op, str, str_len, offset, captures, max_capture_count); - - if (ctx.offset > str_len) - return ctx; - - ctx = zpl_re__consume(re, op, str, str_len, offset, captures, max_capture_count, 1); - offset = ctx.offset; - op = ctx.op; - } break; - - case ZPL_RE_OP_ZERO_OR_MORE_SHORTEST: { - ctx = zpl_re__consume(re, op, str, str_len, offset, captures, max_capture_count, 0); - offset = ctx.offset; - op = ctx.op; - } break; - - case ZPL_RE_OP_ONE_OR_MORE_SHORTEST: { - ctx = zpl_re__exec_single(re, op, str, str_len, offset, captures, max_capture_count); - - if (ctx.offset > str_len) - return ctx; - - ctx = zpl_re__consume(re, op, str, str_len, offset, captures, max_capture_count, 0); - offset = ctx.offset; - op = ctx.op; - } break; - - case ZPL_RE_OP_ZERO_OR_ONE: { - ctx = zpl_re__exec_single(re, op, str, str_len, offset, captures, max_capture_count); - - if (ctx.offset <= str_len) { - zpl_re_ctx possible_ctx = zpl_re__exec(re, ctx.op, str, str_len, ctx.offset, captures, max_capture_count); - - if (possible_ctx.offset <= str_len) { - op = possible_ctx.op; - offset = possible_ctx.offset; - break; - } - } - - next_op = ctx.op; - ctx = zpl_re__exec(re, next_op, str, str_len, offset, captures, max_capture_count); - - if (ctx.offset <= str_len) { - op = ctx.op; - offset = ctx.offset; - break; - } - return zpl_re__ctx_no_match(op); - } break; - - default: { - return zpl_re__ctx_internal_failure(op); - } break; - } - - ctx.op = op; - ctx.offset = offset; - - return ctx; - } - - static zpl_re_ctx zpl_re__exec(zpl_re *re, zpl_isize op, char const *str, zpl_isize str_len, zpl_isize offset, zpl_re_capture *captures, zpl_isize max_capture_count) { - zpl_re_ctx c; - c.op = op; - c.offset = offset; - - while (c.op < re->buf_len) { - c = zpl_re__exec_single(re, c.op, str, str_len, c.offset, captures, max_capture_count); - - if (c.offset > str_len || c.offset == -1) - break; - } - - return c; - } - - static zpl_regex_error zpl_re__emit_ops(zpl_re *re, zpl_isize op_count, ...) { - va_list va; - - if (re->buf_len + op_count > re->buf_cap) { - if (!re->can_realloc) { - return ZPL_RE_ERROR_TOO_LONG; - } - else { - zpl_isize new_cap = (re->buf_cap*2) + op_count; - re->buf = (char *)zpl_resize(re->backing, re->buf, re->buf_cap, new_cap); - re->buf_cap = new_cap; - } - } - - va_start(va, op_count); - for (zpl_isize i = 0; i < op_count; i++) - { - zpl_i32 v = va_arg(va, zpl_i32); - if (v > 256) - return ZPL_RE_ERROR_TOO_LONG; - re->buf[re->buf_len++] = (char)v; - } - va_end(va); - - return ZPL_RE_ERROR_NONE; - } - - static zpl_regex_error zpl_re__emit_ops_buffer(zpl_re *re, zpl_isize op_count, char const *buffer) { - if (re->buf_len + op_count > re->buf_cap) { - if (!re->can_realloc) { - return ZPL_RE_ERROR_TOO_LONG; - } - else { - zpl_isize new_cap = (re->buf_cap*2) + op_count; - re->buf = (char *)zpl_resize(re->backing, re->buf, re->buf_cap, new_cap); - re->buf_cap = new_cap; - } - } - - for (zpl_isize i = 0; i < op_count; i++) - { - re->buf[re->buf_len++] = buffer[i]; - } - - return ZPL_RE_ERROR_NONE; - } - - static int zpl_re__encode_escape(char code) { - switch (code) { - default: break; /* NOTE(bill): It's a normal character */ - - /* TODO(bill): Are there anymore? */ - case 't': return '\t'; - case 'n': return '\n'; - case 'r': return '\r'; - case 'f': return '\f'; - case 'v': return '\v'; - - case '0': return ZPL_RE_CODE_NULL; - - case 's': return ZPL_RE_CODE_WHITESPACE; - case 'S': return ZPL_RE_CODE_NOT_WHITESPACE; - - case 'd': return ZPL_RE_CODE_DIGIT; - case 'D': return ZPL_RE_CODE_NOT_DIGIT; - - case 'a': return ZPL_RE_CODE_ALPHA; - case 'l': return ZPL_RE_CODE_LOWER; - case 'u': return ZPL_RE_CODE_UPPER; - - case 'w': return ZPL_RE_CODE_WORD; - case 'W': return ZPL_RE_CODE_NOT_WORD; - - case 'x': return ZPL_RE_CODE_XDIGIT; - case 'p': return ZPL_RE_CODE_PRINTABLE; - } - return code; - } - - static zpl_regex_error zpl_re__parse_group(zpl_re *re, char const *pattern, zpl_isize len, zpl_isize offset, zpl_isize *new_offset) { - zpl_regex_error err = ZPL_RE_ERROR_NONE; - char buffer[256] = {0}; - zpl_isize buffer_len = 0, buffer_cap = zpl_size_of(buffer); - zpl_b32 closed = 0; - zplreOp op = ZPL_RE_OP_ANY_OF; - - if (pattern[offset] == '^') { - offset++; - op = ZPL_RE_OP_ANY_BUT; - } - - while(!closed && - err == ZPL_RE_ERROR_NONE && - offset < len) - { - if (pattern[offset] == ']') { - err = zpl_re__emit_ops(re, 2, (zpl_i32)op, (zpl_i32)buffer_len); - if (err) break; - - err = zpl_re__emit_ops_buffer(re, buffer_len, (const char*)buffer); - if (err) break; - offset++; - closed = 1; - break; - } - - if (buffer_len >= buffer_cap) - return ZPL_RE_ERROR_TOO_LONG; - - if (pattern[offset] == '\\') { - offset++; - - if ((offset + 1 < len) && zpl_char_is_hex_digit(*(pattern+offset))) { - buffer[buffer_len++] = zpl_re__hex((pattern+offset)); - offset++; - } - else if (offset < len) { - zpl_i32 code = zpl_re__encode_escape(pattern[offset]); - - if (!code || code > 0xff) { - buffer[buffer_len++] = 0; - - if (buffer_len >= buffer_cap) - return ZPL_RE_ERROR_TOO_LONG; - - buffer[buffer_len++] = (code >> 8) & 0xff; - } - else { - buffer[buffer_len++] = code & 0xff; - } - } - } - else { - buffer[buffer_len++] = (unsigned char)pattern[offset]; - } - - offset++; - } - - if (err) return err; - if (!closed) return ZPL_RE_ERROR_MISMATCHED_BLOCKS; - if (new_offset) *new_offset = offset; - return ZPL_RE_ERROR_NONE; - } - - static zpl_regex_error zpl_re__compile_quantifier(zpl_re *re, zpl_isize last_buf_len, unsigned char quantifier) { - zpl_regex_error err; - zpl_isize move_size; - - if ((re->buf[last_buf_len] == ZPL_RE_OP_EXACT_MATCH) && - (re->buf[last_buf_len+1] > 1)) - { - unsigned char last_char = re->buf[re->buf_len-1]; - - re->buf[last_buf_len+1]--; - re->buf_len--; - err = zpl_re__emit_ops(re, 4, (zpl_i32)quantifier, (zpl_i32)ZPL_RE_OP_EXACT_MATCH, 1, (zpl_i32)last_char); - if (err) return err; - return ZPL_RE_ERROR_NONE; - } - - move_size = re->buf_len - last_buf_len + 1; - - err = zpl_re__emit_ops(re, 1, 0); - if (err) return err; - - zpl_memmove(re->buf+last_buf_len+1, re->buf+last_buf_len, move_size); - re->buf[last_buf_len] = quantifier; - - return ZPL_RE_ERROR_NONE; - } - - static zpl_regex_error zpl_re__parse(zpl_re *re, char const *pattern, zpl_isize len, zpl_isize offset, zpl_isize level, zpl_isize *new_offset) { - zpl_regex_error err = ZPL_RE_ERROR_NONE; - zpl_isize last_buf_len = re->buf_len; - zpl_isize branch_begin = re->buf_len; - zpl_isize branch_op = -1; - - while (offset < len) { - switch (pattern[offset++]) { - case '^': { - err = zpl_re__emit_ops(re, 1, ZPL_RE_OP_BEGINNING_OF_LINE); - if (err) return err; - } break; - - case '$': { - err = zpl_re__emit_ops(re, 1, ZPL_RE_OP_END_OF_LINE); - if (err) return err; - } break; - - case '(': { - zpl_isize capture = re->capture_count++; - last_buf_len = re->buf_len; - err = zpl_re__emit_ops(re, 2, ZPL_RE_OP_BEGIN_CAPTURE, (zpl_i32)capture); - if (err) return err; - - err = zpl_re__parse(re, pattern, len, offset, level+1, &offset); - - if ((offset > len) || (pattern[offset-1] != ')')) - return ZPL_RE_ERROR_MISMATCHED_CAPTURES; - - err = zpl_re__emit_ops(re, 2, ZPL_RE_OP_END_CAPTURE, (zpl_i32)capture); - if (err) return err; - } break; - - case ')': { - if (branch_op != -1) - re->buf[branch_op + 1] = (unsigned char)(re->buf_len - (branch_op+2)); - - if (level == 0) - return ZPL_RE_ERROR_MISMATCHED_CAPTURES; - - if (new_offset) *new_offset = offset; - return ZPL_RE_ERROR_NONE; - } break; - - case '[': { - last_buf_len = re->buf_len; - err = zpl_re__parse_group(re, pattern, len, offset, &offset); - if (offset > len) - return err; - } break; - - /* NOTE(bill): Branching magic! */ - case '|': { - if (branch_begin >= re->buf_len) { - return ZPL_RE_ERROR_BRANCH_FAILURE; - } else { - zpl_isize size = re->buf_len - branch_begin; - err = zpl_re__emit_ops(re, 4, 0, 0, ZPL_RE_OP_BRANCH_END, 0); - if (err) return err; - - zpl_memmove(re->buf + branch_begin + 2, re->buf + branch_begin, size); - re->buf[branch_begin] = ZPL_RE_OP_BRANCH_START; - re->buf[branch_begin+1] = (size+2) & 0xff; - branch_op = re->buf_len-2; - } - } break; - - case '.': { - last_buf_len = re->buf_len; - err = zpl_re__emit_ops(re, 1, ZPL_RE_OP_ANY); - if (err) return err; - } break; - - case '*': - case '+': - { - unsigned char quantifier = ZPL_RE_OP_ONE_OR_MORE; - if (pattern[offset-1] == '*') - quantifier = ZPL_RE_OP_ZERO_OR_MORE; - - if (last_buf_len >= re->buf_len) - return ZPL_RE_ERROR_INVALID_QUANTIFIER; - if ((re->buf[last_buf_len] < ZPL_RE_OP_EXACT_MATCH) || - (re->buf[last_buf_len] > ZPL_RE_OP_ANY_BUT)) - return ZPL_RE_ERROR_INVALID_QUANTIFIER; - - if ((offset < len) && (pattern[offset] == '?')) { - quantifier = ZPL_RE_OP_ONE_OR_MORE_SHORTEST; - offset++; - } - - err = zpl_re__compile_quantifier(re, last_buf_len, quantifier); - if (err) return err; - } break; - - case '?': { - if (last_buf_len >= re->buf_len) - return ZPL_RE_ERROR_INVALID_QUANTIFIER; - if ((re->buf[last_buf_len] < ZPL_RE_OP_EXACT_MATCH) || - (re->buf[last_buf_len] > ZPL_RE_OP_ANY_BUT)) - return ZPL_RE_ERROR_INVALID_QUANTIFIER; - - err = zpl_re__compile_quantifier(re, last_buf_len, - (unsigned char)ZPL_RE_OP_ZERO_OR_ONE); - if (err) return err; - } break; - - case '\\': { - last_buf_len = re->buf_len; - if ((offset+1 < len) && zpl_char_is_hex_digit(*(pattern+offset))) { - unsigned char hex_value = zpl_re__hex((pattern+offset)); - offset += 2; - err = zpl_re__emit_ops(re, 2, ZPL_RE_OP_META_MATCH, (int)hex_value); - if (err) return err; - } else if (offset < len) { - int code = zpl_re__encode_escape(pattern[offset++]); - if (!code || (code > 0xff)) { - err = zpl_re__emit_ops(re, 3, ZPL_RE_OP_META_MATCH, 0, (int)((code >> 8) & 0xff)); - if (err) return err; - } else { - err = zpl_re__emit_ops(re, 2, ZPL_RE_OP_META_MATCH, (int)code); - if (err) return err; - } - } - } break; - - /* NOTE(bill): Exact match */ - default: { - char const *match_start; - zpl_isize size = 0; - offset--; - match_start = pattern+offset; - while ((offset < len) && - (zpl_re__strfind(ZPL_RE__LITERAL(ZPL_RE__META_CHARS), pattern[offset], 0) < 0)) { - size++, offset++; - } - - last_buf_len = re->buf_len; - err = zpl_re__emit_ops(re, 2, ZPL_RE_OP_EXACT_MATCH, (int)size); - if (err) return err; - err = zpl_re__emit_ops_buffer(re, size, (char const *)match_start); - if (err) return err; - } break; - } - } - - if (new_offset) *new_offset = offset; - return ZPL_RE_ERROR_NONE; - } - - zpl_regex_error zpl_re_compile_from_buffer(zpl_re *re, char const *pattern, zpl_isize pattern_len, void *buffer, zpl_isize buffer_len) { - zpl_regex_error err; - re->capture_count = 0; - re->buf = (char *)buffer; - re->buf_len = 0; - re->buf_cap = re->buf_len; - re->can_realloc = 0; - - err = zpl_re__parse(re, pattern, pattern_len, 0, 0, 0); - return err; - } - - zpl_regex_error zpl_re_compile(zpl_re *re, zpl_allocator backing, char const *pattern, zpl_isize pattern_len) { - zpl_regex_error err; - zpl_isize cap = pattern_len+128; - zpl_isize offset = 0; - - re->backing = backing; - re->capture_count = 0; - re->buf = (char *)zpl_alloc(backing, cap); - re->buf_len = 0; - re->buf_cap = cap; - re->can_realloc = 1; - - err = zpl_re__parse(re, pattern, pattern_len, 0, 0, &offset); - - if (offset != pattern_len) - zpl_free(backing, re->buf); - - return err; - } - - zpl_isize zpl_re_capture_count(zpl_re *re) { return re->capture_count; } - - zpl_b32 zpl_re_match(zpl_re *re, char const *str, zpl_isize len, zpl_re_capture *captures, zpl_isize max_capture_count, zpl_isize *offset) { - if (re && re->buf_len > 0) { - if (re->buf[0] == ZPL_RE_OP_BEGINNING_OF_LINE) { - zpl_re_ctx c = zpl_re__exec(re, 0, str, len, 0, captures, max_capture_count); - if (c.offset >= 0 && c.offset <= len) { if (offset) *offset = c.offset; return 1; }; - if (c.offset == ZPL_RE__INTERNAL_FAILURE) return 0; - } else { - zpl_isize i; - for (i = 0; i < len; i++) { - zpl_re_ctx c = zpl_re__exec(re, 0, str, len, i, captures, max_capture_count); - if (c.offset >= 0 && c.offset <= len) { if (offset) *offset = c.offset; return 1; }; - if (c.offset == ZPL_RE__INTERNAL_FAILURE) return 0; - } - } - return 0; - } - return 1; - } - - - zpl_b32 zpl_re_match_all(zpl_re *re, char const *str, zpl_isize str_len, zpl_isize max_capture_count, - zpl_re_capture **out_captures) - { - char *end = (char *)str + str_len; - char *p = (char *)str; - - zpl_buffer_make(zpl_re_capture, cps, zpl_heap(), max_capture_count); - - zpl_isize offset = 0; - - while (p < end) - { - zpl_b32 ok = zpl_re_match(re, p, end - p, cps, max_capture_count, &offset); - if (!ok) { - zpl_buffer_free(cps); - return false; - } - - p += offset; - - for (zpl_isize i = 0; i < max_capture_count; i++) { - zpl_array_append(*out_captures, cps[i]); - } - } - - zpl_buffer_free(cps); - - return true; - } - - ZPL_END_C_DECLS +// file: source/regex.c + + +ZPL_BEGIN_C_DECLS + +typedef enum zplreOp { + ZPL_RE_OP_BEGIN_CAPTURE, + ZPL_RE_OP_END_CAPTURE, + + ZPL_RE_OP_BEGINNING_OF_LINE, + ZPL_RE_OP_END_OF_LINE, + + ZPL_RE_OP_EXACT_MATCH, + ZPL_RE_OP_META_MATCH, + + ZPL_RE_OP_ANY, + ZPL_RE_OP_ANY_OF, + ZPL_RE_OP_ANY_BUT, + + ZPL_RE_OP_ZERO_OR_MORE, + ZPL_RE_OP_ONE_OR_MORE, + ZPL_RE_OP_ZERO_OR_MORE_SHORTEST, + ZPL_RE_OP_ONE_OR_MORE_SHORTEST, + ZPL_RE_OP_ZERO_OR_ONE, + + ZPL_RE_OP_BRANCH_START, + ZPL_RE_OP_BRANCH_END +} zplreOp; + +typedef enum zplreCode { + ZPL_RE_CODE_NULL = 0x0000, + ZPL_RE_CODE_WHITESPACE = 0x0100, + ZPL_RE_CODE_NOT_WHITESPACE = 0x0200, + ZPL_RE_CODE_DIGIT = 0x0300, + ZPL_RE_CODE_NOT_DIGIT = 0x0400, + ZPL_RE_CODE_ALPHA = 0x0500, + ZPL_RE_CODE_LOWER = 0x0600, + ZPL_RE_CODE_UPPER = 0x0700, + ZPL_RE_CODE_WORD = 0x0800, + ZPL_RE_CODE_NOT_WORD = 0x0900, + + ZPL_RE_CODE_XDIGIT = 0x0a00, + ZPL_RE_CODE_PRINTABLE = 0x0b00, +} zplreCode; + +typedef struct { + zpl_isize op, offset; +} zpl_re_ctx; + +enum { + ZPL_RE__NO_MATCH = -1, + ZPL_RE__INTERNAL_FAILURE = -2, +}; + +static char const ZPL_RE__META_CHARS[] = "^$()[].*+?|\\"; +static char const ZPL_RE__WHITESPACE[] = " \r\t\n\v\f"; +#define ZPL_RE__LITERAL(str) (str), zpl_size_of(str)-1 + +static zpl_re_ctx zpl_re__exec_single(zpl_re *re, zpl_isize op, char const *str, zpl_isize str_len, zpl_isize offset, zpl_re_capture *captures, zpl_isize max_capture_count); +static zpl_re_ctx zpl_re__exec(zpl_re *re, zpl_isize op, char const *str, zpl_isize str_len, zpl_isize offset, zpl_re_capture *captures, zpl_isize max_capture_count); + +static zpl_re_ctx zpl_re__ctx_no_match(zpl_isize op) { + zpl_re_ctx c; + c.op = op; + c.offset = ZPL_RE__NO_MATCH; + return c; +} + +static zpl_re_ctx zpl_re__ctx_internal_failure(zpl_isize op) { + zpl_re_ctx c; + c.op = op; + c.offset = ZPL_RE__INTERNAL_FAILURE; + return c; +} + +static zpl_u8 zpl_re__hex(char const *s) { + return ((zpl_char_to_hex_digit(*s) << 4) & 0xf0) | (zpl_char_to_hex_digit(*(s+1)) & 0x0f); +} + +static zpl_isize zpl_re__strfind(char const *s, zpl_isize len, char c, zpl_isize offset) { + if (offset < len) { + char const *found = (char const *)zpl_memchr(s+offset, c, len-offset); + if (found) + return found - s; + } + + return -1; +} + +static zpl_b32 zpl_re__match_escape(char c, int code) { + switch (code) { + case ZPL_RE_CODE_NULL: return c == 0; + case ZPL_RE_CODE_WHITESPACE: return zpl_re__strfind(ZPL_RE__LITERAL(ZPL_RE__WHITESPACE), c, 0) >= 0; + case ZPL_RE_CODE_NOT_WHITESPACE: return zpl_re__strfind(ZPL_RE__LITERAL(ZPL_RE__WHITESPACE), c, 0) < 0; + case ZPL_RE_CODE_DIGIT: return (c >= '0' && c <= '9'); + case ZPL_RE_CODE_NOT_DIGIT: return !(c >= '0' && c <= '9'); + case ZPL_RE_CODE_ALPHA: return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); + case ZPL_RE_CODE_LOWER: return (c >= 'a' && c <= 'z'); + case ZPL_RE_CODE_UPPER: return (c >= 'A' && c <= 'Z'); + + /* TODO(bill): Make better? */ + case ZPL_RE_CODE_WORD: return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_'; + case ZPL_RE_CODE_NOT_WORD: return !((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_'); + + /* TODO(bill): Maybe replace with between tests? */ + case ZPL_RE_CODE_XDIGIT: return zpl_re__strfind(ZPL_RE__LITERAL("0123456789ABCDEFabcdef"), c, 0) >= 0; + case ZPL_RE_CODE_PRINTABLE: return c >= 0x20 && c <= 0x7e; + default: break; + } + + return 0; +} + +static zpl_re_ctx zpl_re__consume(zpl_re *re, zpl_isize op, char const *str, zpl_isize str_len, zpl_isize offset, zpl_re_capture *captures, zpl_isize max_capture_count, zpl_b32 is_greedy) +{ + zpl_re_ctx c, best_c, next_c; + + c.op = op; + c.offset = offset; + + best_c.op = ZPL_RE__NO_MATCH; + best_c.offset = offset; + + for (;;) { + c = zpl_re__exec_single(re, op, str, str_len, c.offset, 0, 0); + if (c.offset > str_len || c.offset == -1) break; + if (c.op >= re->buf_len) return c; + + next_c = zpl_re__exec(re, c.op, str, str_len, c.offset, captures, max_capture_count); + if (next_c.offset <= str_len) { + if (captures) + zpl_re__exec(re, c.op, str, str_len, c.offset, captures, max_capture_count); + + best_c = next_c; + if (!is_greedy) break; + } + + if (best_c.op > re->buf_len) + best_c.op = c.op; + + } + + return best_c; +} + +static zpl_re_ctx zpl_re__exec_single(zpl_re *re, zpl_isize op, char const *str, zpl_isize str_len, zpl_isize offset, zpl_re_capture *captures, zpl_isize max_capture_count) { + zpl_re_ctx ctx; + zpl_isize buffer_len; + zpl_isize match_len; + zpl_isize next_op; + zpl_isize skip; + + switch (re->buf[op++]) { + case ZPL_RE_OP_BEGIN_CAPTURE: { + zpl_u8 capture = re->buf[op++]; + if (captures && (capture < max_capture_count)) + captures[capture].str = str + offset; + } break; + + case ZPL_RE_OP_END_CAPTURE: { + zpl_u8 capture = re->buf[op++]; + if (captures && (capture < max_capture_count)) + captures[capture].len = (str + offset) - captures[capture].str; + } break; + + case ZPL_RE_OP_BEGINNING_OF_LINE: { + if (offset != 0) + return zpl_re__ctx_no_match(op); + } break; + + case ZPL_RE_OP_END_OF_LINE: { + if (offset != str_len) + return zpl_re__ctx_no_match(op); + } break; + + case ZPL_RE_OP_BRANCH_START: { + skip = re->buf[op++]; + ctx = zpl_re__exec(re, op, str, str_len, offset, captures, max_capture_count); + if (ctx.offset <= str_len) { + offset = ctx.offset; + op = ctx.op; + } else { + ctx = zpl_re__exec(re, op + skip, str, str_len, offset, captures, max_capture_count); + offset = ctx.offset; + op = ctx.op; + } + } break; + + case ZPL_RE_OP_BRANCH_END: { + skip = re->buf[op++]; + op += skip; + } break; + + case ZPL_RE_OP_ANY: { + if (offset < str_len) { + offset++; + break; + } + return zpl_re__ctx_no_match(op); + } break; + + case ZPL_RE_OP_ANY_OF: { + zpl_isize i; + char cin = str[offset]; + buffer_len = re->buf[op++]; + + if (offset >= str_len) + return zpl_re__ctx_no_match(op + buffer_len); + + for (i = 0; i < buffer_len; i++) { + char cmatch = (char)re->buf[op+i]; + if (!cmatch) { + i++; + if (zpl_re__match_escape(cin, re->buf[op+i] << 8)) + break; + } else if (cin == cmatch) { + break; + } + } + + if (i == buffer_len) + return zpl_re__ctx_no_match(op + buffer_len); + + offset++; + op += buffer_len; + } break; + + case ZPL_RE_OP_ANY_BUT: { + zpl_isize i; + char cin = str[offset]; + buffer_len = re->buf[op++]; + + if (offset >= str_len) + return zpl_re__ctx_no_match(op + buffer_len); + + for (i = 0; i < buffer_len; i++) { + char cmatch = (char)re->buf[op + i]; + if (!cmatch) { + i++; + if (zpl_re__match_escape(cin, re->buf[op+i] << 8)) + return zpl_re__ctx_no_match(op + buffer_len); + } else if (cin == cmatch) { + return zpl_re__ctx_no_match(op + buffer_len); + } + } + + offset++; + op += buffer_len; + } break; + + case ZPL_RE_OP_EXACT_MATCH: { + match_len = re->buf[op++]; + + if ((match_len > (str_len - offset)) || + zpl_strncmp(str+offset, (const char*)re->buf + op, match_len) != 0) + return zpl_re__ctx_no_match(op + match_len); + + op += match_len; + offset += match_len; + } break; + + case ZPL_RE_OP_META_MATCH: { + char cin = (char)re->buf[op++]; + char cmatch = str[offset++]; + + if (!cin) { + if (zpl_re__match_escape(cmatch, re->buf[op++] << 8)) + break; + } + else if (cin == cmatch) break; + + return zpl_re__ctx_no_match(op); + } break; + + case ZPL_RE_OP_ZERO_OR_MORE: { + ctx = zpl_re__consume(re, op, str, str_len, offset, captures, max_capture_count, 1); + offset = ctx.offset; + op = ctx.op; + } break; + + case ZPL_RE_OP_ONE_OR_MORE: { + ctx = zpl_re__exec_single(re, op, str, str_len, offset, captures, max_capture_count); + + if (ctx.offset > str_len) + return ctx; + + ctx = zpl_re__consume(re, op, str, str_len, offset, captures, max_capture_count, 1); + offset = ctx.offset; + op = ctx.op; + } break; + + case ZPL_RE_OP_ZERO_OR_MORE_SHORTEST: { + ctx = zpl_re__consume(re, op, str, str_len, offset, captures, max_capture_count, 0); + offset = ctx.offset; + op = ctx.op; + } break; + + case ZPL_RE_OP_ONE_OR_MORE_SHORTEST: { + ctx = zpl_re__exec_single(re, op, str, str_len, offset, captures, max_capture_count); + + if (ctx.offset > str_len) + return ctx; + + ctx = zpl_re__consume(re, op, str, str_len, offset, captures, max_capture_count, 0); + offset = ctx.offset; + op = ctx.op; + } break; + + case ZPL_RE_OP_ZERO_OR_ONE: { + ctx = zpl_re__exec_single(re, op, str, str_len, offset, captures, max_capture_count); + + if (ctx.offset <= str_len) { + zpl_re_ctx possible_ctx = zpl_re__exec(re, ctx.op, str, str_len, ctx.offset, captures, max_capture_count); + + if (possible_ctx.offset <= str_len) { + op = possible_ctx.op; + offset = possible_ctx.offset; + break; + } + } + + next_op = ctx.op; + ctx = zpl_re__exec(re, next_op, str, str_len, offset, captures, max_capture_count); + + if (ctx.offset <= str_len) { + op = ctx.op; + offset = ctx.offset; + break; + } + return zpl_re__ctx_no_match(op); + } break; + + default: { + return zpl_re__ctx_internal_failure(op); + } break; + } + + ctx.op = op; + ctx.offset = offset; + + return ctx; +} + +static zpl_re_ctx zpl_re__exec(zpl_re *re, zpl_isize op, char const *str, zpl_isize str_len, zpl_isize offset, zpl_re_capture *captures, zpl_isize max_capture_count) { + zpl_re_ctx c; + c.op = op; + c.offset = offset; + + while (c.op < re->buf_len) { + c = zpl_re__exec_single(re, c.op, str, str_len, c.offset, captures, max_capture_count); + + if (c.offset > str_len || c.offset == -1) + break; + } + + return c; +} + +static zpl_regex_error zpl_re__emit_ops(zpl_re *re, zpl_isize op_count, ...) { + va_list va; + + if (re->buf_len + op_count > re->buf_cap) { + if (!re->can_realloc) { + return ZPL_RE_ERROR_TOO_LONG; + } + else { + zpl_isize new_cap = (re->buf_cap*2) + op_count; + re->buf = (char *)zpl_resize(re->backing, re->buf, re->buf_cap, new_cap); + re->buf_cap = new_cap; + } + } + + va_start(va, op_count); + for (zpl_isize i = 0; i < op_count; i++) + { + zpl_i32 v = va_arg(va, zpl_i32); + if (v > 256) + return ZPL_RE_ERROR_TOO_LONG; + re->buf[re->buf_len++] = (char)v; + } + va_end(va); + + return ZPL_RE_ERROR_NONE; +} + +static zpl_regex_error zpl_re__emit_ops_buffer(zpl_re *re, zpl_isize op_count, char const *buffer) { + if (re->buf_len + op_count > re->buf_cap) { + if (!re->can_realloc) { + return ZPL_RE_ERROR_TOO_LONG; + } + else { + zpl_isize new_cap = (re->buf_cap*2) + op_count; + re->buf = (char *)zpl_resize(re->backing, re->buf, re->buf_cap, new_cap); + re->buf_cap = new_cap; + } + } + + for (zpl_isize i = 0; i < op_count; i++) + { + re->buf[re->buf_len++] = buffer[i]; + } + + return ZPL_RE_ERROR_NONE; +} + +static int zpl_re__encode_escape(char code) { + switch (code) { + default: break; /* NOTE(bill): It's a normal character */ + + /* TODO(bill): Are there anymore? */ + case 't': return '\t'; + case 'n': return '\n'; + case 'r': return '\r'; + case 'f': return '\f'; + case 'v': return '\v'; + + case '0': return ZPL_RE_CODE_NULL; + + case 's': return ZPL_RE_CODE_WHITESPACE; + case 'S': return ZPL_RE_CODE_NOT_WHITESPACE; + + case 'd': return ZPL_RE_CODE_DIGIT; + case 'D': return ZPL_RE_CODE_NOT_DIGIT; + + case 'a': return ZPL_RE_CODE_ALPHA; + case 'l': return ZPL_RE_CODE_LOWER; + case 'u': return ZPL_RE_CODE_UPPER; + + case 'w': return ZPL_RE_CODE_WORD; + case 'W': return ZPL_RE_CODE_NOT_WORD; + + case 'x': return ZPL_RE_CODE_XDIGIT; + case 'p': return ZPL_RE_CODE_PRINTABLE; + } + return code; +} + +static zpl_regex_error zpl_re__parse_group(zpl_re *re, char const *pattern, zpl_isize len, zpl_isize offset, zpl_isize *new_offset) { + zpl_regex_error err = ZPL_RE_ERROR_NONE; + char buffer[256] = {0}; + zpl_isize buffer_len = 0, buffer_cap = zpl_size_of(buffer); + zpl_b32 closed = 0; + zplreOp op = ZPL_RE_OP_ANY_OF; + + if (pattern[offset] == '^') { + offset++; + op = ZPL_RE_OP_ANY_BUT; + } + + while(!closed && + err == ZPL_RE_ERROR_NONE && + offset < len) + { + if (pattern[offset] == ']') { + err = zpl_re__emit_ops(re, 2, (zpl_i32)op, (zpl_i32)buffer_len); + if (err) break; + + err = zpl_re__emit_ops_buffer(re, buffer_len, (const char*)buffer); + if (err) break; + offset++; + closed = 1; + break; + } + + if (buffer_len >= buffer_cap) + return ZPL_RE_ERROR_TOO_LONG; + + if (pattern[offset] == '\\') { + offset++; + + if ((offset + 1 < len) && zpl_char_is_hex_digit(*(pattern+offset))) { + buffer[buffer_len++] = zpl_re__hex((pattern+offset)); + offset++; + } + else if (offset < len) { + zpl_i32 code = zpl_re__encode_escape(pattern[offset]); + + if (!code || code > 0xff) { + buffer[buffer_len++] = 0; + + if (buffer_len >= buffer_cap) + return ZPL_RE_ERROR_TOO_LONG; + + buffer[buffer_len++] = (code >> 8) & 0xff; + } + else { + buffer[buffer_len++] = code & 0xff; + } + } + } + else { + buffer[buffer_len++] = (unsigned char)pattern[offset]; + } + + offset++; + } + + if (err) return err; + if (!closed) return ZPL_RE_ERROR_MISMATCHED_BLOCKS; + if (new_offset) *new_offset = offset; + return ZPL_RE_ERROR_NONE; +} + +static zpl_regex_error zpl_re__compile_quantifier(zpl_re *re, zpl_isize last_buf_len, unsigned char quantifier) { + zpl_regex_error err; + zpl_isize move_size; + + if ((re->buf[last_buf_len] == ZPL_RE_OP_EXACT_MATCH) && + (re->buf[last_buf_len+1] > 1)) + { + unsigned char last_char = re->buf[re->buf_len-1]; + + re->buf[last_buf_len+1]--; + re->buf_len--; + err = zpl_re__emit_ops(re, 4, (zpl_i32)quantifier, (zpl_i32)ZPL_RE_OP_EXACT_MATCH, 1, (zpl_i32)last_char); + if (err) return err; + return ZPL_RE_ERROR_NONE; + } + + move_size = re->buf_len - last_buf_len + 1; + + err = zpl_re__emit_ops(re, 1, 0); + if (err) return err; + + zpl_memmove(re->buf+last_buf_len+1, re->buf+last_buf_len, move_size); + re->buf[last_buf_len] = quantifier; + + return ZPL_RE_ERROR_NONE; +} + +static zpl_regex_error zpl_re__parse(zpl_re *re, char const *pattern, zpl_isize len, zpl_isize offset, zpl_isize level, zpl_isize *new_offset) { + zpl_regex_error err = ZPL_RE_ERROR_NONE; + zpl_isize last_buf_len = re->buf_len; + zpl_isize branch_begin = re->buf_len; + zpl_isize branch_op = -1; + + while (offset < len) { + switch (pattern[offset++]) { + case '^': { + err = zpl_re__emit_ops(re, 1, ZPL_RE_OP_BEGINNING_OF_LINE); + if (err) return err; + } break; + + case '$': { + err = zpl_re__emit_ops(re, 1, ZPL_RE_OP_END_OF_LINE); + if (err) return err; + } break; + + case '(': { + zpl_isize capture = re->capture_count++; + last_buf_len = re->buf_len; + err = zpl_re__emit_ops(re, 2, ZPL_RE_OP_BEGIN_CAPTURE, (zpl_i32)capture); + if (err) return err; + + err = zpl_re__parse(re, pattern, len, offset, level+1, &offset); + + if ((offset > len) || (pattern[offset-1] != ')')) + return ZPL_RE_ERROR_MISMATCHED_CAPTURES; + + err = zpl_re__emit_ops(re, 2, ZPL_RE_OP_END_CAPTURE, (zpl_i32)capture); + if (err) return err; + } break; + + case ')': { + if (branch_op != -1) + re->buf[branch_op + 1] = (unsigned char)(re->buf_len - (branch_op+2)); + + if (level == 0) + return ZPL_RE_ERROR_MISMATCHED_CAPTURES; + + if (new_offset) *new_offset = offset; + return ZPL_RE_ERROR_NONE; + } break; + + case '[': { + last_buf_len = re->buf_len; + err = zpl_re__parse_group(re, pattern, len, offset, &offset); + if (offset > len) + return err; + } break; + + /* NOTE(bill): Branching magic! */ + case '|': { + if (branch_begin >= re->buf_len) { + return ZPL_RE_ERROR_BRANCH_FAILURE; + } else { + zpl_isize size = re->buf_len - branch_begin; + err = zpl_re__emit_ops(re, 4, 0, 0, ZPL_RE_OP_BRANCH_END, 0); + if (err) return err; + + zpl_memmove(re->buf + branch_begin + 2, re->buf + branch_begin, size); + re->buf[branch_begin] = ZPL_RE_OP_BRANCH_START; + re->buf[branch_begin+1] = (size+2) & 0xff; + branch_op = re->buf_len-2; + } + } break; + + case '.': { + last_buf_len = re->buf_len; + err = zpl_re__emit_ops(re, 1, ZPL_RE_OP_ANY); + if (err) return err; + } break; + + case '*': + case '+': + { + unsigned char quantifier = ZPL_RE_OP_ONE_OR_MORE; + if (pattern[offset-1] == '*') + quantifier = ZPL_RE_OP_ZERO_OR_MORE; + + if (last_buf_len >= re->buf_len) + return ZPL_RE_ERROR_INVALID_QUANTIFIER; + if ((re->buf[last_buf_len] < ZPL_RE_OP_EXACT_MATCH) || + (re->buf[last_buf_len] > ZPL_RE_OP_ANY_BUT)) + return ZPL_RE_ERROR_INVALID_QUANTIFIER; + + if ((offset < len) && (pattern[offset] == '?')) { + quantifier = ZPL_RE_OP_ONE_OR_MORE_SHORTEST; + offset++; + } + + err = zpl_re__compile_quantifier(re, last_buf_len, quantifier); + if (err) return err; + } break; + + case '?': { + if (last_buf_len >= re->buf_len) + return ZPL_RE_ERROR_INVALID_QUANTIFIER; + if ((re->buf[last_buf_len] < ZPL_RE_OP_EXACT_MATCH) || + (re->buf[last_buf_len] > ZPL_RE_OP_ANY_BUT)) + return ZPL_RE_ERROR_INVALID_QUANTIFIER; + + err = zpl_re__compile_quantifier(re, last_buf_len, + (unsigned char)ZPL_RE_OP_ZERO_OR_ONE); + if (err) return err; + } break; + + case '\\': { + last_buf_len = re->buf_len; + if ((offset+1 < len) && zpl_char_is_hex_digit(*(pattern+offset))) { + unsigned char hex_value = zpl_re__hex((pattern+offset)); + offset += 2; + err = zpl_re__emit_ops(re, 2, ZPL_RE_OP_META_MATCH, (int)hex_value); + if (err) return err; + } else if (offset < len) { + int code = zpl_re__encode_escape(pattern[offset++]); + if (!code || (code > 0xff)) { + err = zpl_re__emit_ops(re, 3, ZPL_RE_OP_META_MATCH, 0, (int)((code >> 8) & 0xff)); + if (err) return err; + } else { + err = zpl_re__emit_ops(re, 2, ZPL_RE_OP_META_MATCH, (int)code); + if (err) return err; + } + } + } break; + + /* NOTE(bill): Exact match */ + default: { + char const *match_start; + zpl_isize size = 0; + offset--; + match_start = pattern+offset; + while ((offset < len) && + (zpl_re__strfind(ZPL_RE__LITERAL(ZPL_RE__META_CHARS), pattern[offset], 0) < 0)) { + size++, offset++; + } + + last_buf_len = re->buf_len; + err = zpl_re__emit_ops(re, 2, ZPL_RE_OP_EXACT_MATCH, (int)size); + if (err) return err; + err = zpl_re__emit_ops_buffer(re, size, (char const *)match_start); + if (err) return err; + } break; + } + } + + if (new_offset) *new_offset = offset; + return ZPL_RE_ERROR_NONE; +} + +zpl_regex_error zpl_re_compile_from_buffer(zpl_re *re, char const *pattern, zpl_isize pattern_len, void *buffer, zpl_isize buffer_len) { + zpl_regex_error err; + re->capture_count = 0; + re->buf = (char *)buffer; + re->buf_len = 0; + re->buf_cap = re->buf_len; + re->can_realloc = 0; + + err = zpl_re__parse(re, pattern, pattern_len, 0, 0, 0); + return err; +} + +zpl_regex_error zpl_re_compile(zpl_re *re, zpl_allocator backing, char const *pattern, zpl_isize pattern_len) { + zpl_regex_error err; + zpl_isize cap = pattern_len+128; + zpl_isize offset = 0; + + re->backing = backing; + re->capture_count = 0; + re->buf = (char *)zpl_alloc(backing, cap); + re->buf_len = 0; + re->buf_cap = cap; + re->can_realloc = 1; + + err = zpl_re__parse(re, pattern, pattern_len, 0, 0, &offset); + + if (offset != pattern_len) + zpl_free(backing, re->buf); + + return err; +} + +zpl_isize zpl_re_capture_count(zpl_re *re) { return re->capture_count; } + +zpl_b32 zpl_re_match(zpl_re *re, char const *str, zpl_isize len, zpl_re_capture *captures, zpl_isize max_capture_count, zpl_isize *offset) { + if (re && re->buf_len > 0) { + if (re->buf[0] == ZPL_RE_OP_BEGINNING_OF_LINE) { + zpl_re_ctx c = zpl_re__exec(re, 0, str, len, 0, captures, max_capture_count); + if (c.offset >= 0 && c.offset <= len) { if (offset) *offset = c.offset; return 1; }; + if (c.offset == ZPL_RE__INTERNAL_FAILURE) return 0; + } else { + zpl_isize i; + for (i = 0; i < len; i++) { + zpl_re_ctx c = zpl_re__exec(re, 0, str, len, i, captures, max_capture_count); + if (c.offset >= 0 && c.offset <= len) { if (offset) *offset = c.offset; return 1; }; + if (c.offset == ZPL_RE__INTERNAL_FAILURE) return 0; + } + } + return 0; + } + return 1; +} + + +zpl_b32 zpl_re_match_all(zpl_re *re, char const *str, zpl_isize str_len, zpl_isize max_capture_count, + zpl_re_capture **out_captures) +{ + char *end = (char *)str + str_len; + char *p = (char *)str; + + zpl_buffer_make(zpl_re_capture, cps, zpl_heap(), max_capture_count); + + zpl_isize offset = 0; + + while (p < end) + { + zpl_b32 ok = zpl_re_match(re, p, end - p, cps, max_capture_count, &offset); + if (!ok) { + zpl_buffer_free(cps); + return false; + } + + p += offset; + + for (zpl_isize i = 0; i < max_capture_count; i++) { + zpl_array_append(*out_captures, cps[i]); + } + } + + zpl_buffer_free(cps); + + return true; +} + +ZPL_END_C_DECLS #endif #if defined(ZPL_MODULE_DLL) - // file: source/dll.c +// file: source/dll.c - #if defined(ZPL_SYSTEM_UNIX) || defined(ZPL_SYSTEM_MACOS) - # include - #endif +#if defined(ZPL_SYSTEM_UNIX) || defined(ZPL_SYSTEM_MACOS) +# include +#endif - ZPL_BEGIN_C_DECLS +ZPL_BEGIN_C_DECLS - //////////////////////////////////////////////////////////////// - // - // DLL Handling - // - // +//////////////////////////////////////////////////////////////// +// +// DLL Handling +// +// - #if defined(ZPL_SYSTEM_WINDOWS) - zpl_dll_handle zpl_dll_load(char const *filepath) { - return cast(zpl_dll_handle) LoadLibraryA(filepath); - } +#if defined(ZPL_SYSTEM_WINDOWS) +zpl_dll_handle zpl_dll_load(char const *filepath) { + return cast(zpl_dll_handle) LoadLibraryA(filepath); +} - void zpl_dll_unload(zpl_dll_handle dll) { - FreeLibrary(cast(HMODULE) dll); - } +void zpl_dll_unload(zpl_dll_handle dll) { + FreeLibrary(cast(HMODULE) dll); +} - zpl_dll_proc zpl_dll_proc_address(zpl_dll_handle dll, char const *proc_name) { - return cast(zpl_dll_proc) GetProcAddress(cast(HMODULE) dll, proc_name); - } +zpl_dll_proc zpl_dll_proc_address(zpl_dll_handle dll, char const *proc_name) { + return cast(zpl_dll_proc) GetProcAddress(cast(HMODULE) dll, proc_name); +} - #else // POSIX +#else // POSIX - zpl_dll_handle zpl_dll_load(char const *filepath) { - return cast(zpl_dll_handle) dlopen(filepath, RTLD_LAZY | RTLD_GLOBAL); - } +zpl_dll_handle zpl_dll_load(char const *filepath) { + return cast(zpl_dll_handle) dlopen(filepath, RTLD_LAZY | RTLD_GLOBAL); +} - void zpl_dll_unload(zpl_dll_handle dll) { - dlclose(dll); - } +void zpl_dll_unload(zpl_dll_handle dll) { + dlclose(dll); +} - zpl_dll_proc zpl_dll_proc_address(zpl_dll_handle dll, char const *proc_name) { - return cast(zpl_dll_proc) dlsym(dll, proc_name); - } +zpl_dll_proc zpl_dll_proc_address(zpl_dll_handle dll, char const *proc_name) { + return cast(zpl_dll_proc) dlsym(dll, proc_name); +} - #endif +#endif - ZPL_END_C_DECLS +ZPL_END_C_DECLS #endif #if defined(ZPL_MODULE_OPTS) - // file: source/opts.c +// file: source/opts.c - //////////////////////////////////////////////////////////////// - // - // CLI Options - // - // +//////////////////////////////////////////////////////////////// +// +// CLI Options +// +// - ZPL_BEGIN_C_DECLS +ZPL_BEGIN_C_DECLS - void zpl_opts_init(zpl_opts *opts, zpl_allocator a, char const *app) { - zpl_opts opts_ = { 0 }; - *opts = opts_; - opts->alloc = a; - opts->appname = app; +void zpl_opts_init(zpl_opts *opts, zpl_allocator a, char const *app) { + zpl_opts opts_ = { 0 }; + *opts = opts_; + opts->alloc = a; + opts->appname = app; + + zpl_array_init(opts->entries, a); + zpl_array_init(opts->positioned, a); + zpl_array_init(opts->errors, a); +} - zpl_array_init(opts->entries, a); - zpl_array_init(opts->positioned, a); - zpl_array_init(opts->errors, a); - } +void zpl_opts_free(zpl_opts *opts) { + for (zpl_i32 i = 0; i < zpl_array_count(opts->entries); ++i) { + zpl_opts_entry *e = opts->entries + i; + if (e->type == ZPL_OPTS_STRING) { + zpl_string_free(e->text); + } + } + + zpl_array_free(opts->entries); + zpl_array_free(opts->positioned); + zpl_array_free(opts->errors); +} - void zpl_opts_free(zpl_opts *opts) { - for (zpl_i32 i = 0; i < zpl_array_count(opts->entries); ++i) { - zpl_opts_entry *e = opts->entries + i; - if (e->type == ZPL_OPTS_STRING) { - zpl_string_free(e->text); - } - } +void zpl_opts_add(zpl_opts *opts, char const *name, char const *lname, const char *desc, zpl_u8 type) { + zpl_opts_entry e = { 0 }; + + e.name = name; + e.lname = lname; + e.desc = desc; + e.type = type; + e.met = false; + e.pos = false; + + zpl_array_append(opts->entries, e); +} - zpl_array_free(opts->entries); - zpl_array_free(opts->positioned); - zpl_array_free(opts->errors); - } +zpl_opts_entry *zpl__opts_find(zpl_opts *opts, char const *name, zpl_usize len, zpl_b32 longname) { + zpl_opts_entry *e = 0; + + for (int i = 0; i < zpl_array_count(opts->entries); ++i) { + e = opts->entries + i; + char const *n = (longname ? e->lname : e->name); + if(!n) continue; + + if (zpl_strnlen(name, len) == zpl_strlen(n) && !zpl_strncmp(n, name, len)) { return e; } + } + + return NULL; +} - void zpl_opts_add(zpl_opts *opts, char const *name, char const *lname, const char *desc, zpl_u8 type) { - zpl_opts_entry e = { 0 }; +void zpl_opts_positional_add(zpl_opts *opts, char const *name) { + zpl_opts_entry *e = zpl__opts_find(opts, name, zpl_strlen(name), true); + + if (e) { + e->pos = true; + zpl_array_append_at(opts->positioned, e, 0); + } +} - e.name = name; - e.lname = lname; - e.desc = desc; - e.type = type; - e.met = false; - e.pos = false; +zpl_b32 zpl_opts_positionals_filled(zpl_opts *opts) { return zpl_array_count(opts->positioned) == 0; } - zpl_array_append(opts->entries, e); - } +zpl_string zpl_opts_string(zpl_opts *opts, char const *name, char const *fallback) { + zpl_opts_entry *e = zpl__opts_find(opts, name, zpl_strlen(name), true); + + return (char *)((e && e->met) ? e->text : fallback); +} - zpl_opts_entry *zpl__opts_find(zpl_opts *opts, char const *name, zpl_usize len, zpl_b32 longname) { - zpl_opts_entry *e = 0; +zpl_f64 zpl_opts_real(zpl_opts *opts, char const *name, zpl_f64 fallback) { + zpl_opts_entry *e = zpl__opts_find(opts, name, zpl_strlen(name), true); + + return (e && e->met) ? e->real : fallback; +} - for (int i = 0; i < zpl_array_count(opts->entries); ++i) { - e = opts->entries + i; - char const *n = (longname ? e->lname : e->name); - if(!n) continue; +zpl_i64 zpl_opts_integer(zpl_opts *opts, char const *name, zpl_i64 fallback) { + zpl_opts_entry *e = zpl__opts_find(opts, name, zpl_strlen(name), true); + + return (e && e->met) ? e->integer : fallback; +} - if (zpl_strnlen(name, len) == zpl_strlen(n) && !zpl_strncmp(n, name, len)) { return e; } - } +void zpl__opts_set_value(zpl_opts *opts, zpl_opts_entry *t, char *b) { + t->met = true; + + switch (t->type) { + case ZPL_OPTS_STRING: { + t->text = zpl_string_make(opts->alloc, b); + } break; + + case ZPL_OPTS_FLOAT: { + t->real = zpl_str_to_f64(b, NULL); + } break; + + case ZPL_OPTS_INT: { + t->integer = zpl_str_to_i64(b, NULL, 10); + } break; + } + + for (zpl_isize i=0; i < zpl_array_count(opts->positioned); i++) { + if (!zpl_strcmp(opts->positioned[i]->lname, t->lname)) { + zpl_array_remove_at(opts->positioned, i); + break; + } + } +} - return NULL; - } +zpl_b32 zpl_opts_has_arg(zpl_opts *opts, char const *name) { + zpl_opts_entry *e = zpl__opts_find(opts, name, zpl_strlen(name), true); + + if (e) { return e->met; } + + return false; +} - void zpl_opts_positional_add(zpl_opts *opts, char const *name) { - zpl_opts_entry *e = zpl__opts_find(opts, name, zpl_strlen(name), true); +void zpl_opts_print_help(zpl_opts *opts) { + zpl_printf("USAGE: %s", opts->appname); + + for (zpl_isize i = zpl_array_count(opts->entries); i >= 0; --i) { + zpl_opts_entry *e = opts->entries + i; + + if (e->pos == (zpl_b32) true) { zpl_printf(" [%s]", e->lname); } + } + + zpl_printf("\nOPTIONS:\n"); + + for (zpl_isize i = 0; i < zpl_array_count(opts->entries); ++i) { + zpl_opts_entry *e = opts->entries + i; + + if(e->name) { + if(e->lname) { zpl_printf("\t-%s, --%s: %s\n", e->name, e->lname, e->desc); } + else { zpl_printf("\t-%s: %s\n", e->name, e->desc); } + } else { zpl_printf("\t--%s: %s\n", e->lname, e->desc); } + } +} - if (e) { - e->pos = true; - zpl_array_append_at(opts->positioned, e, 0); - } - } +void zpl_opts_print_errors(zpl_opts *opts) { + for (int i = 0; i < zpl_array_count(opts->errors); ++i) { + zpl_opts_err *err = (opts->errors + i); + + zpl_printf("ERROR: "); + + switch (err->type) { + case ZPL_OPTS_ERR_OPTION: zpl_printf("Invalid option \"%s\"", err->val); break; + + case ZPL_OPTS_ERR_VALUE: zpl_printf("Invalid value \"%s\"", err->val); break; + + case ZPL_OPTS_ERR_MISSING_VALUE: zpl_printf("Missing value for option \"%s\"", err->val); break; + + case ZPL_OPTS_ERR_EXTRA_VALUE: zpl_printf("Extra value for option \"%s\"", err->val); break; + } + + zpl_printf("\n"); + } +} - zpl_b32 zpl_opts_positionals_filled(zpl_opts *opts) { return zpl_array_count(opts->positioned) == 0; } +void zpl__opts_push_error(zpl_opts *opts, char *b, zpl_u8 errtype) { + zpl_opts_err err = { 0 }; + err.val = b; + err.type = errtype; + zpl_array_append(opts->errors, err); +} - zpl_string zpl_opts_string(zpl_opts *opts, char const *name, char const *fallback) { - zpl_opts_entry *e = zpl__opts_find(opts, name, zpl_strlen(name), true); +zpl_b32 zpl_opts_compile(zpl_opts *opts, int argc, char **argv) { + zpl_b32 had_errors = false; + for (int i = 1; i < argc; ++i) { + char *p = argv[i]; + + if (*p) { + p = cast(char *)zpl_str_trim(p, false); + if (*p == '-') { + zpl_opts_entry *t = 0; + zpl_b32 checkln = false; + if (*(p + 1) == '-') { + checkln = true; + ++p; + } + + char *b = p + 1, *e = b; + + while (zpl_char_is_alphanumeric(*e) || *e == '-' || *e == '_') { ++e; } + + t = zpl__opts_find(opts, b, (e - b), checkln); + + if (t) { + char *ob = b; + b = e; + + /**/ if (*e == '=') { + if (t->type == ZPL_OPTS_FLAG) { + *e = '\0'; + zpl__opts_push_error(opts, ob, ZPL_OPTS_ERR_EXTRA_VALUE); + had_errors = true; + continue; + } + + b = e = e + 1; + } else if (*e == '\0') { + char *sp = argv[i+1]; + + if (sp && *sp != '-' && (zpl_array_count(opts->positioned) < 1 || t->type != ZPL_OPTS_FLAG)) { + if (t->type == ZPL_OPTS_FLAG) { + zpl__opts_push_error(opts, b, ZPL_OPTS_ERR_EXTRA_VALUE); + had_errors = true; + continue; + } + + p = sp; + b = e = sp; + ++i; + } else { + if (t->type != ZPL_OPTS_FLAG) { + zpl__opts_push_error(opts, ob, ZPL_OPTS_ERR_MISSING_VALUE); + had_errors = true; + continue; + } + t->met = true; + continue; + } + } + + e = cast(char *)zpl_str_control_skip(e, '\0'); + zpl__opts_set_value(opts, t, b); + } else { + zpl__opts_push_error(opts, b, ZPL_OPTS_ERR_OPTION); + had_errors = true; + } + } else if (zpl_array_count(opts->positioned)) { + zpl_opts_entry *l = zpl_array_back(opts->positioned); + zpl_array_pop(opts->positioned); + zpl__opts_set_value(opts, l, p); + } else { + zpl__opts_push_error(opts, p, ZPL_OPTS_ERR_VALUE); + had_errors = true; + } + } + } + return !had_errors; +} - return (char *)((e && e->met) ? e->text : fallback); - } - - zpl_f64 zpl_opts_real(zpl_opts *opts, char const *name, zpl_f64 fallback) { - zpl_opts_entry *e = zpl__opts_find(opts, name, zpl_strlen(name), true); - - return (e && e->met) ? e->real : fallback; - } - - zpl_i64 zpl_opts_integer(zpl_opts *opts, char const *name, zpl_i64 fallback) { - zpl_opts_entry *e = zpl__opts_find(opts, name, zpl_strlen(name), true); - - return (e && e->met) ? e->integer : fallback; - } - - void zpl__opts_set_value(zpl_opts *opts, zpl_opts_entry *t, char *b) { - t->met = true; - - switch (t->type) { - case ZPL_OPTS_STRING: { - t->text = zpl_string_make(opts->alloc, b); - } break; - - case ZPL_OPTS_FLOAT: { - t->real = zpl_str_to_f64(b, NULL); - } break; - - case ZPL_OPTS_INT: { - t->integer = zpl_str_to_i64(b, NULL, 10); - } break; - } - - for (zpl_isize i=0; i < zpl_array_count(opts->positioned); i++) { - if (!zpl_strcmp(opts->positioned[i]->lname, t->lname)) { - zpl_array_remove_at(opts->positioned, i); - break; - } - } - } - - zpl_b32 zpl_opts_has_arg(zpl_opts *opts, char const *name) { - zpl_opts_entry *e = zpl__opts_find(opts, name, zpl_strlen(name), true); - - if (e) { return e->met; } - - return false; - } - - void zpl_opts_print_help(zpl_opts *opts) { - zpl_printf("USAGE: %s", opts->appname); - - for (zpl_isize i = zpl_array_count(opts->entries); i >= 0; --i) { - zpl_opts_entry *e = opts->entries + i; - - if (e->pos == (zpl_b32) true) { zpl_printf(" [%s]", e->lname); } - } - - zpl_printf("\nOPTIONS:\n"); - - for (zpl_isize i = 0; i < zpl_array_count(opts->entries); ++i) { - zpl_opts_entry *e = opts->entries + i; - - if(e->name) { - if(e->lname) { zpl_printf("\t-%s, --%s: %s\n", e->name, e->lname, e->desc); } - else { zpl_printf("\t-%s: %s\n", e->name, e->desc); } - } else { zpl_printf("\t--%s: %s\n", e->lname, e->desc); } - } - } - - void zpl_opts_print_errors(zpl_opts *opts) { - for (int i = 0; i < zpl_array_count(opts->errors); ++i) { - zpl_opts_err *err = (opts->errors + i); - - zpl_printf("ERROR: "); - - switch (err->type) { - case ZPL_OPTS_ERR_OPTION: zpl_printf("Invalid option \"%s\"", err->val); break; - - case ZPL_OPTS_ERR_VALUE: zpl_printf("Invalid value \"%s\"", err->val); break; - - case ZPL_OPTS_ERR_MISSING_VALUE: zpl_printf("Missing value for option \"%s\"", err->val); break; - - case ZPL_OPTS_ERR_EXTRA_VALUE: zpl_printf("Extra value for option \"%s\"", err->val); break; - } - - zpl_printf("\n"); - } - } - - void zpl__opts_push_error(zpl_opts *opts, char *b, zpl_u8 errtype) { - zpl_opts_err err = { 0 }; - err.val = b; - err.type = errtype; - zpl_array_append(opts->errors, err); - } - - zpl_b32 zpl_opts_compile(zpl_opts *opts, int argc, char **argv) { - zpl_b32 had_errors = false; - for (int i = 1; i < argc; ++i) { - char *p = argv[i]; - - if (*p) { - p = cast(char *)zpl_str_trim(p, false); - if (*p == '-') { - zpl_opts_entry *t = 0; - zpl_b32 checkln = false; - if (*(p + 1) == '-') { - checkln = true; - ++p; - } - - char *b = p + 1, *e = b; - - while (zpl_char_is_alphanumeric(*e) || *e == '-' || *e == '_') { ++e; } - - t = zpl__opts_find(opts, b, (e - b), checkln); - - if (t) { - char *ob = b; - b = e; - - /**/ if (*e == '=') { - if (t->type == ZPL_OPTS_FLAG) { - *e = '\0'; - zpl__opts_push_error(opts, ob, ZPL_OPTS_ERR_EXTRA_VALUE); - had_errors = true; - continue; - } - - b = e = e + 1; - } else if (*e == '\0') { - char *sp = argv[i+1]; - - if (sp && *sp != '-' && (zpl_array_count(opts->positioned) < 1 || t->type != ZPL_OPTS_FLAG)) { - if (t->type == ZPL_OPTS_FLAG) { - zpl__opts_push_error(opts, b, ZPL_OPTS_ERR_EXTRA_VALUE); - had_errors = true; - continue; - } - - p = sp; - b = e = sp; - ++i; - } else { - if (t->type != ZPL_OPTS_FLAG) { - zpl__opts_push_error(opts, ob, ZPL_OPTS_ERR_MISSING_VALUE); - had_errors = true; - continue; - } - t->met = true; - continue; - } - } - - e = cast(char *)zpl_str_control_skip(e, '\0'); - zpl__opts_set_value(opts, t, b); - } else { - zpl__opts_push_error(opts, b, ZPL_OPTS_ERR_OPTION); - had_errors = true; - } - } else if (zpl_array_count(opts->positioned)) { - zpl_opts_entry *l = zpl_array_back(opts->positioned); - zpl_array_pop(opts->positioned); - zpl__opts_set_value(opts, l, p); - } else { - zpl__opts_push_error(opts, p, ZPL_OPTS_ERR_VALUE); - had_errors = true; - } - } - } - return !had_errors; - } - - ZPL_END_C_DECLS +ZPL_END_C_DECLS #endif #if defined(ZPL_MODULE_PROCESS) - // file: source/process.c +// file: source/process.c - //////////////////////////////////////////////////////////////// - // - // Process creation and manipulation methods - // - // +//////////////////////////////////////////////////////////////// +// +// Process creation and manipulation methods +// +// - ZPL_BEGIN_C_DECLS +ZPL_BEGIN_C_DECLS - static ZPL_ALWAYS_INLINE void zpl__pr_close_file_handle(zpl_file *f) { - ZPL_ASSERT_NOT_NULL(f); - f->fd.p = NULL; - } +static ZPL_ALWAYS_INLINE void zpl__pr_close_file_handle(zpl_file *f) { + ZPL_ASSERT_NOT_NULL(f); + f->fd.p = NULL; +} - static ZPL_ALWAYS_INLINE void zpl__pr_close_file_handles(zpl_pr *process) { - ZPL_ASSERT_NOT_NULL(process); +static ZPL_ALWAYS_INLINE void zpl__pr_close_file_handles(zpl_pr *process) { + ZPL_ASSERT_NOT_NULL(process); + + zpl__pr_close_file_handle(&process->in); + zpl__pr_close_file_handle(&process->out); + zpl__pr_close_file_handle(&process->err); + + process->f_stdin = process->f_stdout = process->f_stderr = NULL; + +#ifdef ZPL_SYSTEM_WINDOWS + process->win32_handle = NULL; +#else + ZPL_NOT_IMPLEMENTED; +#endif +} - zpl__pr_close_file_handle(&process->in); - zpl__pr_close_file_handle(&process->out); - zpl__pr_close_file_handle(&process->err); +enum { + ZPL_PR_HANDLE_MODE_READ, + ZPL_PR_HANDLE_MODE_WRITE, + ZPL_PR_HANDLE_MODES, +}; - process->f_stdin = process->f_stdout = process->f_stderr = NULL; +void *zpl__pr_open_handle(zpl_u8 type, const char *mode, void **handle) { +#ifdef ZPL_SYSTEM_WINDOWS + void *pipes[ZPL_PR_HANDLE_MODES]; + zpl_i32 fd; + + const zpl_u32 flag_inherit = 0x00000001; + SECURITY_ATTRIBUTES sa = {zpl_size_of(sa), 0, 1}; + + if (!CreatePipe(&pipes[0], &pipes[1], cast(LPSECURITY_ATTRIBUTES)&sa, 0)) { + return NULL; + } + + if (!SetHandleInformation(pipes[type], flag_inherit, 0)) { + return NULL; + } + + fd = _open_osfhandle(cast(zpl_intptr)pipes[type], 0); + + if (fd != -1) { + *handle = pipes[1-type]; + return _fdopen(fd, mode); + } + + return NULL; +#else + ZPL_NOT_IMPLEMENTED; + return NULL; +#endif +} - #ifdef ZPL_SYSTEM_WINDOWS - process->win32_handle = NULL; - #else - ZPL_NOT_IMPLEMENTED; - #endif - } - - enum { - ZPL_PR_HANDLE_MODE_READ, - ZPL_PR_HANDLE_MODE_WRITE, - ZPL_PR_HANDLE_MODES, - }; - - void *zpl__pr_open_handle(zpl_u8 type, const char *mode, void **handle) { - #ifdef ZPL_SYSTEM_WINDOWS - void *pipes[ZPL_PR_HANDLE_MODES]; - zpl_i32 fd; - - const zpl_u32 flag_inherit = 0x00000001; - SECURITY_ATTRIBUTES sa = {zpl_size_of(sa), 0, 1}; - - if (!CreatePipe(&pipes[0], &pipes[1], cast(LPSECURITY_ATTRIBUTES)&sa, 0)) { - return NULL; - } - - if (!SetHandleInformation(pipes[type], flag_inherit, 0)) { - return NULL; - } - - fd = _open_osfhandle(cast(zpl_intptr)pipes[type], 0); - - if (fd != -1) { - *handle = pipes[1-type]; - return _fdopen(fd, mode); - } - - return NULL; - #else - ZPL_NOT_IMPLEMENTED; - return NULL; - #endif - } - - zpl_i32 zpl_pr_create(zpl_pr *process, const char **args, zpl_isize argc, zpl_pr_si si, zpl_pr_opts options) { - ZPL_ASSERT_NOT_NULL(process); - zpl_zero_item(process); - - #ifdef ZPL_SYSTEM_WINDOWS - zpl_string cli, env; - zpl_b32 c_env=false; - STARTUPINFOW psi = {0}; - PROCESS_INFORMATION pi = {0}; - zpl_i32 err_code = 0; - zpl_allocator a = zpl_heap(); - const zpl_u32 use_std_handles = 0x00000100; - - psi.cb = zpl_size_of(psi); - psi.dwFlags = use_std_handles | si.flags; - - if (options & ZPL_PR_OPTS_CUSTOM_ENV) { - env = zpl_string_join(zpl_heap(), cast(const char**)si.env, si.env_count, "\0\0"); - env = zpl_string_appendc(env, "\0"); - c_env = true; - } - else if (!(options & ZPL_PR_OPTS_INHERIT_ENV)) { - env = (zpl_string)"\0\0\0\0"; - } else { - env = (zpl_string)NULL; - } - - process->f_stdin = zpl__pr_open_handle(ZPL_PR_HANDLE_MODE_WRITE, "wb", &psi.hStdInput); - process->f_stdout = zpl__pr_open_handle(ZPL_PR_HANDLE_MODE_READ, "rb", &psi.hStdOutput); - - if (options & ZPL_PR_OPTS_COMBINE_STD_OUTPUT) { - process->f_stderr = process->f_stdout; - psi.hStdError = psi.hStdOutput; - } else { - process->f_stderr = zpl__pr_open_handle(ZPL_PR_HANDLE_MODE_READ, "rb", &psi.hStdError); - } - - cli = zpl_string_join(zpl_heap(), args, argc, " "); - - psi.dwX = si.posx; - psi.dwY = si.posy; - psi.dwXSize = si.resx; - psi.dwYSize = si.resy; - psi.dwXCountChars = si.bufx; - psi.dwYCountChars = si.bufy; - psi.dwFillAttribute = si.fill_attr; - psi.wShowWindow = si.show_window; - - wchar_t *w_cli = zpl__alloc_utf8_to_ucs2(a, cli, NULL); - wchar_t *w_workdir = zpl__alloc_utf8_to_ucs2(a, si.workdir, NULL); - - if (!CreateProcessW( - NULL, - w_cli, - NULL, - NULL, - 1, - 0, - env, - w_workdir, - cast(LPSTARTUPINFOW)&psi, - cast(LPPROCESS_INFORMATION)&pi - )) { - err_code = -1; - goto pr_free_data; - } - - process->win32_handle = pi.hProcess; - CloseHandle(pi.hThread); - - zpl_file_connect_handle(&process->in, process->f_stdin); - zpl_file_connect_handle(&process->out, process->f_stdout); - zpl_file_connect_handle(&process->err, process->f_stderr); - - pr_free_data: - zpl_string_free(cli); - zpl_free(a, w_cli); - zpl_free(a, w_workdir); - - if (c_env) - zpl_string_free(env); - - return err_code; - - #else - ZPL_NOT_IMPLEMENTED; - return -1; - #endif - } +zpl_i32 zpl_pr_create(zpl_pr *process, const char **args, zpl_isize argc, zpl_pr_si si, zpl_pr_opts options) { + ZPL_ASSERT_NOT_NULL(process); + zpl_zero_item(process); + +#ifdef ZPL_SYSTEM_WINDOWS + zpl_string cli, env; + zpl_b32 c_env=false; + STARTUPINFOW psi = {0}; + PROCESS_INFORMATION pi = {0}; + zpl_i32 err_code = 0; + zpl_allocator a = zpl_heap(); + const zpl_u32 use_std_handles = 0x00000100; + + psi.cb = zpl_size_of(psi); + psi.dwFlags = use_std_handles | si.flags; + + if (options & ZPL_PR_OPTS_CUSTOM_ENV) { + env = zpl_string_join(zpl_heap(), cast(const char**)si.env, si.env_count, "\0\0"); + env = zpl_string_appendc(env, "\0"); + c_env = true; + } + else if (!(options & ZPL_PR_OPTS_INHERIT_ENV)) { + env = (zpl_string)"\0\0\0\0"; + } else { + env = (zpl_string)NULL; + } + + process->f_stdin = zpl__pr_open_handle(ZPL_PR_HANDLE_MODE_WRITE, "wb", &psi.hStdInput); + process->f_stdout = zpl__pr_open_handle(ZPL_PR_HANDLE_MODE_READ, "rb", &psi.hStdOutput); + + if (options & ZPL_PR_OPTS_COMBINE_STD_OUTPUT) { + process->f_stderr = process->f_stdout; + psi.hStdError = psi.hStdOutput; + } else { + process->f_stderr = zpl__pr_open_handle(ZPL_PR_HANDLE_MODE_READ, "rb", &psi.hStdError); + } + + cli = zpl_string_join(zpl_heap(), args, argc, " "); + + psi.dwX = si.posx; + psi.dwY = si.posy; + psi.dwXSize = si.resx; + psi.dwYSize = si.resy; + psi.dwXCountChars = si.bufx; + psi.dwYCountChars = si.bufy; + psi.dwFillAttribute = si.fill_attr; + psi.wShowWindow = si.show_window; + + wchar_t *w_cli = zpl__alloc_utf8_to_ucs2(a, cli, NULL); + wchar_t *w_workdir = zpl__alloc_utf8_to_ucs2(a, si.workdir, NULL); + + if (!CreateProcessW( + NULL, + w_cli, + NULL, + NULL, + 1, + 0, + env, + w_workdir, + cast(LPSTARTUPINFOW)&psi, + cast(LPPROCESS_INFORMATION)&pi + )) { + err_code = -1; + goto pr_free_data; + } + + process->win32_handle = pi.hProcess; + CloseHandle(pi.hThread); + + zpl_file_connect_handle(&process->in, process->f_stdin); + zpl_file_connect_handle(&process->out, process->f_stdout); + zpl_file_connect_handle(&process->err, process->f_stderr); + + pr_free_data: + zpl_string_free(cli); + zpl_free(a, w_cli); + zpl_free(a, w_workdir); + + if (c_env) + zpl_string_free(env); + + return err_code; + +#else + ZPL_NOT_IMPLEMENTED; + return -1; +#endif +} - zpl_i32 zpl_pr_join(zpl_pr *process) { - zpl_i32 ret_code; +zpl_i32 zpl_pr_join(zpl_pr *process) { + zpl_i32 ret_code; + + ZPL_ASSERT_NOT_NULL(process); + +#ifdef ZPL_SYSTEM_WINDOWS + if (process->f_stdin) { + fclose(cast(FILE *)process->f_stdin); + } + + WaitForSingleObject(process->win32_handle, INFINITE); + + if (!GetExitCodeProcess(process->win32_handle, cast(LPDWORD)&ret_code)) { + zpl_pr_destroy(process); + return -1; + } + + zpl_pr_destroy(process); + + return ret_code; +#else + ZPL_NOT_IMPLEMENTED; + ret_code = -1; + return ret_code; +#endif +} - ZPL_ASSERT_NOT_NULL(process); +void zpl_pr_destroy(zpl_pr *process) { + ZPL_ASSERT_NOT_NULL(process); + +#ifdef ZPL_SYSTEM_WINDOWS + if (process->f_stdin) { + fclose(cast(FILE *)process->f_stdin); + } + + fclose(cast(FILE *)process->f_stdout); + + if (process->f_stderr != process->f_stdout) { + fclose(cast(FILE *)process->f_stderr); + } + + CloseHandle(process->win32_handle); + + zpl__pr_close_file_handles(process); +#else + ZPL_NOT_IMPLEMENTED; +#endif +} - #ifdef ZPL_SYSTEM_WINDOWS - if (process->f_stdin) { - fclose(cast(FILE *)process->f_stdin); - } +void zpl_pr_terminate(zpl_pr *process, zpl_i32 err_code) { + ZPL_ASSERT_NOT_NULL(process); + +#ifdef ZPL_SYSTEM_WINDOWS + TerminateProcess(process->win32_handle, cast(UINT)err_code); + zpl_pr_destroy(process); +#else + ZPL_NOT_IMPLEMENTED; +#endif +} - WaitForSingleObject(process->win32_handle, INFINITE); - - if (!GetExitCodeProcess(process->win32_handle, cast(LPDWORD)&ret_code)) { - zpl_pr_destroy(process); - return -1; - } - - zpl_pr_destroy(process); - - return ret_code; - #else - ZPL_NOT_IMPLEMENTED; - ret_code = -1; - return ret_code; - #endif - } - - void zpl_pr_destroy(zpl_pr *process) { - ZPL_ASSERT_NOT_NULL(process); - - #ifdef ZPL_SYSTEM_WINDOWS - if (process->f_stdin) { - fclose(cast(FILE *)process->f_stdin); - } - - fclose(cast(FILE *)process->f_stdout); - - if (process->f_stderr != process->f_stdout) { - fclose(cast(FILE *)process->f_stderr); - } - - CloseHandle(process->win32_handle); - - zpl__pr_close_file_handles(process); - #else - ZPL_NOT_IMPLEMENTED; - #endif - } - - void zpl_pr_terminate(zpl_pr *process, zpl_i32 err_code) { - ZPL_ASSERT_NOT_NULL(process); - - #ifdef ZPL_SYSTEM_WINDOWS - TerminateProcess(process->win32_handle, cast(UINT)err_code); - zpl_pr_destroy(process); - #else - ZPL_NOT_IMPLEMENTED; - #endif - } - - ZPL_END_C_DECLS +ZPL_END_C_DECLS #endif #if defined(ZPL_MODULE_MATH) - // file: source/math.c - - - #if defined(ZPL_COMPILER_TINYC) && defined(ZPL_NO_MATH_H) - #undef ZPL_NO_MATH_H - #endif - - #if !defined(ZPL_NO_MATH_H) - # include - #endif - - ZPL_BEGIN_C_DECLS - - //////////////////////////////////////////////////////////////// - // - // Math - // - - zpl_f32 zpl_to_radians(zpl_f32 degrees) { return degrees * ZPL_TAU / 360.0f; } - zpl_f32 zpl_to_degrees(zpl_f32 radians) { return radians * 360.0f / ZPL_TAU; } - - zpl_f32 zpl_angle_diff(zpl_f32 radians_a, zpl_f32 radians_b) { - zpl_f32 delta = zpl_mod(radians_b - radians_a, ZPL_TAU); - delta = zpl_mod(delta + 1.5f * ZPL_TAU, ZPL_TAU); - delta -= 0.5f * ZPL_TAU; - return delta; - } - - zpl_f32 zpl_copy_sign(zpl_f32 x, zpl_f32 y) { - zpl_i32 ix, iy; - zpl_f32 r; - zpl_memcopy(&ix, &x, zpl_size_of(x)); - zpl_memcopy(&iy, &y, zpl_size_of(y)); - - ix &= 0x7fffffff; - ix |= iy & 0x80000000; - zpl_memcopy(&r, &ix, zpl_size_of(ix)); - return r; - } - - zpl_f32 zpl_remainder(zpl_f32 x, zpl_f32 y) { return x - (zpl_round(x / y) * y); } - - zpl_f32 zpl_mod(zpl_f32 x, zpl_f32 y) { - zpl_f32 result; - y = zpl_abs(y); - result = zpl_remainder(zpl_abs(x), y); - if (zpl_sign(result)) result += y; - return zpl_copy_sign(result, x); - } - - zpl_f64 zpl_copy_sign64(zpl_f64 x, zpl_f64 y) { - zpl_i64 ix, iy; - zpl_f64 r; - zpl_memcopy(&ix, &x, zpl_size_of(x)); - zpl_memcopy(&iy, &y, zpl_size_of(y)); - - ix &= 0x7fffffffffffffff; - ix |= iy & 0x8000000000000000; - zpl_memcopy(&r, &ix, zpl_size_of(ix)); - return r; - } - - zpl_f64 zpl_floor64(zpl_f64 x) { return cast(zpl_f64)((x >= 0.0) ? cast(zpl_i64) x : cast(zpl_i64)(x - 0.9999999999999999)); } - zpl_f64 zpl_ceil64(zpl_f64 x) { return cast(zpl_f64)((x < 0) ? cast(zpl_i64) x : (cast(zpl_i64) x) + 1); } - zpl_f64 zpl_round64(zpl_f64 x) { return cast(zpl_f64)((x >= 0.0) ? zpl_floor64(x + 0.5) : zpl_ceil64(x - 0.5)); } - zpl_f64 zpl_remainder64(zpl_f64 x, zpl_f64 y) { return x - (zpl_round64(x / y) * y); } - zpl_f64 zpl_abs64(zpl_f64 x) { return x < 0 ? -x : x; } - zpl_f64 zpl_sign64(zpl_f64 x) { return x < 0 ? -1.0 : +1.0; } - - zpl_f64 zpl_mod64(zpl_f64 x, zpl_f64 y) { - zpl_f64 result; - y = zpl_abs64(y); - result = zpl_remainder64(zpl_abs64(x), y); - if (zpl_sign64(result)) result += y; - return zpl_copy_sign64(result, x); - } - - zpl_f32 zpl_quake_rsqrt(zpl_f32 a) { - union { - int i; - zpl_f32 f; - } t; - zpl_f32 x2; - zpl_f32 const three_halfs = 1.5f; - - x2 = a * 0.5f; - t.f = a; - t.i = 0x5f375a86 - (t.i >> 1); /* What the fuck? */ - t.f = t.f * (three_halfs - (x2 * t.f * t.f)); /* 1st iteration */ - t.f = t.f * (three_halfs - (x2 * t.f * t.f)); /* 2nd iteration, this can be removed */ - - return t.f; - } - - #if defined(ZPL_NO_MATH_H) - # if defined(_MSC_VER) - - zpl_f32 zpl_rsqrt(zpl_f32 a) { return _mm_cvtss_f32(_mm_rsqrt_ss(_mm_set_ss(a))); } - zpl_f32 zpl_sqrt(zpl_f32 a) { return _mm_cvtss_f32(_mm_sqrt_ss(_mm_set_ss(a))); }; - - zpl_f32 zpl_sin(zpl_f32 a) { - static zpl_f32 const a0 = +1.91059300966915117e-31f; - static zpl_f32 const a1 = +1.00086760103908896f; - static zpl_f32 const a2 = -1.21276126894734565e-2f; - static zpl_f32 const a3 = -1.38078780785773762e-1f; - static zpl_f32 const a4 = -2.67353392911981221e-2f; - static zpl_f32 const a5 = +2.08026600266304389e-2f; - static zpl_f32 const a6 = -3.03996055049204407e-3f; - static zpl_f32 const a7 = +1.38235642404333740e-4f; - return a0 + a * (a1 + a * (a2 + a * (a3 + a * (a4 + a * (a5 + a * (a6 + a * a7)))))); - } - - zpl_f32 zpl_cos(zpl_f32 a) { - static zpl_f32 const a0 = +1.00238601909309722f; - static zpl_f32 const a1 = -3.81919947353040024e-2f; - static zpl_f32 const a2 = -3.94382342128062756e-1f; - static zpl_f32 const a3 = -1.18134036025221444e-1f; - static zpl_f32 const a4 = +1.07123798512170878e-1f; - static zpl_f32 const a5 = -1.86637164165180873e-2f; - static zpl_f32 const a6 = +9.90140908664079833e-4f; - static zpl_f32 const a7 = -5.23022132118824778e-14f; - return a0 + a * (a1 + a * (a2 + a * (a3 + a * (a4 + a * (a5 + a * (a6 + a * a7)))))); - } - - zpl_f32 zpl_tan(zpl_f32 radians) { - zpl_f32 rr = radians * radians; - zpl_f32 a = 9.5168091e-03f; - a *= rr; - a += 2.900525e-03f; - a *= rr; - a += 2.45650893e-02f; - a *= rr; - a += 5.33740603e-02f; - a *= rr; - a += 1.333923995e-01f; - a *= rr; - a += 3.333314036e-01f; - a *= rr; - a += 1.0f; - a *= radians; - return a; - } - - zpl_f32 zpl_arcsin(zpl_f32 a) { return zpl_arctan2(a, zpl_sqrt((1.0f + a) * (1.0f - a))); } - zpl_f32 zpl_arccos(zpl_f32 a) { return zpl_arctan2(zpl_sqrt((1.0f + a) * (1.0f - a)), a); } - - zpl_f32 zpl_arctan(zpl_f32 a) { - zpl_f32 u = a * a; - zpl_f32 u2 = u * u; - zpl_f32 u3 = u2 * u; - zpl_f32 u4 = u3 * u; - zpl_f32 f = 1.0f + 0.33288950512027f * u - 0.08467922817644f * u2 + 0.03252232640125f * u3 - 0.00749305860992f * u4; - return a / f; - } - - zpl_f32 zpl_arctan2(zpl_f32 y, zpl_f32 x) { - if (zpl_abs(x) > zpl_abs(y)) { - zpl_f32 a = zpl_arctan(y / x); - if (x > 0.0f) - return a; - else - return y > 0.0f ? a + ZPL_TAU_OVER_2 : a - ZPL_TAU_OVER_2; - } else { - zpl_f32 a = zpl_arctan(x / y); - if (x > 0.0f) - return y > 0.0f ? ZPL_TAU_OVER_4 - a : -ZPL_TAU_OVER_4 - a; - else - return y > 0.0f ? ZPL_TAU_OVER_4 + a : -ZPL_TAU_OVER_4 + a; - } - } - - zpl_f32 zpl_exp(zpl_f32 a) { - union { - zpl_f32 f; - int i; - } u, v; - u.i = (int)(6051102 * a + 1056478197); - v.i = (int)(1056478197 - 6051102 * a); - return u.f / v.f; - } - - zpl_f32 zpl_log(zpl_f32 a) { - union { - zpl_f32 f; - int i; - } u = { a }; - return (u.i - 1064866805) * 8.262958405176314e-8f; /* 1 / 12102203.0; */ - } - - zpl_f32 zpl_pow(zpl_f32 a, zpl_f32 b) { - int flipped = 0, e; - zpl_f32 f, r = 1.0f; - if (b < 0) { - flipped = 1; - b = -b; - } - - e = (int)b; - f = zpl_exp(b - e); - - while (e) { - if (e & 1) r *= a; - a *= a; - e >>= 1; - } - - r *= f; - return flipped ? 1.0f / r : r; - } - - # else - - zpl_f32 zpl_rsqrt(zpl_f32 a) { return 1.0f / __builtin_sqrt(a); } - zpl_f32 zpl_sqrt(zpl_f32 a) { return __builtin_sqrt(a); } - zpl_f32 zpl_sin(zpl_f32 radians) { return __builtin_sinf(radians); } - zpl_f32 zpl_cos(zpl_f32 radians) { return __builtin_cosf(radians); } - zpl_f32 zpl_tan(zpl_f32 radians) { return __builtin_tanf(radians); } - zpl_f32 zpl_arcsin(zpl_f32 a) { return __builtin_asinf(a); } - zpl_f32 zpl_arccos(zpl_f32 a) { return __builtin_acosf(a); } - zpl_f32 zpl_arctan(zpl_f32 a) { return __builtin_atanf(a); } - zpl_f32 zpl_arctan2(zpl_f32 y, zpl_f32 x) { return __builtin_atan2f(y, x); } - - zpl_f32 zpl_exp(zpl_f32 x) { return __builtin_expf(x); } - zpl_f32 zpl_log(zpl_f32 x) { return __builtin_logf(x); } - - // TODO: Should this be zpl_exp(y * zpl_log(x)) ??? - zpl_f32 zpl_pow(zpl_f32 x, zpl_f32 y) { return __builtin_powf(x, y); } - - # endif - #else - zpl_f32 zpl_rsqrt(zpl_f32 a) { return 1.0f / sqrtf(a); } - zpl_f32 zpl_sqrt(zpl_f32 a) { return sqrtf(a); }; - zpl_f32 zpl_sin(zpl_f32 radians) { return sinf(radians); }; - zpl_f32 zpl_cos(zpl_f32 radians) { return cosf(radians); }; - zpl_f32 zpl_tan(zpl_f32 radians) { return tanf(radians); }; - zpl_f32 zpl_arcsin(zpl_f32 a) { return asinf(a); }; - zpl_f32 zpl_arccos(zpl_f32 a) { return acosf(a); }; - zpl_f32 zpl_arctan(zpl_f32 a) { return atanf(a); }; - zpl_f32 zpl_arctan2(zpl_f32 y, zpl_f32 x) { return atan2f(y, x); }; - - zpl_f32 zpl_exp(zpl_f32 x) { return expf(x); } - zpl_f32 zpl_log(zpl_f32 x) { return logf(x); } - zpl_f32 zpl_pow(zpl_f32 x, zpl_f32 y) { return powf(x, y); } - #endif - - zpl_f32 zpl_exp2(zpl_f32 x) { return zpl_exp(ZPL_LOG_TWO * x); } - zpl_f32 zpl_log2(zpl_f32 x) { return zpl_log(x) / ZPL_LOG_TWO; } - - zpl_f32 zpl_fast_exp(zpl_f32 x) { - /* NOTE: Only works in the range -1 <= x <= +1 */ - zpl_f32 e = 1.0f + x * (1.0f + x * 0.5f * (1.0f + x * 0.3333333333f * (1.0f + x * 0.25f * (1.0f + x * 0.2f)))); - return e; - } - - zpl_f32 zpl_fast_exp2(zpl_f32 x) { return zpl_fast_exp(ZPL_LOG_TWO * x); } - - zpl_f32 zpl_round(zpl_f32 x) { return (float)((x >= 0.0f) ? zpl_floor(x + 0.5f) : zpl_ceil(x - 0.5f)); } - zpl_f32 zpl_floor(zpl_f32 x) { return (float)((x >= 0.0f) ? (int)x : (int)(x - 0.9999999999999999f)); } - zpl_f32 zpl_ceil(zpl_f32 x) { return (float)((x < 0.0f) ? (int)x : ((int)x) + 1); } - - zpl_f32 zpl_half_to_float(zpl_half value) { - union { - unsigned int i; - zpl_f32 f; - } result; - int s = (value >> 15) & 0x001; - int e = (value >> 10) & 0x01f; - int m = value & 0x3ff; - - if (e == 0) { - if (m == 0) { - /* Plus or minus zero */ - result.i = (unsigned int)(s << 31); - return result.f; - } else { - /* Denormalized number */ - while (!(m & 0x00000400)) { - m <<= 1; - e -= 1; - } - - e += 1; - m &= ~0x00000400; - } - } else if (e == 31) { - if (m == 0) { - /* Positive or negative infinity */ - result.i = (unsigned int)((s << 31) | 0x7f800000); - return result.f; - } else { - /* Nan */ - result.i = (unsigned int)((s << 31) | 0x7f800000 | (m << 13)); - return result.f; - } - } - - e = e + (127 - 15); - m = m << 13; - - result.i = (unsigned int)((s << 31) | (e << 23) | m); - return result.f; - } - - zpl_half zpl_float_to_half(zpl_f32 value) { - union { - unsigned int i; - zpl_f32 f; - } v; - int i, s, e, m; - - v.f = value; - i = (int)v.i; - - s = (i >> 16) & 0x00008000; - e = ((i >> 23) & 0x000000ff) - (127 - 15); - m = i & 0x007fffff; - - if (e <= 0) { - if (e < -10) return (zpl_half)s; - m = (m | 0x00800000) >> (1 - e); - - if (m & 0x00001000) m += 0x00002000; - - return (zpl_half)(s | (m >> 13)); - } else if (e == 0xff - (127 - 15)) { - if (m == 0) { - return (zpl_half)(s | 0x7c00); /* NOTE: infinity */ - } else { - /* NOTE: NAN */ - m >>= 13; - return (zpl_half)(s | 0x7c00 | m | (m == 0)); - } - } else { - if (m & 0x00001000) { - m += 0x00002000; - if (m & 0x00800000) { - m = 0; - e += 1; - } - } - - if (e > 30) { - zpl_f32 volatile f = 1e12f; - int j; - for (j = 0; j < 10; j++) f *= f; /* NOTE: Cause overflow */ - - return (zpl_half)(s | 0x7c00); - } - - return (zpl_half)(s | (e << 10) | (m >> 13)); - } - } - - #define ZPL_VEC2_2OP(a, c, post) \ - a->x = c.x post; \ - a->y = c.y post; - - #define ZPL_VEC2_3OP(a, b, op, c, post) \ - a->x = b.x op c.x post; \ - a->y = b.y op c.y post; - - #define ZPL_VEC3_2OP(a, c, post) \ - a->x = c.x post; \ - a->y = c.y post; \ - a->z = c.z post; - - #define ZPL_VEC3_3OP(a, b, op, c, post) \ - a->x = b.x op c.x post; \ - a->y = b.y op c.y post; \ - a->z = b.z op c.z post; - - #define ZPL_VEC4_2OP(a, c, post) \ - a->x = c.x post; \ - a->y = c.y post; \ - a->z = c.z post; \ - a->w = c.w post; - - #define ZPL_VEC4_3OP(a, b, op, c, post) \ - a->x = b.x op c.x post; \ - a->y = b.y op c.y post; \ - a->z = b.z op c.z post; \ - a->w = b.w op c.w post; - - zpl_vec2 zpl_vec2f_zero(void) { - zpl_vec2 v = { 0, 0 }; - return v; - } - zpl_vec2 zpl_vec2f(zpl_f32 x, zpl_f32 y) { - zpl_vec2 v; - v.x = x; - v.y = y; - return v; - } - zpl_vec2 zpl_vec2fv(zpl_f32 x[2]) { - zpl_vec2 v; - v.x = x[0]; - v.y = x[1]; - return v; - } - - zpl_vec3 zpl_vec3f_zero(void) { - zpl_vec3 v = { 0, 0, 0 }; - return v; - } - zpl_vec3 zpl_vec3f(zpl_f32 x, zpl_f32 y, zpl_f32 z) { - zpl_vec3 v; - v.x = x; - v.y = y; - v.z = z; - return v; - } - zpl_vec3 zpl_vec3fv(zpl_f32 x[3]) { - zpl_vec3 v; - v.x = x[0]; - v.y = x[1]; - v.z = x[2]; - return v; - } - - zpl_vec4 zpl_vec4f_zero(void) { - zpl_vec4 v = { 0, 0, 0, 0 }; - return v; - } - zpl_vec4 zpl_vec4f(zpl_f32 x, zpl_f32 y, zpl_f32 z, zpl_f32 w) { - zpl_vec4 v; - v.x = x; - v.y = y; - v.z = z; - v.w = w; - return v; - } - zpl_vec4 zpl_vec4fv(zpl_f32 x[4]) { - zpl_vec4 v; - v.x = x[0]; - v.y = x[1]; - v.z = x[2]; - v.w = x[3]; - return v; - } - - zpl_f32 zpl_vec2_max(zpl_vec2 v) { return zpl_max(v.x, v.y); } - zpl_f32 zpl_vec2_side(zpl_vec2 p, zpl_vec2 q, zpl_vec2 r) { return ((q.x - p.x) * (r.y - p.y) - (r.x - p.x) * (q.y - p.y)); } - - void zpl_vec2_add(zpl_vec2 *d, zpl_vec2 v0, zpl_vec2 v1) { ZPL_VEC2_3OP(d, v0, +, v1, +0); } - void zpl_vec2_sub(zpl_vec2 *d, zpl_vec2 v0, zpl_vec2 v1) { ZPL_VEC2_3OP(d, v0, -, v1, +0); } - void zpl_vec2_mul(zpl_vec2 *d, zpl_vec2 v, zpl_f32 s) { ZPL_VEC2_2OP(d, v, *s); } - void zpl_vec2_div(zpl_vec2 *d, zpl_vec2 v, zpl_f32 s) { ZPL_VEC2_2OP(d, v, / s); } - - zpl_f32 zpl_vec3_max(zpl_vec3 v) { return zpl_max3(v.x, v.y, v.z); } - - void zpl_vec3_add(zpl_vec3 *d, zpl_vec3 v0, zpl_vec3 v1) { ZPL_VEC3_3OP(d, v0, +, v1, +0); } - void zpl_vec3_sub(zpl_vec3 *d, zpl_vec3 v0, zpl_vec3 v1) { ZPL_VEC3_3OP(d, v0, -, v1, +0); } - void zpl_vec3_mul(zpl_vec3 *d, zpl_vec3 v, zpl_f32 s) { ZPL_VEC3_2OP(d, v, *s); } - void zpl_vec3_div(zpl_vec3 *d, zpl_vec3 v, zpl_f32 s) { ZPL_VEC3_2OP(d, v, / s); } - - void zpl_vec4_add(zpl_vec4 *d, zpl_vec4 v0, zpl_vec4 v1) { ZPL_VEC4_3OP(d, v0, +, v1, +0); } - void zpl_vec4_sub(zpl_vec4 *d, zpl_vec4 v0, zpl_vec4 v1) { ZPL_VEC4_3OP(d, v0, -, v1, +0); } - void zpl_vec4_mul(zpl_vec4 *d, zpl_vec4 v, zpl_f32 s) { ZPL_VEC4_2OP(d, v, *s); } - void zpl_vec4_div(zpl_vec4 *d, zpl_vec4 v, zpl_f32 s) { ZPL_VEC4_2OP(d, v, / s); } - - void zpl_vec2_addeq(zpl_vec2 *d, zpl_vec2 v) { ZPL_VEC2_3OP(d, (*d), +, v, +0); } - void zpl_vec2_subeq(zpl_vec2 *d, zpl_vec2 v) { ZPL_VEC2_3OP(d, (*d), -, v, +0); } - void zpl_vec2_muleq(zpl_vec2 *d, zpl_f32 s) { ZPL_VEC2_2OP(d, (*d), *s); } - void zpl_vec2_diveq(zpl_vec2 *d, zpl_f32 s) { ZPL_VEC2_2OP(d, (*d), / s); } - - void zpl_vec3_addeq(zpl_vec3 *d, zpl_vec3 v) { ZPL_VEC3_3OP(d, (*d), +, v, +0); } - void zpl_vec3_subeq(zpl_vec3 *d, zpl_vec3 v) { ZPL_VEC3_3OP(d, (*d), -, v, +0); } - void zpl_vec3_muleq(zpl_vec3 *d, zpl_f32 s) { ZPL_VEC3_2OP(d, (*d), *s); } - void zpl_vec3_diveq(zpl_vec3 *d, zpl_f32 s) { ZPL_VEC3_2OP(d, (*d), / s); } - - void zpl_vec4_addeq(zpl_vec4 *d, zpl_vec4 v) { ZPL_VEC4_3OP(d, (*d), +, v, +0); } - void zpl_vec4_subeq(zpl_vec4 *d, zpl_vec4 v) { ZPL_VEC4_3OP(d, (*d), -, v, +0); } - void zpl_vec4_muleq(zpl_vec4 *d, zpl_f32 s) { ZPL_VEC4_2OP(d, (*d), *s); } - void zpl_vec4_diveq(zpl_vec4 *d, zpl_f32 s) { ZPL_VEC4_2OP(d, (*d), / s); } - - #undef ZPL_VEC2_2OP - #undef ZPL_VEC2_3OP - #undef ZPL_VEC3_3OP - #undef ZPL_VEC3_2OP - #undef ZPL_VEC4_2OP - #undef ZPL_VEC4_3OP - - zpl_f32 zpl_vec2_dot(zpl_vec2 v0, zpl_vec2 v1) { return v0.x * v1.x + v0.y * v1.y; } - zpl_f32 zpl_vec3_dot(zpl_vec3 v0, zpl_vec3 v1) { return v0.x * v1.x + v0.y * v1.y + v0.z * v1.z; } - zpl_f32 zpl_vec4_dot(zpl_vec4 v0, zpl_vec4 v1) { return v0.x * v1.x + v0.y * v1.y + v0.z * v1.z + v0.w * v1.w; } - - void zpl_vec2_cross(zpl_f32 *d, zpl_vec2 v0, zpl_vec2 v1) { *d = v0.x * v1.y - v1.x * v0.y; } - void zpl_vec3_cross(zpl_vec3 *d, zpl_vec3 v0, zpl_vec3 v1) { - d->x = v0.y * v1.z - v0.z * v1.y; - d->y = v0.z * v1.x - v0.x * v1.z; - d->z = v0.x * v1.y - v0.y * v1.x; - } - - zpl_f32 zpl_vec2_mag2(zpl_vec2 v) { return zpl_vec2_dot(v, v); } - zpl_f32 zpl_vec3_mag2(zpl_vec3 v) { return zpl_vec3_dot(v, v); } - zpl_f32 zpl_vec4_mag2(zpl_vec4 v) { return zpl_vec4_dot(v, v); } - - /* TODO: Create custom sqrt function */ - zpl_f32 zpl_vec2_mag(zpl_vec2 v) { return zpl_sqrt(zpl_vec2_dot(v, v)); } - zpl_f32 zpl_vec3_mag(zpl_vec3 v) { return zpl_sqrt(zpl_vec3_dot(v, v)); } - zpl_f32 zpl_vec4_mag(zpl_vec4 v) { return zpl_sqrt(zpl_vec4_dot(v, v)); } - - void zpl_vec2_norm(zpl_vec2 *d, zpl_vec2 v) { - zpl_f32 inv_mag = zpl_rsqrt(zpl_vec2_dot(v, v)); - zpl_vec2_mul(d, v, inv_mag); - } - void zpl_vec3_norm(zpl_vec3 *d, zpl_vec3 v) { - zpl_f32 inv_mag = zpl_rsqrt(zpl_vec3_dot(v, v)); - zpl_vec3_mul(d, v, inv_mag); - } - void zpl_vec4_norm(zpl_vec4 *d, zpl_vec4 v) { - zpl_f32 inv_mag = zpl_rsqrt(zpl_vec4_dot(v, v)); - zpl_vec4_mul(d, v, inv_mag); - } - - void zpl_vec2_norm0(zpl_vec2 *d, zpl_vec2 v) { - zpl_f32 mag = zpl_vec2_mag(v); - if (mag > 0) - zpl_vec2_div(d, v, mag); - else - *d = zpl_vec2f_zero( ); - } - void zpl_vec3_norm0(zpl_vec3 *d, zpl_vec3 v) { - zpl_f32 mag = zpl_vec3_mag(v); - if (mag > 0) - zpl_vec3_div(d, v, mag); - else - *d = zpl_vec3f_zero( ); - } - void zpl_vec4_norm0(zpl_vec4 *d, zpl_vec4 v) { - zpl_f32 mag = zpl_vec4_mag(v); - if (mag > 0) - zpl_vec4_div(d, v, mag); - else - *d = zpl_vec4f_zero( ); - } - - void zpl_vec2_reflect(zpl_vec2 *d, zpl_vec2 i, zpl_vec2 n) { - zpl_vec2 b = n; - zpl_vec2_muleq(&b, 2.0f * zpl_vec2_dot(n, i)); - zpl_vec2_sub(d, i, b); - } - - void zpl_vec3_reflect(zpl_vec3 *d, zpl_vec3 i, zpl_vec3 n) { - zpl_vec3 b = n; - zpl_vec3_muleq(&b, 2.0f * zpl_vec3_dot(n, i)); - zpl_vec3_sub(d, i, b); - } - - void zpl_vec2_refract(zpl_vec2 *d, zpl_vec2 i, zpl_vec2 n, zpl_f32 eta) { - zpl_vec2 a, b; - zpl_f32 dv, k; - - dv = zpl_vec2_dot(n, i); - k = 1.0f - eta * eta * (1.0f - dv * dv); - zpl_vec2_mul(&a, i, eta); - zpl_vec2_mul(&b, n, eta * dv * zpl_sqrt(k)); - zpl_vec2_sub(d, a, b); - zpl_vec2_muleq(d, (float)(k >= 0.0f)); - } - - void zpl_vec3_refract(zpl_vec3 *d, zpl_vec3 i, zpl_vec3 n, zpl_f32 eta) { - zpl_vec3 a, b; - zpl_f32 dv, k; - - dv = zpl_vec3_dot(n, i); - k = 1.0f - eta * eta * (1.0f - dv * dv); - zpl_vec3_mul(&a, i, eta); - zpl_vec3_mul(&b, n, eta * dv * zpl_sqrt(k)); - zpl_vec3_sub(d, a, b); - zpl_vec3_muleq(d, (float)(k >= 0.0f)); - } - - zpl_f32 zpl_vec2_aspect_ratio(zpl_vec2 v) { return (v.y < 0.0001f) ? 0.0f : v.x / v.y; } - - void zpl_mat2_transpose(zpl_mat2 *m) { zpl_float22_transpose(zpl_float22_m(m)); } - void zpl_mat2_identity(zpl_mat2 *m) { zpl_float22_identity(zpl_float22_m(m)); } - void zpl_mat2_mul(zpl_mat2 *out, zpl_mat2 *m1, zpl_mat2 *m2) { - zpl_float22_mul(zpl_float22_m(out), zpl_float22_m(m1), zpl_float22_m(m2)); - } - - void zpl_float22_identity(zpl_f32 m[2][2]) { - m[0][0] = 1; - m[0][1] = 0; - m[1][0] = 0; - m[1][1] = 1; - } - - void zpl_mat2_copy(zpl_mat2* out, zpl_mat2* m) { - zpl_memcopy(out, m, sizeof(zpl_mat3)); - } - - void zpl_mat2_mul_vec2(zpl_vec2 *out, zpl_mat2 *m, zpl_vec2 in) { zpl_float22_mul_vec2(out, zpl_float22_m(m), in); } - - zpl_mat2 *zpl_mat2_v(zpl_vec2 m[2]) { return (zpl_mat2 *)m; } - zpl_mat2 *zpl_mat2_f(zpl_f32 m[2][2]) { return (zpl_mat2 *)m; } - - zpl_float2 *zpl_float22_m(zpl_mat2 *m) { return (zpl_float2 *)m; } - zpl_float2 *zpl_float22_v(zpl_vec2 m[2]) { return (zpl_float2 *)m; } - zpl_float2 *zpl_float22_4(zpl_f32 m[4]) { return (zpl_float2 *)m; } - - void zpl_float22_transpose(zpl_f32 (*vec)[2]) { - int i, j; - for (j = 0; j < 2; j++) { - for (i = j + 1; i < 2; i++) { - zpl_f32 t = vec[i][j]; - vec[i][j] = vec[j][i]; - vec[j][i] = t; - } - } - } - - void zpl_float22_mul(zpl_f32 (*out)[2], zpl_f32 (*mat1)[2], zpl_f32 (*mat2)[2]) { - int i, j; - zpl_f32 temp1[2][2], temp2[2][2]; - if (mat1 == out) { - zpl_memcopy(temp1, mat1, sizeof(temp1)); - mat1 = temp1; - } - if (mat2 == out) { - zpl_memcopy(temp2, mat2, sizeof(temp2)); - mat2 = temp2; - } - for (j = 0; j < 2; j++) { - for (i = 0; i < 2; i++) { out[j][i] = mat1[0][i] * mat2[j][0] + mat1[1][i] * mat2[j][1]; } - } - } - - void zpl_float22_mul_vec2(zpl_vec2 *out, zpl_f32 m[2][2], zpl_vec2 v) { - out->x = m[0][0] * v.x + m[0][1] * v.y; - out->y = m[1][0] * v.x + m[1][1] * v.y; - } - - zpl_f32 zpl_mat2_determinate(zpl_mat2 *m) { - zpl_float2 *e = zpl_float22_m(m); - return e[0][0] * e[1][1] - e[1][0] * e[0][1]; - } - - void zpl_mat2_inverse(zpl_mat2 *out, zpl_mat2 *in) { - zpl_float2 *o = zpl_float22_m(out); - zpl_float2 *i = zpl_float22_m(in); - - zpl_f32 ood = 1.0f / zpl_mat2_determinate(in); - - o[0][0] = +i[1][1] * ood; - o[0][1] = -i[0][1] * ood; - o[1][0] = -i[1][0] * ood; - o[1][1] = +i[0][0] * ood; - } - - void zpl_mat3_transpose(zpl_mat3 *m) { zpl_float33_transpose(zpl_float33_m(m)); } - void zpl_mat3_identity(zpl_mat3 *m) { zpl_float33_identity(zpl_float33_m(m)); } - - void zpl_mat3_copy(zpl_mat3* out, zpl_mat3* m) { - zpl_memcopy(out, m, sizeof(zpl_mat3)); - } - - void zpl_mat3_mul(zpl_mat3 *out, zpl_mat3 *m1, zpl_mat3 *m2) { - zpl_float33_mul(zpl_float33_m(out), zpl_float33_m(m1), zpl_float33_m(m2)); - } - - void zpl_float33_identity(zpl_f32 m[3][3]) { - m[0][0] = 1; - m[0][1] = 0; - m[0][2] = 0; - m[1][0] = 0; - m[1][1] = 1; - m[1][2] = 0; - m[2][0] = 0; - m[2][1] = 0; - m[2][2] = 1; - } - - void zpl_mat3_mul_vec3(zpl_vec3 *out, zpl_mat3 *m, zpl_vec3 in) { zpl_float33_mul_vec3(out, zpl_float33_m(m), in); } - - zpl_mat3 *zpl_mat3_v(zpl_vec3 m[3]) { return (zpl_mat3 *)m; } - zpl_mat3 *zpl_mat3_f(zpl_f32 m[3][3]) { return (zpl_mat3 *)m; } - - zpl_float3 *zpl_float33_m(zpl_mat3 *m) { return (zpl_float3 *)m; } - zpl_float3 *zpl_float33_v(zpl_vec3 m[3]) { return (zpl_float3 *)m; } - zpl_float3 *zpl_float33_9(zpl_f32 m[9]) { return (zpl_float3 *)m; } - - void zpl_float33_transpose(zpl_f32 (*vec)[3]) { - int i, j; - for (j = 0; j < 3; j++) { - for (i = j + 1; i < 3; i++) { - zpl_f32 t = vec[i][j]; - vec[i][j] = vec[j][i]; - vec[j][i] = t; - } - } - } - - void zpl_float33_mul(zpl_f32 (*out)[3], zpl_f32 (*mat1)[3], zpl_f32 (*mat2)[3]) { - int i, j; - zpl_f32 temp1[3][3], temp2[3][3]; - if (mat1 == out) { - zpl_memcopy(temp1, mat1, sizeof(temp1)); - mat1 = temp1; - } - if (mat2 == out) { - zpl_memcopy(temp2, mat2, sizeof(temp2)); - mat2 = temp2; - } - for (j = 0; j < 3; j++) { - for (i = 0; i < 3; i++) { - out[j][i] = mat1[0][i] * mat2[j][0] + mat1[1][i] * mat2[j][1] + mat1[2][i] * mat2[j][2]; - } - } - } - - void zpl_float33_mul_vec3(zpl_vec3 *out, zpl_f32 m[3][3], zpl_vec3 v) { - out->x = m[0][0] * v.x + m[0][1] * v.y + m[0][2] * v.z; - out->y = m[1][0] * v.x + m[1][1] * v.y + m[1][2] * v.z; - out->z = m[2][0] * v.x + m[2][1] * v.y + m[2][2] * v.z; - } - - zpl_f32 zpl_mat3_determinate(zpl_mat3 *m) { - zpl_float3 *e = zpl_float33_m(m); - zpl_f32 d = - +e[0][0] * (e[1][1] * e[2][2] - e[1][2] * e[2][1]) - -e[0][1] * (e[1][0] * e[2][2] - e[1][2] * e[2][0]) - +e[0][2] * (e[1][0] * e[2][1] - e[1][1] * e[2][0]); - return d; - } - - void zpl_mat3_inverse(zpl_mat3 *out, zpl_mat3 *in) { - zpl_float3 *o = zpl_float33_m(out); - zpl_float3 *i = zpl_float33_m(in); - - zpl_f32 ood = 1.0f / zpl_mat3_determinate(in); - - o[0][0] = +(i[1][1] * i[2][2] - i[2][1] * i[1][2]) * ood; - o[0][1] = -(i[1][0] * i[2][2] - i[2][0] * i[1][2]) * ood; - o[0][2] = +(i[1][0] * i[2][1] - i[2][0] * i[1][1]) * ood; - o[1][0] = -(i[0][1] * i[2][2] - i[2][1] * i[0][2]) * ood; - o[1][1] = +(i[0][0] * i[2][2] - i[2][0] * i[0][2]) * ood; - o[1][2] = -(i[0][0] * i[2][1] - i[2][0] * i[0][1]) * ood; - o[2][0] = +(i[0][1] * i[1][2] - i[1][1] * i[0][2]) * ood; - o[2][1] = -(i[0][0] * i[1][2] - i[1][0] * i[0][2]) * ood; - o[2][2] = +(i[0][0] * i[1][1] - i[1][0] * i[0][1]) * ood; - } - - void zpl_mat4_transpose(zpl_mat4 *m) { zpl_float44_transpose(zpl_float44_m(m)); } - void zpl_mat4_identity(zpl_mat4 *m) { zpl_float44_identity(zpl_float44_m(m)); } - - void zpl_mat4_copy(zpl_mat4* out, zpl_mat4* m) { - zpl_memcopy(out, m, sizeof(zpl_mat4)); - } - - - void zpl_mat4_mul(zpl_mat4 *out, zpl_mat4 *m1, zpl_mat4 *m2) { - zpl_float44_mul(zpl_float44_m(out), zpl_float44_m(m1), zpl_float44_m(m2)); - } - - void zpl_float44_identity(zpl_f32 m[4][4]) { - m[0][0] = 1; - m[0][1] = 0; - m[0][2] = 0; - m[0][3] = 0; - m[1][0] = 0; - m[1][1] = 1; - m[1][2] = 0; - m[1][3] = 0; - m[2][0] = 0; - m[2][1] = 0; - m[2][2] = 1; - m[2][3] = 0; - m[3][0] = 0; - m[3][1] = 0; - m[3][2] = 0; - m[3][3] = 1; - } - - void zpl_mat4_mul_vec4(zpl_vec4 *out, zpl_mat4 *m, zpl_vec4 in) { zpl_float44_mul_vec4(out, zpl_float44_m(m), in); } - - zpl_mat4 *zpl_mat4_v(zpl_vec4 m[4]) { return (zpl_mat4 *)m; } - zpl_mat4 *zpl_mat4_f(zpl_f32 m[4][4]) { return (zpl_mat4 *)m; } - - zpl_float4 *zpl_float44_m(zpl_mat4 *m) { return (zpl_float4 *)m; } - zpl_float4 *zpl_float44_v(zpl_vec4 m[4]) { return (zpl_float4 *)m; } - zpl_float4 *zpl_float44_16(zpl_f32 m[16]) { return (zpl_float4 *)m; } - - void zpl_float44_transpose(zpl_f32 (*vec)[4]) { - zpl_f32 tmp; - tmp = vec[1][0]; - vec[1][0] = vec[0][1]; - vec[0][1] = tmp; - tmp = vec[2][0]; - vec[2][0] = vec[0][2]; - vec[0][2] = tmp; - tmp = vec[3][0]; - vec[3][0] = vec[0][3]; - vec[0][3] = tmp; - tmp = vec[2][1]; - vec[2][1] = vec[1][2]; - vec[1][2] = tmp; - tmp = vec[3][1]; - vec[3][1] = vec[1][3]; - vec[1][3] = tmp; - tmp = vec[3][2]; - vec[3][2] = vec[2][3]; - vec[2][3] = tmp; - } - - void zpl_float44_mul(zpl_f32 (*out)[4], zpl_f32 (*mat1)[4], zpl_f32 (*mat2)[4]) { - int i, j; - zpl_f32 temp1[4][4], temp2[4][4]; - if (mat1 == out) { - zpl_memcopy(temp1, mat1, sizeof(temp1)); - mat1 = temp1; - } - if (mat2 == out) { - zpl_memcopy(temp2, mat2, sizeof(temp2)); - mat2 = temp2; - } - for (j = 0; j < 4; j++) { - for (i = 0; i < 4; i++) { - out[j][i] = - mat1[0][i] * mat2[j][0] + mat1[1][i] * mat2[j][1] - +mat1[2][i] * mat2[j][2] + mat1[3][i] * mat2[j][3]; - } - } - } - - void zpl_float44_mul_vec4(zpl_vec4 *out, zpl_f32 m[4][4], zpl_vec4 v) { - out->x = m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z + m[3][0] * v.w; - out->y = m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z + m[3][1] * v.w; - out->z = m[0][2] * v.x + m[1][2] * v.y + m[2][2] * v.z + m[3][2] * v.w; - out->w = m[0][3] * v.x + m[1][3] * v.y + m[2][3] * v.z + m[3][3] * v.w; - } - - void zpl_mat4_inverse(zpl_mat4 *out, zpl_mat4 *in) { - zpl_float4 *o = zpl_float44_m(out); - zpl_float4 *m = zpl_float44_m(in); - - zpl_f32 ood; - - zpl_f32 sf00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; - zpl_f32 sf01 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; - zpl_f32 sf02 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; - zpl_f32 sf03 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; - zpl_f32 sf04 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; - zpl_f32 sf05 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; - zpl_f32 sf06 = m[1][2] * m[3][3] - m[3][2] * m[1][3]; - zpl_f32 sf07 = m[1][1] * m[3][3] - m[3][1] * m[1][3]; - zpl_f32 sf08 = m[1][1] * m[3][2] - m[3][1] * m[1][2]; - zpl_f32 sf09 = m[1][0] * m[3][3] - m[3][0] * m[1][3]; - zpl_f32 sf10 = m[1][0] * m[3][2] - m[3][0] * m[1][2]; - zpl_f32 sf11 = m[1][1] * m[3][3] - m[3][1] * m[1][3]; - zpl_f32 sf12 = m[1][0] * m[3][1] - m[3][0] * m[1][1]; - zpl_f32 sf13 = m[1][2] * m[2][3] - m[2][2] * m[1][3]; - zpl_f32 sf14 = m[1][1] * m[2][3] - m[2][1] * m[1][3]; - zpl_f32 sf15 = m[1][1] * m[2][2] - m[2][1] * m[1][2]; - zpl_f32 sf16 = m[1][0] * m[2][3] - m[2][0] * m[1][3]; - zpl_f32 sf17 = m[1][0] * m[2][2] - m[2][0] * m[1][2]; - zpl_f32 sf18 = m[1][0] * m[2][1] - m[2][0] * m[1][1]; - - o[0][0] = +(m[1][1] * sf00 - m[1][2] * sf01 + m[1][3] * sf02); - o[1][0] = -(m[1][0] * sf00 - m[1][2] * sf03 + m[1][3] * sf04); - o[2][0] = +(m[1][0] * sf01 - m[1][1] * sf03 + m[1][3] * sf05); - o[3][0] = -(m[1][0] * sf02 - m[1][1] * sf04 + m[1][2] * sf05); - - o[0][1] = -(m[0][1] * sf00 - m[0][2] * sf01 + m[0][3] * sf02); - o[1][1] = +(m[0][0] * sf00 - m[0][2] * sf03 + m[0][3] * sf04); - o[2][1] = -(m[0][0] * sf01 - m[0][1] * sf03 + m[0][3] * sf05); - o[3][1] = +(m[0][0] * sf02 - m[0][1] * sf04 + m[0][2] * sf05); - - o[0][2] = +(m[0][1] * sf06 - m[0][2] * sf07 + m[0][3] * sf08); - o[1][2] = -(m[0][0] * sf06 - m[0][2] * sf09 + m[0][3] * sf10); - o[2][2] = +(m[0][0] * sf11 - m[0][1] * sf09 + m[0][3] * sf12); - o[3][2] = -(m[0][0] * sf08 - m[0][1] * sf10 + m[0][2] * sf12); - - o[0][3] = -(m[0][1] * sf13 - m[0][2] * sf14 + m[0][3] * sf15); - o[1][3] = +(m[0][0] * sf13 - m[0][2] * sf16 + m[0][3] * sf17); - o[2][3] = -(m[0][0] * sf14 - m[0][1] * sf16 + m[0][3] * sf18); - o[3][3] = +(m[0][0] * sf15 - m[0][1] * sf17 + m[0][2] * sf18); - - ood = 1.0f / (m[0][0] * o[0][0] + m[0][1] * o[1][0] + m[0][2] * o[2][0] + m[0][3] * o[3][0]); - - o[0][0] *= ood; o[1][0] *= ood; o[2][0] *= ood; o[3][0] *= ood; - o[0][1] *= ood; o[1][1] *= ood; o[2][1] *= ood; o[3][1] *= ood; - o[0][2] *= ood; o[1][2] *= ood; o[2][2] *= ood; o[3][2] *= ood; - o[0][3] *= ood; o[1][3] *= ood; o[2][3] *= ood; o[3][3] *= ood; - } - - void zpl_mat4_axis_angle(zpl_mat4 *out, zpl_vec3 v, zpl_f32 angle_radians) { - zpl_f32 c, s; - zpl_vec3 axis, t; - zpl_float4 *rot; - - c = zpl_cos(angle_radians); - s = zpl_sin(angle_radians); - - zpl_vec3_norm(&axis, v); - zpl_vec3_mul(&t, axis, 1.0f - c); - - zpl_mat4_identity(out); - rot = zpl_float44_m(out); - - rot[0][0] = c + t.x * axis.x; - rot[0][1] = 0 + t.x * axis.y + s * axis.z; - rot[0][2] = 0 + t.x * axis.z - s * axis.y; - rot[0][3] = 0; - - rot[1][0] = 0 + t.y * axis.x - s * axis.z; - rot[1][1] = c + t.y * axis.y; - rot[1][2] = 0 + t.y * axis.z + s * axis.x; - rot[1][3] = 0; - - rot[2][0] = 0 + t.z * axis.x + s * axis.y; - rot[2][1] = 0 + t.z * axis.y - s * axis.x; - rot[2][2] = c + t.z * axis.z; - rot[2][3] = 0; - } - - void zpl_mat4_to_translate(zpl_mat4* out, zpl_vec3 v) { - zpl_mat4_identity(out); - out->col[3].xyz = v; - } - - void zpl_mat4_to_rotate(zpl_mat4* out, zpl_vec3 v, zpl_f32 angle_radians) { - zpl_mat4_axis_angle(out, v, angle_radians); - } - - void zpl_mat4_to_scale(zpl_mat4* out, zpl_vec3 v) { - zpl_mat4_identity(out); - out->col[0].x = v.x; - out->col[1].y = v.y; - out->col[2].z = v.z; - } - void zpl_mat4_to_scalef(zpl_mat4* out, zpl_f32 s) { - zpl_mat4_identity(out); - out->col[0].x = s; - out->col[1].y = s; - out->col[2].z = s; - } - - void zpl_mat4_translate(zpl_mat4* m, zpl_vec3 v) { - zpl_mat4 mm; - zpl_mat4_to_translate(&mm, v); - zpl_mat4_mul(m, m, &mm); - } - - void zpl_mat4_rotate(zpl_mat4* m, zpl_vec3 v, zpl_f32 angle_radians) { - zpl_mat4 mm; - zpl_mat4_axis_angle(&mm,v, angle_radians); - zpl_mat4_mul(m, m, &mm); - } - - void zpl_mat4_scale(zpl_mat4* m, zpl_vec3 v) { - zpl_mat4 mm; - zpl_mat4_to_scale(&mm, v); - zpl_mat4_mul(m, m, &mm); - } - - void zpl_mat4_scalef(zpl_mat4* m, zpl_f32 s) { - zpl_mat4 mm; - zpl_mat4_to_scalef(&mm, s); - zpl_mat4_mul(m, m, &mm); - } - - void zpl_mat4_ortho2d(zpl_mat4 *out, zpl_f32 left, zpl_f32 right, zpl_f32 bottom, zpl_f32 top) { - zpl_float4 *m; - zpl_mat4_identity(out); - m = zpl_float44_m(out); - - m[0][0] = 2.0f / (right - left); - m[1][1] = 2.0f / (top - bottom); - m[2][2] = -1.0f; - m[3][0] = -(right + left) / (right - left); - m[3][1] = -(top + bottom) / (top - bottom); - } - - void zpl_mat4_ortho3d(zpl_mat4 *out, zpl_f32 left, zpl_f32 right, zpl_f32 bottom, zpl_f32 top, zpl_f32 z_near, zpl_f32 z_far) { - zpl_float4 *m; - zpl_mat4_identity(out); - m = zpl_float44_m(out); - - m[0][0] = +2.0f / (right - left); - m[1][1] = +2.0f / (top - bottom); - m[2][2] = -2.0f / (z_far - z_near); - m[3][0] = -(right + left) / (right - left); - m[3][1] = -(top + bottom) / (top - bottom); - m[3][2] = -(z_far + z_near) / (z_far - z_near); - } - - void zpl_mat4_perspective(zpl_mat4 *out, zpl_f32 fovy, zpl_f32 aspect, zpl_f32 z_near, zpl_f32 z_far) { - zpl_f32 tan_half_fovy = zpl_tan(0.5f * fovy); - zpl_mat4 zero_mat = { 0 }; - zpl_float4 *m = zpl_float44_m(out); - *out = zero_mat; - - m[0][0] = 1.0f / (aspect * tan_half_fovy); - m[1][1] = 1.0f / (tan_half_fovy); - m[2][2] = -(z_far + z_near) / (z_far - z_near); - m[2][3] = -1.0f; - m[3][2] = -2.0f * z_far * z_near / (z_far - z_near); - } - - void zpl_mat4_infinite_perspective(zpl_mat4 *out, zpl_f32 fovy, zpl_f32 aspect, zpl_f32 z_near) { - zpl_f32 range = zpl_tan(0.5f * fovy) * z_near; - zpl_f32 left = -range * aspect; - zpl_f32 right = range * aspect; - zpl_f32 bottom = -range; - zpl_f32 top = range; - zpl_mat4 zero_mat = { 0 }; - zpl_float4 *m = zpl_float44_m(out); - *out = zero_mat; - - m[0][0] = (2.0f * z_near) / (right - left); - m[1][1] = (2.0f * z_near) / (top - bottom); - m[2][2] = -1.0f; - m[2][3] = -1.0f; - m[3][2] = -2.0f * z_near; - } - - void zpl_mat4_ortho2d_dx(zpl_mat4 *out, zpl_f32 left, zpl_f32 right, zpl_f32 bottom, zpl_f32 top) { - zpl_float4 *m; - zpl_mat4_identity(out); - m = zpl_float44_m(out); - - m[0][0] = 2.0f / (right - left); - m[1][1] = 2.0f / (top - bottom); - m[2][2] = -1.0f; - m[3][0] = -(right + left) / (right - left); - m[3][1] = -(top + bottom) / (top - bottom); - } - - void zpl_mat4_ortho3d_dx(zpl_mat4 *out, zpl_f32 left, zpl_f32 right, zpl_f32 bottom, zpl_f32 top, zpl_f32 z_near, zpl_f32 z_far) { - zpl_float4 *m; - zpl_mat4_identity(out); - m = zpl_float44_m(out); - - m[0][0] = +2.0f / (right - left); - m[1][1] = +2.0f / (top - bottom); - m[2][2] = -1.0f / (z_far - z_near); - m[3][0] = -(right + left) / (right - left); - m[3][1] = -(top + bottom) / (top - bottom); - m[3][2] = -( z_near) / (z_far - z_near); - } - - void zpl_mat4_perspective_dx(zpl_mat4 *out, zpl_f32 fovy, zpl_f32 aspect, zpl_f32 z_near, zpl_f32 z_far) { - zpl_f32 tan_half_fovy = zpl_tan(0.5f * fovy); - zpl_mat4 zero_mat = { 0 }; - zpl_float4 *m = zpl_float44_m(out); - *out = zero_mat; - - m[0][0] = 1.0f / (aspect * tan_half_fovy); - m[1][1] = 1.0f / (tan_half_fovy); - m[2][2] = -(z_far ) / (z_far - z_near); - m[2][3] = -1.0f; - m[3][2] = - z_near / (z_far - z_near); - } - - void zpl_mat4_infinite_perspective_dx(zpl_mat4 *out, zpl_f32 fovy, zpl_f32 aspect, zpl_f32 z_near) { - zpl_f32 tan_half_fovy = zpl_tan(0.5f * fovy); - zpl_mat4 zero_mat = { 0 }; - zpl_float4 *m = zpl_float44_m(out); - *out = zero_mat; - - m[0][0] = 1.0f / (aspect * tan_half_fovy); - m[1][1] = 1.0f / (tan_half_fovy); - m[2][2] = -1.0f; - m[2][3] = -1.0f; - m[3][2] = - z_near; - } - - - - void zpl_mat4_look_at(zpl_mat4 *out, zpl_vec3 eye, zpl_vec3 centre, zpl_vec3 up) { - zpl_vec3 f, s, u; - zpl_float4 *m; - - zpl_vec3_sub(&f, centre, eye); - zpl_vec3_norm(&f, f); - - zpl_vec3_cross(&s, f, up); - zpl_vec3_norm(&s, s); - - zpl_vec3_cross(&u, s, f); - - zpl_mat4_identity(out); - m = zpl_float44_m(out); - - m[0][0] = +s.x; - m[1][0] = +s.y; - m[2][0] = +s.z; - - m[0][1] = +u.x; - m[1][1] = +u.y; - m[2][1] = +u.z; - - m[0][2] = -f.x; - m[1][2] = -f.y; - m[2][2] = -f.z; - - m[3][0] = -zpl_vec3_dot(s, eye); - m[3][1] = -zpl_vec3_dot(u, eye); - m[3][2] = +zpl_vec3_dot(f, eye); - } - - void zpl_mat4_look_at_lh(zpl_mat4 *out, zpl_vec3 eye, zpl_vec3 centre, zpl_vec3 up) { - zpl_vec3 f, s, u; - zpl_float4 *m; - - zpl_vec3_sub(&f, centre, eye); - zpl_vec3_norm(&f, f); - - zpl_vec3_cross(&s, up, f); - zpl_vec3_norm(&s, s); - - zpl_vec3_cross(&u, f, s); - - zpl_mat4_identity(out); - m = zpl_float44_m(out); - - m[0][0] = +s.x; - m[1][0] = +s.y; - m[2][0] = +s.z; - - m[0][1] = +u.x; - m[1][1] = +u.y; - m[2][1] = +u.z; - - m[0][2] = +f.x; - m[1][2] = +f.y; - m[2][2] = +f.z; - - m[3][0] = -zpl_vec3_dot(s, eye); - m[3][1] = -zpl_vec3_dot(u, eye); - m[3][2] = -zpl_vec3_dot(f, eye); - } - - zpl_quat zpl_quatf(zpl_f32 x, zpl_f32 y, zpl_f32 z, zpl_f32 w) { - zpl_quat q; - q.x = x; - q.y = y; - q.z = z; - q.w = w; - return q; - } - zpl_quat zpl_quatfv(zpl_f32 e[4]) { - zpl_quat q; - q.x = e[0]; - q.y = e[1]; - q.z = e[2]; - q.w = e[3]; - return q; - } - - zpl_quat zpl_quat_axis_angle(zpl_vec3 axis, zpl_f32 angle_radians) { - zpl_quat q; - zpl_vec3_norm(&q.xyz, axis); - zpl_vec3_muleq(&q.xyz, zpl_sin(0.5f * angle_radians)); - q.w = zpl_cos(0.5f * angle_radians); - return q; - } - - zpl_quat zpl_quat_euler_angles(zpl_f32 pitch, zpl_f32 yaw, zpl_f32 roll) { - /* TODO: Do without multiplication, i.e. make it faster */ - zpl_quat q, p, y, r; - p = zpl_quat_axis_angle(zpl_vec3f(1, 0, 0), pitch); - y = zpl_quat_axis_angle(zpl_vec3f(0, 1, 0), yaw); - r = zpl_quat_axis_angle(zpl_vec3f(0, 0, 1), roll); - - zpl_quat_mul(&q, y, p); - zpl_quat_muleq(&q, r); - - return q; - } - - zpl_quat zpl_quat_identity(void) { - zpl_quat q = { 0, 0, 0, 1 }; - return q; - } - - void zpl_quat_add(zpl_quat *d, zpl_quat q0, zpl_quat q1) { zpl_vec4_add(&d->xyzw, q0.xyzw, q1.xyzw); } - void zpl_quat_sub(zpl_quat *d, zpl_quat q0, zpl_quat q1) { zpl_vec4_sub(&d->xyzw, q0.xyzw, q1.xyzw); } - - void zpl_quat_mul(zpl_quat *d, zpl_quat q0, zpl_quat q1) { - d->x = q0.w * q1.x + q0.x * q1.w + q0.y * q1.z - q0.z * q1.y; - d->y = q0.w * q1.y - q0.x * q1.z + q0.y * q1.w + q0.z * q1.x; - d->z = q0.w * q1.z + q0.x * q1.y - q0.y * q1.x + q0.z * q1.w; - d->w = q0.w * q1.w - q0.x * q1.x - q0.y * q1.y - q0.z * q1.z; - } - - void zpl_quat_div(zpl_quat *d, zpl_quat q0, zpl_quat q1) { - zpl_quat iq1; - zpl_quat_inverse(&iq1, q1); - zpl_quat_mul(d, q0, iq1); - } - - void zpl_quat_mulf(zpl_quat *d, zpl_quat q0, zpl_f32 s) { zpl_vec4_mul(&d->xyzw, q0.xyzw, s); } - void zpl_quat_divf(zpl_quat *d, zpl_quat q0, zpl_f32 s) { zpl_vec4_div(&d->xyzw, q0.xyzw, s); } - - void zpl_quat_addeq(zpl_quat *d, zpl_quat q) { zpl_vec4_addeq(&d->xyzw, q.xyzw); } - void zpl_quat_subeq(zpl_quat *d, zpl_quat q) { zpl_vec4_subeq(&d->xyzw, q.xyzw); } - void zpl_quat_muleq(zpl_quat *d, zpl_quat q) { zpl_quat_mul(d, *d, q); } - void zpl_quat_diveq(zpl_quat *d, zpl_quat q) { zpl_quat_div(d, *d, q); } - - void zpl_quat_muleqf(zpl_quat *d, zpl_f32 s) { zpl_vec4_muleq(&d->xyzw, s); } - void zpl_quat_diveqf(zpl_quat *d, zpl_f32 s) { zpl_vec4_diveq(&d->xyzw, s); } - - zpl_f32 zpl_quat_dot(zpl_quat q0, zpl_quat q1) { - zpl_f32 r = zpl_vec3_dot(q0.xyz, q1.xyz) + q0.w * q1.w; - return r; - } - zpl_f32 zpl_quat_mag(zpl_quat q) { - zpl_f32 r = zpl_sqrt(zpl_quat_dot(q, q)); - return r; - } - - void zpl_quat_norm(zpl_quat *d, zpl_quat q) { zpl_quat_divf(d, q, zpl_quat_mag(q)); } - - void zpl_quat_conj(zpl_quat *d, zpl_quat q) { - d->xyz = zpl_vec3f(-q.x, -q.y, -q.z); - d->w = q.w; - } - void zpl_quat_inverse(zpl_quat *d, zpl_quat q) { - zpl_quat_conj(d, q); - zpl_quat_diveqf(d, zpl_quat_dot(q, q)); - } - - void zpl_quat_axis(zpl_vec3 *axis, zpl_quat q) { - zpl_quat n; - zpl_quat_norm(&n, q); - zpl_vec3_div(axis, n.xyz, zpl_sin(zpl_arccos(q.w))); - } - - zpl_f32 zpl_quat_angle(zpl_quat q) { - zpl_f32 mag = zpl_quat_mag(q); - zpl_f32 c = q.w * (1.0f / mag); - zpl_f32 angle = 2.0f * zpl_arccos(c); - return angle; - } - - zpl_f32 zpl_quat_roll(zpl_quat q) { - return zpl_arctan2(2.0f * q.x * q.y + q.z * q.w, q.x * q.x + q.w * q.w - q.y * q.y - q.z * q.z); - } - zpl_f32 zpl_quat_pitch(zpl_quat q) { - return zpl_arctan2(2.0f * q.y * q.z + q.w * q.x, q.w * q.w - q.x * q.x - q.y * q.y + q.z * q.z); - } - zpl_f32 zpl_quat_yaw(zpl_quat q) { return zpl_arcsin(-2.0f * (q.x * q.z - q.w * q.y)); } - - void zpl_quat_rotate_vec3(zpl_vec3 *d, zpl_quat q, zpl_vec3 v) { - /* zpl_vec3 t = 2.0f * cross(q.xyz, v); - * *d = q.w*t + v + cross(q.xyz, t); - */ - zpl_vec3 t, p; - zpl_vec3_cross(&t, q.xyz, v); - zpl_vec3_muleq(&t, 2.0f); - - zpl_vec3_cross(&p, q.xyz, t); - - zpl_vec3_mul(d, t, q.w); - zpl_vec3_addeq(d, v); - zpl_vec3_addeq(d, p); - } - - void zpl_mat4_from_quat(zpl_mat4 *out, zpl_quat q) { - zpl_float4 *m; - zpl_quat a; - zpl_f32 xx, yy, zz, xy, xz, yz, wx, wy, wz; - - zpl_quat_norm(&a, q); - xx = a.x * a.x; - yy = a.y * a.y; - zz = a.z * a.z; - xy = a.x * a.y; - xz = a.x * a.z; - yz = a.y * a.z; - wx = a.w * a.x; - wy = a.w * a.y; - wz = a.w * a.z; - - zpl_mat4_identity(out); - m = zpl_float44_m(out); - - m[0][0] = 1.0f - 2.0f * (yy + zz); - m[0][1] = 2.0f * (xy + wz); - m[0][2] = 2.0f * (xz - wy); - - m[1][0] = 2.0f * (xy - wz); - m[1][1] = 1.0f - 2.0f * (xx + zz); - m[1][2] = 2.0f * (yz + wx); - - m[2][0] = 2.0f * (xz + wy); - m[2][1] = 2.0f * (yz - wx); - m[2][2] = 1.0f - 2.0f * (xx + yy); - } - - void zpl_quat_from_mat4(zpl_quat *out, zpl_mat4 *mat) { - zpl_float4 *m; - zpl_f32 four_x_squared_minus_1, four_y_squared_minus_1, four_z_squared_minus_1, four_w_squared_minus_1, - four_biggest_squared_minus_1; - int biggest_index = 0; - zpl_f32 biggest_value, mult; - - m = zpl_float44_m(mat); - - four_x_squared_minus_1 = m[0][0] - m[1][1] - m[2][2]; - four_y_squared_minus_1 = m[1][1] - m[0][0] - m[2][2]; - four_z_squared_minus_1 = m[2][2] - m[0][0] - m[1][1]; - four_w_squared_minus_1 = m[0][0] + m[1][1] + m[2][2]; - - four_biggest_squared_minus_1 = four_w_squared_minus_1; - if (four_x_squared_minus_1 > four_biggest_squared_minus_1) { - four_biggest_squared_minus_1 = four_x_squared_minus_1; - biggest_index = 1; - } - if (four_y_squared_minus_1 > four_biggest_squared_minus_1) { - four_biggest_squared_minus_1 = four_y_squared_minus_1; - biggest_index = 2; - } - if (four_z_squared_minus_1 > four_biggest_squared_minus_1) { - four_biggest_squared_minus_1 = four_z_squared_minus_1; - biggest_index = 3; - } - - biggest_value = zpl_sqrt(four_biggest_squared_minus_1 + 1.0f) * 0.5f; - mult = 0.25f / biggest_value; - - switch (biggest_index) { - case 0: - out->w = biggest_value; - out->x = (m[1][2] - m[2][1]) * mult; - out->y = (m[2][0] - m[0][2]) * mult; - out->z = (m[0][1] - m[1][0]) * mult; - break; - case 1: - out->w = (m[1][2] - m[2][1]) * mult; - out->x = biggest_value; - out->y = (m[0][1] + m[1][0]) * mult; - out->z = (m[2][0] + m[0][2]) * mult; - break; - case 2: - out->w = (m[2][0] - m[0][2]) * mult; - out->x = (m[0][1] + m[1][0]) * mult; - out->y = biggest_value; - out->z = (m[1][2] + m[2][1]) * mult; - break; - case 3: - out->w = (m[0][1] - m[1][0]) * mult; - out->x = (m[2][0] + m[0][2]) * mult; - out->y = (m[1][2] + m[2][1]) * mult; - out->z = biggest_value; - break; - } - } - - zpl_f32 zpl_plane_distance(zpl_plane* p, zpl_vec3 v) { - return (p->a * v.x + p->b * v.y + p->c * v.z + p->d); - } - - void zpl_frustum_create(zpl_frustum* out, zpl_mat4* camera, zpl_mat4* proj) { - zpl_mat4 pv; - - zpl_mat4_mul(&pv, camera, proj); - - zpl_plane* fp = 0; - zpl_f32 rmag; - - fp = &out->x1; - fp->a = pv.x.w + pv.x.x; - fp->b = pv.y.w + pv.x.y; - fp->c = pv.z.w + pv.x.z; - fp->d = pv.w.w + pv.x.w; - - rmag = zpl_rsqrt(zpl_square(fp->a) + zpl_square(fp->b) + zpl_square(fp->c)); - - fp->a *= rmag; - fp->b *= rmag; - fp->c *= rmag; - fp->d *= rmag; - - fp = &out->x2; - - fp->a = pv.x.w - pv.x.x; - fp->b = pv.y.w - pv.x.y; - fp->c = pv.z.w - pv.x.z; - fp->d = pv.w.w - pv.x.w; - - rmag = zpl_rsqrt(zpl_square(fp->a) + zpl_square(fp->b) + zpl_square(fp->c)); - - fp->a *= rmag; - fp->b *= rmag; - fp->c *= rmag; - fp->d *= rmag; - - fp = &out->y1; - - fp->a = pv.x.w - pv.y.x; - fp->b = pv.y.w - pv.y.y; - fp->c = pv.z.w - pv.y.w; - fp->d = pv.w.w - pv.y.z; - - rmag = zpl_rsqrt(zpl_square(fp->a) + zpl_square(fp->b) + zpl_square(fp->c)); - - fp->a *= rmag; - fp->b *= rmag; - fp->c *= rmag; - fp->d *= rmag; - - fp = &out->y2; - - fp->a = pv.x.w + pv.y.x; - fp->b = pv.y.w + pv.y.y; - fp->c = pv.z.w + pv.y.z; - fp->d = pv.w.w + pv.y.w; - - rmag = zpl_rsqrt(zpl_square(fp->a) + zpl_square(fp->b) + zpl_square(fp->c)); - - fp->a *= rmag; - fp->b *= rmag; - fp->c *= rmag; - fp->d *= rmag;; - - fp = &out->z1; - - fp->a = pv.x.w + pv.z.x; - fp->b = pv.y.w + pv.z.y; - fp->c = pv.z.w + pv.z.z; - fp->d = pv.w.w + pv.z.w; - - rmag = zpl_rsqrt(zpl_square(fp->a) + zpl_square(fp->b) + zpl_square(fp->c)); - - fp->a *= rmag; - fp->b *= rmag; - fp->c *= rmag; - fp->d *= rmag; - - fp = &out->z2; - - fp->a = pv.x.w - pv.z.x; - fp->b = pv.y.w - pv.z.y; - fp->c = pv.z.w - pv.z.z; - fp->d = pv.w.w - pv.z.w; - - rmag = zpl_rsqrt(zpl_square(fp->a) + zpl_square(fp->b) + zpl_square(fp->c)); - - fp->a *= rmag; - fp->b *= rmag; - fp->c *= rmag; - fp->d *= rmag; - } - - zpl_b8 zpl_frustum_sphere_inside(zpl_frustum* frustum, zpl_vec3 center, zpl_f32 radius) { - if (zpl_plane_distance(&frustum->x1, center) <= -radius) return 0; - if (zpl_plane_distance(&frustum->x2, center) <= -radius) return 0; - if (zpl_plane_distance(&frustum->y1, center) <= -radius) return 0; - if (zpl_plane_distance(&frustum->y2, center) <= -radius) return 0; - if (zpl_plane_distance(&frustum->z1, center) <= -radius) return 0; - if (zpl_plane_distance(&frustum->z2, center) <= -radius) return 0; - - return 1; - } - - zpl_b8 zpl_frustum_point_inside(zpl_frustum* frustum, zpl_vec3 point) { - return zpl_frustum_sphere_inside(frustum, point, 0.0f); - } - - zpl_b8 zpl_frustum_box_inside(zpl_frustum* frustum, zpl_aabb3 aabb) { - zpl_vec3 box, center; - zpl_vec3 v, b; - zpl_vec3_sub(&box, aabb.max, aabb.min); - zpl_vec3_diveq(&box, 2.0f); - zpl_vec3_add(¢er, aabb.min, box); - - b = zpl_vec3f(-box.x, -box.y, -box.z); - zpl_vec3_add(&v, b, center); - - if (zpl_frustum_point_inside(frustum, v)) return 1; - - b = zpl_vec3f(+box.x, -box.y, -box.z); - zpl_vec3_add(&v, b, center); - - if (zpl_frustum_point_inside(frustum, v)) return 1; - - b = zpl_vec3f(-box.x, +box.y, -box.z); - zpl_vec3_add(&v, b, center); - - if (zpl_frustum_point_inside(frustum, v)) return 1; - - b = zpl_vec3f(+box.x, +box.y, -box.z); - zpl_vec3_add(&v, b, center); - - if (zpl_frustum_point_inside(frustum, v)) return 1; - - b = zpl_vec3f(+box.x, +box.y, +box.z); - zpl_vec3_add(&v, b, center); - - if (zpl_frustum_point_inside(frustum, v)) return 1; - - b = zpl_vec3f(-box.x, +box.y, +box.z); - zpl_vec3_add(&v, b, center); - - if (zpl_frustum_point_inside(frustum, v)) return 1; - - b = zpl_vec3f(-box.x, -box.y, +box.z); - zpl_vec3_add(&v, b, center); - - if (zpl_frustum_point_inside(frustum, v)) return 1; - - b = zpl_vec3f(+box.x, -box.y, +box.z); - zpl_vec3_add(&v, b, center); - - if (zpl_frustum_point_inside(frustum, v)) return 1; - - return 0; - } - - zpl_f32 zpl_lerp(zpl_f32 a, zpl_f32 b, zpl_f32 t) { return a * (1.0f - t) + b * t; } - zpl_f32 zpl_unlerp(zpl_f32 t, zpl_f32 a, zpl_f32 b) { return (t - a) / (b - a); } - zpl_f32 zpl_smooth_step(zpl_f32 a, zpl_f32 b, zpl_f32 t) { - zpl_f32 x = (t - a) / (b - a); - return x * x * (3.0f - 2.0f * x); - } - zpl_f32 zpl_smoother_step(zpl_f32 a, zpl_f32 b, zpl_f32 t) { - zpl_f32 x = (t - a) / (b - a); - return x * x * x * (x * (6.0f * x - 15.0f) + 10.0f); - } - - #define ZPL_VEC_LERPN(N, d, a, b, t) \ - zpl_vec##N db; \ - zpl_vec##N##_sub(&db, b, a); \ - zpl_vec##N##_muleq(&db, t); \ - zpl_vec##N##_add(d, a, db) - - void zpl_vec2_lerp(zpl_vec2 *d, zpl_vec2 a, zpl_vec2 b, zpl_f32 t) { ZPL_VEC_LERPN(2, d, a, b, t); } - void zpl_vec3_lerp(zpl_vec3 *d, zpl_vec3 a, zpl_vec3 b, zpl_f32 t) { ZPL_VEC_LERPN(3, d, a, b, t); } - void zpl_vec4_lerp(zpl_vec4 *d, zpl_vec4 a, zpl_vec4 b, zpl_f32 t) { ZPL_VEC_LERPN(4, d, a, b, t); } - - #undef ZPL_VEC_LERPN - - void zpl_vec2_cslerp(zpl_vec2 *d, zpl_vec2 a, zpl_vec2 v0, zpl_vec2 b, zpl_vec2 v1, zpl_f32 t) { - zpl_f32 t2 = t * t; - zpl_f32 ti = (t - 1); - zpl_f32 ti2 = ti * ti; - - zpl_f32 h00 = (1 + 2 * t) * ti2; - zpl_f32 h10 = t * ti2; - zpl_f32 h01 = t2 * (3 - 2 * t); - zpl_f32 h11 = t2 * ti; - - d->x = h00 * a.x + h10 * v0.x + h01 * b.x + h11 * v1.x; - d->y = h00 * a.y + h10 * v0.y + h01 * b.y + h11 * v1.y; - } - - void zpl_vec3_cslerp(zpl_vec3 *d, zpl_vec3 a, zpl_vec3 v0, zpl_vec3 b, zpl_vec3 v1, zpl_f32 t) { - zpl_f32 t2 = t * t; - zpl_f32 ti = (t - 1); - zpl_f32 ti2 = ti * ti; - - zpl_f32 h00 = (1 + 2 * t) * ti2; - zpl_f32 h10 = t * ti2; - zpl_f32 h01 = t2 * (3 - 2 * t); - zpl_f32 h11 = t2 * ti; - - d->x = h00 * a.x + h10 * v0.x + h01 * b.x + h11 * v1.x; - d->y = h00 * a.y + h10 * v0.y + h01 * b.y + h11 * v1.y; - d->z = h00 * a.z + h10 * v0.z + h01 * b.z + h11 * v1.z; - } - - void zpl_vec2_dcslerp(zpl_vec2 *d, zpl_vec2 a, zpl_vec2 v0, zpl_vec2 b, zpl_vec2 v1, zpl_f32 t) { - zpl_f32 t2 = t * t; - - zpl_f32 dh00 = 6 * t2 - 6 * t; - zpl_f32 dh10 = 3 * t2 - 4 * t + 1; - zpl_f32 dh01 = -6 * t2 + 6 * t; - zpl_f32 dh11 = 3 * t2 - 2 * t; - - d->x = dh00 * a.x + dh10 * v0.x + dh01 * b.x + dh11 * v1.x; - d->y = dh00 * a.y + dh10 * v0.y + dh01 * b.y + dh11 * v1.y; - } - - void zpl_vec3_dcslerp(zpl_vec3 *d, zpl_vec3 a, zpl_vec3 v0, zpl_vec3 b, zpl_vec3 v1, zpl_f32 t) { - zpl_f32 t2 = t * t; - - zpl_f32 dh00 = 6 * t2 - 6 * t; - zpl_f32 dh10 = 3 * t2 - 4 * t + 1; - zpl_f32 dh01 = -6 * t2 + 6 * t; - zpl_f32 dh11 = 3 * t2 - 2 * t; - - d->x = dh00 * a.x + dh10 * v0.x + dh01 * b.x + dh11 * v1.x; - d->y = dh00 * a.y + dh10 * v0.y + dh01 * b.y + dh11 * v1.y; - d->z = dh00 * a.z + dh10 * v0.z + dh01 * b.z + dh11 * v1.z; - } - - void zpl_quat_lerp(zpl_quat *d, zpl_quat a, zpl_quat b, zpl_f32 t) { zpl_vec4_lerp(&d->xyzw, a.xyzw, b.xyzw, t); } - void zpl_quat_nlerp(zpl_quat *d, zpl_quat a, zpl_quat b, zpl_f32 t) { - zpl_quat_lerp(d, a, b, t); - zpl_quat_norm(d, *d); - } - - void zpl_quat_slerp(zpl_quat *d, zpl_quat a, zpl_quat b, zpl_f32 t) { - zpl_quat x, y, z; - zpl_f32 cos_theta, angle; - zpl_f32 s1, s0, is; - - z = b; - cos_theta = zpl_quat_dot(a, b); - - if (cos_theta < 0.0f) { - z = zpl_quatf(-b.x, -b.y, -b.z, -b.w); - cos_theta = -cos_theta; - } - - if (cos_theta > 1.0f) { - /* NOTE: Use lerp not nlerp as it's not a real angle or they are not normalized */ - zpl_quat_lerp(d, a, b, t); - } - - angle = zpl_arccos(cos_theta); - - s1 = zpl_sin((1.0f - t) * angle); - s0 = zpl_sin(t * angle); - is = 1.0f / zpl_sin(angle); - zpl_quat_mulf(&x, a, s1); - zpl_quat_mulf(&y, z, s0); - zpl_quat_add(d, x, y); - zpl_quat_muleqf(d, is); - } - - void zpl_quat_slerp_approx(zpl_quat *d, zpl_quat a, zpl_quat b, zpl_f32 t) { - /* NOTE: Derived by taylor expanding the geometric interpolation equation - * Even works okay for nearly anti-parallel versors!!! - */ - /* NOTE: Extra interations cannot be used as they require angle^4 which is not worth it to approximate */ - zpl_f32 tp = t + (1.0f - zpl_quat_dot(a, b)) / 3.0f * t * (-2.0f * t * t + 3.0f * t - 1.0f); - zpl_quat_nlerp(d, a, b, tp); - } - - void zpl_quat_nquad(zpl_quat *d, zpl_quat p, zpl_quat a, zpl_quat b, zpl_quat q, zpl_f32 t) { - zpl_quat x, y; - zpl_quat_nlerp(&x, p, q, t); - zpl_quat_nlerp(&y, a, b, t); - zpl_quat_nlerp(d, x, y, 2.0f * t * (1.0f - t)); - } - - void zpl_quat_squad(zpl_quat *d, zpl_quat p, zpl_quat a, zpl_quat b, zpl_quat q, zpl_f32 t) { - zpl_quat x, y; - zpl_quat_slerp(&x, p, q, t); - zpl_quat_slerp(&y, a, b, t); - zpl_quat_slerp(d, x, y, 2.0f * t * (1.0f - t)); - } - - void zpl_quat_squad_approx(zpl_quat *d, zpl_quat p, zpl_quat a, zpl_quat b, zpl_quat q, zpl_f32 t) { - zpl_quat x, y; - zpl_quat_slerp_approx(&x, p, q, t); - zpl_quat_slerp_approx(&y, a, b, t); - zpl_quat_slerp_approx(d, x, y, 2.0f * t * (1.0f - t)); - } - - zpl_rect2 zpl_rect2f(zpl_vec2 pos, zpl_vec2 dim) { - zpl_rect2 r; - r.pos = pos; - r.dim = dim; - return r; - } - - zpl_rect3 zpl_rect3f(zpl_vec3 pos, zpl_vec3 dim) { - zpl_rect3 r; - r.pos = pos; - r.dim = dim; - return r; - } - - zpl_aabb2 zpl_aabb2f(zpl_f32 minx, zpl_f32 miny, zpl_f32 maxx, zpl_f32 maxy) { - zpl_aabb2 r; - r.min = zpl_vec2f(minx, miny); - r.max = zpl_vec2f(maxx, maxy); - return r; - } - zpl_aabb3 zpl_aabb3f(zpl_f32 minx, zpl_f32 miny, zpl_f32 minz, zpl_f32 maxx, zpl_f32 maxy, zpl_f32 maxz) { - zpl_aabb3 r; - r.min = zpl_vec3f(minx, miny, minz); - r.max = zpl_vec3f(maxx, maxy, maxz); - return r; - } - - zpl_aabb2 zpl_aabb2_rect2(zpl_rect2 a) { - zpl_aabb2 r; - r.min = a.pos; - zpl_vec2_add(&r.max, a.pos, a.dim); - return r; - } - zpl_aabb3 zpl_aabb3_rect3(zpl_rect3 a) { - zpl_aabb3 r; - r.min = a.pos; - zpl_vec3_add(&r.max, a.pos, a.dim); - return r; - } - - zpl_rect2 zpl_rect2_aabb2(zpl_aabb2 a) { - zpl_rect2 r; - r.pos = a.min; - zpl_vec2_sub(&r.dim, a.max, a.min); - return r; - } - zpl_rect3 zpl_rect3_aabb3(zpl_aabb3 a) { - zpl_rect3 r; - r.pos = a.min; - zpl_vec3_sub(&r.dim, a.max, a.min); - return r; - } - - int zpl_rect2_contains(zpl_rect2 a, zpl_f32 x, zpl_f32 y) { - zpl_f32 min_x = zpl_min(a.pos.x, a.pos.x + a.dim.x); - zpl_f32 max_x = zpl_max(a.pos.x, a.pos.x + a.dim.x); - zpl_f32 min_y = zpl_min(a.pos.y, a.pos.y + a.dim.y); - zpl_f32 max_y = zpl_max(a.pos.y, a.pos.y + a.dim.y); - int result = (x >= min_x) & (x < max_x) & (y >= min_y) & (y < max_y); - return result; - } - - int zpl_rect2_contains_vec2(zpl_rect2 a, zpl_vec2 p) { return zpl_rect2_contains(a, p.x, p.y); } - - int zpl_rect2_intersects(zpl_rect2 a, zpl_rect2 b) { - zpl_rect2 r = { 0 }; - return zpl_rect2_intersection_result(a, b, &r); - } - - int zpl_rect2_intersection_result(zpl_rect2 a, zpl_rect2 b, zpl_rect2 *intersection) { - zpl_f32 a_min_x = zpl_min(a.pos.x, a.pos.x + a.dim.x); - zpl_f32 a_max_x = zpl_max(a.pos.x, a.pos.x + a.dim.x); - zpl_f32 a_min_y = zpl_min(a.pos.y, a.pos.y + a.dim.y); - zpl_f32 a_max_y = zpl_max(a.pos.y, a.pos.y + a.dim.y); - - zpl_f32 b_min_x = zpl_min(b.pos.x, b.pos.x + b.dim.x); - zpl_f32 b_max_x = zpl_max(b.pos.x, b.pos.x + b.dim.x); - zpl_f32 b_min_y = zpl_min(b.pos.y, b.pos.y + b.dim.y); - zpl_f32 b_max_y = zpl_max(b.pos.y, b.pos.y + b.dim.y); - - zpl_f32 x0 = zpl_max(a_min_x, b_min_x); - zpl_f32 y0 = zpl_max(a_min_y, b_min_y); - zpl_f32 x1 = zpl_min(a_max_x, b_max_x); - zpl_f32 y1 = zpl_min(a_max_y, b_max_y); - - if ((x0 < x1) && (y0 < y1)) { - zpl_rect2 r = zpl_rect2f(zpl_vec2f(x0, y0), zpl_vec2f(x1 - x0, y1 - y0)); - *intersection = r; - return 1; - } else { - zpl_rect2 r = { 0 }; - *intersection = r; - return 0; - } - } - - int zpl_aabb2_contains(zpl_aabb2 a, zpl_f32 x, zpl_f32 y) { - return (zpl_is_between_limit(x, a.min.x, a.max.x) && zpl_is_between_limit(y, a.min.y, a.max.y)); - } - - int zpl_aabb3_contains(zpl_aabb3 a, zpl_f32 x, zpl_f32 y, zpl_f32 z) { - return (zpl_is_between_limit(x, a.min.x, a.max.x) && zpl_is_between_limit(y, a.min.y, a.max.y) && zpl_is_between_limit(z, a.min.z, a.max.z)); - } - - zpl_aabb2 zpl_aabb2_cut_left(zpl_aabb2 *a, zpl_f32 b) { - zpl_f32 minx = a->min.x; - a->min.x = zpl_min(a->max.x, a->min.x + b); - return zpl_aabb2f(minx, a->min.y, a->min.x, a->max.y); - } - zpl_aabb2 zpl_aabb2_cut_right(zpl_aabb2 *a, zpl_f32 b) { - zpl_f32 maxx = a->max.x; - a->max.x = zpl_max(a->min.x, a->max.x - b); - return zpl_aabb2f(a->max.x, a->min.y, maxx, a->max.y); - } - zpl_aabb2 zpl_aabb2_cut_top(zpl_aabb2 *a, zpl_f32 b) { - zpl_f32 miny = a->min.y; - a->min.y = zpl_min(a->max.y, a->min.y + b); - return zpl_aabb2f(a->min.x, miny, a->max.x, a->min.y); - } - zpl_aabb2 zpl_aabb2_cut_bottom(zpl_aabb2 *a, zpl_f32 b) { - zpl_f32 maxy = a->max.y; - a->max.y = zpl_max(a->min.y, a->max.y - b); - return zpl_aabb2f(a->min.x, a->max.y, a->max.x, maxy); - } - - zpl_aabb2 zpl_aabb2_get_left(const zpl_aabb2 *a, zpl_f32 b) { - zpl_f32 minx = a->min.x; - zpl_f32 aminx = zpl_min(a->max.x, a->min.x + b); - return zpl_aabb2f(minx, a->min.y, aminx, a->max.y); - } - zpl_aabb2 zpl_aabb2_get_right(const zpl_aabb2 *a, zpl_f32 b) { - zpl_f32 maxx = a->max.x; - zpl_f32 amaxx = zpl_max(a->min.x, a->max.x - b); - return zpl_aabb2f(amaxx, a->min.y, maxx, a->max.y); - } - zpl_aabb2 zpl_aabb2_get_top(const zpl_aabb2 *a, zpl_f32 b) { - zpl_f32 miny = a->min.y; - zpl_f32 aminy = zpl_min(a->max.y, a->min.y + b); - return zpl_aabb2f(a->min.x, miny, a->max.x, aminy); - } - zpl_aabb2 zpl_aabb2_get_bottom(const zpl_aabb2 *a, zpl_f32 b) { - zpl_f32 maxy = a->max.y; - zpl_f32 amaxy = zpl_max(a->min.y, a->max.y - b); - return zpl_aabb2f(a->min.x, amaxy, a->max.x, maxy); - } - - zpl_aabb2 zpl_aabb2_add_left(const zpl_aabb2 *a, zpl_f32 b) { - return zpl_aabb2f(a->min.x-b, a->min.y, a->min.x, a->max.y); - } - zpl_aabb2 zpl_aabb2_add_right(const zpl_aabb2 *a, zpl_f32 b) { - return zpl_aabb2f(a->max.x, a->min.y, a->max.x+b, a->max.y); - } - zpl_aabb2 zpl_aabb2_add_top(const zpl_aabb2 *a, zpl_f32 b) { - return zpl_aabb2f(a->min.x, a->min.y-b, a->max.x, a->min.y); - } - zpl_aabb2 zpl_aabb2_add_bottom(const zpl_aabb2 *a, zpl_f32 b) { - return zpl_aabb2f(a->min.x, a->max.y, a->max.x, a->max.y+b); - } - - zpl_aabb2 zpl_aabb2_contract(const zpl_aabb2 *a, zpl_f32 b) { - zpl_aabb2 r = *a; - zpl_vec2 vb = zpl_vec2f(b, b); - zpl_vec2_addeq(&r.min, vb); - zpl_vec2_subeq(&r.max, vb); - - if (zpl_vec2_mag2(r.min) > zpl_vec2_mag2(r.max)) { - return zpl_aabb2f(0,0,0,0); - } - return r; - } - zpl_aabb2 zpl_aabb2_expand(const zpl_aabb2 *a, zpl_f32 b) { - return zpl_aabb2_contract(a, -b); - } - - ZPL_END_C_DECLS +// file: source/math.c + + +#if defined(ZPL_COMPILER_TINYC) && defined(ZPL_NO_MATH_H) +#undef ZPL_NO_MATH_H +#endif + +#if !defined(ZPL_NO_MATH_H) +# include +#endif + +ZPL_BEGIN_C_DECLS + +//////////////////////////////////////////////////////////////// +// +// Math +// + +zpl_f32 zpl_to_radians(zpl_f32 degrees) { return degrees * ZPL_TAU / 360.0f; } +zpl_f32 zpl_to_degrees(zpl_f32 radians) { return radians * 360.0f / ZPL_TAU; } + +zpl_f32 zpl_angle_diff(zpl_f32 radians_a, zpl_f32 radians_b) { + zpl_f32 delta = zpl_mod(radians_b - radians_a, ZPL_TAU); + delta = zpl_mod(delta + 1.5f * ZPL_TAU, ZPL_TAU); + delta -= 0.5f * ZPL_TAU; + return delta; +} + +zpl_f32 zpl_copy_sign(zpl_f32 x, zpl_f32 y) { + zpl_i32 ix, iy; + zpl_f32 r; + zpl_memcopy(&ix, &x, zpl_size_of(x)); + zpl_memcopy(&iy, &y, zpl_size_of(y)); + + ix &= 0x7fffffff; + ix |= iy & 0x80000000; + zpl_memcopy(&r, &ix, zpl_size_of(ix)); + return r; +} + +zpl_f32 zpl_remainder(zpl_f32 x, zpl_f32 y) { return x - (zpl_round(x / y) * y); } + +zpl_f32 zpl_mod(zpl_f32 x, zpl_f32 y) { + zpl_f32 result; + y = zpl_abs(y); + result = zpl_remainder(zpl_abs(x), y); + if (zpl_sign(result)) result += y; + return zpl_copy_sign(result, x); +} + +zpl_f64 zpl_copy_sign64(zpl_f64 x, zpl_f64 y) { + zpl_i64 ix, iy; + zpl_f64 r; + zpl_memcopy(&ix, &x, zpl_size_of(x)); + zpl_memcopy(&iy, &y, zpl_size_of(y)); + + ix &= 0x7fffffffffffffff; + ix |= iy & 0x8000000000000000; + zpl_memcopy(&r, &ix, zpl_size_of(ix)); + return r; +} + +zpl_f64 zpl_floor64(zpl_f64 x) { return cast(zpl_f64)((x >= 0.0) ? cast(zpl_i64) x : cast(zpl_i64)(x - 0.9999999999999999)); } +zpl_f64 zpl_ceil64(zpl_f64 x) { return cast(zpl_f64)((x < 0) ? cast(zpl_i64) x : (cast(zpl_i64) x) + 1); } +zpl_f64 zpl_round64(zpl_f64 x) { return cast(zpl_f64)((x >= 0.0) ? zpl_floor64(x + 0.5) : zpl_ceil64(x - 0.5)); } +zpl_f64 zpl_remainder64(zpl_f64 x, zpl_f64 y) { return x - (zpl_round64(x / y) * y); } +zpl_f64 zpl_abs64(zpl_f64 x) { return x < 0 ? -x : x; } +zpl_f64 zpl_sign64(zpl_f64 x) { return x < 0 ? -1.0 : +1.0; } + +zpl_f64 zpl_mod64(zpl_f64 x, zpl_f64 y) { + zpl_f64 result; + y = zpl_abs64(y); + result = zpl_remainder64(zpl_abs64(x), y); + if (zpl_sign64(result)) result += y; + return zpl_copy_sign64(result, x); +} + +zpl_f32 zpl_quake_rsqrt(zpl_f32 a) { + union { + int i; + zpl_f32 f; + } t; + zpl_f32 x2; + zpl_f32 const three_halfs = 1.5f; + + x2 = a * 0.5f; + t.f = a; + t.i = 0x5f375a86 - (t.i >> 1); /* What the fuck? */ + t.f = t.f * (three_halfs - (x2 * t.f * t.f)); /* 1st iteration */ + t.f = t.f * (three_halfs - (x2 * t.f * t.f)); /* 2nd iteration, this can be removed */ + + return t.f; +} + +#if defined(ZPL_NO_MATH_H) +# if defined(_MSC_VER) + +zpl_f32 zpl_rsqrt(zpl_f32 a) { return _mm_cvtss_f32(_mm_rsqrt_ss(_mm_set_ss(a))); } +zpl_f32 zpl_sqrt(zpl_f32 a) { return _mm_cvtss_f32(_mm_sqrt_ss(_mm_set_ss(a))); }; + +zpl_f32 zpl_sin(zpl_f32 a) { + static zpl_f32 const a0 = +1.91059300966915117e-31f; + static zpl_f32 const a1 = +1.00086760103908896f; + static zpl_f32 const a2 = -1.21276126894734565e-2f; + static zpl_f32 const a3 = -1.38078780785773762e-1f; + static zpl_f32 const a4 = -2.67353392911981221e-2f; + static zpl_f32 const a5 = +2.08026600266304389e-2f; + static zpl_f32 const a6 = -3.03996055049204407e-3f; + static zpl_f32 const a7 = +1.38235642404333740e-4f; + return a0 + a * (a1 + a * (a2 + a * (a3 + a * (a4 + a * (a5 + a * (a6 + a * a7)))))); +} + +zpl_f32 zpl_cos(zpl_f32 a) { + static zpl_f32 const a0 = +1.00238601909309722f; + static zpl_f32 const a1 = -3.81919947353040024e-2f; + static zpl_f32 const a2 = -3.94382342128062756e-1f; + static zpl_f32 const a3 = -1.18134036025221444e-1f; + static zpl_f32 const a4 = +1.07123798512170878e-1f; + static zpl_f32 const a5 = -1.86637164165180873e-2f; + static zpl_f32 const a6 = +9.90140908664079833e-4f; + static zpl_f32 const a7 = -5.23022132118824778e-14f; + return a0 + a * (a1 + a * (a2 + a * (a3 + a * (a4 + a * (a5 + a * (a6 + a * a7)))))); +} + +zpl_f32 zpl_tan(zpl_f32 radians) { + zpl_f32 rr = radians * radians; + zpl_f32 a = 9.5168091e-03f; + a *= rr; + a += 2.900525e-03f; + a *= rr; + a += 2.45650893e-02f; + a *= rr; + a += 5.33740603e-02f; + a *= rr; + a += 1.333923995e-01f; + a *= rr; + a += 3.333314036e-01f; + a *= rr; + a += 1.0f; + a *= radians; + return a; +} + +zpl_f32 zpl_arcsin(zpl_f32 a) { return zpl_arctan2(a, zpl_sqrt((1.0f + a) * (1.0f - a))); } +zpl_f32 zpl_arccos(zpl_f32 a) { return zpl_arctan2(zpl_sqrt((1.0f + a) * (1.0f - a)), a); } + +zpl_f32 zpl_arctan(zpl_f32 a) { + zpl_f32 u = a * a; + zpl_f32 u2 = u * u; + zpl_f32 u3 = u2 * u; + zpl_f32 u4 = u3 * u; + zpl_f32 f = 1.0f + 0.33288950512027f * u - 0.08467922817644f * u2 + 0.03252232640125f * u3 - 0.00749305860992f * u4; + return a / f; +} + +zpl_f32 zpl_arctan2(zpl_f32 y, zpl_f32 x) { + if (zpl_abs(x) > zpl_abs(y)) { + zpl_f32 a = zpl_arctan(y / x); + if (x > 0.0f) + return a; + else + return y > 0.0f ? a + ZPL_TAU_OVER_2 : a - ZPL_TAU_OVER_2; + } else { + zpl_f32 a = zpl_arctan(x / y); + if (x > 0.0f) + return y > 0.0f ? ZPL_TAU_OVER_4 - a : -ZPL_TAU_OVER_4 - a; + else + return y > 0.0f ? ZPL_TAU_OVER_4 + a : -ZPL_TAU_OVER_4 + a; + } +} + +zpl_f32 zpl_exp(zpl_f32 a) { + union { + zpl_f32 f; + int i; + } u, v; + u.i = (int)(6051102 * a + 1056478197); + v.i = (int)(1056478197 - 6051102 * a); + return u.f / v.f; +} + +zpl_f32 zpl_log(zpl_f32 a) { + union { + zpl_f32 f; + int i; + } u = { a }; + return (u.i - 1064866805) * 8.262958405176314e-8f; /* 1 / 12102203.0; */ +} + +zpl_f32 zpl_pow(zpl_f32 a, zpl_f32 b) { + int flipped = 0, e; + zpl_f32 f, r = 1.0f; + if (b < 0) { + flipped = 1; + b = -b; + } + + e = (int)b; + f = zpl_exp(b - e); + + while (e) { + if (e & 1) r *= a; + a *= a; + e >>= 1; + } + + r *= f; + return flipped ? 1.0f / r : r; +} + +# else + +zpl_f32 zpl_rsqrt(zpl_f32 a) { return 1.0f / __builtin_sqrt(a); } +zpl_f32 zpl_sqrt(zpl_f32 a) { return __builtin_sqrt(a); } +zpl_f32 zpl_sin(zpl_f32 radians) { return __builtin_sinf(radians); } +zpl_f32 zpl_cos(zpl_f32 radians) { return __builtin_cosf(radians); } +zpl_f32 zpl_tan(zpl_f32 radians) { return __builtin_tanf(radians); } +zpl_f32 zpl_arcsin(zpl_f32 a) { return __builtin_asinf(a); } +zpl_f32 zpl_arccos(zpl_f32 a) { return __builtin_acosf(a); } +zpl_f32 zpl_arctan(zpl_f32 a) { return __builtin_atanf(a); } +zpl_f32 zpl_arctan2(zpl_f32 y, zpl_f32 x) { return __builtin_atan2f(y, x); } + +zpl_f32 zpl_exp(zpl_f32 x) { return __builtin_expf(x); } +zpl_f32 zpl_log(zpl_f32 x) { return __builtin_logf(x); } + +// TODO: Should this be zpl_exp(y * zpl_log(x)) ??? +zpl_f32 zpl_pow(zpl_f32 x, zpl_f32 y) { return __builtin_powf(x, y); } + +# endif +#else +zpl_f32 zpl_rsqrt(zpl_f32 a) { return 1.0f / sqrtf(a); } +zpl_f32 zpl_sqrt(zpl_f32 a) { return sqrtf(a); }; +zpl_f32 zpl_sin(zpl_f32 radians) { return sinf(radians); }; +zpl_f32 zpl_cos(zpl_f32 radians) { return cosf(radians); }; +zpl_f32 zpl_tan(zpl_f32 radians) { return tanf(radians); }; +zpl_f32 zpl_arcsin(zpl_f32 a) { return asinf(a); }; +zpl_f32 zpl_arccos(zpl_f32 a) { return acosf(a); }; +zpl_f32 zpl_arctan(zpl_f32 a) { return atanf(a); }; +zpl_f32 zpl_arctan2(zpl_f32 y, zpl_f32 x) { return atan2f(y, x); }; + +zpl_f32 zpl_exp(zpl_f32 x) { return expf(x); } +zpl_f32 zpl_log(zpl_f32 x) { return logf(x); } +zpl_f32 zpl_pow(zpl_f32 x, zpl_f32 y) { return powf(x, y); } +#endif + +zpl_f32 zpl_exp2(zpl_f32 x) { return zpl_exp(ZPL_LOG_TWO * x); } +zpl_f32 zpl_log2(zpl_f32 x) { return zpl_log(x) / ZPL_LOG_TWO; } + +zpl_f32 zpl_fast_exp(zpl_f32 x) { + /* NOTE: Only works in the range -1 <= x <= +1 */ + zpl_f32 e = 1.0f + x * (1.0f + x * 0.5f * (1.0f + x * 0.3333333333f * (1.0f + x * 0.25f * (1.0f + x * 0.2f)))); + return e; +} + +zpl_f32 zpl_fast_exp2(zpl_f32 x) { return zpl_fast_exp(ZPL_LOG_TWO * x); } + +zpl_f32 zpl_round(zpl_f32 x) { return (float)((x >= 0.0f) ? zpl_floor(x + 0.5f) : zpl_ceil(x - 0.5f)); } +zpl_f32 zpl_floor(zpl_f32 x) { return (float)((x >= 0.0f) ? (int)x : (int)(x - 0.9999999999999999f)); } +zpl_f32 zpl_ceil(zpl_f32 x) { return (float)((x < 0.0f) ? (int)x : ((int)x) + 1); } + +zpl_f32 zpl_half_to_float(zpl_half value) { + union { + unsigned int i; + zpl_f32 f; + } result; + int s = (value >> 15) & 0x001; + int e = (value >> 10) & 0x01f; + int m = value & 0x3ff; + + if (e == 0) { + if (m == 0) { + /* Plus or minus zero */ + result.i = (unsigned int)(s << 31); + return result.f; + } else { + /* Denormalized number */ + while (!(m & 0x00000400)) { + m <<= 1; + e -= 1; + } + + e += 1; + m &= ~0x00000400; + } + } else if (e == 31) { + if (m == 0) { + /* Positive or negative infinity */ + result.i = (unsigned int)((s << 31) | 0x7f800000); + return result.f; + } else { + /* Nan */ + result.i = (unsigned int)((s << 31) | 0x7f800000 | (m << 13)); + return result.f; + } + } + + e = e + (127 - 15); + m = m << 13; + + result.i = (unsigned int)((s << 31) | (e << 23) | m); + return result.f; +} + +zpl_half zpl_float_to_half(zpl_f32 value) { + union { + unsigned int i; + zpl_f32 f; + } v; + int i, s, e, m; + + v.f = value; + i = (int)v.i; + + s = (i >> 16) & 0x00008000; + e = ((i >> 23) & 0x000000ff) - (127 - 15); + m = i & 0x007fffff; + + if (e <= 0) { + if (e < -10) return (zpl_half)s; + m = (m | 0x00800000) >> (1 - e); + + if (m & 0x00001000) m += 0x00002000; + + return (zpl_half)(s | (m >> 13)); + } else if (e == 0xff - (127 - 15)) { + if (m == 0) { + return (zpl_half)(s | 0x7c00); /* NOTE: infinity */ + } else { + /* NOTE: NAN */ + m >>= 13; + return (zpl_half)(s | 0x7c00 | m | (m == 0)); + } + } else { + if (m & 0x00001000) { + m += 0x00002000; + if (m & 0x00800000) { + m = 0; + e += 1; + } + } + + if (e > 30) { + zpl_f32 volatile f = 1e12f; + int j; + for (j = 0; j < 10; j++) f *= f; /* NOTE: Cause overflow */ + + return (zpl_half)(s | 0x7c00); + } + + return (zpl_half)(s | (e << 10) | (m >> 13)); + } +} + +#define ZPL_VEC2_2OP(a, c, post) \ +a->x = c.x post; \ +a->y = c.y post; + +#define ZPL_VEC2_3OP(a, b, op, c, post) \ +a->x = b.x op c.x post; \ +a->y = b.y op c.y post; + +#define ZPL_VEC3_2OP(a, c, post) \ +a->x = c.x post; \ +a->y = c.y post; \ +a->z = c.z post; + +#define ZPL_VEC3_3OP(a, b, op, c, post) \ +a->x = b.x op c.x post; \ +a->y = b.y op c.y post; \ +a->z = b.z op c.z post; + +#define ZPL_VEC4_2OP(a, c, post) \ +a->x = c.x post; \ +a->y = c.y post; \ +a->z = c.z post; \ +a->w = c.w post; + +#define ZPL_VEC4_3OP(a, b, op, c, post) \ +a->x = b.x op c.x post; \ +a->y = b.y op c.y post; \ +a->z = b.z op c.z post; \ +a->w = b.w op c.w post; + +zpl_vec2 zpl_vec2f_zero(void) { + zpl_vec2 v = { 0, 0 }; + return v; +} +zpl_vec2 zpl_vec2f(zpl_f32 x, zpl_f32 y) { + zpl_vec2 v; + v.x = x; + v.y = y; + return v; +} +zpl_vec2 zpl_vec2fv(zpl_f32 x[2]) { + zpl_vec2 v; + v.x = x[0]; + v.y = x[1]; + return v; +} + +zpl_vec3 zpl_vec3f_zero(void) { + zpl_vec3 v = { 0, 0, 0 }; + return v; +} +zpl_vec3 zpl_vec3f(zpl_f32 x, zpl_f32 y, zpl_f32 z) { + zpl_vec3 v; + v.x = x; + v.y = y; + v.z = z; + return v; +} +zpl_vec3 zpl_vec3fv(zpl_f32 x[3]) { + zpl_vec3 v; + v.x = x[0]; + v.y = x[1]; + v.z = x[2]; + return v; +} + +zpl_vec4 zpl_vec4f_zero(void) { + zpl_vec4 v = { 0, 0, 0, 0 }; + return v; +} +zpl_vec4 zpl_vec4f(zpl_f32 x, zpl_f32 y, zpl_f32 z, zpl_f32 w) { + zpl_vec4 v; + v.x = x; + v.y = y; + v.z = z; + v.w = w; + return v; +} +zpl_vec4 zpl_vec4fv(zpl_f32 x[4]) { + zpl_vec4 v; + v.x = x[0]; + v.y = x[1]; + v.z = x[2]; + v.w = x[3]; + return v; +} + +zpl_f32 zpl_vec2_max(zpl_vec2 v) { return zpl_max(v.x, v.y); } +zpl_f32 zpl_vec2_side(zpl_vec2 p, zpl_vec2 q, zpl_vec2 r) { return ((q.x - p.x) * (r.y - p.y) - (r.x - p.x) * (q.y - p.y)); } + +void zpl_vec2_add(zpl_vec2 *d, zpl_vec2 v0, zpl_vec2 v1) { ZPL_VEC2_3OP(d, v0, +, v1, +0); } +void zpl_vec2_sub(zpl_vec2 *d, zpl_vec2 v0, zpl_vec2 v1) { ZPL_VEC2_3OP(d, v0, -, v1, +0); } +void zpl_vec2_mul(zpl_vec2 *d, zpl_vec2 v, zpl_f32 s) { ZPL_VEC2_2OP(d, v, *s); } +void zpl_vec2_div(zpl_vec2 *d, zpl_vec2 v, zpl_f32 s) { ZPL_VEC2_2OP(d, v, / s); } + +zpl_f32 zpl_vec3_max(zpl_vec3 v) { return zpl_max3(v.x, v.y, v.z); } + +void zpl_vec3_add(zpl_vec3 *d, zpl_vec3 v0, zpl_vec3 v1) { ZPL_VEC3_3OP(d, v0, +, v1, +0); } +void zpl_vec3_sub(zpl_vec3 *d, zpl_vec3 v0, zpl_vec3 v1) { ZPL_VEC3_3OP(d, v0, -, v1, +0); } +void zpl_vec3_mul(zpl_vec3 *d, zpl_vec3 v, zpl_f32 s) { ZPL_VEC3_2OP(d, v, *s); } +void zpl_vec3_div(zpl_vec3 *d, zpl_vec3 v, zpl_f32 s) { ZPL_VEC3_2OP(d, v, / s); } + +void zpl_vec4_add(zpl_vec4 *d, zpl_vec4 v0, zpl_vec4 v1) { ZPL_VEC4_3OP(d, v0, +, v1, +0); } +void zpl_vec4_sub(zpl_vec4 *d, zpl_vec4 v0, zpl_vec4 v1) { ZPL_VEC4_3OP(d, v0, -, v1, +0); } +void zpl_vec4_mul(zpl_vec4 *d, zpl_vec4 v, zpl_f32 s) { ZPL_VEC4_2OP(d, v, *s); } +void zpl_vec4_div(zpl_vec4 *d, zpl_vec4 v, zpl_f32 s) { ZPL_VEC4_2OP(d, v, / s); } + +void zpl_vec2_addeq(zpl_vec2 *d, zpl_vec2 v) { ZPL_VEC2_3OP(d, (*d), +, v, +0); } +void zpl_vec2_subeq(zpl_vec2 *d, zpl_vec2 v) { ZPL_VEC2_3OP(d, (*d), -, v, +0); } +void zpl_vec2_muleq(zpl_vec2 *d, zpl_f32 s) { ZPL_VEC2_2OP(d, (*d), *s); } +void zpl_vec2_diveq(zpl_vec2 *d, zpl_f32 s) { ZPL_VEC2_2OP(d, (*d), / s); } + +void zpl_vec3_addeq(zpl_vec3 *d, zpl_vec3 v) { ZPL_VEC3_3OP(d, (*d), +, v, +0); } +void zpl_vec3_subeq(zpl_vec3 *d, zpl_vec3 v) { ZPL_VEC3_3OP(d, (*d), -, v, +0); } +void zpl_vec3_muleq(zpl_vec3 *d, zpl_f32 s) { ZPL_VEC3_2OP(d, (*d), *s); } +void zpl_vec3_diveq(zpl_vec3 *d, zpl_f32 s) { ZPL_VEC3_2OP(d, (*d), / s); } + +void zpl_vec4_addeq(zpl_vec4 *d, zpl_vec4 v) { ZPL_VEC4_3OP(d, (*d), +, v, +0); } +void zpl_vec4_subeq(zpl_vec4 *d, zpl_vec4 v) { ZPL_VEC4_3OP(d, (*d), -, v, +0); } +void zpl_vec4_muleq(zpl_vec4 *d, zpl_f32 s) { ZPL_VEC4_2OP(d, (*d), *s); } +void zpl_vec4_diveq(zpl_vec4 *d, zpl_f32 s) { ZPL_VEC4_2OP(d, (*d), / s); } + +#undef ZPL_VEC2_2OP +#undef ZPL_VEC2_3OP +#undef ZPL_VEC3_3OP +#undef ZPL_VEC3_2OP +#undef ZPL_VEC4_2OP +#undef ZPL_VEC4_3OP + +zpl_f32 zpl_vec2_dot(zpl_vec2 v0, zpl_vec2 v1) { return v0.x * v1.x + v0.y * v1.y; } +zpl_f32 zpl_vec3_dot(zpl_vec3 v0, zpl_vec3 v1) { return v0.x * v1.x + v0.y * v1.y + v0.z * v1.z; } +zpl_f32 zpl_vec4_dot(zpl_vec4 v0, zpl_vec4 v1) { return v0.x * v1.x + v0.y * v1.y + v0.z * v1.z + v0.w * v1.w; } + +void zpl_vec2_cross(zpl_f32 *d, zpl_vec2 v0, zpl_vec2 v1) { *d = v0.x * v1.y - v1.x * v0.y; } +void zpl_vec3_cross(zpl_vec3 *d, zpl_vec3 v0, zpl_vec3 v1) { + d->x = v0.y * v1.z - v0.z * v1.y; + d->y = v0.z * v1.x - v0.x * v1.z; + d->z = v0.x * v1.y - v0.y * v1.x; +} + +zpl_f32 zpl_vec2_mag2(zpl_vec2 v) { return zpl_vec2_dot(v, v); } +zpl_f32 zpl_vec3_mag2(zpl_vec3 v) { return zpl_vec3_dot(v, v); } +zpl_f32 zpl_vec4_mag2(zpl_vec4 v) { return zpl_vec4_dot(v, v); } + +/* TODO: Create custom sqrt function */ +zpl_f32 zpl_vec2_mag(zpl_vec2 v) { return zpl_sqrt(zpl_vec2_dot(v, v)); } +zpl_f32 zpl_vec3_mag(zpl_vec3 v) { return zpl_sqrt(zpl_vec3_dot(v, v)); } +zpl_f32 zpl_vec4_mag(zpl_vec4 v) { return zpl_sqrt(zpl_vec4_dot(v, v)); } + +void zpl_vec2_norm(zpl_vec2 *d, zpl_vec2 v) { + zpl_f32 inv_mag = zpl_rsqrt(zpl_vec2_dot(v, v)); + zpl_vec2_mul(d, v, inv_mag); +} +void zpl_vec3_norm(zpl_vec3 *d, zpl_vec3 v) { + zpl_f32 inv_mag = zpl_rsqrt(zpl_vec3_dot(v, v)); + zpl_vec3_mul(d, v, inv_mag); +} +void zpl_vec4_norm(zpl_vec4 *d, zpl_vec4 v) { + zpl_f32 inv_mag = zpl_rsqrt(zpl_vec4_dot(v, v)); + zpl_vec4_mul(d, v, inv_mag); +} + +void zpl_vec2_norm0(zpl_vec2 *d, zpl_vec2 v) { + zpl_f32 mag = zpl_vec2_mag(v); + if (mag > 0) + zpl_vec2_div(d, v, mag); + else + *d = zpl_vec2f_zero( ); +} +void zpl_vec3_norm0(zpl_vec3 *d, zpl_vec3 v) { + zpl_f32 mag = zpl_vec3_mag(v); + if (mag > 0) + zpl_vec3_div(d, v, mag); + else + *d = zpl_vec3f_zero( ); +} +void zpl_vec4_norm0(zpl_vec4 *d, zpl_vec4 v) { + zpl_f32 mag = zpl_vec4_mag(v); + if (mag > 0) + zpl_vec4_div(d, v, mag); + else + *d = zpl_vec4f_zero( ); +} + +void zpl_vec2_reflect(zpl_vec2 *d, zpl_vec2 i, zpl_vec2 n) { + zpl_vec2 b = n; + zpl_vec2_muleq(&b, 2.0f * zpl_vec2_dot(n, i)); + zpl_vec2_sub(d, i, b); +} + +void zpl_vec3_reflect(zpl_vec3 *d, zpl_vec3 i, zpl_vec3 n) { + zpl_vec3 b = n; + zpl_vec3_muleq(&b, 2.0f * zpl_vec3_dot(n, i)); + zpl_vec3_sub(d, i, b); +} + +void zpl_vec2_refract(zpl_vec2 *d, zpl_vec2 i, zpl_vec2 n, zpl_f32 eta) { + zpl_vec2 a, b; + zpl_f32 dv, k; + + dv = zpl_vec2_dot(n, i); + k = 1.0f - eta * eta * (1.0f - dv * dv); + zpl_vec2_mul(&a, i, eta); + zpl_vec2_mul(&b, n, eta * dv * zpl_sqrt(k)); + zpl_vec2_sub(d, a, b); + zpl_vec2_muleq(d, (float)(k >= 0.0f)); +} + +void zpl_vec3_refract(zpl_vec3 *d, zpl_vec3 i, zpl_vec3 n, zpl_f32 eta) { + zpl_vec3 a, b; + zpl_f32 dv, k; + + dv = zpl_vec3_dot(n, i); + k = 1.0f - eta * eta * (1.0f - dv * dv); + zpl_vec3_mul(&a, i, eta); + zpl_vec3_mul(&b, n, eta * dv * zpl_sqrt(k)); + zpl_vec3_sub(d, a, b); + zpl_vec3_muleq(d, (float)(k >= 0.0f)); +} + +zpl_f32 zpl_vec2_aspect_ratio(zpl_vec2 v) { return (v.y < 0.0001f) ? 0.0f : v.x / v.y; } + +void zpl_mat2_transpose(zpl_mat2 *m) { zpl_float22_transpose(zpl_float22_m(m)); } +void zpl_mat2_identity(zpl_mat2 *m) { zpl_float22_identity(zpl_float22_m(m)); } +void zpl_mat2_mul(zpl_mat2 *out, zpl_mat2 *m1, zpl_mat2 *m2) { + zpl_float22_mul(zpl_float22_m(out), zpl_float22_m(m1), zpl_float22_m(m2)); +} + +void zpl_float22_identity(zpl_f32 m[2][2]) { + m[0][0] = 1; + m[0][1] = 0; + m[1][0] = 0; + m[1][1] = 1; +} + +void zpl_mat2_copy(zpl_mat2* out, zpl_mat2* m) { + zpl_memcopy(out, m, sizeof(zpl_mat3)); +} + +void zpl_mat2_mul_vec2(zpl_vec2 *out, zpl_mat2 *m, zpl_vec2 in) { zpl_float22_mul_vec2(out, zpl_float22_m(m), in); } + +zpl_mat2 *zpl_mat2_v(zpl_vec2 m[2]) { return (zpl_mat2 *)m; } +zpl_mat2 *zpl_mat2_f(zpl_f32 m[2][2]) { return (zpl_mat2 *)m; } + +zpl_float2 *zpl_float22_m(zpl_mat2 *m) { return (zpl_float2 *)m; } +zpl_float2 *zpl_float22_v(zpl_vec2 m[2]) { return (zpl_float2 *)m; } +zpl_float2 *zpl_float22_4(zpl_f32 m[4]) { return (zpl_float2 *)m; } + +void zpl_float22_transpose(zpl_f32 (*vec)[2]) { + int i, j; + for (j = 0; j < 2; j++) { + for (i = j + 1; i < 2; i++) { + zpl_f32 t = vec[i][j]; + vec[i][j] = vec[j][i]; + vec[j][i] = t; + } + } +} + +void zpl_float22_mul(zpl_f32 (*out)[2], zpl_f32 (*mat1)[2], zpl_f32 (*mat2)[2]) { + int i, j; + zpl_f32 temp1[2][2], temp2[2][2]; + if (mat1 == out) { + zpl_memcopy(temp1, mat1, sizeof(temp1)); + mat1 = temp1; + } + if (mat2 == out) { + zpl_memcopy(temp2, mat2, sizeof(temp2)); + mat2 = temp2; + } + for (j = 0; j < 2; j++) { + for (i = 0; i < 2; i++) { out[j][i] = mat1[0][i] * mat2[j][0] + mat1[1][i] * mat2[j][1]; } + } +} + +void zpl_float22_mul_vec2(zpl_vec2 *out, zpl_f32 m[2][2], zpl_vec2 v) { + out->x = m[0][0] * v.x + m[0][1] * v.y; + out->y = m[1][0] * v.x + m[1][1] * v.y; +} + +zpl_f32 zpl_mat2_determinate(zpl_mat2 *m) { + zpl_float2 *e = zpl_float22_m(m); + return e[0][0] * e[1][1] - e[1][0] * e[0][1]; +} + +void zpl_mat2_inverse(zpl_mat2 *out, zpl_mat2 *in) { + zpl_float2 *o = zpl_float22_m(out); + zpl_float2 *i = zpl_float22_m(in); + + zpl_f32 ood = 1.0f / zpl_mat2_determinate(in); + + o[0][0] = +i[1][1] * ood; + o[0][1] = -i[0][1] * ood; + o[1][0] = -i[1][0] * ood; + o[1][1] = +i[0][0] * ood; +} + +void zpl_mat3_transpose(zpl_mat3 *m) { zpl_float33_transpose(zpl_float33_m(m)); } +void zpl_mat3_identity(zpl_mat3 *m) { zpl_float33_identity(zpl_float33_m(m)); } + +void zpl_mat3_copy(zpl_mat3* out, zpl_mat3* m) { + zpl_memcopy(out, m, sizeof(zpl_mat3)); +} + +void zpl_mat3_mul(zpl_mat3 *out, zpl_mat3 *m1, zpl_mat3 *m2) { + zpl_float33_mul(zpl_float33_m(out), zpl_float33_m(m1), zpl_float33_m(m2)); +} + +void zpl_float33_identity(zpl_f32 m[3][3]) { + m[0][0] = 1; + m[0][1] = 0; + m[0][2] = 0; + m[1][0] = 0; + m[1][1] = 1; + m[1][2] = 0; + m[2][0] = 0; + m[2][1] = 0; + m[2][2] = 1; +} + +void zpl_mat3_mul_vec3(zpl_vec3 *out, zpl_mat3 *m, zpl_vec3 in) { zpl_float33_mul_vec3(out, zpl_float33_m(m), in); } + +zpl_mat3 *zpl_mat3_v(zpl_vec3 m[3]) { return (zpl_mat3 *)m; } +zpl_mat3 *zpl_mat3_f(zpl_f32 m[3][3]) { return (zpl_mat3 *)m; } + +zpl_float3 *zpl_float33_m(zpl_mat3 *m) { return (zpl_float3 *)m; } +zpl_float3 *zpl_float33_v(zpl_vec3 m[3]) { return (zpl_float3 *)m; } +zpl_float3 *zpl_float33_9(zpl_f32 m[9]) { return (zpl_float3 *)m; } + +void zpl_float33_transpose(zpl_f32 (*vec)[3]) { + int i, j; + for (j = 0; j < 3; j++) { + for (i = j + 1; i < 3; i++) { + zpl_f32 t = vec[i][j]; + vec[i][j] = vec[j][i]; + vec[j][i] = t; + } + } +} + +void zpl_float33_mul(zpl_f32 (*out)[3], zpl_f32 (*mat1)[3], zpl_f32 (*mat2)[3]) { + int i, j; + zpl_f32 temp1[3][3], temp2[3][3]; + if (mat1 == out) { + zpl_memcopy(temp1, mat1, sizeof(temp1)); + mat1 = temp1; + } + if (mat2 == out) { + zpl_memcopy(temp2, mat2, sizeof(temp2)); + mat2 = temp2; + } + for (j = 0; j < 3; j++) { + for (i = 0; i < 3; i++) { + out[j][i] = mat1[0][i] * mat2[j][0] + mat1[1][i] * mat2[j][1] + mat1[2][i] * mat2[j][2]; + } + } +} + +void zpl_float33_mul_vec3(zpl_vec3 *out, zpl_f32 m[3][3], zpl_vec3 v) { + out->x = m[0][0] * v.x + m[0][1] * v.y + m[0][2] * v.z; + out->y = m[1][0] * v.x + m[1][1] * v.y + m[1][2] * v.z; + out->z = m[2][0] * v.x + m[2][1] * v.y + m[2][2] * v.z; +} + +zpl_f32 zpl_mat3_determinate(zpl_mat3 *m) { + zpl_float3 *e = zpl_float33_m(m); + zpl_f32 d = + +e[0][0] * (e[1][1] * e[2][2] - e[1][2] * e[2][1]) + -e[0][1] * (e[1][0] * e[2][2] - e[1][2] * e[2][0]) + +e[0][2] * (e[1][0] * e[2][1] - e[1][1] * e[2][0]); + return d; +} + +void zpl_mat3_inverse(zpl_mat3 *out, zpl_mat3 *in) { + zpl_float3 *o = zpl_float33_m(out); + zpl_float3 *i = zpl_float33_m(in); + + zpl_f32 ood = 1.0f / zpl_mat3_determinate(in); + + o[0][0] = +(i[1][1] * i[2][2] - i[2][1] * i[1][2]) * ood; + o[0][1] = -(i[1][0] * i[2][2] - i[2][0] * i[1][2]) * ood; + o[0][2] = +(i[1][0] * i[2][1] - i[2][0] * i[1][1]) * ood; + o[1][0] = -(i[0][1] * i[2][2] - i[2][1] * i[0][2]) * ood; + o[1][1] = +(i[0][0] * i[2][2] - i[2][0] * i[0][2]) * ood; + o[1][2] = -(i[0][0] * i[2][1] - i[2][0] * i[0][1]) * ood; + o[2][0] = +(i[0][1] * i[1][2] - i[1][1] * i[0][2]) * ood; + o[2][1] = -(i[0][0] * i[1][2] - i[1][0] * i[0][2]) * ood; + o[2][2] = +(i[0][0] * i[1][1] - i[1][0] * i[0][1]) * ood; +} + +void zpl_mat4_transpose(zpl_mat4 *m) { zpl_float44_transpose(zpl_float44_m(m)); } +void zpl_mat4_identity(zpl_mat4 *m) { zpl_float44_identity(zpl_float44_m(m)); } + +void zpl_mat4_copy(zpl_mat4* out, zpl_mat4* m) { + zpl_memcopy(out, m, sizeof(zpl_mat4)); +} + + +void zpl_mat4_mul(zpl_mat4 *out, zpl_mat4 *m1, zpl_mat4 *m2) { + zpl_float44_mul(zpl_float44_m(out), zpl_float44_m(m1), zpl_float44_m(m2)); +} + +void zpl_float44_identity(zpl_f32 m[4][4]) { + m[0][0] = 1; + m[0][1] = 0; + m[0][2] = 0; + m[0][3] = 0; + m[1][0] = 0; + m[1][1] = 1; + m[1][2] = 0; + m[1][3] = 0; + m[2][0] = 0; + m[2][1] = 0; + m[2][2] = 1; + m[2][3] = 0; + m[3][0] = 0; + m[3][1] = 0; + m[3][2] = 0; + m[3][3] = 1; +} + +void zpl_mat4_mul_vec4(zpl_vec4 *out, zpl_mat4 *m, zpl_vec4 in) { zpl_float44_mul_vec4(out, zpl_float44_m(m), in); } + +zpl_mat4 *zpl_mat4_v(zpl_vec4 m[4]) { return (zpl_mat4 *)m; } +zpl_mat4 *zpl_mat4_f(zpl_f32 m[4][4]) { return (zpl_mat4 *)m; } + +zpl_float4 *zpl_float44_m(zpl_mat4 *m) { return (zpl_float4 *)m; } +zpl_float4 *zpl_float44_v(zpl_vec4 m[4]) { return (zpl_float4 *)m; } +zpl_float4 *zpl_float44_16(zpl_f32 m[16]) { return (zpl_float4 *)m; } + +void zpl_float44_transpose(zpl_f32 (*vec)[4]) { + zpl_f32 tmp; + tmp = vec[1][0]; + vec[1][0] = vec[0][1]; + vec[0][1] = tmp; + tmp = vec[2][0]; + vec[2][0] = vec[0][2]; + vec[0][2] = tmp; + tmp = vec[3][0]; + vec[3][0] = vec[0][3]; + vec[0][3] = tmp; + tmp = vec[2][1]; + vec[2][1] = vec[1][2]; + vec[1][2] = tmp; + tmp = vec[3][1]; + vec[3][1] = vec[1][3]; + vec[1][3] = tmp; + tmp = vec[3][2]; + vec[3][2] = vec[2][3]; + vec[2][3] = tmp; +} + +void zpl_float44_mul(zpl_f32 (*out)[4], zpl_f32 (*mat1)[4], zpl_f32 (*mat2)[4]) { + int i, j; + zpl_f32 temp1[4][4], temp2[4][4]; + if (mat1 == out) { + zpl_memcopy(temp1, mat1, sizeof(temp1)); + mat1 = temp1; + } + if (mat2 == out) { + zpl_memcopy(temp2, mat2, sizeof(temp2)); + mat2 = temp2; + } + for (j = 0; j < 4; j++) { + for (i = 0; i < 4; i++) { + out[j][i] = + mat1[0][i] * mat2[j][0] + mat1[1][i] * mat2[j][1] + +mat1[2][i] * mat2[j][2] + mat1[3][i] * mat2[j][3]; + } + } +} + +void zpl_float44_mul_vec4(zpl_vec4 *out, zpl_f32 m[4][4], zpl_vec4 v) { + out->x = m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z + m[3][0] * v.w; + out->y = m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z + m[3][1] * v.w; + out->z = m[0][2] * v.x + m[1][2] * v.y + m[2][2] * v.z + m[3][2] * v.w; + out->w = m[0][3] * v.x + m[1][3] * v.y + m[2][3] * v.z + m[3][3] * v.w; +} + +void zpl_mat4_inverse(zpl_mat4 *out, zpl_mat4 *in) { + zpl_float4 *o = zpl_float44_m(out); + zpl_float4 *m = zpl_float44_m(in); + + zpl_f32 ood; + + zpl_f32 sf00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; + zpl_f32 sf01 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; + zpl_f32 sf02 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; + zpl_f32 sf03 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; + zpl_f32 sf04 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; + zpl_f32 sf05 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; + zpl_f32 sf06 = m[1][2] * m[3][3] - m[3][2] * m[1][3]; + zpl_f32 sf07 = m[1][1] * m[3][3] - m[3][1] * m[1][3]; + zpl_f32 sf08 = m[1][1] * m[3][2] - m[3][1] * m[1][2]; + zpl_f32 sf09 = m[1][0] * m[3][3] - m[3][0] * m[1][3]; + zpl_f32 sf10 = m[1][0] * m[3][2] - m[3][0] * m[1][2]; + zpl_f32 sf11 = m[1][1] * m[3][3] - m[3][1] * m[1][3]; + zpl_f32 sf12 = m[1][0] * m[3][1] - m[3][0] * m[1][1]; + zpl_f32 sf13 = m[1][2] * m[2][3] - m[2][2] * m[1][3]; + zpl_f32 sf14 = m[1][1] * m[2][3] - m[2][1] * m[1][3]; + zpl_f32 sf15 = m[1][1] * m[2][2] - m[2][1] * m[1][2]; + zpl_f32 sf16 = m[1][0] * m[2][3] - m[2][0] * m[1][3]; + zpl_f32 sf17 = m[1][0] * m[2][2] - m[2][0] * m[1][2]; + zpl_f32 sf18 = m[1][0] * m[2][1] - m[2][0] * m[1][1]; + + o[0][0] = +(m[1][1] * sf00 - m[1][2] * sf01 + m[1][3] * sf02); + o[1][0] = -(m[1][0] * sf00 - m[1][2] * sf03 + m[1][3] * sf04); + o[2][0] = +(m[1][0] * sf01 - m[1][1] * sf03 + m[1][3] * sf05); + o[3][0] = -(m[1][0] * sf02 - m[1][1] * sf04 + m[1][2] * sf05); + + o[0][1] = -(m[0][1] * sf00 - m[0][2] * sf01 + m[0][3] * sf02); + o[1][1] = +(m[0][0] * sf00 - m[0][2] * sf03 + m[0][3] * sf04); + o[2][1] = -(m[0][0] * sf01 - m[0][1] * sf03 + m[0][3] * sf05); + o[3][1] = +(m[0][0] * sf02 - m[0][1] * sf04 + m[0][2] * sf05); + + o[0][2] = +(m[0][1] * sf06 - m[0][2] * sf07 + m[0][3] * sf08); + o[1][2] = -(m[0][0] * sf06 - m[0][2] * sf09 + m[0][3] * sf10); + o[2][2] = +(m[0][0] * sf11 - m[0][1] * sf09 + m[0][3] * sf12); + o[3][2] = -(m[0][0] * sf08 - m[0][1] * sf10 + m[0][2] * sf12); + + o[0][3] = -(m[0][1] * sf13 - m[0][2] * sf14 + m[0][3] * sf15); + o[1][3] = +(m[0][0] * sf13 - m[0][2] * sf16 + m[0][3] * sf17); + o[2][3] = -(m[0][0] * sf14 - m[0][1] * sf16 + m[0][3] * sf18); + o[3][3] = +(m[0][0] * sf15 - m[0][1] * sf17 + m[0][2] * sf18); + + ood = 1.0f / (m[0][0] * o[0][0] + m[0][1] * o[1][0] + m[0][2] * o[2][0] + m[0][3] * o[3][0]); + + o[0][0] *= ood; o[1][0] *= ood; o[2][0] *= ood; o[3][0] *= ood; + o[0][1] *= ood; o[1][1] *= ood; o[2][1] *= ood; o[3][1] *= ood; + o[0][2] *= ood; o[1][2] *= ood; o[2][2] *= ood; o[3][2] *= ood; + o[0][3] *= ood; o[1][3] *= ood; o[2][3] *= ood; o[3][3] *= ood; +} + +void zpl_mat4_axis_angle(zpl_mat4 *out, zpl_vec3 v, zpl_f32 angle_radians) { + zpl_f32 c, s; + zpl_vec3 axis, t; + zpl_float4 *rot; + + c = zpl_cos(angle_radians); + s = zpl_sin(angle_radians); + + zpl_vec3_norm(&axis, v); + zpl_vec3_mul(&t, axis, 1.0f - c); + + zpl_mat4_identity(out); + rot = zpl_float44_m(out); + + rot[0][0] = c + t.x * axis.x; + rot[0][1] = 0 + t.x * axis.y + s * axis.z; + rot[0][2] = 0 + t.x * axis.z - s * axis.y; + rot[0][3] = 0; + + rot[1][0] = 0 + t.y * axis.x - s * axis.z; + rot[1][1] = c + t.y * axis.y; + rot[1][2] = 0 + t.y * axis.z + s * axis.x; + rot[1][3] = 0; + + rot[2][0] = 0 + t.z * axis.x + s * axis.y; + rot[2][1] = 0 + t.z * axis.y - s * axis.x; + rot[2][2] = c + t.z * axis.z; + rot[2][3] = 0; +} + +void zpl_mat4_to_translate(zpl_mat4* out, zpl_vec3 v) { + zpl_mat4_identity(out); + out->col[3].xyz = v; +} + +void zpl_mat4_to_rotate(zpl_mat4* out, zpl_vec3 v, zpl_f32 angle_radians) { + zpl_mat4_axis_angle(out, v, angle_radians); +} + +void zpl_mat4_to_scale(zpl_mat4* out, zpl_vec3 v) { + zpl_mat4_identity(out); + out->col[0].x = v.x; + out->col[1].y = v.y; + out->col[2].z = v.z; +} +void zpl_mat4_to_scalef(zpl_mat4* out, zpl_f32 s) { + zpl_mat4_identity(out); + out->col[0].x = s; + out->col[1].y = s; + out->col[2].z = s; +} + +void zpl_mat4_translate(zpl_mat4* m, zpl_vec3 v) { + zpl_mat4 mm; + zpl_mat4_to_translate(&mm, v); + zpl_mat4_mul(m, m, &mm); +} + +void zpl_mat4_rotate(zpl_mat4* m, zpl_vec3 v, zpl_f32 angle_radians) { + zpl_mat4 mm; + zpl_mat4_axis_angle(&mm,v, angle_radians); + zpl_mat4_mul(m, m, &mm); +} + +void zpl_mat4_scale(zpl_mat4* m, zpl_vec3 v) { + zpl_mat4 mm; + zpl_mat4_to_scale(&mm, v); + zpl_mat4_mul(m, m, &mm); +} + +void zpl_mat4_scalef(zpl_mat4* m, zpl_f32 s) { + zpl_mat4 mm; + zpl_mat4_to_scalef(&mm, s); + zpl_mat4_mul(m, m, &mm); +} + +void zpl_mat4_ortho2d(zpl_mat4 *out, zpl_f32 left, zpl_f32 right, zpl_f32 bottom, zpl_f32 top) { + zpl_float4 *m; + zpl_mat4_identity(out); + m = zpl_float44_m(out); + + m[0][0] = 2.0f / (right - left); + m[1][1] = 2.0f / (top - bottom); + m[2][2] = -1.0f; + m[3][0] = -(right + left) / (right - left); + m[3][1] = -(top + bottom) / (top - bottom); +} + +void zpl_mat4_ortho3d(zpl_mat4 *out, zpl_f32 left, zpl_f32 right, zpl_f32 bottom, zpl_f32 top, zpl_f32 z_near, zpl_f32 z_far) { + zpl_float4 *m; + zpl_mat4_identity(out); + m = zpl_float44_m(out); + + m[0][0] = +2.0f / (right - left); + m[1][1] = +2.0f / (top - bottom); + m[2][2] = -2.0f / (z_far - z_near); + m[3][0] = -(right + left) / (right - left); + m[3][1] = -(top + bottom) / (top - bottom); + m[3][2] = -(z_far + z_near) / (z_far - z_near); +} + +void zpl_mat4_perspective(zpl_mat4 *out, zpl_f32 fovy, zpl_f32 aspect, zpl_f32 z_near, zpl_f32 z_far) { + zpl_f32 tan_half_fovy = zpl_tan(0.5f * fovy); + zpl_mat4 zero_mat = { 0 }; + zpl_float4 *m = zpl_float44_m(out); + *out = zero_mat; + + m[0][0] = 1.0f / (aspect * tan_half_fovy); + m[1][1] = 1.0f / (tan_half_fovy); + m[2][2] = -(z_far + z_near) / (z_far - z_near); + m[2][3] = -1.0f; + m[3][2] = -2.0f * z_far * z_near / (z_far - z_near); +} + +void zpl_mat4_infinite_perspective(zpl_mat4 *out, zpl_f32 fovy, zpl_f32 aspect, zpl_f32 z_near) { + zpl_f32 range = zpl_tan(0.5f * fovy) * z_near; + zpl_f32 left = -range * aspect; + zpl_f32 right = range * aspect; + zpl_f32 bottom = -range; + zpl_f32 top = range; + zpl_mat4 zero_mat = { 0 }; + zpl_float4 *m = zpl_float44_m(out); + *out = zero_mat; + + m[0][0] = (2.0f * z_near) / (right - left); + m[1][1] = (2.0f * z_near) / (top - bottom); + m[2][2] = -1.0f; + m[2][3] = -1.0f; + m[3][2] = -2.0f * z_near; +} + +void zpl_mat4_ortho2d_dx(zpl_mat4 *out, zpl_f32 left, zpl_f32 right, zpl_f32 bottom, zpl_f32 top) { + zpl_float4 *m; + zpl_mat4_identity(out); + m = zpl_float44_m(out); + + m[0][0] = 2.0f / (right - left); + m[1][1] = 2.0f / (top - bottom); + m[2][2] = -1.0f; + m[3][0] = -(right + left) / (right - left); + m[3][1] = -(top + bottom) / (top - bottom); +} + +void zpl_mat4_ortho3d_dx(zpl_mat4 *out, zpl_f32 left, zpl_f32 right, zpl_f32 bottom, zpl_f32 top, zpl_f32 z_near, zpl_f32 z_far) { + zpl_float4 *m; + zpl_mat4_identity(out); + m = zpl_float44_m(out); + + m[0][0] = +2.0f / (right - left); + m[1][1] = +2.0f / (top - bottom); + m[2][2] = -1.0f / (z_far - z_near); + m[3][0] = -(right + left) / (right - left); + m[3][1] = -(top + bottom) / (top - bottom); + m[3][2] = -( z_near) / (z_far - z_near); +} + +void zpl_mat4_perspective_dx(zpl_mat4 *out, zpl_f32 fovy, zpl_f32 aspect, zpl_f32 z_near, zpl_f32 z_far) { + zpl_f32 tan_half_fovy = zpl_tan(0.5f * fovy); + zpl_mat4 zero_mat = { 0 }; + zpl_float4 *m = zpl_float44_m(out); + *out = zero_mat; + + m[0][0] = 1.0f / (aspect * tan_half_fovy); + m[1][1] = 1.0f / (tan_half_fovy); + m[2][2] = -(z_far ) / (z_far - z_near); + m[2][3] = -1.0f; + m[3][2] = - z_near / (z_far - z_near); +} + +void zpl_mat4_infinite_perspective_dx(zpl_mat4 *out, zpl_f32 fovy, zpl_f32 aspect, zpl_f32 z_near) { + zpl_f32 tan_half_fovy = zpl_tan(0.5f * fovy); + zpl_mat4 zero_mat = { 0 }; + zpl_float4 *m = zpl_float44_m(out); + *out = zero_mat; + + m[0][0] = 1.0f / (aspect * tan_half_fovy); + m[1][1] = 1.0f / (tan_half_fovy); + m[2][2] = -1.0f; + m[2][3] = -1.0f; + m[3][2] = - z_near; +} + + + +void zpl_mat4_look_at(zpl_mat4 *out, zpl_vec3 eye, zpl_vec3 centre, zpl_vec3 up) { + zpl_vec3 f, s, u; + zpl_float4 *m; + + zpl_vec3_sub(&f, centre, eye); + zpl_vec3_norm(&f, f); + + zpl_vec3_cross(&s, f, up); + zpl_vec3_norm(&s, s); + + zpl_vec3_cross(&u, s, f); + + zpl_mat4_identity(out); + m = zpl_float44_m(out); + + m[0][0] = +s.x; + m[1][0] = +s.y; + m[2][0] = +s.z; + + m[0][1] = +u.x; + m[1][1] = +u.y; + m[2][1] = +u.z; + + m[0][2] = -f.x; + m[1][2] = -f.y; + m[2][2] = -f.z; + + m[3][0] = -zpl_vec3_dot(s, eye); + m[3][1] = -zpl_vec3_dot(u, eye); + m[3][2] = +zpl_vec3_dot(f, eye); +} + +void zpl_mat4_look_at_lh(zpl_mat4 *out, zpl_vec3 eye, zpl_vec3 centre, zpl_vec3 up) { + zpl_vec3 f, s, u; + zpl_float4 *m; + + zpl_vec3_sub(&f, centre, eye); + zpl_vec3_norm(&f, f); + + zpl_vec3_cross(&s, up, f); + zpl_vec3_norm(&s, s); + + zpl_vec3_cross(&u, f, s); + + zpl_mat4_identity(out); + m = zpl_float44_m(out); + + m[0][0] = +s.x; + m[1][0] = +s.y; + m[2][0] = +s.z; + + m[0][1] = +u.x; + m[1][1] = +u.y; + m[2][1] = +u.z; + + m[0][2] = +f.x; + m[1][2] = +f.y; + m[2][2] = +f.z; + + m[3][0] = -zpl_vec3_dot(s, eye); + m[3][1] = -zpl_vec3_dot(u, eye); + m[3][2] = -zpl_vec3_dot(f, eye); +} + +zpl_quat zpl_quatf(zpl_f32 x, zpl_f32 y, zpl_f32 z, zpl_f32 w) { + zpl_quat q; + q.x = x; + q.y = y; + q.z = z; + q.w = w; + return q; +} +zpl_quat zpl_quatfv(zpl_f32 e[4]) { + zpl_quat q; + q.x = e[0]; + q.y = e[1]; + q.z = e[2]; + q.w = e[3]; + return q; +} + +zpl_quat zpl_quat_axis_angle(zpl_vec3 axis, zpl_f32 angle_radians) { + zpl_quat q; + zpl_vec3_norm(&q.xyz, axis); + zpl_vec3_muleq(&q.xyz, zpl_sin(0.5f * angle_radians)); + q.w = zpl_cos(0.5f * angle_radians); + return q; +} + +zpl_quat zpl_quat_euler_angles(zpl_f32 pitch, zpl_f32 yaw, zpl_f32 roll) { + /* TODO: Do without multiplication, i.e. make it faster */ + zpl_quat q, p, y, r; + p = zpl_quat_axis_angle(zpl_vec3f(1, 0, 0), pitch); + y = zpl_quat_axis_angle(zpl_vec3f(0, 1, 0), yaw); + r = zpl_quat_axis_angle(zpl_vec3f(0, 0, 1), roll); + + zpl_quat_mul(&q, y, p); + zpl_quat_muleq(&q, r); + + return q; +} + +zpl_quat zpl_quat_identity(void) { + zpl_quat q = { 0, 0, 0, 1 }; + return q; +} + +void zpl_quat_add(zpl_quat *d, zpl_quat q0, zpl_quat q1) { zpl_vec4_add(&d->xyzw, q0.xyzw, q1.xyzw); } +void zpl_quat_sub(zpl_quat *d, zpl_quat q0, zpl_quat q1) { zpl_vec4_sub(&d->xyzw, q0.xyzw, q1.xyzw); } + +void zpl_quat_mul(zpl_quat *d, zpl_quat q0, zpl_quat q1) { + d->x = q0.w * q1.x + q0.x * q1.w + q0.y * q1.z - q0.z * q1.y; + d->y = q0.w * q1.y - q0.x * q1.z + q0.y * q1.w + q0.z * q1.x; + d->z = q0.w * q1.z + q0.x * q1.y - q0.y * q1.x + q0.z * q1.w; + d->w = q0.w * q1.w - q0.x * q1.x - q0.y * q1.y - q0.z * q1.z; +} + +void zpl_quat_div(zpl_quat *d, zpl_quat q0, zpl_quat q1) { + zpl_quat iq1; + zpl_quat_inverse(&iq1, q1); + zpl_quat_mul(d, q0, iq1); +} + +void zpl_quat_mulf(zpl_quat *d, zpl_quat q0, zpl_f32 s) { zpl_vec4_mul(&d->xyzw, q0.xyzw, s); } +void zpl_quat_divf(zpl_quat *d, zpl_quat q0, zpl_f32 s) { zpl_vec4_div(&d->xyzw, q0.xyzw, s); } + +void zpl_quat_addeq(zpl_quat *d, zpl_quat q) { zpl_vec4_addeq(&d->xyzw, q.xyzw); } +void zpl_quat_subeq(zpl_quat *d, zpl_quat q) { zpl_vec4_subeq(&d->xyzw, q.xyzw); } +void zpl_quat_muleq(zpl_quat *d, zpl_quat q) { zpl_quat_mul(d, *d, q); } +void zpl_quat_diveq(zpl_quat *d, zpl_quat q) { zpl_quat_div(d, *d, q); } + +void zpl_quat_muleqf(zpl_quat *d, zpl_f32 s) { zpl_vec4_muleq(&d->xyzw, s); } +void zpl_quat_diveqf(zpl_quat *d, zpl_f32 s) { zpl_vec4_diveq(&d->xyzw, s); } + +zpl_f32 zpl_quat_dot(zpl_quat q0, zpl_quat q1) { + zpl_f32 r = zpl_vec3_dot(q0.xyz, q1.xyz) + q0.w * q1.w; + return r; +} +zpl_f32 zpl_quat_mag(zpl_quat q) { + zpl_f32 r = zpl_sqrt(zpl_quat_dot(q, q)); + return r; +} + +void zpl_quat_norm(zpl_quat *d, zpl_quat q) { zpl_quat_divf(d, q, zpl_quat_mag(q)); } + +void zpl_quat_conj(zpl_quat *d, zpl_quat q) { + d->xyz = zpl_vec3f(-q.x, -q.y, -q.z); + d->w = q.w; +} +void zpl_quat_inverse(zpl_quat *d, zpl_quat q) { + zpl_quat_conj(d, q); + zpl_quat_diveqf(d, zpl_quat_dot(q, q)); +} + +void zpl_quat_axis(zpl_vec3 *axis, zpl_quat q) { + zpl_quat n; + zpl_quat_norm(&n, q); + zpl_vec3_div(axis, n.xyz, zpl_sin(zpl_arccos(q.w))); +} + +zpl_f32 zpl_quat_angle(zpl_quat q) { + zpl_f32 mag = zpl_quat_mag(q); + zpl_f32 c = q.w * (1.0f / mag); + zpl_f32 angle = 2.0f * zpl_arccos(c); + return angle; +} + +zpl_f32 zpl_quat_roll(zpl_quat q) { + return zpl_arctan2(2.0f * q.x * q.y + q.z * q.w, q.x * q.x + q.w * q.w - q.y * q.y - q.z * q.z); +} +zpl_f32 zpl_quat_pitch(zpl_quat q) { + return zpl_arctan2(2.0f * q.y * q.z + q.w * q.x, q.w * q.w - q.x * q.x - q.y * q.y + q.z * q.z); +} +zpl_f32 zpl_quat_yaw(zpl_quat q) { return zpl_arcsin(-2.0f * (q.x * q.z - q.w * q.y)); } + +void zpl_quat_rotate_vec3(zpl_vec3 *d, zpl_quat q, zpl_vec3 v) { + /* zpl_vec3 t = 2.0f * cross(q.xyz, v); + * *d = q.w*t + v + cross(q.xyz, t); + */ + zpl_vec3 t, p; + zpl_vec3_cross(&t, q.xyz, v); + zpl_vec3_muleq(&t, 2.0f); + + zpl_vec3_cross(&p, q.xyz, t); + + zpl_vec3_mul(d, t, q.w); + zpl_vec3_addeq(d, v); + zpl_vec3_addeq(d, p); +} + +void zpl_mat4_from_quat(zpl_mat4 *out, zpl_quat q) { + zpl_float4 *m; + zpl_quat a; + zpl_f32 xx, yy, zz, xy, xz, yz, wx, wy, wz; + + zpl_quat_norm(&a, q); + xx = a.x * a.x; + yy = a.y * a.y; + zz = a.z * a.z; + xy = a.x * a.y; + xz = a.x * a.z; + yz = a.y * a.z; + wx = a.w * a.x; + wy = a.w * a.y; + wz = a.w * a.z; + + zpl_mat4_identity(out); + m = zpl_float44_m(out); + + m[0][0] = 1.0f - 2.0f * (yy + zz); + m[0][1] = 2.0f * (xy + wz); + m[0][2] = 2.0f * (xz - wy); + + m[1][0] = 2.0f * (xy - wz); + m[1][1] = 1.0f - 2.0f * (xx + zz); + m[1][2] = 2.0f * (yz + wx); + + m[2][0] = 2.0f * (xz + wy); + m[2][1] = 2.0f * (yz - wx); + m[2][2] = 1.0f - 2.0f * (xx + yy); +} + +void zpl_quat_from_mat4(zpl_quat *out, zpl_mat4 *mat) { + zpl_float4 *m; + zpl_f32 four_x_squared_minus_1, four_y_squared_minus_1, four_z_squared_minus_1, four_w_squared_minus_1, + four_biggest_squared_minus_1; + int biggest_index = 0; + zpl_f32 biggest_value, mult; + + m = zpl_float44_m(mat); + + four_x_squared_minus_1 = m[0][0] - m[1][1] - m[2][2]; + four_y_squared_minus_1 = m[1][1] - m[0][0] - m[2][2]; + four_z_squared_minus_1 = m[2][2] - m[0][0] - m[1][1]; + four_w_squared_minus_1 = m[0][0] + m[1][1] + m[2][2]; + + four_biggest_squared_minus_1 = four_w_squared_minus_1; + if (four_x_squared_minus_1 > four_biggest_squared_minus_1) { + four_biggest_squared_minus_1 = four_x_squared_minus_1; + biggest_index = 1; + } + if (four_y_squared_minus_1 > four_biggest_squared_minus_1) { + four_biggest_squared_minus_1 = four_y_squared_minus_1; + biggest_index = 2; + } + if (four_z_squared_minus_1 > four_biggest_squared_minus_1) { + four_biggest_squared_minus_1 = four_z_squared_minus_1; + biggest_index = 3; + } + + biggest_value = zpl_sqrt(four_biggest_squared_minus_1 + 1.0f) * 0.5f; + mult = 0.25f / biggest_value; + + switch (biggest_index) { + case 0: + out->w = biggest_value; + out->x = (m[1][2] - m[2][1]) * mult; + out->y = (m[2][0] - m[0][2]) * mult; + out->z = (m[0][1] - m[1][0]) * mult; + break; + case 1: + out->w = (m[1][2] - m[2][1]) * mult; + out->x = biggest_value; + out->y = (m[0][1] + m[1][0]) * mult; + out->z = (m[2][0] + m[0][2]) * mult; + break; + case 2: + out->w = (m[2][0] - m[0][2]) * mult; + out->x = (m[0][1] + m[1][0]) * mult; + out->y = biggest_value; + out->z = (m[1][2] + m[2][1]) * mult; + break; + case 3: + out->w = (m[0][1] - m[1][0]) * mult; + out->x = (m[2][0] + m[0][2]) * mult; + out->y = (m[1][2] + m[2][1]) * mult; + out->z = biggest_value; + break; + } +} + +zpl_f32 zpl_plane_distance(zpl_plane* p, zpl_vec3 v) { + return (p->a * v.x + p->b * v.y + p->c * v.z + p->d); +} + +void zpl_frustum_create(zpl_frustum* out, zpl_mat4* camera, zpl_mat4* proj) { + zpl_mat4 pv; + + zpl_mat4_mul(&pv, camera, proj); + + zpl_plane* fp = 0; + zpl_f32 rmag; + + fp = &out->x1; + fp->a = pv.x.w + pv.x.x; + fp->b = pv.y.w + pv.x.y; + fp->c = pv.z.w + pv.x.z; + fp->d = pv.w.w + pv.x.w; + + rmag = zpl_rsqrt(zpl_square(fp->a) + zpl_square(fp->b) + zpl_square(fp->c)); + + fp->a *= rmag; + fp->b *= rmag; + fp->c *= rmag; + fp->d *= rmag; + + fp = &out->x2; + + fp->a = pv.x.w - pv.x.x; + fp->b = pv.y.w - pv.x.y; + fp->c = pv.z.w - pv.x.z; + fp->d = pv.w.w - pv.x.w; + + rmag = zpl_rsqrt(zpl_square(fp->a) + zpl_square(fp->b) + zpl_square(fp->c)); + + fp->a *= rmag; + fp->b *= rmag; + fp->c *= rmag; + fp->d *= rmag; + + fp = &out->y1; + + fp->a = pv.x.w - pv.y.x; + fp->b = pv.y.w - pv.y.y; + fp->c = pv.z.w - pv.y.w; + fp->d = pv.w.w - pv.y.z; + + rmag = zpl_rsqrt(zpl_square(fp->a) + zpl_square(fp->b) + zpl_square(fp->c)); + + fp->a *= rmag; + fp->b *= rmag; + fp->c *= rmag; + fp->d *= rmag; + + fp = &out->y2; + + fp->a = pv.x.w + pv.y.x; + fp->b = pv.y.w + pv.y.y; + fp->c = pv.z.w + pv.y.z; + fp->d = pv.w.w + pv.y.w; + + rmag = zpl_rsqrt(zpl_square(fp->a) + zpl_square(fp->b) + zpl_square(fp->c)); + + fp->a *= rmag; + fp->b *= rmag; + fp->c *= rmag; + fp->d *= rmag;; + + fp = &out->z1; + + fp->a = pv.x.w + pv.z.x; + fp->b = pv.y.w + pv.z.y; + fp->c = pv.z.w + pv.z.z; + fp->d = pv.w.w + pv.z.w; + + rmag = zpl_rsqrt(zpl_square(fp->a) + zpl_square(fp->b) + zpl_square(fp->c)); + + fp->a *= rmag; + fp->b *= rmag; + fp->c *= rmag; + fp->d *= rmag; + + fp = &out->z2; + + fp->a = pv.x.w - pv.z.x; + fp->b = pv.y.w - pv.z.y; + fp->c = pv.z.w - pv.z.z; + fp->d = pv.w.w - pv.z.w; + + rmag = zpl_rsqrt(zpl_square(fp->a) + zpl_square(fp->b) + zpl_square(fp->c)); + + fp->a *= rmag; + fp->b *= rmag; + fp->c *= rmag; + fp->d *= rmag; +} + +zpl_b8 zpl_frustum_sphere_inside(zpl_frustum* frustum, zpl_vec3 center, zpl_f32 radius) { + if (zpl_plane_distance(&frustum->x1, center) <= -radius) return 0; + if (zpl_plane_distance(&frustum->x2, center) <= -radius) return 0; + if (zpl_plane_distance(&frustum->y1, center) <= -radius) return 0; + if (zpl_plane_distance(&frustum->y2, center) <= -radius) return 0; + if (zpl_plane_distance(&frustum->z1, center) <= -radius) return 0; + if (zpl_plane_distance(&frustum->z2, center) <= -radius) return 0; + + return 1; +} + +zpl_b8 zpl_frustum_point_inside(zpl_frustum* frustum, zpl_vec3 point) { + return zpl_frustum_sphere_inside(frustum, point, 0.0f); +} + +zpl_b8 zpl_frustum_box_inside(zpl_frustum* frustum, zpl_aabb3 aabb) { + zpl_vec3 box, center; + zpl_vec3 v, b; + zpl_vec3_sub(&box, aabb.max, aabb.min); + zpl_vec3_diveq(&box, 2.0f); + zpl_vec3_add(¢er, aabb.min, box); + + b = zpl_vec3f(-box.x, -box.y, -box.z); + zpl_vec3_add(&v, b, center); + + if (zpl_frustum_point_inside(frustum, v)) return 1; + + b = zpl_vec3f(+box.x, -box.y, -box.z); + zpl_vec3_add(&v, b, center); + + if (zpl_frustum_point_inside(frustum, v)) return 1; + + b = zpl_vec3f(-box.x, +box.y, -box.z); + zpl_vec3_add(&v, b, center); + + if (zpl_frustum_point_inside(frustum, v)) return 1; + + b = zpl_vec3f(+box.x, +box.y, -box.z); + zpl_vec3_add(&v, b, center); + + if (zpl_frustum_point_inside(frustum, v)) return 1; + + b = zpl_vec3f(+box.x, +box.y, +box.z); + zpl_vec3_add(&v, b, center); + + if (zpl_frustum_point_inside(frustum, v)) return 1; + + b = zpl_vec3f(-box.x, +box.y, +box.z); + zpl_vec3_add(&v, b, center); + + if (zpl_frustum_point_inside(frustum, v)) return 1; + + b = zpl_vec3f(-box.x, -box.y, +box.z); + zpl_vec3_add(&v, b, center); + + if (zpl_frustum_point_inside(frustum, v)) return 1; + + b = zpl_vec3f(+box.x, -box.y, +box.z); + zpl_vec3_add(&v, b, center); + + if (zpl_frustum_point_inside(frustum, v)) return 1; + + return 0; +} + +zpl_f32 zpl_lerp(zpl_f32 a, zpl_f32 b, zpl_f32 t) { return a * (1.0f - t) + b * t; } +zpl_f32 zpl_unlerp(zpl_f32 t, zpl_f32 a, zpl_f32 b) { return (t - a) / (b - a); } +zpl_f32 zpl_smooth_step(zpl_f32 a, zpl_f32 b, zpl_f32 t) { + zpl_f32 x = (t - a) / (b - a); + return x * x * (3.0f - 2.0f * x); +} +zpl_f32 zpl_smoother_step(zpl_f32 a, zpl_f32 b, zpl_f32 t) { + zpl_f32 x = (t - a) / (b - a); + return x * x * x * (x * (6.0f * x - 15.0f) + 10.0f); +} + +#define ZPL_VEC_LERPN(N, d, a, b, t) \ +zpl_vec##N db; \ +zpl_vec##N##_sub(&db, b, a); \ +zpl_vec##N##_muleq(&db, t); \ +zpl_vec##N##_add(d, a, db) + +void zpl_vec2_lerp(zpl_vec2 *d, zpl_vec2 a, zpl_vec2 b, zpl_f32 t) { ZPL_VEC_LERPN(2, d, a, b, t); } +void zpl_vec3_lerp(zpl_vec3 *d, zpl_vec3 a, zpl_vec3 b, zpl_f32 t) { ZPL_VEC_LERPN(3, d, a, b, t); } +void zpl_vec4_lerp(zpl_vec4 *d, zpl_vec4 a, zpl_vec4 b, zpl_f32 t) { ZPL_VEC_LERPN(4, d, a, b, t); } + +#undef ZPL_VEC_LERPN + +void zpl_vec2_cslerp(zpl_vec2 *d, zpl_vec2 a, zpl_vec2 v0, zpl_vec2 b, zpl_vec2 v1, zpl_f32 t) { + zpl_f32 t2 = t * t; + zpl_f32 ti = (t - 1); + zpl_f32 ti2 = ti * ti; + + zpl_f32 h00 = (1 + 2 * t) * ti2; + zpl_f32 h10 = t * ti2; + zpl_f32 h01 = t2 * (3 - 2 * t); + zpl_f32 h11 = t2 * ti; + + d->x = h00 * a.x + h10 * v0.x + h01 * b.x + h11 * v1.x; + d->y = h00 * a.y + h10 * v0.y + h01 * b.y + h11 * v1.y; +} + +void zpl_vec3_cslerp(zpl_vec3 *d, zpl_vec3 a, zpl_vec3 v0, zpl_vec3 b, zpl_vec3 v1, zpl_f32 t) { + zpl_f32 t2 = t * t; + zpl_f32 ti = (t - 1); + zpl_f32 ti2 = ti * ti; + + zpl_f32 h00 = (1 + 2 * t) * ti2; + zpl_f32 h10 = t * ti2; + zpl_f32 h01 = t2 * (3 - 2 * t); + zpl_f32 h11 = t2 * ti; + + d->x = h00 * a.x + h10 * v0.x + h01 * b.x + h11 * v1.x; + d->y = h00 * a.y + h10 * v0.y + h01 * b.y + h11 * v1.y; + d->z = h00 * a.z + h10 * v0.z + h01 * b.z + h11 * v1.z; +} + +void zpl_vec2_dcslerp(zpl_vec2 *d, zpl_vec2 a, zpl_vec2 v0, zpl_vec2 b, zpl_vec2 v1, zpl_f32 t) { + zpl_f32 t2 = t * t; + + zpl_f32 dh00 = 6 * t2 - 6 * t; + zpl_f32 dh10 = 3 * t2 - 4 * t + 1; + zpl_f32 dh01 = -6 * t2 + 6 * t; + zpl_f32 dh11 = 3 * t2 - 2 * t; + + d->x = dh00 * a.x + dh10 * v0.x + dh01 * b.x + dh11 * v1.x; + d->y = dh00 * a.y + dh10 * v0.y + dh01 * b.y + dh11 * v1.y; +} + +void zpl_vec3_dcslerp(zpl_vec3 *d, zpl_vec3 a, zpl_vec3 v0, zpl_vec3 b, zpl_vec3 v1, zpl_f32 t) { + zpl_f32 t2 = t * t; + + zpl_f32 dh00 = 6 * t2 - 6 * t; + zpl_f32 dh10 = 3 * t2 - 4 * t + 1; + zpl_f32 dh01 = -6 * t2 + 6 * t; + zpl_f32 dh11 = 3 * t2 - 2 * t; + + d->x = dh00 * a.x + dh10 * v0.x + dh01 * b.x + dh11 * v1.x; + d->y = dh00 * a.y + dh10 * v0.y + dh01 * b.y + dh11 * v1.y; + d->z = dh00 * a.z + dh10 * v0.z + dh01 * b.z + dh11 * v1.z; +} + +void zpl_quat_lerp(zpl_quat *d, zpl_quat a, zpl_quat b, zpl_f32 t) { zpl_vec4_lerp(&d->xyzw, a.xyzw, b.xyzw, t); } +void zpl_quat_nlerp(zpl_quat *d, zpl_quat a, zpl_quat b, zpl_f32 t) { + zpl_quat_lerp(d, a, b, t); + zpl_quat_norm(d, *d); +} + +void zpl_quat_slerp(zpl_quat *d, zpl_quat a, zpl_quat b, zpl_f32 t) { + zpl_quat x, y, z; + zpl_f32 cos_theta, angle; + zpl_f32 s1, s0, is; + + z = b; + cos_theta = zpl_quat_dot(a, b); + + if (cos_theta < 0.0f) { + z = zpl_quatf(-b.x, -b.y, -b.z, -b.w); + cos_theta = -cos_theta; + } + + if (cos_theta > 1.0f) { + /* NOTE: Use lerp not nlerp as it's not a real angle or they are not normalized */ + zpl_quat_lerp(d, a, b, t); + } + + angle = zpl_arccos(cos_theta); + + s1 = zpl_sin((1.0f - t) * angle); + s0 = zpl_sin(t * angle); + is = 1.0f / zpl_sin(angle); + zpl_quat_mulf(&x, a, s1); + zpl_quat_mulf(&y, z, s0); + zpl_quat_add(d, x, y); + zpl_quat_muleqf(d, is); +} + +void zpl_quat_slerp_approx(zpl_quat *d, zpl_quat a, zpl_quat b, zpl_f32 t) { + /* NOTE: Derived by taylor expanding the geometric interpolation equation + * Even works okay for nearly anti-parallel versors!!! + */ + /* NOTE: Extra interations cannot be used as they require angle^4 which is not worth it to approximate */ + zpl_f32 tp = t + (1.0f - zpl_quat_dot(a, b)) / 3.0f * t * (-2.0f * t * t + 3.0f * t - 1.0f); + zpl_quat_nlerp(d, a, b, tp); +} + +void zpl_quat_nquad(zpl_quat *d, zpl_quat p, zpl_quat a, zpl_quat b, zpl_quat q, zpl_f32 t) { + zpl_quat x, y; + zpl_quat_nlerp(&x, p, q, t); + zpl_quat_nlerp(&y, a, b, t); + zpl_quat_nlerp(d, x, y, 2.0f * t * (1.0f - t)); +} + +void zpl_quat_squad(zpl_quat *d, zpl_quat p, zpl_quat a, zpl_quat b, zpl_quat q, zpl_f32 t) { + zpl_quat x, y; + zpl_quat_slerp(&x, p, q, t); + zpl_quat_slerp(&y, a, b, t); + zpl_quat_slerp(d, x, y, 2.0f * t * (1.0f - t)); +} + +void zpl_quat_squad_approx(zpl_quat *d, zpl_quat p, zpl_quat a, zpl_quat b, zpl_quat q, zpl_f32 t) { + zpl_quat x, y; + zpl_quat_slerp_approx(&x, p, q, t); + zpl_quat_slerp_approx(&y, a, b, t); + zpl_quat_slerp_approx(d, x, y, 2.0f * t * (1.0f - t)); +} + +zpl_rect2 zpl_rect2f(zpl_vec2 pos, zpl_vec2 dim) { + zpl_rect2 r; + r.pos = pos; + r.dim = dim; + return r; +} + +zpl_rect3 zpl_rect3f(zpl_vec3 pos, zpl_vec3 dim) { + zpl_rect3 r; + r.pos = pos; + r.dim = dim; + return r; +} + +zpl_aabb2 zpl_aabb2f(zpl_f32 minx, zpl_f32 miny, zpl_f32 maxx, zpl_f32 maxy) { + zpl_aabb2 r; + r.min = zpl_vec2f(minx, miny); + r.max = zpl_vec2f(maxx, maxy); + return r; +} +zpl_aabb3 zpl_aabb3f(zpl_f32 minx, zpl_f32 miny, zpl_f32 minz, zpl_f32 maxx, zpl_f32 maxy, zpl_f32 maxz) { + zpl_aabb3 r; + r.min = zpl_vec3f(minx, miny, minz); + r.max = zpl_vec3f(maxx, maxy, maxz); + return r; +} + +zpl_aabb2 zpl_aabb2_rect2(zpl_rect2 a) { + zpl_aabb2 r; + r.min = a.pos; + zpl_vec2_add(&r.max, a.pos, a.dim); + return r; +} +zpl_aabb3 zpl_aabb3_rect3(zpl_rect3 a) { + zpl_aabb3 r; + r.min = a.pos; + zpl_vec3_add(&r.max, a.pos, a.dim); + return r; +} + +zpl_rect2 zpl_rect2_aabb2(zpl_aabb2 a) { + zpl_rect2 r; + r.pos = a.min; + zpl_vec2_sub(&r.dim, a.max, a.min); + return r; +} +zpl_rect3 zpl_rect3_aabb3(zpl_aabb3 a) { + zpl_rect3 r; + r.pos = a.min; + zpl_vec3_sub(&r.dim, a.max, a.min); + return r; +} + +int zpl_rect2_contains(zpl_rect2 a, zpl_f32 x, zpl_f32 y) { + zpl_f32 min_x = zpl_min(a.pos.x, a.pos.x + a.dim.x); + zpl_f32 max_x = zpl_max(a.pos.x, a.pos.x + a.dim.x); + zpl_f32 min_y = zpl_min(a.pos.y, a.pos.y + a.dim.y); + zpl_f32 max_y = zpl_max(a.pos.y, a.pos.y + a.dim.y); + int result = (x >= min_x) & (x < max_x) & (y >= min_y) & (y < max_y); + return result; +} + +int zpl_rect2_contains_vec2(zpl_rect2 a, zpl_vec2 p) { return zpl_rect2_contains(a, p.x, p.y); } + +int zpl_rect2_intersects(zpl_rect2 a, zpl_rect2 b) { + zpl_rect2 r = { 0 }; + return zpl_rect2_intersection_result(a, b, &r); +} + +int zpl_rect2_intersection_result(zpl_rect2 a, zpl_rect2 b, zpl_rect2 *intersection) { + zpl_f32 a_min_x = zpl_min(a.pos.x, a.pos.x + a.dim.x); + zpl_f32 a_max_x = zpl_max(a.pos.x, a.pos.x + a.dim.x); + zpl_f32 a_min_y = zpl_min(a.pos.y, a.pos.y + a.dim.y); + zpl_f32 a_max_y = zpl_max(a.pos.y, a.pos.y + a.dim.y); + + zpl_f32 b_min_x = zpl_min(b.pos.x, b.pos.x + b.dim.x); + zpl_f32 b_max_x = zpl_max(b.pos.x, b.pos.x + b.dim.x); + zpl_f32 b_min_y = zpl_min(b.pos.y, b.pos.y + b.dim.y); + zpl_f32 b_max_y = zpl_max(b.pos.y, b.pos.y + b.dim.y); + + zpl_f32 x0 = zpl_max(a_min_x, b_min_x); + zpl_f32 y0 = zpl_max(a_min_y, b_min_y); + zpl_f32 x1 = zpl_min(a_max_x, b_max_x); + zpl_f32 y1 = zpl_min(a_max_y, b_max_y); + + if ((x0 < x1) && (y0 < y1)) { + zpl_rect2 r = zpl_rect2f(zpl_vec2f(x0, y0), zpl_vec2f(x1 - x0, y1 - y0)); + *intersection = r; + return 1; + } else { + zpl_rect2 r = { 0 }; + *intersection = r; + return 0; + } +} + +int zpl_aabb2_contains(zpl_aabb2 a, zpl_f32 x, zpl_f32 y) { + return (zpl_is_between_limit(x, a.min.x, a.max.x) && zpl_is_between_limit(y, a.min.y, a.max.y)); +} + +int zpl_aabb3_contains(zpl_aabb3 a, zpl_f32 x, zpl_f32 y, zpl_f32 z) { + return (zpl_is_between_limit(x, a.min.x, a.max.x) && zpl_is_between_limit(y, a.min.y, a.max.y) && zpl_is_between_limit(z, a.min.z, a.max.z)); +} + +zpl_aabb2 zpl_aabb2_cut_left(zpl_aabb2 *a, zpl_f32 b) { + zpl_f32 minx = a->min.x; + a->min.x = zpl_min(a->max.x, a->min.x + b); + return zpl_aabb2f(minx, a->min.y, a->min.x, a->max.y); +} +zpl_aabb2 zpl_aabb2_cut_right(zpl_aabb2 *a, zpl_f32 b) { + zpl_f32 maxx = a->max.x; + a->max.x = zpl_max(a->min.x, a->max.x - b); + return zpl_aabb2f(a->max.x, a->min.y, maxx, a->max.y); +} +zpl_aabb2 zpl_aabb2_cut_top(zpl_aabb2 *a, zpl_f32 b) { + zpl_f32 miny = a->min.y; + a->min.y = zpl_min(a->max.y, a->min.y + b); + return zpl_aabb2f(a->min.x, miny, a->max.x, a->min.y); +} +zpl_aabb2 zpl_aabb2_cut_bottom(zpl_aabb2 *a, zpl_f32 b) { + zpl_f32 maxy = a->max.y; + a->max.y = zpl_max(a->min.y, a->max.y - b); + return zpl_aabb2f(a->min.x, a->max.y, a->max.x, maxy); +} + +zpl_aabb2 zpl_aabb2_get_left(const zpl_aabb2 *a, zpl_f32 b) { + zpl_f32 minx = a->min.x; + zpl_f32 aminx = zpl_min(a->max.x, a->min.x + b); + return zpl_aabb2f(minx, a->min.y, aminx, a->max.y); +} +zpl_aabb2 zpl_aabb2_get_right(const zpl_aabb2 *a, zpl_f32 b) { + zpl_f32 maxx = a->max.x; + zpl_f32 amaxx = zpl_max(a->min.x, a->max.x - b); + return zpl_aabb2f(amaxx, a->min.y, maxx, a->max.y); +} +zpl_aabb2 zpl_aabb2_get_top(const zpl_aabb2 *a, zpl_f32 b) { + zpl_f32 miny = a->min.y; + zpl_f32 aminy = zpl_min(a->max.y, a->min.y + b); + return zpl_aabb2f(a->min.x, miny, a->max.x, aminy); +} +zpl_aabb2 zpl_aabb2_get_bottom(const zpl_aabb2 *a, zpl_f32 b) { + zpl_f32 maxy = a->max.y; + zpl_f32 amaxy = zpl_max(a->min.y, a->max.y - b); + return zpl_aabb2f(a->min.x, amaxy, a->max.x, maxy); +} + +zpl_aabb2 zpl_aabb2_add_left(const zpl_aabb2 *a, zpl_f32 b) { + return zpl_aabb2f(a->min.x-b, a->min.y, a->min.x, a->max.y); +} +zpl_aabb2 zpl_aabb2_add_right(const zpl_aabb2 *a, zpl_f32 b) { + return zpl_aabb2f(a->max.x, a->min.y, a->max.x+b, a->max.y); +} +zpl_aabb2 zpl_aabb2_add_top(const zpl_aabb2 *a, zpl_f32 b) { + return zpl_aabb2f(a->min.x, a->min.y-b, a->max.x, a->min.y); +} +zpl_aabb2 zpl_aabb2_add_bottom(const zpl_aabb2 *a, zpl_f32 b) { + return zpl_aabb2f(a->min.x, a->max.y, a->max.x, a->max.y+b); +} + +zpl_aabb2 zpl_aabb2_contract(const zpl_aabb2 *a, zpl_f32 b) { + zpl_aabb2 r = *a; + zpl_vec2 vb = zpl_vec2f(b, b); + zpl_vec2_addeq(&r.min, vb); + zpl_vec2_subeq(&r.max, vb); + + if (zpl_vec2_mag2(r.min) > zpl_vec2_mag2(r.max)) { + return zpl_aabb2f(0,0,0,0); + } + return r; +} +zpl_aabb2 zpl_aabb2_expand(const zpl_aabb2 *a, zpl_f32 b) { + return zpl_aabb2_contract(a, -b); +} + +ZPL_END_C_DECLS #endif #if defined(ZPL_MODULE_THREADING) - // file: source/threading/fence.c - - - ZPL_BEGIN_C_DECLS - - #if defined(_MSC_VER) - /* Microsoft C/C++-compatible compiler */ - # include - #elif defined(__GNUC__) && (defined(__x86_64__) || defined(__i386__)) - /* GCC-compatible compiler, targeting x86/x86-64 */ - # include - #elif defined(__GNUC__) && defined(__ARM_NEON__) - /* GCC-compatible compiler, targeting ARM with NEON */ - # include - #elif defined(__GNUC__) && defined(__IWMMXT__) - /* GCC-compatible compiler, targeting ARM with WMMX */ - # include - #elif (defined(__GNUC__) || defined(__xlC__)) && (defined(__VEC__) || defined(__ALTIVEC__)) - /* XLC or GCC-compatible compiler, targeting PowerPC with VMX/VSX */ - # include - #elif defined(__GNUC__) && defined(__SPE__) - /* GCC-compatible compiler, targeting PowerPC with SPE */ - # include - #endif - - void zpl_yield_thread(void) { - # if defined(ZPL_SYSTEM_WINDOWS) - _mm_pause(); - # elif defined(ZPL_SYSTEM_OSX) || defined(ZPL_COMPILER_TINYC) - __asm__ volatile ("" : : : "memory"); - # elif defined(ZPL_CPU_X86) - _mm_pause(); - # endif - } - - void zpl_mfence(void) { - # if defined(ZPL_SYSTEM_WINDOWS) - _ReadWriteBarrier(); - # elif defined(ZPL_COMPILER_TINYC) - __asm__ volatile ("" : : : "memory"); - # elif defined(ZPL_SYSTEM_OSX) - __sync_synchronize(); - # elif defined(ZPL_CPU_X86) - _mm_mfence(); - # endif - } - - void zpl_sfence(void) { - # if defined(ZPL_SYSTEM_WINDOWS) - _WriteBarrier(); - # elif defined(ZPL_SYSTEM_OSX) || defined(ZPL_COMPILER_TINYC) - __asm__ volatile ("" : : : "memory"); - # elif defined(ZPL_CPU_X86) - _mm_sfence(); - # endif - } - - void zpl_lfence(void) { - # if defined(ZPL_SYSTEM_WINDOWS) - _ReadBarrier(); - # elif defined(ZPL_SYSTEM_OSX) || defined(ZPL_COMPILER_TINYC) - __asm__ volatile ("" : : : "memory"); - # elif defined(ZPL_CPU_X86) - _mm_lfence(); - # endif - } - - ZPL_END_C_DECLS - // file: source/threading/atomic.c - - - ZPL_BEGIN_C_DECLS - - //////////////////////////////////////////////////////////////// - // - // Concurrency - // - // - // IMPORTANT TODO: Use compiler intrinsics for the atomics - - #if defined(ZPL_COMPILER_MSVC) && !defined(ZPL_COMPILER_CLANG) - zpl_i32 zpl_atomic32_load (zpl_atomic32 const *a) { return a->value; } - void zpl_atomic32_store(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) value) { a->value = value; } - - zpl_i32 zpl_atomic32_compare_exchange(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) expected, zpl_atomicarg(zpl_i32) desired) { - return _InterlockedCompareExchange(cast(long *)a, desired, expected); - } - zpl_i32 zpl_atomic32_exchange(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) desired) { - return _InterlockedExchange(cast(long *)a, desired); - } - zpl_i32 zpl_atomic32_fetch_add(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) operand) { - return _InterlockedExchangeAdd(cast(long *)a, operand); - } - zpl_i32 zpl_atomic32_fetch_and(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) operand) { - return _InterlockedAnd(cast(long *)a, operand); - } - zpl_i32 zpl_atomic32_fetch_or(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) operand) { - return _InterlockedOr(cast(long *)a, operand); - } - - zpl_i64 zpl_atomic64_load(zpl_atomic64 const *a) { - # if defined(ZPL_ARCH_64_BIT) - return a->value; - # elif ZPL_CPU_X86 - // NOTE: The most compatible way to get an atomic 64-bit load on x86 is with cmpxchg8b - zpl_atomicarg(zpl_i64) result; - __asm { - mov esi, a; - mov ebx, eax; - mov ecx, edx; - lock cmpxchg8b [esi]; - mov dword ptr result, eax; - mov dword ptr result[4], edx; - } - return result; - # else - # error TODO: atomics for this CPU - # endif - } - - void zpl_atomic64_store(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) value) { - # if defined(ZPL_ARCH_64_BIT) - a->value = value; - # elif ZPL_CPU_X86 - // NOTE: The most compatible way to get an atomic 64-bit store on x86 is with cmpxchg8b - __asm { - mov esi, a; - mov ebx, dword ptr value; - mov ecx, dword ptr value[4]; - retry: - cmpxchg8b [esi]; - jne retry; - } - # else - # error TODO: atomics for this CPU - # endif - } - - zpl_i64 zpl_atomic64_compare_exchange(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) expected, zpl_atomicarg(zpl_i64) desired) { - return _InterlockedCompareExchange64(cast(zpl_atomicarg(zpl_i64) *)a, desired, expected); - } - - zpl_i64 zpl_atomic64_exchange(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) desired) { - # if defined(ZPL_ARCH_64_BIT) - return _InterlockedExchange64(cast(zpl_atomicarg(zpl_i64) *)a, desired); - # elif ZPL_CPU_X86 - zpl_atomicarg(zpl_i64) expected = a->value; - for (;;) { - zpl_atomicarg(zpl_i64) original = _InterlockedCompareExchange64(cast(zpl_atomicarg(zpl_i64) *)a, desired, expected); - if (original == expected) - return original; - expected = original; - } - # else - # error TODO: atomics for this CPU - # endif - } - - zpl_i64 zpl_atomic64_fetch_add(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) operand) { - # if defined(ZPL_ARCH_64_BIT) - return _InterlockedExchangeAdd64(cast(zpl_atomicarg(zpl_i64) *)a, operand); - # elif ZPL_CPU_X86 - zpl_atomicarg(zpl_i64) expected = a->value; - for (;;) { - zpl_atomicarg(zpl_i64) original = _InterlockedCompareExchange64(cast(zpl_atomicarg(zpl_i64) *)a, expected + operand, expected); - if (original == expected) - return original; - expected = original; - } - # else - # error TODO: atomics for this CPU - # endif - } - - zpl_i64 zpl_atomic64_fetch_and(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) operand) { - # if defined(ZPL_ARCH_64_BIT) - return _InterlockedAnd64(cast(zpl_atomicarg(zpl_i64) *)a, operand); - # elif ZPL_CPU_X86 - zpl_atomicarg(zpl_i64) expected = a->value; - for (;;) { - zpl_atomicarg(zpl_i64) original = _InterlockedCompareExchange64(cast(zpl_atomicarg(zpl_i64) *)a, expected & operand, expected); - if (original == expected) - return original; - expected = original; - } - # else - # error TODO: atomics for this CPU - # endif - } - - zpl_i64 zpl_atomic64_fetch_or(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) operand) { - # if defined(ZPL_ARCH_64_BIT) - return _InterlockedOr64(cast(zpl_atomicarg(zpl_i64) *)a, operand); - # elif ZPL_CPU_X86 - zpl_atomicarg(zpl_i64) expected = a->value; - for (;;) { - zpl_atomicarg(zpl_i64) original = _InterlockedCompareExchange64(cast(zpl_atomicarg(zpl_i64) *)a, expected | operand, expected); - if (original == expected) - return original; - expected = original; - } - # else - # error TODO: atomics for this CPU - # endif - } - - #elif defined(ZPL_CPU_X86) - - zpl_i32 zpl_atomic32_load (zpl_atomic32 const *a) { return a->value; } - void zpl_atomic32_store(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) value) { a->value = value; } - - zpl_i32 zpl_atomic32_compare_exchange(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) expected, zpl_atomicarg(zpl_i32) desired) { - zpl_atomicarg(zpl_i32) original; - __asm__( - "lock; cmpxchgl %2, %1" - : "=a"(original), "+m"(a->value) - : "q"(desired), "0"(expected) - ); - return original; - } - - zpl_i32 zpl_atomic32_exchange(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) desired) { - // NOTE: No lock prefix is necessary for xchgl - zpl_atomicarg(zpl_i32) original; - __asm__( - "xchgl %0, %1" - : "=r"(original), "+m"(a->value) - : "0"(desired) - ); - return original; - } - - zpl_i32 zpl_atomic32_fetch_add(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) operand) { - zpl_atomicarg(zpl_i32) original; - __asm__( - "lock; xaddl %0, %1" - : "=r"(original), "+m"(a->value) - : "0"(operand) - ); - return original; - } - - zpl_i32 zpl_atomic32_fetch_and(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) operand) { - zpl_atomicarg(zpl_i32) original; - zpl_atomicarg(zpl_i32) tmp; - __asm__( - "1: movl %1, %0\n" - " movl %0, %2\n" - " andl %3, %2\n" - " lock; cmpxchgl %2, %1\n" - " jne 1b" - : "=&a"(original), "+m"(a->value), "=&r"(tmp) - : "r"(operand) - ); - return original; - } - - zpl_i32 zpl_atomic32_fetch_or(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) operand) { - zpl_atomicarg(zpl_i32) original; - zpl_atomicarg(zpl_i32) temp; - __asm__( - "1: movl %1, %0\n" - " movl %0, %2\n" - " orl %3, %2\n" - " lock; cmpxchgl %2, %1\n" - " jne 1b" - : "=&a"(original), "+m"(a->value), "=&r"(temp) - : "r"(operand) - ); - return original; - } - - - zpl_i64 zpl_atomic64_load(zpl_atomic64 const *a) { - # if defined(ZPL_ARCH_64_BIT) - return a->value; - # else - zpl_atomicarg(zpl_i64) original; - __asm__( - "movl %%ebx, %%eax\n" - "movl %%ecx, %%edx\n" - "lock; cmpxchg8b %1" - : "=&A"(original) - : "m"(a->value) - ); - return original; - # endif - } - - void zpl_atomic64_store(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) value) { - # if defined(ZPL_ARCH_64_BIT) - a->value = value; - # else - zpl_atomicarg(zpl_i64) expected = a->value; - __asm__( - "1: cmpxchg8b %0\n" - " jne 1b" - : "=m"(a->value) - : "b"((zpl_atomicarg(zpl_i32))value), "c"((zpl_atomicarg(zpl_i32))(value >> 32)), "A"(expected) - ); - # endif - } - - zpl_i64 zpl_atomic64_compare_exchange(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) expected, zpl_atomicarg(zpl_i64) desired) { - # if defined(ZPL_ARCH_64_BIT) - zpl_atomicarg(zpl_i64) original; - __asm__( - "lock; cmpxchgq %2, %1" - : "=a"(original), "+m"(a->value) - : "q"(desired), "0"(expected) - ); - return original; - # else - zpl_atomicarg(zpl_i64) original; - __asm__( - "lock; cmpxchg8b %1" - : "=A"(original), "+m"(a->value) - : "b"((zpl_atomicarg(zpl_i32))desired), "c"((zpl_atomicarg(zpl_i32))(desired >> 32)), "0"(expected) - ); - return original; - # endif - } - - zpl_i64 zpl_atomic64_exchange(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) desired) { - # if defined(ZPL_ARCH_64_BIT) - zpl_atomicarg(zpl_i64) original; - __asm__( - "xchgq %0, %1" - : "=r"(original), "+m"(a->value) - : "0"(desired) - ); - return original; - # else - zpl_atomicarg(zpl_i64) original = a->value; - for (;;) { - zpl_atomicarg(zpl_i64) previous = zpl_atomic64_compare_exchange(a, original, desired); - if (original == previous) - return original; - original = previous; - } - # endif - } - - zpl_i64 zpl_atomic64_fetch_add(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) operand) { - # if defined(ZPL_ARCH_64_BIT) - zpl_atomicarg(zpl_i64) original; - __asm__( - "lock; xaddq %0, %1" - : "=r"(original), "+m"(a->value) - : "0"(operand) - ); - return original; - # else - for (;;) { - zpl_atomicarg(zpl_i64) original = a->value; - if (zpl_atomic64_compare_exchange(a, original, original + operand) == original) - return original; - } - # endif - } - - zpl_i64 zpl_atomic64_fetch_and(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) operand) { - # if defined(ZPL_ARCH_64_BIT) - zpl_atomicarg(zpl_i64) original; - zpl_atomicarg(zpl_i64) tmp; - __asm__( - "1: movq %1, %0\n" - " movq %0, %2\n" - " andq %3, %2\n" - " lock; cmpxchgq %2, %1\n" - " jne 1b" - : "=&a"(original), "+m"(a->value), "=&r"(tmp) - : "r"(operand) - ); - return original; - # else - for (;;) { - zpl_atomicarg(zpl_i64) original = a->value; - if (zpl_atomic64_compare_exchange(a, original, original & operand) == original) - return original; - } - # endif - } - - zpl_i64 zpl_atomic64_fetch_or(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) operand) { - # if defined(ZPL_ARCH_64_BIT) - zpl_atomicarg(zpl_i64) original; - zpl_atomicarg(zpl_i64) temp; - __asm__( - "1: movq %1, %0\n" - " movq %0, %2\n" - " orq %3, %2\n" - " lock; cmpxchgq %2, %1\n" - " jne 1b" - : "=&a"(original), "+m"(a->value), "=&r"(temp) - : "r"(operand) - ); - return original; - # else - for (;;) { - zpl_atomicarg(zpl_i64) original = a->value; - if (zpl_atomic64_compare_exchange(a, original, original | operand) == original) - return original; - } - # endif - } - - #elif !defined(ZPL_COMPILER_MSVC) - zpl_i32 zpl_atomic32_load (zpl_atomic32 const *a) { - return __atomic_load_n((zpl_i32*)&a->value, __ATOMIC_SEQ_CST); - } - void zpl_atomic32_store(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) value) { - __atomic_store((zpl_i32*)&a->value, (zpl_i32*)&value, __ATOMIC_SEQ_CST); - } - - zpl_i32 zpl_atomic32_compare_exchange(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) expected, zpl_atomicarg(zpl_i32) desired) { - return __atomic_compare_exchange_n((zpl_i32*)&a->value, (zpl_i32*)&expected, desired, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); - } - - zpl_i32 zpl_atomic32_exchange(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) desired) { - return __atomic_exchange_n((zpl_i32*)&a->value, desired, __ATOMIC_SEQ_CST); - } - - zpl_i32 zpl_atomic32_fetch_add(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) operand) { - return __atomic_fetch_add((zpl_i32*)&a->value, operand, __ATOMIC_SEQ_CST); - } - - zpl_i32 zpl_atomic32_fetch_and(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) operand) { - return __atomic_fetch_and((zpl_i32*)&a->value, operand, __ATOMIC_SEQ_CST); - } - - zpl_i32 zpl_atomic32_fetch_or(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) operand) { - return __atomic_fetch_or((zpl_i32*)&a->value, operand, __ATOMIC_SEQ_CST); - } - - zpl_i64 zpl_atomic64_load(zpl_atomic64 const *a) { - return __atomic_load_n((zpl_i64*)&a->value, __ATOMIC_SEQ_CST); - } - - void zpl_atomic64_store(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) value) { - __atomic_store((zpl_i64*)&a->value, (zpl_i64*)&value, __ATOMIC_SEQ_CST); - } - - zpl_i64 zpl_atomic64_compare_exchange(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) expected, zpl_atomicarg(zpl_i64) desired) { - return __atomic_compare_exchange_n((zpl_i64*)&a->value, (zpl_i64*)&expected, desired, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); - } - - zpl_i64 zpl_atomic64_exchange(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) desired) { - return __atomic_exchange_n((zpl_i64*)&a->value, desired, __ATOMIC_SEQ_CST); - } - - zpl_i64 zpl_atomic64_fetch_add(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) operand) { - return __atomic_fetch_add((zpl_i64*)&a->value, operand, __ATOMIC_SEQ_CST); - } - - zpl_i64 zpl_atomic64_fetch_and(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) operand) { - return __atomic_fetch_and((zpl_i64*)&a->value, operand, __ATOMIC_SEQ_CST); - } - - zpl_i64 zpl_atomic64_fetch_or(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) operand) { - return __atomic_fetch_or((zpl_i64*)&a->value, operand, __ATOMIC_SEQ_CST); - } - - #else - # error TODO: Implement Atomics for this CPU - #endif - - - - zpl_b32 zpl_atomic32_spin_lock(zpl_atomic32 *a, zpl_isize time_out) { - zpl_atomicarg(zpl_i32) old_value = zpl_atomic32_compare_exchange(a, 1, 0); - zpl_i32 counter = 0; - while (old_value != 0 && (time_out < 0 || counter++ < time_out)) { - zpl_yield_thread(); - old_value = zpl_atomic32_compare_exchange(a, 1, 0); - zpl_mfence(); - } - return old_value == 0; - } - - void zpl_atomic32_spin_unlock(zpl_atomic32 *a) { - zpl_atomic32_store(a, 0); - zpl_mfence(); - } - - zpl_b32 zpl_atomic64_spin_lock(zpl_atomic64 *a, zpl_isize time_out) { - zpl_atomicarg(zpl_i64) old_value = zpl_atomic64_compare_exchange(a, 1, 0); - zpl_atomicarg(zpl_i64) counter = 0; - while (old_value != 0 && (time_out < 0 || counter++ < time_out)) { - zpl_yield_thread(); - old_value = zpl_atomic64_compare_exchange(a, 1, 0); - zpl_mfence(); - } - return old_value == 0; - } - - void zpl_atomic64_spin_unlock(zpl_atomic64 *a) { - zpl_atomic64_store(a, 0); - zpl_mfence(); - } - - zpl_b32 zpl_atomic32_try_acquire_lock(zpl_atomic32 *a) { - zpl_atomicarg(zpl_i32) old_value; - zpl_yield_thread(); - old_value = zpl_atomic32_compare_exchange(a, 1, 0); - zpl_mfence(); - return old_value == 0; - } - - zpl_b32 zpl_atomic64_try_acquire_lock(zpl_atomic64 *a) { - zpl_atomicarg(zpl_i64) old_value; - zpl_yield_thread(); - old_value = zpl_atomic64_compare_exchange(a, 1, 0); - zpl_mfence(); - return old_value == 0; - } - - - - #if defined(ZPL_ARCH_32_BIT) - - void* zpl_atomic_ptr_load(zpl_atomic_ptr const *a) { - return (void *)cast(zpl_intptr)zpl_atomic32_load(cast(zpl_atomic32 const *)a); - } - void zpl_atomic_ptr_store(zpl_atomic_ptr *a, zpl_atomicarg(void *)value) { - zpl_atomic32_store(cast(zpl_atomic32 *)a, cast(zpl_atomicarg(zpl_i32))cast(zpl_intptr)value); - } - void* zpl_atomic_ptr_compare_exchange(zpl_atomic_ptr *a, zpl_atomicarg(void *)expected, zpl_atomicarg(void *)desired) { - return (void *)cast(zpl_intptr)zpl_atomic32_compare_exchange(cast(zpl_atomic32 *)a, cast(zpl_atomicarg(zpl_i32))cast(zpl_intptr)expected, cast(zpl_atomicarg(zpl_i32))cast(zpl_intptr)desired); - } - void* zpl_atomic_ptr_exchange(zpl_atomic_ptr *a, zpl_atomicarg(void *)desired) { - return (void *)cast(zpl_intptr)zpl_atomic32_exchange(cast(zpl_atomic32 *)a, cast(zpl_atomicarg(zpl_i32))cast(zpl_intptr)desired); - } - void* zpl_atomic_ptr_fetch_add(zpl_atomic_ptr *a, zpl_atomicarg(void *)operand) { - return (void *)cast(zpl_intptr)zpl_atomic32_fetch_add(cast(zpl_atomic32 *)a, cast(zpl_atomicarg(zpl_i32))cast(zpl_intptr)operand); - } - void* zpl_atomic_ptr_fetch_and(zpl_atomic_ptr *a, zpl_atomicarg(void *)operand) { - return (void *)cast(zpl_intptr)zpl_atomic32_fetch_and(cast(zpl_atomic32 *)a, cast(zpl_atomicarg(zpl_i32))cast(zpl_intptr)operand); - } - void* zpl_atomic_ptr_fetch_or(zpl_atomic_ptr *a, zpl_atomicarg(void *)operand) { - return (void *)cast(zpl_intptr)zpl_atomic32_fetch_or(cast(zpl_atomic32 *)a, cast(zpl_atomicarg(zpl_i32))cast(zpl_intptr)operand); - } - zpl_b32 zpl_atomic_ptr_spin_lock(zpl_atomic_ptr *a, zpl_isize time_out) { - return zpl_atomic32_spin_lock(cast(zpl_atomic32 *)a, time_out); - } - void zpl_atomic_ptr_spin_unlock(zpl_atomic_ptr *a) { - zpl_atomic32_spin_unlock(cast(zpl_atomic32 *)a); - } - zpl_b32 zpl_atomic_ptr_try_acquire_lock(zpl_atomic_ptr *a) { - return zpl_atomic32_try_acquire_lock(cast(zpl_atomic32 *)a); - } - - #elif defined(ZPL_ARCH_64_BIT) - - void* zpl_atomic_ptr_load(zpl_atomic_ptr const *a) { - return (void *)cast(zpl_intptr)zpl_atomic64_load(cast(zpl_atomic64 const *)a); - } - void zpl_atomic_ptr_store(zpl_atomic_ptr *a, zpl_atomicarg(void *)value) { - zpl_atomic64_store(cast(zpl_atomic64 *)a, cast(zpl_i64)cast(zpl_intptr)value); - } - void* zpl_atomic_ptr_compare_exchange(zpl_atomic_ptr *a, zpl_atomicarg(void *)expected, zpl_atomicarg(void *)desired) { - return (void *)cast(zpl_intptr)zpl_atomic64_compare_exchange(cast(zpl_atomic64 *)a, cast(zpl_i64)cast(zpl_intptr)expected, cast(zpl_i64)cast(zpl_intptr)desired); - } - void* zpl_atomic_ptr_exchange(zpl_atomic_ptr *a, zpl_atomicarg(void *)desired) { - return (void *)cast(zpl_intptr)zpl_atomic64_exchange(cast(zpl_atomic64 *)a, cast(zpl_i64)cast(zpl_intptr)desired); - } - void* zpl_atomic_ptr_fetch_add(zpl_atomic_ptr *a, zpl_atomicarg(void *)operand) { - return (void *)cast(zpl_intptr)zpl_atomic64_fetch_add(cast(zpl_atomic64 *)a, cast(zpl_i64)cast(zpl_intptr)operand); - } - void* zpl_atomic_ptr_fetch_and(zpl_atomic_ptr *a, zpl_atomicarg(void *)operand) { - return (void *)cast(zpl_intptr)zpl_atomic64_fetch_and(cast(zpl_atomic64 *)a, cast(zpl_i64)cast(zpl_intptr)operand); - } - void* zpl_atomic_ptr_fetch_or(zpl_atomic_ptr *a, zpl_atomicarg(void *)operand) { - return (void *)cast(zpl_intptr)zpl_atomic64_fetch_or(cast(zpl_atomic64 *)a, cast(zpl_i64)cast(zpl_intptr)operand); - } - zpl_b32 zpl_atomic_ptr_spin_lock(zpl_atomic_ptr *a, zpl_isize time_out) { - return zpl_atomic64_spin_lock(cast(zpl_atomic64 *)a, time_out); - } - void zpl_atomic_ptr_spin_unlock(zpl_atomic_ptr *a) { - zpl_atomic64_spin_unlock(cast(zpl_atomic64 *)a); - } - zpl_b32 zpl_atomic_ptr_try_acquire_lock(zpl_atomic_ptr *a) { - return zpl_atomic64_try_acquire_lock(cast(zpl_atomic64 *)a); - } - - #endif - - ZPL_END_C_DECLS - // file: source/threading/sem.c - - - ZPL_BEGIN_C_DECLS - - void zpl_semaphore_release(zpl_semaphore *s) { zpl_semaphore_post(s, 1); } - - #if defined(ZPL_SYSTEM_WINDOWS) - - void zpl_semaphore_init (zpl_semaphore *s) { s->win32_handle = CreateSemaphoreA(NULL, 0, ZPL_I32_MAX, NULL); } - void zpl_semaphore_destroy(zpl_semaphore *s) { CloseHandle(s->win32_handle); } - void zpl_semaphore_post (zpl_semaphore *s, zpl_i32 count) { ReleaseSemaphore(s->win32_handle, count, NULL); } - void zpl_semaphore_wait (zpl_semaphore *s) { WaitForSingleObject(s->win32_handle, INFINITE); } - - #elif defined(ZPL_SYSTEM_OSX) - - void zpl_semaphore_init (zpl_semaphore *s) { semaphore_create(mach_task_self(), &s->osx_handle, SYNC_POLICY_FIFO, 0); } - void zpl_semaphore_destroy(zpl_semaphore *s) { semaphore_destroy(mach_task_self(), s->osx_handle); } - void zpl_semaphore_post (zpl_semaphore *s, zpl_i32 count) { while (count --> 0) semaphore_signal(s->osx_handle); } - void zpl_semaphore_wait (zpl_semaphore *s) { semaphore_wait(s->osx_handle); } - - #elif defined(ZPL_SYSTEM_UNIX) - - void zpl_semaphore_init (zpl_semaphore *s) { sem_init(&s->unix_handle, 0, 0); } - void zpl_semaphore_destroy(zpl_semaphore *s) { sem_destroy(&s->unix_handle); } - void zpl_semaphore_post (zpl_semaphore *s, zpl_i32 count) { while (count --> 0) sem_post(&s->unix_handle); } - void zpl_semaphore_wait (zpl_semaphore *s) { int i; do { i = sem_wait(&s->unix_handle); } while (i == -1 && errno == EINTR); } - - #else - # error Semaphores for this OS are not implemented - #endif - - ZPL_END_C_DECLS - // file: source/threading/mutex.c - - - ZPL_BEGIN_C_DECLS - - void zpl_mutex_init(zpl_mutex *m) { - # if defined(ZPL_SYSTEM_WINDOWS) - InitializeCriticalSection((CRITICAL_SECTION*)m->win32_critical_section); - # else - pthread_mutex_init(&m->pthread_mutex, NULL); - # endif - } - - void zpl_mutex_destroy(zpl_mutex *m) { - # if defined(ZPL_SYSTEM_WINDOWS) - DeleteCriticalSection((CRITICAL_SECTION*)m->win32_critical_section); - # else - pthread_mutex_destroy(&m->pthread_mutex); - # endif - } - - void zpl_mutex_lock(zpl_mutex *m) { - # if defined(ZPL_SYSTEM_WINDOWS) - EnterCriticalSection((CRITICAL_SECTION*)m->win32_critical_section); - # else - pthread_mutex_lock(&m->pthread_mutex); - # endif - } - - zpl_b32 zpl_mutex_try_lock(zpl_mutex *m) { - # if defined(ZPL_SYSTEM_WINDOWS) - return TryEnterCriticalSection((CRITICAL_SECTION*)m->win32_critical_section); - # else - return pthread_mutex_trylock(&m->pthread_mutex); - # endif - } - - void zpl_mutex_unlock(zpl_mutex *m) { - # if defined(ZPL_SYSTEM_WINDOWS) - LeaveCriticalSection((CRITICAL_SECTION*)m->win32_critical_section); - # else - pthread_mutex_unlock(&m->pthread_mutex); - # endif - } - - ZPL_END_C_DECLS - // file: source/threading/thread.c - - - ZPL_BEGIN_C_DECLS - - zpl_b32 zpl_thread_is_running(zpl_thread const *t) { return t->is_running != 0; } - - void zpl_thread_init(zpl_thread *t) { - zpl_zero_item(t); - - # if defined(ZPL_SYSTEM_WINDOWS) - t->win32_handle = INVALID_HANDLE_VALUE; - # else - t->posix_handle = 0; - # endif - - zpl_semaphore_init(&t->semaphore); - } - - void zpl_thread_destroy(zpl_thread *t) { - if (t->is_running) zpl_thread_join(t); - zpl_semaphore_destroy(&t->semaphore); - } - - void zpl__thread_run(zpl_thread *t) { - zpl_semaphore_release(&t->semaphore); - t->return_value = t->proc(t); - } - - #if defined(ZPL_SYSTEM_WINDOWS) - DWORD __stdcall zpl__thread_proc(void *arg) { - zpl_thread *t = cast(zpl_thread *)arg; - zpl__thread_run(t); - t->is_running = false; - return 0; - } - #else - void *zpl__thread_proc(void *arg) { - zpl_thread *t = cast(zpl_thread *)arg; - zpl__thread_run(t); - t->is_running = false; - return NULL; - } - #endif - - void zpl_thread_start(zpl_thread *t, zpl_thread_proc proc, void *user_data) { - zpl_thread_start_with_stack(t, proc, user_data, 0); - } - - void zpl_thread_start_with_stack(zpl_thread *t, zpl_thread_proc proc, void *user_data, zpl_isize stack_size) { - ZPL_ASSERT(!t->is_running); - ZPL_ASSERT(proc != NULL); - t->proc = proc; - t->user_data = user_data; - t->stack_size = stack_size; - - # if defined(ZPL_SYSTEM_WINDOWS) - t->win32_handle = CreateThread(NULL, stack_size, zpl__thread_proc, t, 0, NULL); - ZPL_ASSERT_MSG(t->win32_handle != NULL, "CreateThread: GetLastError"); - # else - { - pthread_attr_t attr; - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); - if (stack_size != 0) - pthread_attr_setstacksize(&attr, stack_size); - pthread_create(&t->posix_handle, &attr, zpl__thread_proc, t); - pthread_attr_destroy(&attr); - } - # endif - - t->is_running = true; - zpl_semaphore_wait(&t->semaphore); - } - - void zpl_thread_join(zpl_thread *t) { - if (!t->is_running) return; - - # if defined(ZPL_SYSTEM_WINDOWS) - WaitForSingleObject(t->win32_handle, INFINITE); - CloseHandle(t->win32_handle); - t->win32_handle = INVALID_HANDLE_VALUE; - # else - pthread_join(t->posix_handle, NULL); - t->posix_handle = 0; - # endif - t->is_running = false; - } - - zpl_u32 zpl_thread_current_id(void) { - zpl_u32 thread_id; - # if defined(ZPL_SYSTEM_WINDOWS) - # if defined(ZPL_ARCH_32_BIT) && defined(ZPL_CPU_X86) - thread_id = (cast(zpl_u32 *)__readfsdword(24))[9]; - # elif defined(ZPL_ARCH_64_BIT) && defined(ZPL_CPU_X86) - thread_id = (cast(zpl_u32 *)__readgsqword(48))[18]; - # else - thread_id = GetCurrentThreadId(); - # endif - - # elif defined(ZPL_SYSTEM_OSX) && defined(ZPL_ARCH_64_BIT) - thread_id = pthread_mach_thread_np(pthread_self()); - # elif defined(ZPL_ARCH_32_BIT) && defined(ZPL_CPU_X86) - __asm__("mov %%gs:0x08,%0" : "=r"(thread_id)); - # elif defined(ZPL_ARCH_64_BIT) && defined(ZPL_CPU_X86) - __asm__("mov %%fs:0x10,%0" : "=r"(thread_id)); - # elif defined(__ARM_ARCH) - thread_id = pthread_self(); - # else - # error Unsupported architecture for zpl_thread_current_id() - # endif - - return thread_id; - } - - void zpl_thread_set_name(zpl_thread *t, char const *name) { - # if defined(ZPL_COMPILER_MSVC) - # pragma pack(push, 8) - typedef struct { - DWORD type; - char const *name; - DWORD id; - DWORD flags; - } zplprivThreadName; - # pragma pack(pop) - - zplprivThreadName tn; - tn.type = 0x1000; - tn.name = name; - tn.id = GetThreadId(cast(HANDLE)t->win32_handle); - tn.flags = 0; - - __try { - RaiseException(0x406d1388, 0, zpl_size_of(tn)/4, cast(ULONG_PTR *)&tn); - } __except(1 /*EXCEPTION_EXECUTE_HANDLER*/) { - } - - # elif defined(ZPL_SYSTEM_WINDOWS) && !defined(ZPL_COMPILER_MSVC) - zpl_unused(t); - zpl_unused(name); - // IMPORTANT TODO: Set thread name for GCC/Clang on windows - return; - # elif defined(ZPL_SYSTEM_OSX) - // TODO: Test if this works - pthread_setname_np(name); - # else - zpl_unused(t); - zpl_unused(name); - // TODO: Test if this works - // pthread_set_name_np(t->posix_handle, name); - # endif - } - - ZPL_END_C_DECLS - // file: source/threading/sync.c - - - ZPL_BEGIN_C_DECLS - - void zpl_sync_init(zpl_sync *s) { - zpl_zero_item(s); - zpl_mutex_init(&s->mutex); - zpl_mutex_init(&s->start); - zpl_semaphore_init(&s->release); - } - - void zpl_sync_destroy(zpl_sync *s) { - if (s->waiting) { - ZPL_PANIC("Cannot destroy while threads are waiting!"); - } - - zpl_mutex_destroy(&s->mutex); - zpl_mutex_destroy(&s->start); - zpl_semaphore_destroy(&s->release); - } - - void zpl_sync_set_target(zpl_sync *s, zpl_i32 count) { - zpl_mutex_lock(&s->start); - - zpl_mutex_lock(&s->mutex); - ZPL_ASSERT(s->target == 0); - s->target = count; - s->current = 0; - s->waiting = 0; - zpl_mutex_unlock(&s->mutex); - } - - void zpl_sync_release(zpl_sync *s) { - if (s->waiting) { - zpl_semaphore_release(&s->release); - } else { - s->target = 0; - zpl_mutex_unlock(&s->start); - } - } - - zpl_i32 zpl_sync_reach(zpl_sync *s) { - zpl_i32 n; - zpl_mutex_lock(&s->mutex); - ZPL_ASSERT(s->current < s->target); - n = ++s->current; // NOTE: Record this value to avoid possible race if `return s->current` was done - if (s->current == s->target) - zpl_sync_release(s); - zpl_mutex_unlock(&s->mutex); - return n; - } - - void zpl_sync_reach_and_wait(zpl_sync *s) { - zpl_mutex_lock(&s->mutex); - ZPL_ASSERT(s->current < s->target); - s->current++; - if (s->current == s->target) { - zpl_sync_release(s); - zpl_mutex_unlock(&s->mutex); - } else { - s->waiting++; // NOTE: Waiting, so one more waiter - zpl_mutex_unlock(&s->mutex); // NOTE: Release the mutex to other threads - zpl_semaphore_wait(&s->release); // NOTE: Wait for merge completion - zpl_mutex_lock(&s->mutex); // NOTE: On merge completion, lock mutex - s->waiting--; // NOTE: Done waiting - zpl_sync_release(s); // NOTE: Restart the next waiter - zpl_mutex_unlock(&s->mutex); - } - } - - ZPL_END_C_DECLS - // file: source/threading/affinity.c - - - #if defined(ZPL_SYSTEM_MACOS) - # include - #endif - - ZPL_BEGIN_C_DECLS - - #if defined(ZPL_SYSTEM_WINDOWS) || defined(ZPL_SYSTEM_CYGWIN) - - void zpl_affinity_init(zpl_affinity *a) { - SYSTEM_LOGICAL_PROCESSOR_INFORMATION *start_processor_info = NULL; - DWORD length = 0; - zpl_b32 result = GetLogicalProcessorInformation(NULL, &length); - - zpl_zero_item(a); - - if (!result && GetLastError() == 122l /*ERROR_INSUFFICIENT_BUFFER*/ && length > 0) { - start_processor_info = cast(SYSTEM_LOGICAL_PROCESSOR_INFORMATION *)zpl_alloc(zpl_heap_allocator(), length); - result = GetLogicalProcessorInformation(start_processor_info, &length); - if (result) { - SYSTEM_LOGICAL_PROCESSOR_INFORMATION *end_processor_info, *processor_info; - - a->is_accurate = true; - a->core_count = 0; - a->thread_count = 0; - end_processor_info = cast(SYSTEM_LOGICAL_PROCESSOR_INFORMATION *)zpl_pointer_add(start_processor_info, length); - - for (processor_info = start_processor_info; - processor_info < end_processor_info; - processor_info++) { - if (processor_info->Relationship == RelationProcessorCore) { - zpl_isize thread = zpl_count_set_bits(processor_info->ProcessorMask); - if (thread == 0) { - a->is_accurate = false; - } else if (a->thread_count + thread > ZPL_WIN32_MAX_THREADS) { - a->is_accurate = false; - } else { - ZPL_ASSERT(a->core_count <= a->thread_count && - a->thread_count < ZPL_WIN32_MAX_THREADS); - a->core_masks[a->core_count++] = processor_info->ProcessorMask; - a->thread_count += thread; - } - } - } - } - - zpl_free(zpl_heap_allocator(), start_processor_info); - } - - ZPL_ASSERT(a->core_count <= a->thread_count); - if (a->thread_count == 0) { - a->is_accurate = false; - a->core_count = 1; - a->thread_count = 1; - a->core_masks[0] = 1; - } - - } - - void zpl_affinity_destroy(zpl_affinity *a) { - zpl_unused(a); - } - - zpl_b32 zpl_affinity_set(zpl_affinity *a, zpl_isize core, zpl_isize thread) { - zpl_usize available_mask, check_mask = 1; - ZPL_ASSERT(thread < zpl_affinity_thread_count_for_core(a, core)); - - available_mask = a->core_masks[core]; - for (;;) { - if ((available_mask & check_mask) != 0) { - if (thread-- == 0) { - zpl_usize result = SetThreadAffinityMask(GetCurrentThread(), check_mask); - return result != 0; - } - } - check_mask <<= 1; // NOTE: Onto the next bit - } - } - - zpl_isize zpl_affinity_thread_count_for_core(zpl_affinity *a, zpl_isize core) { - ZPL_ASSERT(core >= 0 && core < a->core_count); - return zpl_count_set_bits(a->core_masks[core]); - } - - #elif defined(ZPL_SYSTEM_MACOS) - void zpl_affinity_init(zpl_affinity *a) { - zpl_usize count, count_size = zpl_size_of(count); - - a->is_accurate = false; - a->thread_count = 1; - a->core_count = 1; - a->threads_per_core = 1; - - if (sysctlbyname("hw.logicalcpu", &count, &count_size, NULL, 0) == 0) { - if (count > 0) { - a->thread_count = count; - // Get # of physical cores - if (sysctlbyname("hw.physicalcpu", &count, &count_size, NULL, 0) == 0) { - if (count > 0) { - a->core_count = count; - a->threads_per_core = a->thread_count / count; - if (a->threads_per_core < 1) - a->threads_per_core = 1; - else - a->is_accurate = true; - } - } - } - } - - } - - void zpl_affinity_destroy(zpl_affinity *a) { - zpl_unused(a); - } - - zpl_b32 zpl_affinity_set(zpl_affinity *a, zpl_isize core, zpl_isize thread_index) { - zpl_isize index; - thread_t thread; - thread_affinity_policy_data_t info; - kern_return_t result; - - ZPL_ASSERT(core < a->core_count); - ZPL_ASSERT(thread_index < a->threads_per_core); - - index = core * a->threads_per_core + thread_index; - thread = mach_thread_self(); - info.affinity_tag = cast(integer_t)index; - result = thread_policy_set(thread, THREAD_AFFINITY_POLICY, cast(thread_policy_t)&info, THREAD_AFFINITY_POLICY_COUNT); - return result == KERN_SUCCESS; - } - - zpl_isize zpl_affinity_thread_count_for_core(zpl_affinity *a, zpl_isize core) { - ZPL_ASSERT(core >= 0 && core < a->core_count); - return a->threads_per_core; - } - - #elif defined(ZPL_SYSTEM_LINUX) || defined(ZPL_SYSTEM_FREEBSD) || defined(ZPL_SYSTEM_OPENBSD) - - // IMPORTANT TODO: This zpl_affinity stuff for linux needs be improved a lot! - // NOTE(zangent): I have to read /proc/cpuinfo to get the number of threads per core. - - void zpl_affinity_init(zpl_affinity *a) { - zpl_b32 accurate = true; - zpl_isize threads = 0; - - a->thread_count = 1; - a->core_count = sysconf(_SC_NPROCESSORS_ONLN); - a->threads_per_core = 1; - - - if(a->core_count <= 0) { - a->core_count = 1; - accurate = false; - } - - // Parsing /proc/cpuinfo to get the number of threads per core. - // NOTE(zangent): This calls the CPU's threads "cores", although the wording - // is kind of weird. This should be right, though. - FILE *cpu_info = fopen("/proc/cpuinfo", "r"); - if (cpu_info != NULL) { - for (;;) { - // The 'temporary char'. Everything goes into this char, - // so that we can check against EOF at the end of this loop. - int c; - - # define AF__CHECK(letter) ((c = getc(cpu_info)) == letter) - if (AF__CHECK('c') && AF__CHECK('p') && AF__CHECK('u') && AF__CHECK(' ') && - AF__CHECK('c') && AF__CHECK('o') && AF__CHECK('r') && AF__CHECK('e') && AF__CHECK('s')) { - // We're on a CPU info line. - while (!AF__CHECK(EOF)) { - if (c == '\n') { - break; - } else if (c < '0' || '9' > c) { - continue; - } - threads = threads * 10 + (c - '0'); - } - break; - } else { - while (!AF__CHECK('\n')) { - if (c==EOF) { - break; - } - } - } - if (c == EOF) { - break; - } - # undef AF__CHECK - } - - fclose(cpu_info); - } - - if (threads == 0) { - threads = 1; - accurate = false; - } - - a->threads_per_core = threads; - a->thread_count = a->threads_per_core * a->core_count; - a->is_accurate = accurate; - - } - - void zpl_affinity_destroy(zpl_affinity *a) { - zpl_unused(a); - } - - zpl_b32 zpl_affinity_set(zpl_affinity * a, zpl_isize core, zpl_isize thread_index) { - zpl_unused(a); - zpl_unused(core); - zpl_unused(thread_index); - return true; - } - - zpl_isize zpl_affinity_thread_count_for_core(zpl_affinity *a, zpl_isize core) { - ZPL_ASSERT(0 <= core && core < a->core_count); - return a->threads_per_core; - } - - #elif defined(ZPL_SYSTEM_EMSCRIPTEN) - # error No affinity implementation for Emscripten - #else - # error TODO: Unknown system - #endif - - ZPL_END_C_DECLS +// file: source/threading/fence.c + + +ZPL_BEGIN_C_DECLS + +#if defined(_MSC_VER) +/* Microsoft C/C++-compatible compiler */ +# include +#elif defined(__GNUC__) && (defined(__x86_64__) || defined(__i386__)) +/* GCC-compatible compiler, targeting x86/x86-64 */ +# include +#elif defined(__GNUC__) && defined(__ARM_NEON__) +/* GCC-compatible compiler, targeting ARM with NEON */ +# include +#elif defined(__GNUC__) && defined(__IWMMXT__) +/* GCC-compatible compiler, targeting ARM with WMMX */ +# include +#elif (defined(__GNUC__) || defined(__xlC__)) && (defined(__VEC__) || defined(__ALTIVEC__)) +/* XLC or GCC-compatible compiler, targeting PowerPC with VMX/VSX */ +# include +#elif defined(__GNUC__) && defined(__SPE__) +/* GCC-compatible compiler, targeting PowerPC with SPE */ +# include +#endif + +void zpl_yield_thread(void) { +# if defined(ZPL_SYSTEM_WINDOWS) + _mm_pause(); +# elif defined(ZPL_SYSTEM_OSX) || defined(ZPL_COMPILER_TINYC) + __asm__ volatile ("" : : : "memory"); +# elif defined(ZPL_CPU_X86) + _mm_pause(); +# endif +} + +void zpl_mfence(void) { +# if defined(ZPL_SYSTEM_WINDOWS) + _ReadWriteBarrier(); +# elif defined(ZPL_COMPILER_TINYC) + __asm__ volatile ("" : : : "memory"); +# elif defined(ZPL_SYSTEM_OSX) + __sync_synchronize(); +# elif defined(ZPL_CPU_X86) + _mm_mfence(); +# endif +} + +void zpl_sfence(void) { +# if defined(ZPL_SYSTEM_WINDOWS) + _WriteBarrier(); +# elif defined(ZPL_SYSTEM_OSX) || defined(ZPL_COMPILER_TINYC) + __asm__ volatile ("" : : : "memory"); +# elif defined(ZPL_CPU_X86) + _mm_sfence(); +# endif +} + +void zpl_lfence(void) { +# if defined(ZPL_SYSTEM_WINDOWS) + _ReadBarrier(); +# elif defined(ZPL_SYSTEM_OSX) || defined(ZPL_COMPILER_TINYC) + __asm__ volatile ("" : : : "memory"); +# elif defined(ZPL_CPU_X86) + _mm_lfence(); +# endif +} + +ZPL_END_C_DECLS +// file: source/threading/atomic.c + + +ZPL_BEGIN_C_DECLS + +//////////////////////////////////////////////////////////////// +// +// Concurrency +// +// +// IMPORTANT TODO: Use compiler intrinsics for the atomics + +#if defined(ZPL_COMPILER_MSVC) && !defined(ZPL_COMPILER_CLANG) +zpl_i32 zpl_atomic32_load (zpl_atomic32 const *a) { return a->value; } +void zpl_atomic32_store(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) value) { a->value = value; } + +zpl_i32 zpl_atomic32_compare_exchange(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) expected, zpl_atomicarg(zpl_i32) desired) { + return _InterlockedCompareExchange(cast(long *)a, desired, expected); +} +zpl_i32 zpl_atomic32_exchange(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) desired) { + return _InterlockedExchange(cast(long *)a, desired); +} +zpl_i32 zpl_atomic32_fetch_add(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) operand) { + return _InterlockedExchangeAdd(cast(long *)a, operand); +} +zpl_i32 zpl_atomic32_fetch_and(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) operand) { + return _InterlockedAnd(cast(long *)a, operand); +} +zpl_i32 zpl_atomic32_fetch_or(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) operand) { + return _InterlockedOr(cast(long *)a, operand); +} + +zpl_i64 zpl_atomic64_load(zpl_atomic64 const *a) { +# if defined(ZPL_ARCH_64_BIT) + return a->value; +# elif ZPL_CPU_X86 + // NOTE: The most compatible way to get an atomic 64-bit load on x86 is with cmpxchg8b + zpl_atomicarg(zpl_i64) result; + __asm { + mov esi, a; + mov ebx, eax; + mov ecx, edx; + lock cmpxchg8b [esi]; + mov dword ptr result, eax; + mov dword ptr result[4], edx; + } + return result; +# else +# error TODO: atomics for this CPU +# endif +} + +void zpl_atomic64_store(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) value) { +# if defined(ZPL_ARCH_64_BIT) + a->value = value; +# elif ZPL_CPU_X86 + // NOTE: The most compatible way to get an atomic 64-bit store on x86 is with cmpxchg8b + __asm { + mov esi, a; + mov ebx, dword ptr value; + mov ecx, dword ptr value[4]; + retry: + cmpxchg8b [esi]; + jne retry; + } +# else +# error TODO: atomics for this CPU +# endif +} + +zpl_i64 zpl_atomic64_compare_exchange(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) expected, zpl_atomicarg(zpl_i64) desired) { + return _InterlockedCompareExchange64(cast(zpl_atomicarg(zpl_i64) *)a, desired, expected); +} + +zpl_i64 zpl_atomic64_exchange(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) desired) { +# if defined(ZPL_ARCH_64_BIT) + return _InterlockedExchange64(cast(zpl_atomicarg(zpl_i64) *)a, desired); +# elif ZPL_CPU_X86 + zpl_atomicarg(zpl_i64) expected = a->value; + for (;;) { + zpl_atomicarg(zpl_i64) original = _InterlockedCompareExchange64(cast(zpl_atomicarg(zpl_i64) *)a, desired, expected); + if (original == expected) + return original; + expected = original; + } +# else +# error TODO: atomics for this CPU +# endif +} + +zpl_i64 zpl_atomic64_fetch_add(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) operand) { +# if defined(ZPL_ARCH_64_BIT) + return _InterlockedExchangeAdd64(cast(zpl_atomicarg(zpl_i64) *)a, operand); +# elif ZPL_CPU_X86 + zpl_atomicarg(zpl_i64) expected = a->value; + for (;;) { + zpl_atomicarg(zpl_i64) original = _InterlockedCompareExchange64(cast(zpl_atomicarg(zpl_i64) *)a, expected + operand, expected); + if (original == expected) + return original; + expected = original; + } +# else +# error TODO: atomics for this CPU +# endif +} + +zpl_i64 zpl_atomic64_fetch_and(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) operand) { +# if defined(ZPL_ARCH_64_BIT) + return _InterlockedAnd64(cast(zpl_atomicarg(zpl_i64) *)a, operand); +# elif ZPL_CPU_X86 + zpl_atomicarg(zpl_i64) expected = a->value; + for (;;) { + zpl_atomicarg(zpl_i64) original = _InterlockedCompareExchange64(cast(zpl_atomicarg(zpl_i64) *)a, expected & operand, expected); + if (original == expected) + return original; + expected = original; + } +# else +# error TODO: atomics for this CPU +# endif +} + +zpl_i64 zpl_atomic64_fetch_or(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) operand) { +# if defined(ZPL_ARCH_64_BIT) + return _InterlockedOr64(cast(zpl_atomicarg(zpl_i64) *)a, operand); +# elif ZPL_CPU_X86 + zpl_atomicarg(zpl_i64) expected = a->value; + for (;;) { + zpl_atomicarg(zpl_i64) original = _InterlockedCompareExchange64(cast(zpl_atomicarg(zpl_i64) *)a, expected | operand, expected); + if (original == expected) + return original; + expected = original; + } +# else +# error TODO: atomics for this CPU +# endif +} + +#elif defined(ZPL_CPU_X86) + +zpl_i32 zpl_atomic32_load (zpl_atomic32 const *a) { return a->value; } +void zpl_atomic32_store(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) value) { a->value = value; } + +zpl_i32 zpl_atomic32_compare_exchange(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) expected, zpl_atomicarg(zpl_i32) desired) { + zpl_atomicarg(zpl_i32) original; + __asm__( + "lock; cmpxchgl %2, %1" + : "=a"(original), "+m"(a->value) + : "q"(desired), "0"(expected) + ); + return original; +} + +zpl_i32 zpl_atomic32_exchange(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) desired) { + // NOTE: No lock prefix is necessary for xchgl + zpl_atomicarg(zpl_i32) original; + __asm__( + "xchgl %0, %1" + : "=r"(original), "+m"(a->value) + : "0"(desired) + ); + return original; +} + +zpl_i32 zpl_atomic32_fetch_add(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) operand) { + zpl_atomicarg(zpl_i32) original; + __asm__( + "lock; xaddl %0, %1" + : "=r"(original), "+m"(a->value) + : "0"(operand) + ); + return original; +} + +zpl_i32 zpl_atomic32_fetch_and(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) operand) { + zpl_atomicarg(zpl_i32) original; + zpl_atomicarg(zpl_i32) tmp; + __asm__( + "1: movl %1, %0\n" + " movl %0, %2\n" + " andl %3, %2\n" + " lock; cmpxchgl %2, %1\n" + " jne 1b" + : "=&a"(original), "+m"(a->value), "=&r"(tmp) + : "r"(operand) + ); + return original; +} + +zpl_i32 zpl_atomic32_fetch_or(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) operand) { + zpl_atomicarg(zpl_i32) original; + zpl_atomicarg(zpl_i32) temp; + __asm__( + "1: movl %1, %0\n" + " movl %0, %2\n" + " orl %3, %2\n" + " lock; cmpxchgl %2, %1\n" + " jne 1b" + : "=&a"(original), "+m"(a->value), "=&r"(temp) + : "r"(operand) + ); + return original; +} + + +zpl_i64 zpl_atomic64_load(zpl_atomic64 const *a) { +# if defined(ZPL_ARCH_64_BIT) + return a->value; +# else + zpl_atomicarg(zpl_i64) original; + __asm__( + "movl %%ebx, %%eax\n" + "movl %%ecx, %%edx\n" + "lock; cmpxchg8b %1" + : "=&A"(original) + : "m"(a->value) + ); + return original; +# endif +} + +void zpl_atomic64_store(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) value) { +# if defined(ZPL_ARCH_64_BIT) + a->value = value; +# else + zpl_atomicarg(zpl_i64) expected = a->value; + __asm__( + "1: cmpxchg8b %0\n" + " jne 1b" + : "=m"(a->value) + : "b"((zpl_atomicarg(zpl_i32))value), "c"((zpl_atomicarg(zpl_i32))(value >> 32)), "A"(expected) + ); +# endif +} + +zpl_i64 zpl_atomic64_compare_exchange(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) expected, zpl_atomicarg(zpl_i64) desired) { +# if defined(ZPL_ARCH_64_BIT) + zpl_atomicarg(zpl_i64) original; + __asm__( + "lock; cmpxchgq %2, %1" + : "=a"(original), "+m"(a->value) + : "q"(desired), "0"(expected) + ); + return original; +# else + zpl_atomicarg(zpl_i64) original; + __asm__( + "lock; cmpxchg8b %1" + : "=A"(original), "+m"(a->value) + : "b"((zpl_atomicarg(zpl_i32))desired), "c"((zpl_atomicarg(zpl_i32))(desired >> 32)), "0"(expected) + ); + return original; +# endif +} + +zpl_i64 zpl_atomic64_exchange(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) desired) { +# if defined(ZPL_ARCH_64_BIT) + zpl_atomicarg(zpl_i64) original; + __asm__( + "xchgq %0, %1" + : "=r"(original), "+m"(a->value) + : "0"(desired) + ); + return original; +# else + zpl_atomicarg(zpl_i64) original = a->value; + for (;;) { + zpl_atomicarg(zpl_i64) previous = zpl_atomic64_compare_exchange(a, original, desired); + if (original == previous) + return original; + original = previous; + } +# endif +} + +zpl_i64 zpl_atomic64_fetch_add(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) operand) { +# if defined(ZPL_ARCH_64_BIT) + zpl_atomicarg(zpl_i64) original; + __asm__( + "lock; xaddq %0, %1" + : "=r"(original), "+m"(a->value) + : "0"(operand) + ); + return original; +# else + for (;;) { + zpl_atomicarg(zpl_i64) original = a->value; + if (zpl_atomic64_compare_exchange(a, original, original + operand) == original) + return original; + } +# endif +} + +zpl_i64 zpl_atomic64_fetch_and(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) operand) { +# if defined(ZPL_ARCH_64_BIT) + zpl_atomicarg(zpl_i64) original; + zpl_atomicarg(zpl_i64) tmp; + __asm__( + "1: movq %1, %0\n" + " movq %0, %2\n" + " andq %3, %2\n" + " lock; cmpxchgq %2, %1\n" + " jne 1b" + : "=&a"(original), "+m"(a->value), "=&r"(tmp) + : "r"(operand) + ); + return original; +# else + for (;;) { + zpl_atomicarg(zpl_i64) original = a->value; + if (zpl_atomic64_compare_exchange(a, original, original & operand) == original) + return original; + } +# endif +} + +zpl_i64 zpl_atomic64_fetch_or(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) operand) { +# if defined(ZPL_ARCH_64_BIT) + zpl_atomicarg(zpl_i64) original; + zpl_atomicarg(zpl_i64) temp; + __asm__( + "1: movq %1, %0\n" + " movq %0, %2\n" + " orq %3, %2\n" + " lock; cmpxchgq %2, %1\n" + " jne 1b" + : "=&a"(original), "+m"(a->value), "=&r"(temp) + : "r"(operand) + ); + return original; +# else + for (;;) { + zpl_atomicarg(zpl_i64) original = a->value; + if (zpl_atomic64_compare_exchange(a, original, original | operand) == original) + return original; + } +# endif +} + +#elif !defined(ZPL_COMPILER_MSVC) +zpl_i32 zpl_atomic32_load (zpl_atomic32 const *a) { + return __atomic_load_n((zpl_i32*)&a->value, __ATOMIC_SEQ_CST); +} +void zpl_atomic32_store(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) value) { + __atomic_store((zpl_i32*)&a->value, (zpl_i32*)&value, __ATOMIC_SEQ_CST); +} + +zpl_i32 zpl_atomic32_compare_exchange(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) expected, zpl_atomicarg(zpl_i32) desired) { + return __atomic_compare_exchange_n((zpl_i32*)&a->value, (zpl_i32*)&expected, desired, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); +} + +zpl_i32 zpl_atomic32_exchange(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) desired) { + return __atomic_exchange_n((zpl_i32*)&a->value, desired, __ATOMIC_SEQ_CST); +} + +zpl_i32 zpl_atomic32_fetch_add(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) operand) { + return __atomic_fetch_add((zpl_i32*)&a->value, operand, __ATOMIC_SEQ_CST); +} + +zpl_i32 zpl_atomic32_fetch_and(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) operand) { + return __atomic_fetch_and((zpl_i32*)&a->value, operand, __ATOMIC_SEQ_CST); +} + +zpl_i32 zpl_atomic32_fetch_or(zpl_atomic32 *a, zpl_atomicarg(zpl_i32) operand) { + return __atomic_fetch_or((zpl_i32*)&a->value, operand, __ATOMIC_SEQ_CST); +} + +zpl_i64 zpl_atomic64_load(zpl_atomic64 const *a) { + return __atomic_load_n((zpl_i64*)&a->value, __ATOMIC_SEQ_CST); +} + +void zpl_atomic64_store(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) value) { + __atomic_store((zpl_i64*)&a->value, (zpl_i64*)&value, __ATOMIC_SEQ_CST); +} + +zpl_i64 zpl_atomic64_compare_exchange(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) expected, zpl_atomicarg(zpl_i64) desired) { + return __atomic_compare_exchange_n((zpl_i64*)&a->value, (zpl_i64*)&expected, desired, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); +} + +zpl_i64 zpl_atomic64_exchange(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) desired) { + return __atomic_exchange_n((zpl_i64*)&a->value, desired, __ATOMIC_SEQ_CST); +} + +zpl_i64 zpl_atomic64_fetch_add(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) operand) { + return __atomic_fetch_add((zpl_i64*)&a->value, operand, __ATOMIC_SEQ_CST); +} + +zpl_i64 zpl_atomic64_fetch_and(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) operand) { + return __atomic_fetch_and((zpl_i64*)&a->value, operand, __ATOMIC_SEQ_CST); +} + +zpl_i64 zpl_atomic64_fetch_or(zpl_atomic64 *a, zpl_atomicarg(zpl_i64) operand) { + return __atomic_fetch_or((zpl_i64*)&a->value, operand, __ATOMIC_SEQ_CST); +} + +#else +# error TODO: Implement Atomics for this CPU +#endif + + + +zpl_b32 zpl_atomic32_spin_lock(zpl_atomic32 *a, zpl_isize time_out) { + zpl_atomicarg(zpl_i32) old_value = zpl_atomic32_compare_exchange(a, 1, 0); + zpl_i32 counter = 0; + while (old_value != 0 && (time_out < 0 || counter++ < time_out)) { + zpl_yield_thread(); + old_value = zpl_atomic32_compare_exchange(a, 1, 0); + zpl_mfence(); + } + return old_value == 0; +} + +void zpl_atomic32_spin_unlock(zpl_atomic32 *a) { + zpl_atomic32_store(a, 0); + zpl_mfence(); +} + +zpl_b32 zpl_atomic64_spin_lock(zpl_atomic64 *a, zpl_isize time_out) { + zpl_atomicarg(zpl_i64) old_value = zpl_atomic64_compare_exchange(a, 1, 0); + zpl_atomicarg(zpl_i64) counter = 0; + while (old_value != 0 && (time_out < 0 || counter++ < time_out)) { + zpl_yield_thread(); + old_value = zpl_atomic64_compare_exchange(a, 1, 0); + zpl_mfence(); + } + return old_value == 0; +} + +void zpl_atomic64_spin_unlock(zpl_atomic64 *a) { + zpl_atomic64_store(a, 0); + zpl_mfence(); +} + +zpl_b32 zpl_atomic32_try_acquire_lock(zpl_atomic32 *a) { + zpl_atomicarg(zpl_i32) old_value; + zpl_yield_thread(); + old_value = zpl_atomic32_compare_exchange(a, 1, 0); + zpl_mfence(); + return old_value == 0; +} + +zpl_b32 zpl_atomic64_try_acquire_lock(zpl_atomic64 *a) { + zpl_atomicarg(zpl_i64) old_value; + zpl_yield_thread(); + old_value = zpl_atomic64_compare_exchange(a, 1, 0); + zpl_mfence(); + return old_value == 0; +} + + + +#if defined(ZPL_ARCH_32_BIT) + +void* zpl_atomic_ptr_load(zpl_atomic_ptr const *a) { + return (void *)cast(zpl_intptr)zpl_atomic32_load(cast(zpl_atomic32 const *)a); +} +void zpl_atomic_ptr_store(zpl_atomic_ptr *a, zpl_atomicarg(void *)value) { + zpl_atomic32_store(cast(zpl_atomic32 *)a, cast(zpl_atomicarg(zpl_i32))cast(zpl_intptr)value); +} +void* zpl_atomic_ptr_compare_exchange(zpl_atomic_ptr *a, zpl_atomicarg(void *)expected, zpl_atomicarg(void *)desired) { + return (void *)cast(zpl_intptr)zpl_atomic32_compare_exchange(cast(zpl_atomic32 *)a, cast(zpl_atomicarg(zpl_i32))cast(zpl_intptr)expected, cast(zpl_atomicarg(zpl_i32))cast(zpl_intptr)desired); +} +void* zpl_atomic_ptr_exchange(zpl_atomic_ptr *a, zpl_atomicarg(void *)desired) { + return (void *)cast(zpl_intptr)zpl_atomic32_exchange(cast(zpl_atomic32 *)a, cast(zpl_atomicarg(zpl_i32))cast(zpl_intptr)desired); +} +void* zpl_atomic_ptr_fetch_add(zpl_atomic_ptr *a, zpl_atomicarg(void *)operand) { + return (void *)cast(zpl_intptr)zpl_atomic32_fetch_add(cast(zpl_atomic32 *)a, cast(zpl_atomicarg(zpl_i32))cast(zpl_intptr)operand); +} +void* zpl_atomic_ptr_fetch_and(zpl_atomic_ptr *a, zpl_atomicarg(void *)operand) { + return (void *)cast(zpl_intptr)zpl_atomic32_fetch_and(cast(zpl_atomic32 *)a, cast(zpl_atomicarg(zpl_i32))cast(zpl_intptr)operand); +} +void* zpl_atomic_ptr_fetch_or(zpl_atomic_ptr *a, zpl_atomicarg(void *)operand) { + return (void *)cast(zpl_intptr)zpl_atomic32_fetch_or(cast(zpl_atomic32 *)a, cast(zpl_atomicarg(zpl_i32))cast(zpl_intptr)operand); +} +zpl_b32 zpl_atomic_ptr_spin_lock(zpl_atomic_ptr *a, zpl_isize time_out) { + return zpl_atomic32_spin_lock(cast(zpl_atomic32 *)a, time_out); +} +void zpl_atomic_ptr_spin_unlock(zpl_atomic_ptr *a) { + zpl_atomic32_spin_unlock(cast(zpl_atomic32 *)a); +} +zpl_b32 zpl_atomic_ptr_try_acquire_lock(zpl_atomic_ptr *a) { + return zpl_atomic32_try_acquire_lock(cast(zpl_atomic32 *)a); +} + +#elif defined(ZPL_ARCH_64_BIT) + +void* zpl_atomic_ptr_load(zpl_atomic_ptr const *a) { + return (void *)cast(zpl_intptr)zpl_atomic64_load(cast(zpl_atomic64 const *)a); +} +void zpl_atomic_ptr_store(zpl_atomic_ptr *a, zpl_atomicarg(void *)value) { + zpl_atomic64_store(cast(zpl_atomic64 *)a, cast(zpl_i64)cast(zpl_intptr)value); +} +void* zpl_atomic_ptr_compare_exchange(zpl_atomic_ptr *a, zpl_atomicarg(void *)expected, zpl_atomicarg(void *)desired) { + return (void *)cast(zpl_intptr)zpl_atomic64_compare_exchange(cast(zpl_atomic64 *)a, cast(zpl_i64)cast(zpl_intptr)expected, cast(zpl_i64)cast(zpl_intptr)desired); +} +void* zpl_atomic_ptr_exchange(zpl_atomic_ptr *a, zpl_atomicarg(void *)desired) { + return (void *)cast(zpl_intptr)zpl_atomic64_exchange(cast(zpl_atomic64 *)a, cast(zpl_i64)cast(zpl_intptr)desired); +} +void* zpl_atomic_ptr_fetch_add(zpl_atomic_ptr *a, zpl_atomicarg(void *)operand) { + return (void *)cast(zpl_intptr)zpl_atomic64_fetch_add(cast(zpl_atomic64 *)a, cast(zpl_i64)cast(zpl_intptr)operand); +} +void* zpl_atomic_ptr_fetch_and(zpl_atomic_ptr *a, zpl_atomicarg(void *)operand) { + return (void *)cast(zpl_intptr)zpl_atomic64_fetch_and(cast(zpl_atomic64 *)a, cast(zpl_i64)cast(zpl_intptr)operand); +} +void* zpl_atomic_ptr_fetch_or(zpl_atomic_ptr *a, zpl_atomicarg(void *)operand) { + return (void *)cast(zpl_intptr)zpl_atomic64_fetch_or(cast(zpl_atomic64 *)a, cast(zpl_i64)cast(zpl_intptr)operand); +} +zpl_b32 zpl_atomic_ptr_spin_lock(zpl_atomic_ptr *a, zpl_isize time_out) { + return zpl_atomic64_spin_lock(cast(zpl_atomic64 *)a, time_out); +} +void zpl_atomic_ptr_spin_unlock(zpl_atomic_ptr *a) { + zpl_atomic64_spin_unlock(cast(zpl_atomic64 *)a); +} +zpl_b32 zpl_atomic_ptr_try_acquire_lock(zpl_atomic_ptr *a) { + return zpl_atomic64_try_acquire_lock(cast(zpl_atomic64 *)a); +} + +#endif + +ZPL_END_C_DECLS +// file: source/threading/sem.c + + +ZPL_BEGIN_C_DECLS + +void zpl_semaphore_release(zpl_semaphore *s) { zpl_semaphore_post(s, 1); } + +#if defined(ZPL_SYSTEM_WINDOWS) + +void zpl_semaphore_init (zpl_semaphore *s) { s->win32_handle = CreateSemaphoreA(NULL, 0, ZPL_I32_MAX, NULL); } +void zpl_semaphore_destroy(zpl_semaphore *s) { CloseHandle(s->win32_handle); } +void zpl_semaphore_post (zpl_semaphore *s, zpl_i32 count) { ReleaseSemaphore(s->win32_handle, count, NULL); } +void zpl_semaphore_wait (zpl_semaphore *s) { WaitForSingleObject(s->win32_handle, INFINITE); } + +#elif defined(ZPL_SYSTEM_OSX) + +void zpl_semaphore_init (zpl_semaphore *s) { semaphore_create(mach_task_self(), &s->osx_handle, SYNC_POLICY_FIFO, 0); } +void zpl_semaphore_destroy(zpl_semaphore *s) { semaphore_destroy(mach_task_self(), s->osx_handle); } +void zpl_semaphore_post (zpl_semaphore *s, zpl_i32 count) { while (count --> 0) semaphore_signal(s->osx_handle); } +void zpl_semaphore_wait (zpl_semaphore *s) { semaphore_wait(s->osx_handle); } + +#elif defined(ZPL_SYSTEM_UNIX) + +void zpl_semaphore_init (zpl_semaphore *s) { sem_init(&s->unix_handle, 0, 0); } +void zpl_semaphore_destroy(zpl_semaphore *s) { sem_destroy(&s->unix_handle); } +void zpl_semaphore_post (zpl_semaphore *s, zpl_i32 count) { while (count --> 0) sem_post(&s->unix_handle); } +void zpl_semaphore_wait (zpl_semaphore *s) { int i; do { i = sem_wait(&s->unix_handle); } while (i == -1 && errno == EINTR); } + +#else +# error Semaphores for this OS are not implemented +#endif + +ZPL_END_C_DECLS +// file: source/threading/mutex.c + + +ZPL_BEGIN_C_DECLS + +void zpl_mutex_init(zpl_mutex *m) { +# if defined(ZPL_SYSTEM_WINDOWS) + InitializeCriticalSection((CRITICAL_SECTION*)m->win32_critical_section); +# else + pthread_mutex_init(&m->pthread_mutex, NULL); +# endif +} + +void zpl_mutex_destroy(zpl_mutex *m) { +# if defined(ZPL_SYSTEM_WINDOWS) + DeleteCriticalSection((CRITICAL_SECTION*)m->win32_critical_section); +# else + pthread_mutex_destroy(&m->pthread_mutex); +# endif +} + +void zpl_mutex_lock(zpl_mutex *m) { +# if defined(ZPL_SYSTEM_WINDOWS) + EnterCriticalSection((CRITICAL_SECTION*)m->win32_critical_section); +# else + pthread_mutex_lock(&m->pthread_mutex); +# endif +} + +zpl_b32 zpl_mutex_try_lock(zpl_mutex *m) { +# if defined(ZPL_SYSTEM_WINDOWS) + return TryEnterCriticalSection((CRITICAL_SECTION*)m->win32_critical_section); +# else + return pthread_mutex_trylock(&m->pthread_mutex); +# endif +} + +void zpl_mutex_unlock(zpl_mutex *m) { +# if defined(ZPL_SYSTEM_WINDOWS) + LeaveCriticalSection((CRITICAL_SECTION*)m->win32_critical_section); +# else + pthread_mutex_unlock(&m->pthread_mutex); +# endif +} + +ZPL_END_C_DECLS +// file: source/threading/thread.c + + +ZPL_BEGIN_C_DECLS + +zpl_b32 zpl_thread_is_running(zpl_thread const *t) { return t->is_running != 0; } + +void zpl_thread_init(zpl_thread *t) { + zpl_zero_item(t); + +# if defined(ZPL_SYSTEM_WINDOWS) + t->win32_handle = INVALID_HANDLE_VALUE; +# else + t->posix_handle = 0; +# endif + + zpl_semaphore_init(&t->semaphore); +} + +void zpl_thread_destroy(zpl_thread *t) { + if (t->is_running) zpl_thread_join(t); + zpl_semaphore_destroy(&t->semaphore); +} + +void zpl__thread_run(zpl_thread *t) { + zpl_semaphore_release(&t->semaphore); + t->return_value = t->proc(t); +} + +#if defined(ZPL_SYSTEM_WINDOWS) +DWORD __stdcall zpl__thread_proc(void *arg) { + zpl_thread *t = cast(zpl_thread *)arg; + zpl__thread_run(t); + t->is_running = false; + return 0; +} +#else +void *zpl__thread_proc(void *arg) { + zpl_thread *t = cast(zpl_thread *)arg; + zpl__thread_run(t); + t->is_running = false; + return NULL; +} +#endif + +void zpl_thread_start(zpl_thread *t, zpl_thread_proc proc, void *user_data) { + zpl_thread_start_with_stack(t, proc, user_data, 0); +} + +void zpl_thread_start_with_stack(zpl_thread *t, zpl_thread_proc proc, void *user_data, zpl_isize stack_size) { + ZPL_ASSERT(!t->is_running); + ZPL_ASSERT(proc != NULL); + t->proc = proc; + t->user_data = user_data; + t->stack_size = stack_size; + +# if defined(ZPL_SYSTEM_WINDOWS) + t->win32_handle = CreateThread(NULL, stack_size, zpl__thread_proc, t, 0, NULL); + ZPL_ASSERT_MSG(t->win32_handle != NULL, "CreateThread: GetLastError"); +# else + { + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + if (stack_size != 0) + pthread_attr_setstacksize(&attr, stack_size); + pthread_create(&t->posix_handle, &attr, zpl__thread_proc, t); + pthread_attr_destroy(&attr); + } +# endif + + t->is_running = true; + zpl_semaphore_wait(&t->semaphore); +} + +void zpl_thread_join(zpl_thread *t) { + if (!t->is_running) return; + +# if defined(ZPL_SYSTEM_WINDOWS) + WaitForSingleObject(t->win32_handle, INFINITE); + CloseHandle(t->win32_handle); + t->win32_handle = INVALID_HANDLE_VALUE; +# else + pthread_join(t->posix_handle, NULL); + t->posix_handle = 0; +# endif + t->is_running = false; +} + +zpl_u32 zpl_thread_current_id(void) { + zpl_u32 thread_id; +# if defined(ZPL_SYSTEM_WINDOWS) +# if defined(ZPL_ARCH_32_BIT) && defined(ZPL_CPU_X86) + thread_id = (cast(zpl_u32 *)__readfsdword(24))[9]; +# elif defined(ZPL_ARCH_64_BIT) && defined(ZPL_CPU_X86) + thread_id = (cast(zpl_u32 *)__readgsqword(48))[18]; +# else + thread_id = GetCurrentThreadId(); +# endif + +# elif defined(ZPL_SYSTEM_OSX) && defined(ZPL_ARCH_64_BIT) + thread_id = pthread_mach_thread_np(pthread_self()); +# elif defined(ZPL_ARCH_32_BIT) && defined(ZPL_CPU_X86) + __asm__("mov %%gs:0x08,%0" : "=r"(thread_id)); +# elif defined(ZPL_ARCH_64_BIT) && defined(ZPL_CPU_X86) + __asm__("mov %%fs:0x10,%0" : "=r"(thread_id)); +# elif defined(__ARM_ARCH) + thread_id = pthread_self(); +# else +# error Unsupported architecture for zpl_thread_current_id() +# endif + + return thread_id; +} + +void zpl_thread_set_name(zpl_thread *t, char const *name) { +# if defined(ZPL_COMPILER_MSVC) +# pragma pack(push, 8) + typedef struct { + DWORD type; + char const *name; + DWORD id; + DWORD flags; + } zplprivThreadName; +# pragma pack(pop) + + zplprivThreadName tn; + tn.type = 0x1000; + tn.name = name; + tn.id = GetThreadId(cast(HANDLE)t->win32_handle); + tn.flags = 0; + + __try { + RaiseException(0x406d1388, 0, zpl_size_of(tn)/4, cast(ULONG_PTR *)&tn); + } __except(1 /*EXCEPTION_EXECUTE_HANDLER*/) { + } + +# elif defined(ZPL_SYSTEM_WINDOWS) && !defined(ZPL_COMPILER_MSVC) + zpl_unused(t); + zpl_unused(name); + // IMPORTANT TODO: Set thread name for GCC/Clang on windows + return; +# elif defined(ZPL_SYSTEM_OSX) + // TODO: Test if this works + pthread_setname_np(name); +# else + zpl_unused(t); + zpl_unused(name); + // TODO: Test if this works + // pthread_set_name_np(t->posix_handle, name); +# endif +} + +ZPL_END_C_DECLS +// file: source/threading/sync.c + + +ZPL_BEGIN_C_DECLS + +void zpl_sync_init(zpl_sync *s) { + zpl_zero_item(s); + zpl_mutex_init(&s->mutex); + zpl_mutex_init(&s->start); + zpl_semaphore_init(&s->release); +} + +void zpl_sync_destroy(zpl_sync *s) { + if (s->waiting) { + ZPL_PANIC("Cannot destroy while threads are waiting!"); + } + + zpl_mutex_destroy(&s->mutex); + zpl_mutex_destroy(&s->start); + zpl_semaphore_destroy(&s->release); +} + +void zpl_sync_set_target(zpl_sync *s, zpl_i32 count) { + zpl_mutex_lock(&s->start); + + zpl_mutex_lock(&s->mutex); + ZPL_ASSERT(s->target == 0); + s->target = count; + s->current = 0; + s->waiting = 0; + zpl_mutex_unlock(&s->mutex); +} + +void zpl_sync_release(zpl_sync *s) { + if (s->waiting) { + zpl_semaphore_release(&s->release); + } else { + s->target = 0; + zpl_mutex_unlock(&s->start); + } +} + +zpl_i32 zpl_sync_reach(zpl_sync *s) { + zpl_i32 n; + zpl_mutex_lock(&s->mutex); + ZPL_ASSERT(s->current < s->target); + n = ++s->current; // NOTE: Record this value to avoid possible race if `return s->current` was done + if (s->current == s->target) + zpl_sync_release(s); + zpl_mutex_unlock(&s->mutex); + return n; +} + +void zpl_sync_reach_and_wait(zpl_sync *s) { + zpl_mutex_lock(&s->mutex); + ZPL_ASSERT(s->current < s->target); + s->current++; + if (s->current == s->target) { + zpl_sync_release(s); + zpl_mutex_unlock(&s->mutex); + } else { + s->waiting++; // NOTE: Waiting, so one more waiter + zpl_mutex_unlock(&s->mutex); // NOTE: Release the mutex to other threads + zpl_semaphore_wait(&s->release); // NOTE: Wait for merge completion + zpl_mutex_lock(&s->mutex); // NOTE: On merge completion, lock mutex + s->waiting--; // NOTE: Done waiting + zpl_sync_release(s); // NOTE: Restart the next waiter + zpl_mutex_unlock(&s->mutex); + } +} + +ZPL_END_C_DECLS +// file: source/threading/affinity.c + + +#if defined(ZPL_SYSTEM_MACOS) +# include +#endif + +ZPL_BEGIN_C_DECLS + +#if defined(ZPL_SYSTEM_WINDOWS) || defined(ZPL_SYSTEM_CYGWIN) + +void zpl_affinity_init(zpl_affinity *a) { + SYSTEM_LOGICAL_PROCESSOR_INFORMATION *start_processor_info = NULL; + DWORD length = 0; + zpl_b32 result = GetLogicalProcessorInformation(NULL, &length); + + zpl_zero_item(a); + + if (!result && GetLastError() == 122l /*ERROR_INSUFFICIENT_BUFFER*/ && length > 0) { + start_processor_info = cast(SYSTEM_LOGICAL_PROCESSOR_INFORMATION *)zpl_alloc(zpl_heap_allocator(), length); + result = GetLogicalProcessorInformation(start_processor_info, &length); + if (result) { + SYSTEM_LOGICAL_PROCESSOR_INFORMATION *end_processor_info, *processor_info; + + a->is_accurate = true; + a->core_count = 0; + a->thread_count = 0; + end_processor_info = cast(SYSTEM_LOGICAL_PROCESSOR_INFORMATION *)zpl_pointer_add(start_processor_info, length); + + for (processor_info = start_processor_info; + processor_info < end_processor_info; + processor_info++) { + if (processor_info->Relationship == RelationProcessorCore) { + zpl_isize thread = zpl_count_set_bits(processor_info->ProcessorMask); + if (thread == 0) { + a->is_accurate = false; + } else if (a->thread_count + thread > ZPL_WIN32_MAX_THREADS) { + a->is_accurate = false; + } else { + ZPL_ASSERT(a->core_count <= a->thread_count && + a->thread_count < ZPL_WIN32_MAX_THREADS); + a->core_masks[a->core_count++] = processor_info->ProcessorMask; + a->thread_count += thread; + } + } + } + } + + zpl_free(zpl_heap_allocator(), start_processor_info); + } + + ZPL_ASSERT(a->core_count <= a->thread_count); + if (a->thread_count == 0) { + a->is_accurate = false; + a->core_count = 1; + a->thread_count = 1; + a->core_masks[0] = 1; + } + +} + +void zpl_affinity_destroy(zpl_affinity *a) { + zpl_unused(a); +} + +zpl_b32 zpl_affinity_set(zpl_affinity *a, zpl_isize core, zpl_isize thread) { + zpl_usize available_mask, check_mask = 1; + ZPL_ASSERT(thread < zpl_affinity_thread_count_for_core(a, core)); + + available_mask = a->core_masks[core]; + for (;;) { + if ((available_mask & check_mask) != 0) { + if (thread-- == 0) { + zpl_usize result = SetThreadAffinityMask(GetCurrentThread(), check_mask); + return result != 0; + } + } + check_mask <<= 1; // NOTE: Onto the next bit + } +} + +zpl_isize zpl_affinity_thread_count_for_core(zpl_affinity *a, zpl_isize core) { + ZPL_ASSERT(core >= 0 && core < a->core_count); + return zpl_count_set_bits(a->core_masks[core]); +} + +#elif defined(ZPL_SYSTEM_MACOS) +void zpl_affinity_init(zpl_affinity *a) { + zpl_usize count, count_size = zpl_size_of(count); + + a->is_accurate = false; + a->thread_count = 1; + a->core_count = 1; + a->threads_per_core = 1; + + if (sysctlbyname("hw.logicalcpu", &count, &count_size, NULL, 0) == 0) { + if (count > 0) { + a->thread_count = count; + // Get # of physical cores + if (sysctlbyname("hw.physicalcpu", &count, &count_size, NULL, 0) == 0) { + if (count > 0) { + a->core_count = count; + a->threads_per_core = a->thread_count / count; + if (a->threads_per_core < 1) + a->threads_per_core = 1; + else + a->is_accurate = true; + } + } + } + } + +} + +void zpl_affinity_destroy(zpl_affinity *a) { + zpl_unused(a); +} + +zpl_b32 zpl_affinity_set(zpl_affinity *a, zpl_isize core, zpl_isize thread_index) { + zpl_isize index; + thread_t thread; + thread_affinity_policy_data_t info; + kern_return_t result; + + ZPL_ASSERT(core < a->core_count); + ZPL_ASSERT(thread_index < a->threads_per_core); + + index = core * a->threads_per_core + thread_index; + thread = mach_thread_self(); + info.affinity_tag = cast(integer_t)index; + result = thread_policy_set(thread, THREAD_AFFINITY_POLICY, cast(thread_policy_t)&info, THREAD_AFFINITY_POLICY_COUNT); + return result == KERN_SUCCESS; +} + +zpl_isize zpl_affinity_thread_count_for_core(zpl_affinity *a, zpl_isize core) { + ZPL_ASSERT(core >= 0 && core < a->core_count); + return a->threads_per_core; +} + +#elif defined(ZPL_SYSTEM_LINUX) || defined(ZPL_SYSTEM_FREEBSD) || defined(ZPL_SYSTEM_OPENBSD) + +// IMPORTANT TODO: This zpl_affinity stuff for linux needs be improved a lot! +// NOTE(zangent): I have to read /proc/cpuinfo to get the number of threads per core. + +void zpl_affinity_init(zpl_affinity *a) { + zpl_b32 accurate = true; + zpl_isize threads = 0; + + a->thread_count = 1; + a->core_count = sysconf(_SC_NPROCESSORS_ONLN); + a->threads_per_core = 1; + + + if(a->core_count <= 0) { + a->core_count = 1; + accurate = false; + } + + // Parsing /proc/cpuinfo to get the number of threads per core. + // NOTE(zangent): This calls the CPU's threads "cores", although the wording + // is kind of weird. This should be right, though. + FILE *cpu_info = fopen("/proc/cpuinfo", "r"); + if (cpu_info != NULL) { + for (;;) { + // The 'temporary char'. Everything goes into this char, + // so that we can check against EOF at the end of this loop. + int c; + +# define AF__CHECK(letter) ((c = getc(cpu_info)) == letter) + if (AF__CHECK('c') && AF__CHECK('p') && AF__CHECK('u') && AF__CHECK(' ') && + AF__CHECK('c') && AF__CHECK('o') && AF__CHECK('r') && AF__CHECK('e') && AF__CHECK('s')) { + // We're on a CPU info line. + while (!AF__CHECK(EOF)) { + if (c == '\n') { + break; + } else if (c < '0' || '9' > c) { + continue; + } + threads = threads * 10 + (c - '0'); + } + break; + } else { + while (!AF__CHECK('\n')) { + if (c==EOF) { + break; + } + } + } + if (c == EOF) { + break; + } +# undef AF__CHECK + } + + fclose(cpu_info); + } + + if (threads == 0) { + threads = 1; + accurate = false; + } + + a->threads_per_core = threads; + a->thread_count = a->threads_per_core * a->core_count; + a->is_accurate = accurate; + +} + +void zpl_affinity_destroy(zpl_affinity *a) { + zpl_unused(a); +} + +zpl_b32 zpl_affinity_set(zpl_affinity * a, zpl_isize core, zpl_isize thread_index) { + zpl_unused(a); + zpl_unused(core); + zpl_unused(thread_index); + return true; +} + +zpl_isize zpl_affinity_thread_count_for_core(zpl_affinity *a, zpl_isize core) { + ZPL_ASSERT(0 <= core && core < a->core_count); + return a->threads_per_core; +} + +#elif defined(ZPL_SYSTEM_EMSCRIPTEN) +# error No affinity implementation for Emscripten +#else +# error TODO: Unknown system +#endif + +ZPL_END_C_DECLS # if defined(ZPL_MODULE_JOBS) - // file: source/jobs.c +// file: source/jobs.c - /////////////////////////////////////////////////////////////// - // - // Thread Pool - // +/////////////////////////////////////////////////////////////// +// +// Thread Pool +// - ZPL_BEGIN_C_DECLS +ZPL_BEGIN_C_DECLS - ZPL_RING_DEFINE(zpl__jobs_ring_, zpl_thread_job); +ZPL_RING_DEFINE(zpl__jobs_ring_, zpl_thread_job); - zpl_global const zpl_u32 zpl__jobs_chances[ZPL_JOBS_MAX_PRIORITIES] = { - 2, 3, 5, 7, 11 - }; +zpl_global const zpl_u32 zpl__jobs_chances[ZPL_JOBS_MAX_PRIORITIES] = { + 2, 3, 5, 7, 11 +}; - zpl_isize zpl__jobs_entry(struct zpl_thread *thread) { - zpl_thread_worker *tw = (zpl_thread_worker *)thread->user_data; +zpl_isize zpl__jobs_entry(struct zpl_thread *thread) { + zpl_thread_worker *tw = (zpl_thread_worker *)thread->user_data; + + for (;;) { + zpl_u32 status = zpl_atomic32_load(&tw->status); + + switch (status) { + case ZPL_JOBS_STATUS_READY: { + zpl_atomic32_store(&tw->status, ZPL_JOBS_STATUS_BUSY); + tw->job.proc(tw->job.data); + zpl_atomic32_compare_exchange(&tw->status, ZPL_JOBS_STATUS_BUSY, ZPL_JOBS_STATUS_WAITING); + +# ifdef ZPL_JOBS_DEBUG + ++tw->hits; +# endif + } break; + + case ZPL_JOBS_STATUS_WAITING: { +# ifdef ZPL_JOBS_DEBUG + ++tw->idle; +# endif + zpl_yield(); + } break; + + case ZPL_JOBS_STATUS_TERM: { + return 0; + } break; + } + } + + return 0; +} - for (;;) { - zpl_u32 status = zpl_atomic32_load(&tw->status); +void zpl_jobs_init(zpl_jobs_system *pool, zpl_allocator a, zpl_u32 max_threads) { + zpl_jobs_init_with_limit(pool, a, max_threads, ZPL_JOBS_MAX_QUEUE); +} - switch (status) { - case ZPL_JOBS_STATUS_READY: { - zpl_atomic32_store(&tw->status, ZPL_JOBS_STATUS_BUSY); - tw->job.proc(tw->job.data); - zpl_atomic32_compare_exchange(&tw->status, ZPL_JOBS_STATUS_BUSY, ZPL_JOBS_STATUS_WAITING); +void zpl_jobs_init_with_limit(zpl_jobs_system *pool, zpl_allocator a, zpl_u32 max_threads, zpl_u32 max_jobs) { + zpl_jobs_system pool_ = { 0 }; + *pool = pool_; + + pool->alloc = a; + pool->max_threads = max_threads; + pool->max_jobs = max_jobs; + pool->counter = 0; + + zpl_buffer_init(pool->workers, a, max_threads); + + for (zpl_usize i = 0; i < ZPL_JOBS_MAX_PRIORITIES; ++i) { + zpl_thread_queue *q = &pool->queues[i]; + zpl__jobs_ring_init(&q->jobs, a, max_jobs); + q->chance = zpl__jobs_chances[i]; + } + + for (zpl_usize i = 0; i < max_threads; ++i) { + zpl_thread_worker worker_ = { 0 }; + zpl_thread_worker *tw = pool->workers + i; + *tw = worker_; + + zpl_thread_init(&tw->thread); + zpl_atomic32_store(&tw->status, ZPL_JOBS_STATUS_WAITING); + zpl_thread_start(&tw->thread, zpl__jobs_entry, (void *)tw); + } +} - # ifdef ZPL_JOBS_DEBUG - ++tw->hits; - # endif - } break; +void zpl_jobs_free(zpl_jobs_system *pool) { + for (zpl_usize i = 0; i < pool->max_threads; ++i) { + zpl_thread_worker *tw = pool->workers + i; + + zpl_atomic32_store(&tw->status, ZPL_JOBS_STATUS_TERM); + zpl_thread_destroy(&tw->thread); + } + + zpl_buffer_free(pool->workers); + + for (zpl_usize i = 0; i < ZPL_JOBS_MAX_PRIORITIES; ++i) { + zpl_thread_queue *q = &pool->queues[i]; + zpl__jobs_ring_free(&q->jobs); + } +} - case ZPL_JOBS_STATUS_WAITING: { - # ifdef ZPL_JOBS_DEBUG - ++tw->idle; - # endif - zpl_yield(); - } break; +zpl_b32 zpl_jobs_enqueue_with_priority(zpl_jobs_system *pool, zpl_jobs_proc proc, void *data, zpl_jobs_priority priority) { + ZPL_ASSERT(priority >= 0 && priority < ZPL_JOBS_MAX_PRIORITIES); + ZPL_ASSERT_NOT_NULL(proc); + zpl_thread_job job = {0}; + job.proc = proc; + job.data = data; + + if (!zpl_jobs_full(pool, priority)) { + zpl__jobs_ring_append(&pool->queues[priority].jobs, job); + return true; + } + return false; +} - case ZPL_JOBS_STATUS_TERM: { - return 0; - } break; - } - } +zpl_b32 zpl_jobs_enqueue(zpl_jobs_system *pool, zpl_jobs_proc proc, void *data) { + return zpl_jobs_enqueue_with_priority(pool, proc, data, ZPL_JOBS_PRIORITY_NORMAL); +} - return 0; - } +zpl_b32 zpl_jobs_empty(zpl_jobs_system *pool, zpl_jobs_priority priority) { + ZPL_ASSERT(priority >= 0 && priority < ZPL_JOBS_MAX_PRIORITIES); + return zpl__jobs_ring_empty(&pool->queues[priority].jobs); +} - void zpl_jobs_init(zpl_jobs_system *pool, zpl_allocator a, zpl_u32 max_threads) { - zpl_jobs_init_with_limit(pool, a, max_threads, ZPL_JOBS_MAX_QUEUE); - } +zpl_b32 zpl_jobs_full(zpl_jobs_system *pool, zpl_jobs_priority priority) { + ZPL_ASSERT(priority >= 0 && priority < ZPL_JOBS_MAX_PRIORITIES); + return zpl__jobs_ring_full(&pool->queues[priority].jobs); +} - void zpl_jobs_init_with_limit(zpl_jobs_system *pool, zpl_allocator a, zpl_u32 max_threads, zpl_u32 max_jobs) { - zpl_jobs_system pool_ = { 0 }; - *pool = pool_; +zpl_b32 zpl_jobs_done(zpl_jobs_system *pool) { + for (zpl_usize i = 0; i < pool->max_threads; ++i) { + zpl_thread_worker *tw = pool->workers + i; + if (zpl_atomic32_load(&tw->status) != ZPL_JOBS_STATUS_WAITING) { + return false; + } + } + + return zpl_jobs_empty_all(pool); +} - pool->alloc = a; - pool->max_threads = max_threads; - pool->max_jobs = max_jobs; - pool->counter = 0; +zpl_b32 zpl_jobs_empty_all(zpl_jobs_system *pool) { + for (zpl_usize i = 0; i < ZPL_JOBS_MAX_PRIORITIES; ++i) { + if (!zpl_jobs_empty(pool, (zpl_jobs_priority)i)) { + return false; + } + } + return true; +} - zpl_buffer_init(pool->workers, a, max_threads); +zpl_b32 zpl_jobs_full_all(zpl_jobs_system *pool) { + for (zpl_usize i = 0; i < ZPL_JOBS_MAX_PRIORITIES; ++i) { + if (!zpl_jobs_full(pool, (zpl_jobs_priority)i)) { + return false; + } + } + return true; +} - for (zpl_usize i = 0; i < ZPL_JOBS_MAX_PRIORITIES; ++i) { - zpl_thread_queue *q = &pool->queues[i]; - zpl__jobs_ring_init(&q->jobs, a, max_jobs); - q->chance = zpl__jobs_chances[i]; - } +zpl_b32 zpl_jobs_process(zpl_jobs_system *pool) { + if (zpl_jobs_empty_all(pool)) { + return false; + } + // NOTE: Process the jobs + for (zpl_usize i = 0; i < pool->max_threads; ++i) { + zpl_thread_worker *tw = pool->workers + i; + zpl_u32 status = zpl_atomic32_load(&tw->status); + zpl_b32 last_empty = false; + + if (status == ZPL_JOBS_STATUS_WAITING) { + for (zpl_usize j = 0; j < ZPL_JOBS_MAX_PRIORITIES; ++j) { + zpl_thread_queue *q = &pool->queues[j]; + if (zpl_jobs_empty(pool, (zpl_jobs_priority)j)) { + last_empty = (j+1 == ZPL_JOBS_MAX_PRIORITIES); + continue; + } + if (!last_empty && ((pool->counter++ % q->chance) != 0)) { + continue; + } + + last_empty = false; + tw->job = *zpl__jobs_ring_get(&q->jobs); + zpl_atomic32_store(&tw->status, ZPL_JOBS_STATUS_READY); +# ifdef ZPL_JOBS_DEBUG + ++q->hits; +# endif + break; + } + } + } + + return true; +} - for (zpl_usize i = 0; i < max_threads; ++i) { - zpl_thread_worker worker_ = { 0 }; - zpl_thread_worker *tw = pool->workers + i; - *tw = worker_; - - zpl_thread_init(&tw->thread); - zpl_atomic32_store(&tw->status, ZPL_JOBS_STATUS_WAITING); - zpl_thread_start(&tw->thread, zpl__jobs_entry, (void *)tw); - } - } - - void zpl_jobs_free(zpl_jobs_system *pool) { - for (zpl_usize i = 0; i < pool->max_threads; ++i) { - zpl_thread_worker *tw = pool->workers + i; - - zpl_atomic32_store(&tw->status, ZPL_JOBS_STATUS_TERM); - zpl_thread_destroy(&tw->thread); - } - - zpl_buffer_free(pool->workers); - - for (zpl_usize i = 0; i < ZPL_JOBS_MAX_PRIORITIES; ++i) { - zpl_thread_queue *q = &pool->queues[i]; - zpl__jobs_ring_free(&q->jobs); - } - } - - zpl_b32 zpl_jobs_enqueue_with_priority(zpl_jobs_system *pool, zpl_jobs_proc proc, void *data, zpl_jobs_priority priority) { - ZPL_ASSERT(priority >= 0 && priority < ZPL_JOBS_MAX_PRIORITIES); - ZPL_ASSERT_NOT_NULL(proc); - zpl_thread_job job = {0}; - job.proc = proc; - job.data = data; - - if (!zpl_jobs_full(pool, priority)) { - zpl__jobs_ring_append(&pool->queues[priority].jobs, job); - return true; - } - return false; - } - - zpl_b32 zpl_jobs_enqueue(zpl_jobs_system *pool, zpl_jobs_proc proc, void *data) { - return zpl_jobs_enqueue_with_priority(pool, proc, data, ZPL_JOBS_PRIORITY_NORMAL); - } - - zpl_b32 zpl_jobs_empty(zpl_jobs_system *pool, zpl_jobs_priority priority) { - ZPL_ASSERT(priority >= 0 && priority < ZPL_JOBS_MAX_PRIORITIES); - return zpl__jobs_ring_empty(&pool->queues[priority].jobs); - } - - zpl_b32 zpl_jobs_full(zpl_jobs_system *pool, zpl_jobs_priority priority) { - ZPL_ASSERT(priority >= 0 && priority < ZPL_JOBS_MAX_PRIORITIES); - return zpl__jobs_ring_full(&pool->queues[priority].jobs); - } - - zpl_b32 zpl_jobs_done(zpl_jobs_system *pool) { - for (zpl_usize i = 0; i < pool->max_threads; ++i) { - zpl_thread_worker *tw = pool->workers + i; - if (zpl_atomic32_load(&tw->status) != ZPL_JOBS_STATUS_WAITING) { - return false; - } - } - - return zpl_jobs_empty_all(pool); - } - - zpl_b32 zpl_jobs_empty_all(zpl_jobs_system *pool) { - for (zpl_usize i = 0; i < ZPL_JOBS_MAX_PRIORITIES; ++i) { - if (!zpl_jobs_empty(pool, (zpl_jobs_priority)i)) { - return false; - } - } - return true; - } - - zpl_b32 zpl_jobs_full_all(zpl_jobs_system *pool) { - for (zpl_usize i = 0; i < ZPL_JOBS_MAX_PRIORITIES; ++i) { - if (!zpl_jobs_full(pool, (zpl_jobs_priority)i)) { - return false; - } - } - return true; - } - - zpl_b32 zpl_jobs_process(zpl_jobs_system *pool) { - if (zpl_jobs_empty_all(pool)) { - return false; - } - // NOTE: Process the jobs - for (zpl_usize i = 0; i < pool->max_threads; ++i) { - zpl_thread_worker *tw = pool->workers + i; - zpl_u32 status = zpl_atomic32_load(&tw->status); - zpl_b32 last_empty = false; - - if (status == ZPL_JOBS_STATUS_WAITING) { - for (zpl_usize j = 0; j < ZPL_JOBS_MAX_PRIORITIES; ++j) { - zpl_thread_queue *q = &pool->queues[j]; - if (zpl_jobs_empty(pool, (zpl_jobs_priority)j)) { - last_empty = (j+1 == ZPL_JOBS_MAX_PRIORITIES); - continue; - } - if (!last_empty && ((pool->counter++ % q->chance) != 0)) { - continue; - } - - last_empty = false; - tw->job = *zpl__jobs_ring_get(&q->jobs); - zpl_atomic32_store(&tw->status, ZPL_JOBS_STATUS_READY); - # ifdef ZPL_JOBS_DEBUG - ++q->hits; - # endif - break; - } - } - } - - return true; - } - - ZPL_END_C_DECLS +ZPL_END_C_DECLS # endif # if defined(ZPL_MODULE_COROUTINES) - // file: source/coroutines.c +// file: source/coroutines.c - //////////////////////////////////////////////////////////////// - // - // Coroutines - // - // +//////////////////////////////////////////////////////////////// +// +// Coroutines +// +// - ZPL_BEGIN_C_DECLS +ZPL_BEGIN_C_DECLS - struct { - zpl_b32 is_ready; - zpl_jobs_system coroutines; - zpl_thread runner; - zpl_atomic32 request_term; - zpl_mutex is_processing; - } zpl__co_internals; +struct { + zpl_b32 is_ready; + zpl_jobs_system coroutines; + zpl_thread runner; + zpl_atomic32 request_term; + zpl_mutex is_processing; +} zpl__co_internals; - zpl_thread_local zpl_u8 zpl__co_yield_barrier; +zpl_thread_local zpl_u8 zpl__co_yield_barrier; - zpl_isize zpl__co_runner(struct zpl_thread *t) { - do { - if (zpl_atomic32_load(&zpl__co_internals.request_term)) - break; +zpl_isize zpl__co_runner(struct zpl_thread *t) { + do { + if (zpl_atomic32_load(&zpl__co_internals.request_term)) + break; + + zpl_b32 lock = zpl_mutex_try_lock(&zpl__co_internals.is_processing); + + while (!lock) { + zpl_yield_thread(); + lock = zpl_mutex_try_lock(&zpl__co_internals.is_processing); + + if (zpl_atomic32_load(&zpl__co_internals.request_term)) + break; + + zpl_mfence(); + } + + zpl_jobs_process(&zpl__co_internals.coroutines); + zpl_mutex_unlock(&zpl__co_internals.is_processing); + } while (1); + + return 0; +} - zpl_b32 lock = zpl_mutex_try_lock(&zpl__co_internals.is_processing); +void zpl__co_job(void *data) { + zpl_co *co = cast(zpl_co *)data; + + zpl_atomic32_store(&co->status, ZPL_CO_RUNNING); + co->f(co); + zpl_atomic32_store(&co->status, ZPL_CO_DEAD); +} - while (!lock) { - zpl_yield_thread(); - lock = zpl_mutex_try_lock(&zpl__co_internals.is_processing); +void zpl_co_init(zpl_allocator a, zpl_u32 max_threads) { + if (!zpl__co_internals.is_ready) { + zpl_zero_item(&zpl__co_internals); + zpl_mutex_init(&zpl__co_internals.is_processing); + zpl_jobs_init(&zpl__co_internals.coroutines, a, max_threads); + zpl_thread_init(&zpl__co_internals.runner); + zpl_thread_start(&zpl__co_internals.runner, zpl__co_runner, NULL); + zpl_atomic32_store(&zpl__co_internals.request_term, 0); + zpl__co_internals.is_ready = 1; + + // Set up a barrier so that we won't let user call zpl_co_yield in a main thread. + zpl__co_yield_barrier = 1; + } +} - if (zpl_atomic32_load(&zpl__co_internals.request_term)) - break; +void zpl_co_destroy(void) { + zpl_atomic32_exchange(&zpl__co_internals.request_term, 1); + zpl_thread_destroy(&zpl__co_internals.runner); + zpl_mutex_destroy(&zpl__co_internals.is_processing); + zpl_jobs_free(&zpl__co_internals.coroutines); + zpl__co_internals.is_ready = 0; + zpl_mfence(); +} - zpl_mfence(); - } +void zpl_co_make(zpl_co *co, zpl_co_proc f) { + ZPL_ASSERT_MSG(zpl__co_internals.is_ready, "Coroutines module is not initialized. Call zpl_co_init first!"); + ZPL_ASSERT_NOT_NULL(co); + + zpl_zero_item(co); + co->f = f; + zpl_atomic32_store(&co->status, ZPL_CO_READY); + zpl_atomic32_store(&co->resume, 0); +} - zpl_jobs_process(&zpl__co_internals.coroutines); - zpl_mutex_unlock(&zpl__co_internals.is_processing); - } while (1); +void zpl_co_resume(zpl_co *co, void *data) { + ZPL_ASSERT_NOT_NULL(co); + + if (data != NULL) { + zpl_atomic32_store(&co->push_arg, 1); + co->data_stack[co->data_write_idx++] = data; + zpl_atomic32_spin_unlock(&co->push_arg); + zpl_mfence(); + } + + zpl_i32 status = zpl_atomic32_load(&co->status); + + // Initialize a job + if (status == ZPL_CO_READY) { + + if (data) + co->data = co->data_stack[co->data_read_idx++]; + + zpl_atomic32_store(&co->status, ZPL_CO_ENQUEUED); + zpl_mfence(); + + zpl_mutex_lock(&zpl__co_internals.is_processing); + zpl_jobs_enqueue(&zpl__co_internals.coroutines, zpl__co_job, cast(void *)co); + zpl_mutex_unlock(&zpl__co_internals.is_processing); + } + else { + zpl_atomic32_fetch_add(&co->resume, 1); + zpl_mfence(); + } +} - return 0; - } +void zpl_co_yield(zpl_co *co) { + zpl_i32 value; + ZPL_ASSERT_NOT_NULL(co); + ZPL_ASSERT_MSG((!zpl__co_yield_barrier), "zpl_co_yield can only be called inside of coroutines!"); + + zpl_atomic32_store(&co->status, ZPL_CO_WAITING); + + value = zpl_atomic32_load(&co->resume); + + while (value == 0) { + zpl_yield_thread(); + value = zpl_atomic32_load(&co->resume); + zpl_mfence(); + } + + zpl_atomic32_spin_lock(&co->push_arg, -1); + co->data = co->data_stack[co->data_read_idx++]; + + // null pointer is present, no arg is found, so return back by 1 index + if (co->data == NULL) { + co->data_read_idx--; + } + + zpl_atomic32_spin_unlock(&co->push_arg); + + zpl_atomic32_store(&co->status, ZPL_CO_RUNNING); + zpl_atomic32_fetch_add(&co->resume, -1); +} - void zpl__co_job(void *data) { - zpl_co *co = cast(zpl_co *)data; - - zpl_atomic32_store(&co->status, ZPL_CO_RUNNING); - co->f(co); - zpl_atomic32_store(&co->status, ZPL_CO_DEAD); - } - - void zpl_co_init(zpl_allocator a, zpl_u32 max_threads) { - if (!zpl__co_internals.is_ready) { - zpl_zero_item(&zpl__co_internals); - zpl_mutex_init(&zpl__co_internals.is_processing); - zpl_jobs_init(&zpl__co_internals.coroutines, a, max_threads); - zpl_thread_init(&zpl__co_internals.runner); - zpl_thread_start(&zpl__co_internals.runner, zpl__co_runner, NULL); - zpl_atomic32_store(&zpl__co_internals.request_term, 0); - zpl__co_internals.is_ready = 1; - - // Set up a barrier so that we won't let user call zpl_co_yield in a main thread. - zpl__co_yield_barrier = 1; - } - } - - void zpl_co_destroy(void) { - zpl_atomic32_exchange(&zpl__co_internals.request_term, 1); - zpl_thread_destroy(&zpl__co_internals.runner); - zpl_mutex_destroy(&zpl__co_internals.is_processing); - zpl_jobs_free(&zpl__co_internals.coroutines); - zpl__co_internals.is_ready = 0; - zpl_mfence(); - } - - void zpl_co_make(zpl_co *co, zpl_co_proc f) { - ZPL_ASSERT_MSG(zpl__co_internals.is_ready, "Coroutines module is not initialized. Call zpl_co_init first!"); - ZPL_ASSERT_NOT_NULL(co); - - zpl_zero_item(co); - co->f = f; - zpl_atomic32_store(&co->status, ZPL_CO_READY); - zpl_atomic32_store(&co->resume, 0); - } - - void zpl_co_resume(zpl_co *co, void *data) { - ZPL_ASSERT_NOT_NULL(co); - - if (data != NULL) { - zpl_atomic32_store(&co->push_arg, 1); - co->data_stack[co->data_write_idx++] = data; - zpl_atomic32_spin_unlock(&co->push_arg); - zpl_mfence(); - } - - zpl_i32 status = zpl_atomic32_load(&co->status); - - // Initialize a job - if (status == ZPL_CO_READY) { - - if (data) - co->data = co->data_stack[co->data_read_idx++]; - - zpl_atomic32_store(&co->status, ZPL_CO_ENQUEUED); - zpl_mfence(); - - zpl_mutex_lock(&zpl__co_internals.is_processing); - zpl_jobs_enqueue(&zpl__co_internals.coroutines, zpl__co_job, cast(void *)co); - zpl_mutex_unlock(&zpl__co_internals.is_processing); - } - else { - zpl_atomic32_fetch_add(&co->resume, 1); - zpl_mfence(); - } - } - - void zpl_co_yield(zpl_co *co) { - zpl_i32 value; - ZPL_ASSERT_NOT_NULL(co); - ZPL_ASSERT_MSG((!zpl__co_yield_barrier), "zpl_co_yield can only be called inside of coroutines!"); - - zpl_atomic32_store(&co->status, ZPL_CO_WAITING); - - value = zpl_atomic32_load(&co->resume); - - while (value == 0) { - zpl_yield_thread(); - value = zpl_atomic32_load(&co->resume); - zpl_mfence(); - } - - zpl_atomic32_spin_lock(&co->push_arg, -1); - co->data = co->data_stack[co->data_read_idx++]; - - // null pointer is present, no arg is found, so return back by 1 index - if (co->data == NULL) { - co->data_read_idx--; - } - - zpl_atomic32_spin_unlock(&co->push_arg); - - zpl_atomic32_store(&co->status, ZPL_CO_RUNNING); - zpl_atomic32_fetch_add(&co->resume, -1); - } - - ZPL_END_C_DECLS +ZPL_END_C_DECLS # endif #endif #if defined(ZPL_MODULE_PARSER) - // file: source/adt.c - - ZPL_BEGIN_C_DECLS - - zpl_u8 zpl_adt_make_branch(zpl_adt_node *node, zpl_allocator backing, char const *name, zpl_u8 type) { - ZPL_ASSERT(type == ZPL_ADT_TYPE_OBJECT || type == ZPL_ADT_TYPE_ARRAY); - zpl_zero_item(node); - node->type = type; - node->name = name; - zpl_array_init(node->nodes, backing); - return 0; - } - - zpl_u8 zpl_adt_destroy_branch(zpl_adt_node *node) { - ZPL_ASSERT_NOT_NULL(node); - if ((node->type == ZPL_ADT_TYPE_OBJECT || node->type == ZPL_ADT_TYPE_ARRAY) && node->nodes) { - for (zpl_isize i = 0; i < zpl_array_count(node->nodes); ++i) { zpl_adt_destroy_branch(node->nodes + i); } - - zpl_array_free(node->nodes); - } - return 0; - } - - zpl_u8 zpl_adt_make_leaf(zpl_adt_node *node, char const *name, zpl_u8 type) { - ZPL_ASSERT(type != ZPL_ADT_TYPE_OBJECT && type != ZPL_ADT_TYPE_ARRAY); - zpl_zero_item(node); - node->type = type; - node->name = name; - return 0; - } - - zpl_adt_node *zpl_adt_find(zpl_adt_node *node, char const *name, zpl_b32 deep_search) { - if (node->type != ZPL_ADT_TYPE_OBJECT) { - return NULL; - } - - for (zpl_isize i = 0; i < zpl_array_count(node->nodes); i++) { - if (!zpl_strcmp(node->nodes[i].name, name)) { - return (node->nodes + i); - } - } - - if (deep_search) { - for (zpl_isize i = 0; i < zpl_array_count(node->nodes); i++) { - zpl_adt_node *res = zpl_adt_find(node->nodes + i, name, deep_search); - - if (res != NULL) - return res; - } - } - - return NULL; - } - - zpl_adt_node *zpl_adt_alloc_at(zpl_adt_node *parent, zpl_isize index) { - if (!parent || (parent->type != ZPL_ADT_TYPE_OBJECT && parent->type != ZPL_ADT_TYPE_ARRAY)) { - return NULL; - } - - if (!parent->nodes) - return NULL; - - if (index < 0 || index > zpl_array_count(parent->nodes)) - return NULL; - - zpl_adt_node o = {0}; - zpl_array_append_at(parent->nodes, o, index); - - return parent->nodes + index; - } - - zpl_adt_node *zpl_adt_alloc(zpl_adt_node *parent) { - if (!parent || (parent->type != ZPL_ADT_TYPE_OBJECT && parent->type != ZPL_ADT_TYPE_ARRAY)) { - return NULL; - } - - if (!parent->nodes) - return NULL; - - return zpl_adt_alloc_at(parent, zpl_array_count(parent->nodes)); - } - - - void zpl_adt_set_obj(zpl_adt_node *obj, char const *name, zpl_allocator backing) { - zpl_adt_make_branch(obj, backing, name, ZPL_ADT_TYPE_OBJECT); - } - void zpl_adt_set_arr(zpl_adt_node *obj, char const *name, zpl_allocator backing) { - zpl_adt_make_branch(obj, backing, name, ZPL_ADT_TYPE_ARRAY); - } - void zpl_adt_set_str(zpl_adt_node *obj, char const *name, char const *value) { - zpl_adt_make_leaf(obj, name, ZPL_ADT_TYPE_STRING); - obj->string = value; - } - void zpl_adt_set_flt(zpl_adt_node *obj, char const *name, zpl_f64 value) { - zpl_adt_make_leaf(obj, name, ZPL_ADT_TYPE_REAL); - obj->real = value; - } - void zpl_adt_set_int(zpl_adt_node *obj, char const *name, zpl_i64 value) { - zpl_adt_make_leaf(obj, name, ZPL_ADT_TYPE_INTEGER); - obj->integer = value; - } - - zpl_adt_node *zpl_adt_move_node_at(zpl_adt_node *node, zpl_adt_node *old_parent, zpl_adt_node *new_parent, zpl_isize index) { - ZPL_ASSERT_NOT_NULL(node); - ZPL_ASSERT_NOT_NULL(old_parent); - ZPL_ASSERT_NOT_NULL(new_parent); - ZPL_ASSERT(new_parent->type == ZPL_ADT_TYPE_ARRAY || new_parent->type == ZPL_ADT_TYPE_OBJECT); - ZPL_ASSERT(node >= old_parent->nodes); - ZPL_ASSERT(node <= zpl_array_end(old_parent->nodes)); - ZPL_ASSERT(index >= 0 && index <= zpl_array_count(new_parent->nodes)); - zpl_adt_node *new_node = zpl_adt_alloc_at(new_parent, index); - *new_node = *node; - zpl_adt_remove_node(node, old_parent); - return new_node; - } - - zpl_adt_node *zpl_adt_move_node(zpl_adt_node *node, zpl_adt_node *old_parent, zpl_adt_node *new_parent) { - ZPL_ASSERT_NOT_NULL(new_parent); - ZPL_ASSERT(new_parent->type == ZPL_ADT_TYPE_ARRAY || new_parent->type == ZPL_ADT_TYPE_OBJECT); - return zpl_adt_move_node_at(node, old_parent, new_parent, zpl_array_count(new_parent->nodes)); - } - - void zpl_adt_swap_nodes(zpl_adt_node *node, zpl_adt_node *other_node, zpl_adt_node *parent) { - zpl_adt_swap_nodes_between_parents(node, other_node, parent, parent); - } - - void zpl_adt_swap_nodes_between_parents(zpl_adt_node *node, zpl_adt_node *other_node, zpl_adt_node *parent, zpl_adt_node *other_parent) { - ZPL_ASSERT_NOT_NULL(node); - ZPL_ASSERT_NOT_NULL(other_node); - ZPL_ASSERT_NOT_NULL(parent); - ZPL_ASSERT_NOT_NULL(other_parent); - ZPL_ASSERT(node >= parent->nodes && node <= zpl_array_end(parent->nodes)); - ZPL_ASSERT(other_node >= other_parent->nodes && other_node <= zpl_array_end(other_parent->nodes)); - zpl_isize index = (zpl_pointer_diff(parent->nodes, node) / zpl_size_of(zpl_adt_node)); - zpl_isize index2 = (zpl_pointer_diff(other_parent->nodes, other_node) / zpl_size_of(zpl_adt_node)); - zpl_adt_node temp = parent->nodes[index]; - parent->nodes[index] = other_parent->nodes[index2]; - other_parent->nodes[index2] = temp; - } - - void zpl_adt_remove_node(zpl_adt_node *node, zpl_adt_node *parent) { - ZPL_ASSERT_NOT_NULL(node); - ZPL_ASSERT_NOT_NULL(parent); - ZPL_ASSERT(node >= parent->nodes); - ZPL_ASSERT(node <= zpl_array_end(parent->nodes)); - zpl_isize index = (zpl_pointer_diff(parent->nodes, node) / zpl_size_of(zpl_adt_node)); - zpl_array_remove_at(parent->nodes, index); - } - - - zpl_adt_node *zpl_adt_inset_obj(zpl_adt_node *parent, char const *name) { - zpl_adt_node *o = zpl_adt_alloc(parent); - zpl_adt_set_obj(o, name, ZPL_ARRAY_HEADER(parent->nodes)->allocator); - return o; - } - zpl_adt_node *zpl_adt_inset_arr(zpl_adt_node *parent, char const *name) { - zpl_adt_node *o = zpl_adt_alloc(parent); - zpl_adt_set_arr(o, name, ZPL_ARRAY_HEADER(parent->nodes)->allocator); - return o; - } - zpl_adt_node *zpl_adt_inset_str(zpl_adt_node *parent, char const *name, char const *value) { - zpl_adt_node *o = zpl_adt_alloc(parent); - zpl_adt_set_str(o, name, value); - return o; - } - zpl_adt_node *zpl_adt_inset_flt(zpl_adt_node *parent, char const *name, zpl_f64 value) { - zpl_adt_node *o = zpl_adt_alloc(parent); - zpl_adt_set_flt(o, name, value); - return o; - } - zpl_adt_node *zpl_adt_inset_int(zpl_adt_node *parent, char const *name, zpl_i64 value) { - zpl_adt_node *o = zpl_adt_alloc(parent); - zpl_adt_set_int(o, name, value); - return o; - } - - /* parser helpers */ - - char *zpl_adt_parse_number(zpl_adt_node *node, char* base) { - ZPL_ASSERT_NOT_NULL(node); - ZPL_ASSERT_NOT_NULL(base); - char *p = base, *e = p; - - /* skip false positives and special cases */ - if (!!zpl_strchr("eE", *p) || (!!zpl_strchr(".+-", *p) && !zpl_char_is_hex_digit(*(p+1)) && *(p+1) != '.')) { - return ++base; - } - - node->type = ZPL_ADT_TYPE_INTEGER; - node->neg_zero = false; - - zpl_isize ib = 0; - char buf[48] = { 0 }; - - if (*e == '+') - ++e; - else if (*e == '-') { - buf[ib++] = *e++; - } - - if (*e == '.') { - node->type = ZPL_ADT_TYPE_REAL; - node->props = ZPL_ADT_PROPS_IS_PARSED_REAL; - node->lead_digit = false; - buf[ib++] = '0'; - do { - buf[ib++] = *e; - } while (zpl_char_is_digit(*++e)); - } else { - if (!zpl_strncmp(e, "0x", 2) || !zpl_strncmp(e, "0X", 2)) { node->props = ZPL_ADT_PROPS_IS_HEX; } - while (zpl_char_is_hex_digit(*e) || zpl_char_to_lower(*e) == 'x') { buf[ib++] = *e++; } - - if (*e == '.') { - node->type = ZPL_ADT_TYPE_REAL; - node->lead_digit = true; - zpl_u32 step = 0; - - do { - buf[ib++] = *e; - ++step; - } while (zpl_char_is_digit(*++e)); - - if (step < 2) { buf[ib++] = '0'; } - } - } - - zpl_u8 exp = 0; - zpl_f32 eb = 10; - char expbuf[6] = { 0 }; - zpl_isize expi = 0; - - if (*e && !!zpl_strchr("eE", *e)) { - ++e; - if (*e == '+' || *e == '-' || zpl_char_is_digit(*e)) { - if (*e == '-') { eb = 0.1f; } - if (!zpl_char_is_digit(*e)) { ++e; } - while (zpl_char_is_digit(*e)) { expbuf[expi++] = *e++; } - } - - exp = (zpl_u8)zpl_str_to_i64(expbuf, NULL, 10); - } - - if (node->type == ZPL_ADT_TYPE_INTEGER) { - node->integer = zpl_str_to_i64(buf, 0, 0); - /* special case: negative zero */ - if (node->integer == 0 && buf[0] == '-') { - node->neg_zero = true; - } - while (exp-- > 0) { node->integer *= (zpl_i64)eb; } - } else { - node->real = zpl_str_to_f64(buf, 0); - - char *q = buf, *base_str = q, *base_str2 = q; - base_str = cast(char *)zpl_str_skip(base_str, '.'); - *base_str = '\0'; - base_str2 = base_str + 1; - char *base_str_off = base_str2; - while (*base_str_off++ == '0') node->base2_offset++; - - node->base = (zpl_i32)zpl_str_to_i64(q, 0, 0); - node->base2 = (zpl_i32)zpl_str_to_i64(base_str2, 0, 0); - - if (exp) { - node->exp = exp * (!(eb == 10.0f) ? -1 : 1); - node->props = ZPL_ADT_PROPS_IS_EXP; - } - - /* special case: negative zero */ - if (node->base == 0 && buf[0] == '-') { - node->neg_zero = true; - } - - while (exp-- > 0) { node->real *= eb; } - } - return e; - } - - void zpl_adt_print_number(zpl_file *file, zpl_adt_node *node) { - ZPL_ASSERT_NOT_NULL(file); - ZPL_ASSERT_NOT_NULL(node); - ZPL_ASSERT(node->type == ZPL_ADT_TYPE_INTEGER || node->type == ZPL_ADT_TYPE_REAL); - - if (node->neg_zero) { - zpl_fprintf(file, "-"); - } - - switch (node->type) { - case ZPL_ADT_TYPE_INTEGER: { - if (node->props == ZPL_ADT_PROPS_IS_HEX) { - zpl_fprintf(file, "0x%llx", (long long)node->integer); - } else { - zpl_fprintf(file, "%lld", (long long)node->integer); - } - } break; - - case ZPL_ADT_TYPE_REAL: { - if (node->props == ZPL_ADT_PROPS_NAN) { - zpl_fprintf(file, "NaN"); - } else if (node->props == ZPL_ADT_PROPS_NAN_NEG) { - zpl_fprintf(file, "-NaN"); - } else if (node->props == ZPL_ADT_PROPS_INFINITY) { - zpl_fprintf(file, "Infinity"); - } else if (node->props == ZPL_ADT_PROPS_INFINITY_NEG) { - zpl_fprintf(file, "-Infinity"); - } else if (node->props == ZPL_ADT_PROPS_TRUE) { - zpl_fprintf(file, "true"); - } else if (node->props == ZPL_ADT_PROPS_FALSE) { - zpl_fprintf(file, "false"); - } else if (node->props == ZPL_ADT_PROPS_NULL) { - zpl_fprintf(file, "null"); - } else if (node->props == ZPL_ADT_PROPS_IS_EXP) { - zpl_fprintf(file, "%lld.%0*d%llde%lld", (long long)node->base, node->base2_offset, 0, (long long)node->base2, (long long)node->exp); - } else if (node->props == ZPL_ADT_PROPS_IS_PARSED_REAL) { - if (!node->lead_digit) - zpl_fprintf(file, ".%0*d%lld", node->base2_offset, 0, (long long)node->base2); - else - zpl_fprintf(file, "%lld.%0*d%lld", (long long int)node->base2_offset, 0, (int)node->base, (long long)node->base2); - } else { - zpl_fprintf(file, "%f", node->real); - } - } break; - } - } - - void zpl_adt_print_string(zpl_file *file, zpl_adt_node *node, char const* escaped_chars, char escape_symbol) { - ZPL_ASSERT_NOT_NULL(file); - ZPL_ASSERT_NOT_NULL(node); - ZPL_ASSERT_NOT_NULL(escaped_chars); - ZPL_ASSERT(node->type == ZPL_ADT_TYPE_STRING || node->type == ZPL_ADT_TYPE_MULTISTRING); - - /* escape string */ - char const* p = node->string, *b = p; - do { - p = zpl_str_skip_any(p, escaped_chars); - zpl_fprintf(file, "%.*s", zpl_ptr_diff(b, p), b); - if (*p && !!zpl_strchr(escaped_chars, *p)) { - zpl_fprintf(file, "%c%c", escape_symbol, *p); - p++; - } - b = p; - } while (*p); - } - - void zpl_adt_str_to_number(zpl_adt_node *node) { - ZPL_ASSERT(node); - - if (node->type == ZPL_ADT_TYPE_REAL || node->type == ZPL_ADT_TYPE_INTEGER) return; /* this is already converted/parsed */ - ZPL_ASSERT(node->type == ZPL_ADT_TYPE_STRING || node->type == ZPL_ADT_TYPE_MULTISTRING); - zpl_adt_parse_number(node, (char *)node->string); - } - - ZPL_END_C_DECLS - - /* parsers */ - // file: source/parsers/json.c - - //////////////////////////////////////////////////////////////// - // - // JSON5 Parser - // - // - - - #ifdef ZPL_JSON_DEBUG - #define ZPL_JSON_ASSERT(msg) ZPL_PANIC(msg) - #else - #define ZPL_JSON_ASSERT(msg) - #endif - - ZPL_BEGIN_C_DECLS - - char *zpl__json_parse_object(zpl_adt_node *obj, char *base, zpl_allocator a, zpl_u8 *err_code); - char *zpl__json_parse_array(zpl_adt_node *obj, char *base, zpl_allocator a, zpl_u8 *err_code); - char *zpl__json_parse_value(zpl_adt_node *obj, char *base, zpl_allocator a, zpl_u8 *err_code); - char *zpl__json_parse_name(zpl_adt_node *obj, char *base, zpl_u8 *err_code); - char *zpl__json_trim(char *base, zpl_b32 catch_newline); - void zpl__json_write_value(zpl_file *f, zpl_adt_node *o, zpl_adt_node *t, zpl_isize indent, zpl_b32 is_inline, zpl_b32 is_last); - #define zpl___ind(x) if (x > 0) zpl_fprintf(f, "%*r", x, ' '); - - zpl_u8 zpl_json_parse(zpl_adt_node *root, char *text, zpl_allocator a) { - zpl_u8 err_code = ZPL_JSON_ERROR_NONE; - ZPL_ASSERT(root); - ZPL_ASSERT(text); - zpl_zero_item(root); - text = zpl__json_trim(text, true); - - if (!zpl_strchr("{[", *text)) { - root->cfg_mode = true; - } - - zpl__json_parse_object(root, text, a, &err_code); - return err_code; - } - - void zpl_json_free(zpl_adt_node *obj) { - zpl_adt_destroy_branch(obj); - } - - zpl_string zpl_json_write_string(zpl_allocator a, zpl_adt_node *obj, zpl_isize indent) { - zpl_file tmp; - zpl_file_stream_new(&tmp, a); - zpl_json_write(&tmp, obj, indent); - zpl_isize fsize; - zpl_u8* buf = zpl_file_stream_buf(&tmp, &fsize); - zpl_string output = zpl_string_make_length(a, (char *)buf, fsize+1); - zpl_file_close(&tmp); - return output; - } - - /* private */ - - static ZPL_ALWAYS_INLINE zpl_b32 zpl__json_is_assign_char(char c) { return !!zpl_strchr(":=|", c); } - static ZPL_ALWAYS_INLINE zpl_b32 zpl__json_is_delim_char(char c) { return !!zpl_strchr(",|\n", c); } - ZPL_DEF_INLINE zpl_b32 zpl__json_validate_name(char const *str, char *err); - - #define jx(x) !zpl_char_is_hex_digit(str[x]) - ZPL_IMPL_INLINE zpl_b32 zpl__json_validate_name(char const *str, char *err) { - while (*str) { - /* todo: refactor name validation. */ - if ((str[0] == '\\' && !zpl_char_is_control(str[1])) && - (str[0] == '\\' && jx(1) && jx(2) && jx(3) && jx(4))) { - if (err) *err = *str; - return false; - } - - ++str; - } - - return true; - } - #undef jx - - char *zpl__json_parse_array(zpl_adt_node *obj, char *base, zpl_allocator a, zpl_u8 *err_code) { - ZPL_ASSERT(obj && base); - char *p = base; - - obj->type = ZPL_ADT_TYPE_ARRAY; - zpl_array_init(obj->nodes, a); - - while (*p) { - p = zpl__json_trim(p, false); - - if (*p == ']') { - return p; - } - - zpl_adt_node elem = { 0 }; - p = zpl__json_parse_value(&elem, p, a, err_code); - - if (*err_code != ZPL_JSON_ERROR_NONE) { return NULL; } - - zpl_array_append(obj->nodes, elem); - - p = zpl__json_trim(p, false); - - if (*p == ',') { - ++p; - continue; - } else { - if (*p != ']') { - ZPL_JSON_ASSERT("end of array unfulfilled"); - *err_code = ZPL_JSON_ERROR_ARRAY_LEFT_OPEN; - return NULL; - } - return p; - } - } - - *err_code = ZPL_JSON_ERROR_INTERNAL; - return NULL; - } - - char *zpl__json_parse_value(zpl_adt_node *obj, char *base, zpl_allocator a, zpl_u8 *err_code) { - ZPL_ASSERT(obj && base); - char *p = base, *b = p, *e = p; - - if (!!zpl_strchr("`\"'", *p)) { - char c = *p; - obj->type = (c == '`') ? ZPL_ADT_TYPE_MULTISTRING : ZPL_ADT_TYPE_STRING; - b = e = p + 1; - obj->string = b; - e = cast(char *)zpl_str_skip_literal(e, c); - *e = '\0', p = e + 1; - } else if (zpl_char_is_alpha(*p) || (*p == '-' && !zpl_char_is_digit(*(p + 1)))) { - if (zpl_str_has_prefix(p, "true")) { - obj->type = ZPL_ADT_TYPE_REAL; - obj->props = ZPL_ADT_PROPS_TRUE; - obj->real = 1; - p += 4; - } else if (zpl_str_has_prefix(p, "false")) { - obj->type = ZPL_ADT_TYPE_REAL; - obj->props = ZPL_ADT_PROPS_FALSE; - obj->real = 0; - p += 5; - } else if (zpl_str_has_prefix(p, "null")) { - obj->type = ZPL_ADT_TYPE_REAL; - obj->props = ZPL_ADT_PROPS_NULL; - obj->real = 0; - p += 4; - } else if (zpl_str_has_prefix(p, "Infinity")) { - obj->type = ZPL_ADT_TYPE_REAL; - obj->real = ZPL_INFINITY; - obj->props = ZPL_ADT_PROPS_INFINITY; - p += 8; - } else if (zpl_str_has_prefix(p, "-Infinity")) { - obj->type = ZPL_ADT_TYPE_REAL; - obj->real = -ZPL_INFINITY; - obj->props = ZPL_ADT_PROPS_INFINITY_NEG; - p += 9; - } else if (zpl_str_has_prefix(p, "NaN")) { - obj->type = ZPL_ADT_TYPE_REAL; - obj->real = ZPL_NAN; - obj->props = ZPL_ADT_PROPS_NAN; - p += 3; - } else if (zpl_str_has_prefix(p, "-NaN")) { - obj->type = ZPL_ADT_TYPE_REAL; - obj->real = -ZPL_NAN; - obj->props = ZPL_ADT_PROPS_NAN_NEG; - p += 4; - } else { - ZPL_JSON_ASSERT("unknown keyword"); - *err_code = ZPL_JSON_ERROR_UNKNOWN_KEYWORD; - return NULL; - } - } else if (zpl_char_is_digit(*p) || *p == '+' || *p == '-' || *p == '.') { - /* defer operation to our helper method. */ - p = zpl_adt_parse_number(obj, p); - } else if (!!zpl_strchr("[{", *p)) { - p = zpl__json_parse_object(obj, p, a, err_code); - ++p; - } - - return p; - } - - char *zpl__json_parse_object(zpl_adt_node *obj, char *base, zpl_allocator a, zpl_u8 *err_code) { - ZPL_ASSERT(obj && base); - char *p = base; - - zpl_array_init(obj->nodes, a); - obj->type = ZPL_ADT_TYPE_OBJECT; - - p = zpl__json_trim(p, false); - /**/ if (*p == '{') { ++p; } - else if (*p == '[') { /* special case for when we call this func on an array. */ - ++p; - obj->type = ZPL_ADT_TYPE_ARRAY; - return zpl__json_parse_array(obj, p, a, err_code); - } - - do { - zpl_adt_node node = { 0 }; - p = zpl__json_trim(p, false); - if (*p == '}' && obj->type == ZPL_ADT_TYPE_OBJECT) return p; - else if (*p == ']' && obj->type == ZPL_ADT_TYPE_ARRAY) return p; - else if (!!zpl_strchr("}]", *p)) { - ZPL_JSON_ASSERT("mismatched end pair"); - *err_code = ZPL_JSON_ERROR_OBJECT_END_PAIR_MISMATCHED; - return NULL; - } - - /* First, we parse the key, then we proceed to the value itself. */ - p = zpl__json_parse_name(&node, p, err_code); - if (err_code && *err_code != ZPL_JSON_ERROR_NONE) { return NULL; } - p = zpl__json_trim(p + 1, false); - p = zpl__json_parse_value(&node, p, a, err_code); - if (err_code && *err_code != ZPL_JSON_ERROR_NONE) { return NULL; } - - zpl_array_append(obj->nodes, node); - - char *end_p = p; - p = zpl__json_trim(p, true); - - /* this code analyses the keyvalue pair delimiter used in the packet. */ - if (zpl__json_is_delim_char(*p)) { - zpl_adt_node *n = zpl_array_end(obj->nodes); - n->delim_style = ZPL_ADT_DELIM_STYLE_COMMA; - - if (*p == '\n') - n->delim_style = ZPL_ADT_DELIM_STYLE_NEWLINE; - else if (*p == '|') { - n->delim_style = ZPL_ADT_DELIM_STYLE_LINE; - n->delim_line_width = cast(zpl_u8)(p-end_p); - } - ++p; - } - p = zpl__json_trim(p, false); - } while (*p); - return p; - } - - char *zpl__json_parse_name(zpl_adt_node *node, char *base, zpl_u8 *err_code) { - char *p = base, *b = p, *e = p; - if (*p == '"' || *p == '\'' || zpl_char_is_alpha(*p) || *p == '_' || *p == '$') { - if (*p == '"' || *p == '\'') { - if (*p == '"') { - node->name_style = ZPL_ADT_NAME_STYLE_DOUBLE_QUOTE; - } else if (*p == '\'') { - node->name_style = ZPL_ADT_NAME_STYLE_SINGLE_QUOTE; - } - char c = *p; - b = ++p; - e = cast(char *)zpl_str_control_skip(b, c); - node->name = b; - - /* we can safely null-terminate here, since "e" points to the quote pair end. */ - *e++ = '\0'; - } - else { - b = e = p; - zpl_str_advance_while(e, *e && (zpl_char_is_alphanumeric(*e) || *e == '_') && !zpl_char_is_space(*e) && !zpl__json_is_assign_char(*e)); - node->name = b; - node->name_style = ZPL_ADT_NAME_STYLE_NO_QUOTES; - /* we defer null-termination as it can potentially wipe our assign char as well. */ - } - - char *assign_p = e; - p = zpl__json_trim(e, false); - node->assign_line_width = cast(zpl_u8)(p-assign_p); - - if (*p && !zpl__json_is_assign_char(*p)) { - ZPL_JSON_ASSERT("invalid assignment"); - *err_code = ZPL_JSON_ERROR_INVALID_ASSIGNMENT; - return NULL; - } - else - { - if (*p == '=') - node->assign_style = ZPL_ADT_ASSIGN_STYLE_EQUALS; - else if (*p == '|') - node->assign_style = ZPL_ADT_ASSIGN_STYLE_LINE; - else node->assign_style = ZPL_ADT_ASSIGN_STYLE_COLON; - } - - /* since we already know the assign style, we can cut it here for unquoted names */ - if (node->name_style == ZPL_ADT_NAME_STYLE_NO_QUOTES && *e) - *e = '\0'; - } - - if (node->name && !zpl__json_validate_name(node->name, NULL)) { - ZPL_JSON_ASSERT("invalid name"); - *err_code = ZPL_JSON_ERROR_INVALID_NAME; - return NULL; - } - - return p; - } - - char *zpl__json_trim(char *base, zpl_b32 catch_newline) { - ZPL_ASSERT_NOT_NULL(base); - char *p = base; - do { - if (zpl_str_has_prefix(p, "//")) { - const char *e = zpl_str_skip(p, '\n'); - p += (e-p); - } - else if (zpl_str_has_prefix(p, "/*")) { - const char *e = zpl_str_skip(p+2, '*'); - if (*e && *(e+1) == '/') { - e+=2; /* advance past end comment block */ - p += (e-p); - } - } - else if (*p == '\n' && catch_newline) { - return p; - } - else if (!zpl_char_is_space(*p)) { - return p; - } - } while (*p++); - return NULL; - } - - void zpl_json_write(zpl_file *f, zpl_adt_node *o, zpl_isize indent) { - if (!o) - return; - - ZPL_ASSERT(o->type == ZPL_ADT_TYPE_OBJECT || o->type == ZPL_ADT_TYPE_ARRAY); - - zpl___ind(indent - 4); - if (!o->cfg_mode) - zpl_fprintf(f, "%c\n", o->type == ZPL_ADT_TYPE_OBJECT ? '{' : '['); - else { - indent -= 4; - } - - if (o->nodes) { - zpl_isize cnt = zpl_array_count(o->nodes); - - for (int i = 0; i < cnt; ++i) { - zpl__json_write_value(f, o->nodes + i, o, indent, false, !(i < cnt - 1)); - } - } - - zpl___ind(indent); - - if (indent > 0) { - zpl_fprintf(f, "%c", o->type == ZPL_ADT_TYPE_OBJECT ? '}' : ']'); - } else { - if (!o->cfg_mode) zpl_fprintf(f, "%c\n", o->type == ZPL_ADT_TYPE_OBJECT ? '}' : ']'); - } - } - - void zpl__json_write_value(zpl_file *f, zpl_adt_node *o, zpl_adt_node *t, zpl_isize indent, zpl_b32 is_inline, zpl_b32 is_last) { - zpl_adt_node *node = o; - indent += 4; - - if (!is_inline) { - zpl___ind(indent); - - if (t->type != ZPL_ADT_TYPE_ARRAY) { - switch (node->name_style) { - case ZPL_ADT_NAME_STYLE_DOUBLE_QUOTE: { - zpl_fprintf(f, "\"%s\"", node->name); - } break; - - case ZPL_ADT_NAME_STYLE_SINGLE_QUOTE: { - zpl_fprintf(f, "\'%s\'", node->name); - } break; - - case ZPL_ADT_NAME_STYLE_NO_QUOTES: { - zpl_fprintf(f, "%s", node->name); - } break; - } - - if (o->assign_style == ZPL_ADT_ASSIGN_STYLE_COLON) - zpl_fprintf(f, ": "); - else { - zpl___ind(zpl_max(o->assign_line_width, 1)); - - if (o->assign_style == ZPL_ADT_ASSIGN_STYLE_EQUALS) - zpl_fprintf(f, "= "); - else if (o->assign_style == ZPL_ADT_ASSIGN_STYLE_LINE) { - zpl_fprintf(f, "| "); - } - } - } - } - - switch (node->type) { - case ZPL_ADT_TYPE_STRING: { - zpl_fprintf(f, "\""); - zpl_adt_print_string(f, node, "\"", '\\'); - zpl_fprintf(f, "\""); - } break; - - case ZPL_ADT_TYPE_MULTISTRING: { - zpl_fprintf(f, "`"); - zpl_adt_print_string(f, node, "`", '\\'); - zpl_fprintf(f, "`"); - } break; - - case ZPL_ADT_TYPE_ARRAY: { - zpl_fprintf(f, "["); - zpl_isize elemn = zpl_array_count(node->nodes); - for (int j = 0; j < elemn; ++j) { - zpl_isize ind = ((node->nodes + j)->type == ZPL_ADT_TYPE_OBJECT || (node->nodes + j)->type == ZPL_ADT_TYPE_ARRAY) ? 0 : -4; - zpl__json_write_value(f, node->nodes + j, o, ind, true, true); - - if (j < elemn - 1) { zpl_fprintf(f, ", "); } - } - zpl_fprintf(f, "]"); - } break; - - case ZPL_ADT_TYPE_REAL: - case ZPL_ADT_TYPE_INTEGER: { - zpl_adt_print_number(f, node); - } break; - - case ZPL_ADT_TYPE_OBJECT: { - zpl_json_write(f, node, indent); - } break; - } - - if (!is_inline) { - if (o->delim_style != ZPL_ADT_DELIM_STYLE_COMMA) { - if (o->delim_style == ZPL_ADT_DELIM_STYLE_NEWLINE) - zpl_fprintf(f, "\n"); - else if (o->delim_style == ZPL_ADT_DELIM_STYLE_LINE) { - zpl___ind(o->delim_line_width); - zpl_fprintf(f, "|\n"); - } - } - else { - if (!is_last) { - zpl_fprintf(f, ",\n"); - } else { - zpl_fprintf(f, "\n"); - } - } - } - } - - #undef zpl___ind - - ZPL_END_C_DECLS - // file: source/parsers/csv.c - - - #ifdef ZPL_CSV_DEBUG - #define ZPL_CSV_ASSERT(msg) ZPL_PANIC(msg) - #else - #define ZPL_CSV_ASSERT(msg) - #endif - - - ZPL_BEGIN_C_DECLS - - zpl_u8 zpl_csv_parse_delimiter(zpl_csv_object *root, char *text, zpl_allocator allocator, zpl_b32 has_header, char delim) { - zpl_csv_error err = ZPL_CSV_ERROR_NONE; - ZPL_ASSERT_NOT_NULL(root); - ZPL_ASSERT_NOT_NULL(text); - zpl_zero_item(root); - zpl_adt_make_branch(root, allocator, NULL, has_header ? ZPL_ADT_TYPE_OBJECT : ZPL_ADT_TYPE_ARRAY); - char *p = text, *b = p, *e = p; - zpl_isize colc = 0, total_colc = 0; - - do { - char d = 0; - p = cast(char *)zpl_str_trim(p, false); - if (*p == 0) break; - zpl_adt_node row_item = {0}; - row_item.type = ZPL_ADT_TYPE_STRING; - row_item.name_style = ZPL_ADT_NAME_STYLE_NO_QUOTES; - - /* handle string literals */ - if (*p == '"') { - p = b = e = p+1; - row_item.string = b; - row_item.name_style = ZPL_ADT_NAME_STYLE_DOUBLE_QUOTE; - do { - e = cast(char *)zpl_str_skip(e, '"'); - if (*e && *(e+1) == '"') { - e += 2; - } - else break; - } while (*e); - if (*e == 0) { - ZPL_CSV_ASSERT("unmatched quoted string"); - err = ZPL_CSV_ERROR_UNEXPECTED_END_OF_INPUT; - return err; - } - *e = 0; - p = cast(char *)zpl_str_trim(e+1, true); - d = *p; - - /* unescape escaped quotes (so that unescaped text escapes :) */ - { - char *ep = b; - do { - if (*ep == '"' && *(ep+1) == '"') { - zpl_memmove(ep, ep+1, zpl_strlen(ep)); - } - ep++; - } while (*ep); - } - } - else if (*p == delim) { - d = *p; - row_item.string = ""; - } - else if (*p) { - /* regular data */ - b = e = p; - row_item.string = b; - do { - e++; - } while (*e && *e != delim && *e != '\n'); - if (*e) { - p = cast(char *)zpl_str_trim(e, true); - while (zpl_char_is_space(*(e-1))) { e--; } - d = *p; - *e = 0; - } - else { - d = 0; - p = e; - } - - /* check if number and process if so */ - zpl_b32 skip_number = false; - char *num_p = b; - do { - if (!zpl_char_is_hex_digit(*num_p) && (!zpl_strchr("+-.eExX", *num_p))) { - skip_number = true; - break; - } - } while (*num_p++); - - if (!skip_number) { - zpl_adt_str_to_number(&row_item); - } - } - - if (colc >= zpl_array_count(root->nodes)) { - zpl_adt_inset_arr(root, NULL); - } - - zpl_array_append(root->nodes[colc].nodes, row_item); - - if (d == delim) { - colc++; - p++; - } - else if (d == '\n' || d == 0) { - /* check if number of rows is not mismatched */ - if (total_colc < colc) total_colc = colc; - else if (total_colc != colc) { - ZPL_CSV_ASSERT("mismatched rows"); - err = ZPL_CSV_ERROR_MISMATCHED_ROWS; - return err; - } - colc = 0; - if (d != 0) p++; - } - } while(*p); - - if (zpl_array_count(root->nodes) == 0) { - ZPL_CSV_ASSERT("unexpected end of input. stream is empty."); - err = ZPL_CSV_ERROR_UNEXPECTED_END_OF_INPUT; - return err; - } - - /* consider first row as a header. */ - if (has_header) { - for (zpl_isize i = 0; i < zpl_array_count(root->nodes); i++) { - zpl_csv_object *col = root->nodes + i; - zpl_csv_object *hdr = col->nodes; - col->name = hdr->string; - zpl_array_remove_at(col->nodes, 0); - } - } - - return err; - } - void zpl_csv_free(zpl_csv_object *obj) { - zpl_adt_destroy_branch(obj); - } - - void zpl__csv_write_record(zpl_file *file, zpl_csv_object *node) { - switch (node->type) { - case ZPL_ADT_TYPE_STRING: { - switch (node->name_style) { - case ZPL_ADT_NAME_STYLE_DOUBLE_QUOTE: { - zpl_fprintf(file, "\""); - zpl_adt_print_string(file, node, "\"", '"'); - zpl_fprintf(file, "\""); - } break; - - case ZPL_ADT_NAME_STYLE_NO_QUOTES: { - zpl_fprintf(file, "%s", node->string); - } break; - } - } break; - - case ZPL_ADT_TYPE_REAL: - case ZPL_ADT_TYPE_INTEGER: { - zpl_adt_print_number(file, node); - } break; - } - } - - void zpl__csv_write_header(zpl_file *file, zpl_csv_object *header) { - zpl_csv_object temp = *header; - temp.string = temp.name; - temp.type = ZPL_ADT_TYPE_STRING; - zpl__csv_write_record(file, &temp); - } - - void zpl_csv_write_delimiter(zpl_file *file, zpl_csv_object *obj, char delimiter) { - ZPL_ASSERT_NOT_NULL(file); - ZPL_ASSERT_NOT_NULL(obj); - ZPL_ASSERT(obj->nodes); - zpl_isize cols = zpl_array_count(obj->nodes); - if (cols == 0) return; - - zpl_isize rows = zpl_array_count(obj->nodes[0].nodes); - if (rows == 0) return; - - zpl_b32 has_headers = obj->nodes[0].name != NULL; - - if (has_headers) { - for (zpl_isize i = 0; i < cols; i++) { - zpl__csv_write_header(file, &obj->nodes[i]); - if (i+1 != cols) { - zpl_fprintf(file, ","); - } - } - zpl_fprintf(file, "\n"); - } - - for (zpl_isize r = 0; r < rows; r++) { - for (zpl_isize i = 0; i < cols; i++) { - zpl__csv_write_record(file, &obj->nodes[i].nodes[r]); - if (i+1 != cols) { - zpl_fprintf(file, ","); - } - } - zpl_fprintf(file, "\n"); - } - } - - zpl_string zpl_csv_write_string_delimiter(zpl_allocator a, zpl_csv_object *obj, char delimiter) { - zpl_file tmp; - zpl_file_stream_new(&tmp, a); - zpl_csv_write_delimiter(&tmp, obj, delimiter); - zpl_isize fsize; - zpl_u8* buf = zpl_file_stream_buf(&tmp, &fsize); - zpl_string output = zpl_string_make_length(a, (char *)buf, fsize+1); - zpl_file_close(&tmp); - return output; - } - - ZPL_END_C_DECLS +// file: source/adt.c + +ZPL_BEGIN_C_DECLS + +zpl_u8 zpl_adt_make_branch(zpl_adt_node *node, zpl_allocator backing, char const *name, zpl_u8 type) { + ZPL_ASSERT(type == ZPL_ADT_TYPE_OBJECT || type == ZPL_ADT_TYPE_ARRAY); + zpl_zero_item(node); + node->type = type; + node->name = name; + zpl_array_init(node->nodes, backing); + return 0; +} + +zpl_u8 zpl_adt_destroy_branch(zpl_adt_node *node) { + ZPL_ASSERT_NOT_NULL(node); + if ((node->type == ZPL_ADT_TYPE_OBJECT || node->type == ZPL_ADT_TYPE_ARRAY) && node->nodes) { + for (zpl_isize i = 0; i < zpl_array_count(node->nodes); ++i) { zpl_adt_destroy_branch(node->nodes + i); } + + zpl_array_free(node->nodes); + } + return 0; +} + +zpl_u8 zpl_adt_make_leaf(zpl_adt_node *node, char const *name, zpl_u8 type) { + ZPL_ASSERT(type != ZPL_ADT_TYPE_OBJECT && type != ZPL_ADT_TYPE_ARRAY); + zpl_zero_item(node); + node->type = type; + node->name = name; + return 0; +} + +zpl_adt_node *zpl_adt_find(zpl_adt_node *node, char const *name, zpl_b32 deep_search) { + if (node->type != ZPL_ADT_TYPE_OBJECT) { + return NULL; + } + + for (zpl_isize i = 0; i < zpl_array_count(node->nodes); i++) { + if (!zpl_strcmp(node->nodes[i].name, name)) { + return (node->nodes + i); + } + } + + if (deep_search) { + for (zpl_isize i = 0; i < zpl_array_count(node->nodes); i++) { + zpl_adt_node *res = zpl_adt_find(node->nodes + i, name, deep_search); + + if (res != NULL) + return res; + } + } + + return NULL; +} + +zpl_adt_node *zpl_adt_alloc_at(zpl_adt_node *parent, zpl_isize index) { + if (!parent || (parent->type != ZPL_ADT_TYPE_OBJECT && parent->type != ZPL_ADT_TYPE_ARRAY)) { + return NULL; + } + + if (!parent->nodes) + return NULL; + + if (index < 0 || index > zpl_array_count(parent->nodes)) + return NULL; + + zpl_adt_node o = {0}; + zpl_array_append_at(parent->nodes, o, index); + + return parent->nodes + index; +} + +zpl_adt_node *zpl_adt_alloc(zpl_adt_node *parent) { + if (!parent || (parent->type != ZPL_ADT_TYPE_OBJECT && parent->type != ZPL_ADT_TYPE_ARRAY)) { + return NULL; + } + + if (!parent->nodes) + return NULL; + + return zpl_adt_alloc_at(parent, zpl_array_count(parent->nodes)); +} + + +void zpl_adt_set_obj(zpl_adt_node *obj, char const *name, zpl_allocator backing) { + zpl_adt_make_branch(obj, backing, name, ZPL_ADT_TYPE_OBJECT); +} +void zpl_adt_set_arr(zpl_adt_node *obj, char const *name, zpl_allocator backing) { + zpl_adt_make_branch(obj, backing, name, ZPL_ADT_TYPE_ARRAY); +} +void zpl_adt_set_str(zpl_adt_node *obj, char const *name, char const *value) { + zpl_adt_make_leaf(obj, name, ZPL_ADT_TYPE_STRING); + obj->string = value; +} +void zpl_adt_set_flt(zpl_adt_node *obj, char const *name, zpl_f64 value) { + zpl_adt_make_leaf(obj, name, ZPL_ADT_TYPE_REAL); + obj->real = value; +} +void zpl_adt_set_int(zpl_adt_node *obj, char const *name, zpl_i64 value) { + zpl_adt_make_leaf(obj, name, ZPL_ADT_TYPE_INTEGER); + obj->integer = value; +} + +zpl_adt_node *zpl_adt_move_node_at(zpl_adt_node *node, zpl_adt_node *old_parent, zpl_adt_node *new_parent, zpl_isize index) { + ZPL_ASSERT_NOT_NULL(node); + ZPL_ASSERT_NOT_NULL(old_parent); + ZPL_ASSERT_NOT_NULL(new_parent); + ZPL_ASSERT(new_parent->type == ZPL_ADT_TYPE_ARRAY || new_parent->type == ZPL_ADT_TYPE_OBJECT); + ZPL_ASSERT(node >= old_parent->nodes); + ZPL_ASSERT(node <= zpl_array_end(old_parent->nodes)); + ZPL_ASSERT(index >= 0 && index <= zpl_array_count(new_parent->nodes)); + zpl_adt_node *new_node = zpl_adt_alloc_at(new_parent, index); + *new_node = *node; + zpl_adt_remove_node(node, old_parent); + return new_node; +} + +zpl_adt_node *zpl_adt_move_node(zpl_adt_node *node, zpl_adt_node *old_parent, zpl_adt_node *new_parent) { + ZPL_ASSERT_NOT_NULL(new_parent); + ZPL_ASSERT(new_parent->type == ZPL_ADT_TYPE_ARRAY || new_parent->type == ZPL_ADT_TYPE_OBJECT); + return zpl_adt_move_node_at(node, old_parent, new_parent, zpl_array_count(new_parent->nodes)); +} + +void zpl_adt_swap_nodes(zpl_adt_node *node, zpl_adt_node *other_node, zpl_adt_node *parent) { + zpl_adt_swap_nodes_between_parents(node, other_node, parent, parent); +} + +void zpl_adt_swap_nodes_between_parents(zpl_adt_node *node, zpl_adt_node *other_node, zpl_adt_node *parent, zpl_adt_node *other_parent) { + ZPL_ASSERT_NOT_NULL(node); + ZPL_ASSERT_NOT_NULL(other_node); + ZPL_ASSERT_NOT_NULL(parent); + ZPL_ASSERT_NOT_NULL(other_parent); + ZPL_ASSERT(node >= parent->nodes && node <= zpl_array_end(parent->nodes)); + ZPL_ASSERT(other_node >= other_parent->nodes && other_node <= zpl_array_end(other_parent->nodes)); + zpl_isize index = (zpl_pointer_diff(parent->nodes, node) / zpl_size_of(zpl_adt_node)); + zpl_isize index2 = (zpl_pointer_diff(other_parent->nodes, other_node) / zpl_size_of(zpl_adt_node)); + zpl_adt_node temp = parent->nodes[index]; + parent->nodes[index] = other_parent->nodes[index2]; + other_parent->nodes[index2] = temp; +} + +void zpl_adt_remove_node(zpl_adt_node *node, zpl_adt_node *parent) { + ZPL_ASSERT_NOT_NULL(node); + ZPL_ASSERT_NOT_NULL(parent); + ZPL_ASSERT(node >= parent->nodes); + ZPL_ASSERT(node <= zpl_array_end(parent->nodes)); + zpl_isize index = (zpl_pointer_diff(parent->nodes, node) / zpl_size_of(zpl_adt_node)); + zpl_array_remove_at(parent->nodes, index); +} + + +zpl_adt_node *zpl_adt_inset_obj(zpl_adt_node *parent, char const *name) { + zpl_adt_node *o = zpl_adt_alloc(parent); + zpl_adt_set_obj(o, name, ZPL_ARRAY_HEADER(parent->nodes)->allocator); + return o; +} +zpl_adt_node *zpl_adt_inset_arr(zpl_adt_node *parent, char const *name) { + zpl_adt_node *o = zpl_adt_alloc(parent); + zpl_adt_set_arr(o, name, ZPL_ARRAY_HEADER(parent->nodes)->allocator); + return o; +} +zpl_adt_node *zpl_adt_inset_str(zpl_adt_node *parent, char const *name, char const *value) { + zpl_adt_node *o = zpl_adt_alloc(parent); + zpl_adt_set_str(o, name, value); + return o; +} +zpl_adt_node *zpl_adt_inset_flt(zpl_adt_node *parent, char const *name, zpl_f64 value) { + zpl_adt_node *o = zpl_adt_alloc(parent); + zpl_adt_set_flt(o, name, value); + return o; +} +zpl_adt_node *zpl_adt_inset_int(zpl_adt_node *parent, char const *name, zpl_i64 value) { + zpl_adt_node *o = zpl_adt_alloc(parent); + zpl_adt_set_int(o, name, value); + return o; +} + +/* parser helpers */ + +char *zpl_adt_parse_number(zpl_adt_node *node, char* base) { + ZPL_ASSERT_NOT_NULL(node); + ZPL_ASSERT_NOT_NULL(base); + char *p = base, *e = p; + + /* skip false positives and special cases */ + if (!!zpl_strchr("eE", *p) || (!!zpl_strchr(".+-", *p) && !zpl_char_is_hex_digit(*(p+1)) && *(p+1) != '.')) { + return ++base; + } + + node->type = ZPL_ADT_TYPE_INTEGER; + node->neg_zero = false; + + zpl_isize ib = 0; + char buf[48] = { 0 }; + + if (*e == '+') + ++e; + else if (*e == '-') { + buf[ib++] = *e++; + } + + if (*e == '.') { + node->type = ZPL_ADT_TYPE_REAL; + node->props = ZPL_ADT_PROPS_IS_PARSED_REAL; + node->lead_digit = false; + buf[ib++] = '0'; + do { + buf[ib++] = *e; + } while (zpl_char_is_digit(*++e)); + } else { + if (!zpl_strncmp(e, "0x", 2) || !zpl_strncmp(e, "0X", 2)) { node->props = ZPL_ADT_PROPS_IS_HEX; } + while (zpl_char_is_hex_digit(*e) || zpl_char_to_lower(*e) == 'x') { buf[ib++] = *e++; } + + if (*e == '.') { + node->type = ZPL_ADT_TYPE_REAL; + node->lead_digit = true; + zpl_u32 step = 0; + + do { + buf[ib++] = *e; + ++step; + } while (zpl_char_is_digit(*++e)); + + if (step < 2) { buf[ib++] = '0'; } + } + } + + zpl_u8 exp = 0; + zpl_f32 eb = 10; + char expbuf[6] = { 0 }; + zpl_isize expi = 0; + + if (*e && !!zpl_strchr("eE", *e)) { + ++e; + if (*e == '+' || *e == '-' || zpl_char_is_digit(*e)) { + if (*e == '-') { eb = 0.1f; } + if (!zpl_char_is_digit(*e)) { ++e; } + while (zpl_char_is_digit(*e)) { expbuf[expi++] = *e++; } + } + + exp = (zpl_u8)zpl_str_to_i64(expbuf, NULL, 10); + } + + if (node->type == ZPL_ADT_TYPE_INTEGER) { + node->integer = zpl_str_to_i64(buf, 0, 0); + /* special case: negative zero */ + if (node->integer == 0 && buf[0] == '-') { + node->neg_zero = true; + } + while (exp-- > 0) { node->integer *= (zpl_i64)eb; } + } else { + node->real = zpl_str_to_f64(buf, 0); + + char *q = buf, *base_str = q, *base_str2 = q; + base_str = cast(char *)zpl_str_skip(base_str, '.'); + *base_str = '\0'; + base_str2 = base_str + 1; + char *base_str_off = base_str2; + while (*base_str_off++ == '0') node->base2_offset++; + + node->base = (zpl_i32)zpl_str_to_i64(q, 0, 0); + node->base2 = (zpl_i32)zpl_str_to_i64(base_str2, 0, 0); + + if (exp) { + node->exp = exp * (!(eb == 10.0f) ? -1 : 1); + node->props = ZPL_ADT_PROPS_IS_EXP; + } + + /* special case: negative zero */ + if (node->base == 0 && buf[0] == '-') { + node->neg_zero = true; + } + + while (exp-- > 0) { node->real *= eb; } + } + return e; +} + +void zpl_adt_print_number(zpl_file *file, zpl_adt_node *node) { + ZPL_ASSERT_NOT_NULL(file); + ZPL_ASSERT_NOT_NULL(node); + ZPL_ASSERT(node->type == ZPL_ADT_TYPE_INTEGER || node->type == ZPL_ADT_TYPE_REAL); + + if (node->neg_zero) { + zpl_fprintf(file, "-"); + } + + switch (node->type) { + case ZPL_ADT_TYPE_INTEGER: { + if (node->props == ZPL_ADT_PROPS_IS_HEX) { + zpl_fprintf(file, "0x%llx", (long long)node->integer); + } else { + zpl_fprintf(file, "%lld", (long long)node->integer); + } + } break; + + case ZPL_ADT_TYPE_REAL: { + if (node->props == ZPL_ADT_PROPS_NAN) { + zpl_fprintf(file, "NaN"); + } else if (node->props == ZPL_ADT_PROPS_NAN_NEG) { + zpl_fprintf(file, "-NaN"); + } else if (node->props == ZPL_ADT_PROPS_INFINITY) { + zpl_fprintf(file, "Infinity"); + } else if (node->props == ZPL_ADT_PROPS_INFINITY_NEG) { + zpl_fprintf(file, "-Infinity"); + } else if (node->props == ZPL_ADT_PROPS_TRUE) { + zpl_fprintf(file, "true"); + } else if (node->props == ZPL_ADT_PROPS_FALSE) { + zpl_fprintf(file, "false"); + } else if (node->props == ZPL_ADT_PROPS_NULL) { + zpl_fprintf(file, "null"); + } else if (node->props == ZPL_ADT_PROPS_IS_EXP) { + zpl_fprintf(file, "%lld.%0*d%llde%lld", (long long)node->base, node->base2_offset, 0, (long long)node->base2, (long long)node->exp); + } else if (node->props == ZPL_ADT_PROPS_IS_PARSED_REAL) { + if (!node->lead_digit) + zpl_fprintf(file, ".%0*d%lld", node->base2_offset, 0, (long long)node->base2); + else + zpl_fprintf(file, "%lld.%0*d%lld", (long long int)node->base2_offset, 0, (int)node->base, (long long)node->base2); + } else { + zpl_fprintf(file, "%f", node->real); + } + } break; + } +} + +void zpl_adt_print_string(zpl_file *file, zpl_adt_node *node, char const* escaped_chars, char escape_symbol) { + ZPL_ASSERT_NOT_NULL(file); + ZPL_ASSERT_NOT_NULL(node); + ZPL_ASSERT_NOT_NULL(escaped_chars); + ZPL_ASSERT(node->type == ZPL_ADT_TYPE_STRING || node->type == ZPL_ADT_TYPE_MULTISTRING); + + /* escape string */ + char const* p = node->string, *b = p; + do { + p = zpl_str_skip_any(p, escaped_chars); + zpl_fprintf(file, "%.*s", zpl_ptr_diff(b, p), b); + if (*p && !!zpl_strchr(escaped_chars, *p)) { + zpl_fprintf(file, "%c%c", escape_symbol, *p); + p++; + } + b = p; + } while (*p); +} + +void zpl_adt_str_to_number(zpl_adt_node *node) { + ZPL_ASSERT(node); + + if (node->type == ZPL_ADT_TYPE_REAL || node->type == ZPL_ADT_TYPE_INTEGER) return; /* this is already converted/parsed */ + ZPL_ASSERT(node->type == ZPL_ADT_TYPE_STRING || node->type == ZPL_ADT_TYPE_MULTISTRING); + zpl_adt_parse_number(node, (char *)node->string); +} + +ZPL_END_C_DECLS + +/* parsers */ +// file: source/parsers/json.c + +//////////////////////////////////////////////////////////////// +// +// JSON5 Parser +// +// + + +#ifdef ZPL_JSON_DEBUG +#define ZPL_JSON_ASSERT(msg) ZPL_PANIC(msg) +#else +#define ZPL_JSON_ASSERT(msg) +#endif + +ZPL_BEGIN_C_DECLS + +char *zpl__json_parse_object(zpl_adt_node *obj, char *base, zpl_allocator a, zpl_u8 *err_code); +char *zpl__json_parse_array(zpl_adt_node *obj, char *base, zpl_allocator a, zpl_u8 *err_code); +char *zpl__json_parse_value(zpl_adt_node *obj, char *base, zpl_allocator a, zpl_u8 *err_code); +char *zpl__json_parse_name(zpl_adt_node *obj, char *base, zpl_u8 *err_code); +char *zpl__json_trim(char *base, zpl_b32 catch_newline); +void zpl__json_write_value(zpl_file *f, zpl_adt_node *o, zpl_adt_node *t, zpl_isize indent, zpl_b32 is_inline, zpl_b32 is_last); +#define zpl___ind(x) if (x > 0) zpl_fprintf(f, "%*r", x, ' '); + +zpl_u8 zpl_json_parse(zpl_adt_node *root, char *text, zpl_allocator a) { + zpl_u8 err_code = ZPL_JSON_ERROR_NONE; + ZPL_ASSERT(root); + ZPL_ASSERT(text); + zpl_zero_item(root); + text = zpl__json_trim(text, true); + + if (!zpl_strchr("{[", *text)) { + root->cfg_mode = true; + } + + zpl__json_parse_object(root, text, a, &err_code); + return err_code; +} + +void zpl_json_free(zpl_adt_node *obj) { + zpl_adt_destroy_branch(obj); +} + +zpl_string zpl_json_write_string(zpl_allocator a, zpl_adt_node *obj, zpl_isize indent) { + zpl_file tmp; + zpl_file_stream_new(&tmp, a); + zpl_json_write(&tmp, obj, indent); + zpl_isize fsize; + zpl_u8* buf = zpl_file_stream_buf(&tmp, &fsize); + zpl_string output = zpl_string_make_length(a, (char *)buf, fsize+1); + zpl_file_close(&tmp); + return output; +} + +/* private */ + +static ZPL_ALWAYS_INLINE zpl_b32 zpl__json_is_assign_char(char c) { return !!zpl_strchr(":=|", c); } +static ZPL_ALWAYS_INLINE zpl_b32 zpl__json_is_delim_char(char c) { return !!zpl_strchr(",|\n", c); } +ZPL_DEF_INLINE zpl_b32 zpl__json_validate_name(char const *str, char *err); + +#define jx(x) !zpl_char_is_hex_digit(str[x]) +ZPL_IMPL_INLINE zpl_b32 zpl__json_validate_name(char const *str, char *err) { + while (*str) { + /* todo: refactor name validation. */ + if ((str[0] == '\\' && !zpl_char_is_control(str[1])) && + (str[0] == '\\' && jx(1) && jx(2) && jx(3) && jx(4))) { + if (err) *err = *str; + return false; + } + + ++str; + } + + return true; +} +#undef jx + +char *zpl__json_parse_array(zpl_adt_node *obj, char *base, zpl_allocator a, zpl_u8 *err_code) { + ZPL_ASSERT(obj && base); + char *p = base; + + obj->type = ZPL_ADT_TYPE_ARRAY; + zpl_array_init(obj->nodes, a); + + while (*p) { + p = zpl__json_trim(p, false); + + if (*p == ']') { + return p; + } + + zpl_adt_node elem = { 0 }; + p = zpl__json_parse_value(&elem, p, a, err_code); + + if (*err_code != ZPL_JSON_ERROR_NONE) { return NULL; } + + zpl_array_append(obj->nodes, elem); + + p = zpl__json_trim(p, false); + + if (*p == ',') { + ++p; + continue; + } else { + if (*p != ']') { + ZPL_JSON_ASSERT("end of array unfulfilled"); + *err_code = ZPL_JSON_ERROR_ARRAY_LEFT_OPEN; + return NULL; + } + return p; + } + } + + *err_code = ZPL_JSON_ERROR_INTERNAL; + return NULL; +} + +char *zpl__json_parse_value(zpl_adt_node *obj, char *base, zpl_allocator a, zpl_u8 *err_code) { + ZPL_ASSERT(obj && base); + char *p = base, *b = p, *e = p; + + if (!!zpl_strchr("`\"'", *p)) { + char c = *p; + obj->type = (c == '`') ? ZPL_ADT_TYPE_MULTISTRING : ZPL_ADT_TYPE_STRING; + b = e = p + 1; + obj->string = b; + e = cast(char *)zpl_str_skip_literal(e, c); + *e = '\0', p = e + 1; + } else if (zpl_char_is_alpha(*p) || (*p == '-' && !zpl_char_is_digit(*(p + 1)))) { + if (zpl_str_has_prefix(p, "true")) { + obj->type = ZPL_ADT_TYPE_REAL; + obj->props = ZPL_ADT_PROPS_TRUE; + obj->real = 1; + p += 4; + } else if (zpl_str_has_prefix(p, "false")) { + obj->type = ZPL_ADT_TYPE_REAL; + obj->props = ZPL_ADT_PROPS_FALSE; + obj->real = 0; + p += 5; + } else if (zpl_str_has_prefix(p, "null")) { + obj->type = ZPL_ADT_TYPE_REAL; + obj->props = ZPL_ADT_PROPS_NULL; + obj->real = 0; + p += 4; + } else if (zpl_str_has_prefix(p, "Infinity")) { + obj->type = ZPL_ADT_TYPE_REAL; + obj->real = ZPL_INFINITY; + obj->props = ZPL_ADT_PROPS_INFINITY; + p += 8; + } else if (zpl_str_has_prefix(p, "-Infinity")) { + obj->type = ZPL_ADT_TYPE_REAL; + obj->real = -ZPL_INFINITY; + obj->props = ZPL_ADT_PROPS_INFINITY_NEG; + p += 9; + } else if (zpl_str_has_prefix(p, "NaN")) { + obj->type = ZPL_ADT_TYPE_REAL; + obj->real = ZPL_NAN; + obj->props = ZPL_ADT_PROPS_NAN; + p += 3; + } else if (zpl_str_has_prefix(p, "-NaN")) { + obj->type = ZPL_ADT_TYPE_REAL; + obj->real = -ZPL_NAN; + obj->props = ZPL_ADT_PROPS_NAN_NEG; + p += 4; + } else { + ZPL_JSON_ASSERT("unknown keyword"); + *err_code = ZPL_JSON_ERROR_UNKNOWN_KEYWORD; + return NULL; + } + } else if (zpl_char_is_digit(*p) || *p == '+' || *p == '-' || *p == '.') { + /* defer operation to our helper method. */ + p = zpl_adt_parse_number(obj, p); + } else if (!!zpl_strchr("[{", *p)) { + p = zpl__json_parse_object(obj, p, a, err_code); + ++p; + } + + return p; +} + +char *zpl__json_parse_object(zpl_adt_node *obj, char *base, zpl_allocator a, zpl_u8 *err_code) { + ZPL_ASSERT(obj && base); + char *p = base; + + zpl_array_init(obj->nodes, a); + obj->type = ZPL_ADT_TYPE_OBJECT; + + p = zpl__json_trim(p, false); + /**/ if (*p == '{') { ++p; } + else if (*p == '[') { /* special case for when we call this func on an array. */ + ++p; + obj->type = ZPL_ADT_TYPE_ARRAY; + return zpl__json_parse_array(obj, p, a, err_code); + } + + do { + zpl_adt_node node = { 0 }; + p = zpl__json_trim(p, false); + if (*p == '}' && obj->type == ZPL_ADT_TYPE_OBJECT) return p; + else if (*p == ']' && obj->type == ZPL_ADT_TYPE_ARRAY) return p; + else if (!!zpl_strchr("}]", *p)) { + ZPL_JSON_ASSERT("mismatched end pair"); + *err_code = ZPL_JSON_ERROR_OBJECT_END_PAIR_MISMATCHED; + return NULL; + } + + /* First, we parse the key, then we proceed to the value itself. */ + p = zpl__json_parse_name(&node, p, err_code); + if (err_code && *err_code != ZPL_JSON_ERROR_NONE) { return NULL; } + p = zpl__json_trim(p + 1, false); + p = zpl__json_parse_value(&node, p, a, err_code); + if (err_code && *err_code != ZPL_JSON_ERROR_NONE) { return NULL; } + + zpl_array_append(obj->nodes, node); + + char *end_p = p; + p = zpl__json_trim(p, true); + + /* this code analyses the keyvalue pair delimiter used in the packet. */ + if (zpl__json_is_delim_char(*p)) { + zpl_adt_node *n = zpl_array_end(obj->nodes); + n->delim_style = ZPL_ADT_DELIM_STYLE_COMMA; + + if (*p == '\n') + n->delim_style = ZPL_ADT_DELIM_STYLE_NEWLINE; + else if (*p == '|') { + n->delim_style = ZPL_ADT_DELIM_STYLE_LINE; + n->delim_line_width = cast(zpl_u8)(p-end_p); + } + ++p; + } + p = zpl__json_trim(p, false); + } while (*p); + return p; +} + +char *zpl__json_parse_name(zpl_adt_node *node, char *base, zpl_u8 *err_code) { + char *p = base, *b = p, *e = p; + if (*p == '"' || *p == '\'' || zpl_char_is_alpha(*p) || *p == '_' || *p == '$') { + if (*p == '"' || *p == '\'') { + if (*p == '"') { + node->name_style = ZPL_ADT_NAME_STYLE_DOUBLE_QUOTE; + } else if (*p == '\'') { + node->name_style = ZPL_ADT_NAME_STYLE_SINGLE_QUOTE; + } + char c = *p; + b = ++p; + e = cast(char *)zpl_str_control_skip(b, c); + node->name = b; + + /* we can safely null-terminate here, since "e" points to the quote pair end. */ + *e++ = '\0'; + } + else { + b = e = p; + zpl_str_advance_while(e, *e && (zpl_char_is_alphanumeric(*e) || *e == '_') && !zpl_char_is_space(*e) && !zpl__json_is_assign_char(*e)); + node->name = b; + node->name_style = ZPL_ADT_NAME_STYLE_NO_QUOTES; + /* we defer null-termination as it can potentially wipe our assign char as well. */ + } + + char *assign_p = e; + p = zpl__json_trim(e, false); + node->assign_line_width = cast(zpl_u8)(p-assign_p); + + if (*p && !zpl__json_is_assign_char(*p)) { + ZPL_JSON_ASSERT("invalid assignment"); + *err_code = ZPL_JSON_ERROR_INVALID_ASSIGNMENT; + return NULL; + } + else + { + if (*p == '=') + node->assign_style = ZPL_ADT_ASSIGN_STYLE_EQUALS; + else if (*p == '|') + node->assign_style = ZPL_ADT_ASSIGN_STYLE_LINE; + else node->assign_style = ZPL_ADT_ASSIGN_STYLE_COLON; + } + + /* since we already know the assign style, we can cut it here for unquoted names */ + if (node->name_style == ZPL_ADT_NAME_STYLE_NO_QUOTES && *e) + *e = '\0'; + } + + if (node->name && !zpl__json_validate_name(node->name, NULL)) { + ZPL_JSON_ASSERT("invalid name"); + *err_code = ZPL_JSON_ERROR_INVALID_NAME; + return NULL; + } + + return p; +} + +char *zpl__json_trim(char *base, zpl_b32 catch_newline) { + ZPL_ASSERT_NOT_NULL(base); + char *p = base; + do { + if (zpl_str_has_prefix(p, "//")) { + const char *e = zpl_str_skip(p, '\n'); + p += (e-p); + } + else if (zpl_str_has_prefix(p, "/*")) { + const char *e = zpl_str_skip(p+2, '*'); + if (*e && *(e+1) == '/') { + e+=2; /* advance past end comment block */ + p += (e-p); + } + } + else if (*p == '\n' && catch_newline) { + return p; + } + else if (!zpl_char_is_space(*p)) { + return p; + } + } while (*p++); + return NULL; +} + +void zpl_json_write(zpl_file *f, zpl_adt_node *o, zpl_isize indent) { + if (!o) + return; + + ZPL_ASSERT(o->type == ZPL_ADT_TYPE_OBJECT || o->type == ZPL_ADT_TYPE_ARRAY); + + zpl___ind(indent - 4); + if (!o->cfg_mode) + zpl_fprintf(f, "%c\n", o->type == ZPL_ADT_TYPE_OBJECT ? '{' : '['); + else { + indent -= 4; + } + + if (o->nodes) { + zpl_isize cnt = zpl_array_count(o->nodes); + + for (int i = 0; i < cnt; ++i) { + zpl__json_write_value(f, o->nodes + i, o, indent, false, !(i < cnt - 1)); + } + } + + zpl___ind(indent); + + if (indent > 0) { + zpl_fprintf(f, "%c", o->type == ZPL_ADT_TYPE_OBJECT ? '}' : ']'); + } else { + if (!o->cfg_mode) zpl_fprintf(f, "%c\n", o->type == ZPL_ADT_TYPE_OBJECT ? '}' : ']'); + } +} + +void zpl__json_write_value(zpl_file *f, zpl_adt_node *o, zpl_adt_node *t, zpl_isize indent, zpl_b32 is_inline, zpl_b32 is_last) { + zpl_adt_node *node = o; + indent += 4; + + if (!is_inline) { + zpl___ind(indent); + + if (t->type != ZPL_ADT_TYPE_ARRAY) { + switch (node->name_style) { + case ZPL_ADT_NAME_STYLE_DOUBLE_QUOTE: { + zpl_fprintf(f, "\"%s\"", node->name); + } break; + + case ZPL_ADT_NAME_STYLE_SINGLE_QUOTE: { + zpl_fprintf(f, "\'%s\'", node->name); + } break; + + case ZPL_ADT_NAME_STYLE_NO_QUOTES: { + zpl_fprintf(f, "%s", node->name); + } break; + } + + if (o->assign_style == ZPL_ADT_ASSIGN_STYLE_COLON) + zpl_fprintf(f, ": "); + else { + zpl___ind(zpl_max(o->assign_line_width, 1)); + + if (o->assign_style == ZPL_ADT_ASSIGN_STYLE_EQUALS) + zpl_fprintf(f, "= "); + else if (o->assign_style == ZPL_ADT_ASSIGN_STYLE_LINE) { + zpl_fprintf(f, "| "); + } + } + } + } + + switch (node->type) { + case ZPL_ADT_TYPE_STRING: { + zpl_fprintf(f, "\""); + zpl_adt_print_string(f, node, "\"", '\\'); + zpl_fprintf(f, "\""); + } break; + + case ZPL_ADT_TYPE_MULTISTRING: { + zpl_fprintf(f, "`"); + zpl_adt_print_string(f, node, "`", '\\'); + zpl_fprintf(f, "`"); + } break; + + case ZPL_ADT_TYPE_ARRAY: { + zpl_fprintf(f, "["); + zpl_isize elemn = zpl_array_count(node->nodes); + for (int j = 0; j < elemn; ++j) { + zpl_isize ind = ((node->nodes + j)->type == ZPL_ADT_TYPE_OBJECT || (node->nodes + j)->type == ZPL_ADT_TYPE_ARRAY) ? 0 : -4; + zpl__json_write_value(f, node->nodes + j, o, ind, true, true); + + if (j < elemn - 1) { zpl_fprintf(f, ", "); } + } + zpl_fprintf(f, "]"); + } break; + + case ZPL_ADT_TYPE_REAL: + case ZPL_ADT_TYPE_INTEGER: { + zpl_adt_print_number(f, node); + } break; + + case ZPL_ADT_TYPE_OBJECT: { + zpl_json_write(f, node, indent); + } break; + } + + if (!is_inline) { + if (o->delim_style != ZPL_ADT_DELIM_STYLE_COMMA) { + if (o->delim_style == ZPL_ADT_DELIM_STYLE_NEWLINE) + zpl_fprintf(f, "\n"); + else if (o->delim_style == ZPL_ADT_DELIM_STYLE_LINE) { + zpl___ind(o->delim_line_width); + zpl_fprintf(f, "|\n"); + } + } + else { + if (!is_last) { + zpl_fprintf(f, ",\n"); + } else { + zpl_fprintf(f, "\n"); + } + } + } +} + +#undef zpl___ind + +ZPL_END_C_DECLS +// file: source/parsers/csv.c + + +#ifdef ZPL_CSV_DEBUG +#define ZPL_CSV_ASSERT(msg) ZPL_PANIC(msg) +#else +#define ZPL_CSV_ASSERT(msg) +#endif + + +ZPL_BEGIN_C_DECLS + +zpl_u8 zpl_csv_parse_delimiter(zpl_csv_object *root, char *text, zpl_allocator allocator, zpl_b32 has_header, char delim) { + zpl_csv_error err = ZPL_CSV_ERROR_NONE; + ZPL_ASSERT_NOT_NULL(root); + ZPL_ASSERT_NOT_NULL(text); + zpl_zero_item(root); + zpl_adt_make_branch(root, allocator, NULL, has_header ? ZPL_ADT_TYPE_OBJECT : ZPL_ADT_TYPE_ARRAY); + char *p = text, *b = p, *e = p; + zpl_isize colc = 0, total_colc = 0; + + do { + char d = 0; + p = cast(char *)zpl_str_trim(p, false); + if (*p == 0) break; + zpl_adt_node row_item = {0}; + row_item.type = ZPL_ADT_TYPE_STRING; + row_item.name_style = ZPL_ADT_NAME_STYLE_NO_QUOTES; + + /* handle string literals */ + if (*p == '"') { + p = b = e = p+1; + row_item.string = b; + row_item.name_style = ZPL_ADT_NAME_STYLE_DOUBLE_QUOTE; + do { + e = cast(char *)zpl_str_skip(e, '"'); + if (*e && *(e+1) == '"') { + e += 2; + } + else break; + } while (*e); + if (*e == 0) { + ZPL_CSV_ASSERT("unmatched quoted string"); + err = ZPL_CSV_ERROR_UNEXPECTED_END_OF_INPUT; + return err; + } + *e = 0; + p = cast(char *)zpl_str_trim(e+1, true); + d = *p; + + /* unescape escaped quotes (so that unescaped text escapes :) */ + { + char *ep = b; + do { + if (*ep == '"' && *(ep+1) == '"') { + zpl_memmove(ep, ep+1, zpl_strlen(ep)); + } + ep++; + } while (*ep); + } + } + else if (*p == delim) { + d = *p; + row_item.string = ""; + } + else if (*p) { + /* regular data */ + b = e = p; + row_item.string = b; + do { + e++; + } while (*e && *e != delim && *e != '\n'); + if (*e) { + p = cast(char *)zpl_str_trim(e, true); + while (zpl_char_is_space(*(e-1))) { e--; } + d = *p; + *e = 0; + } + else { + d = 0; + p = e; + } + + /* check if number and process if so */ + zpl_b32 skip_number = false; + char *num_p = b; + do { + if (!zpl_char_is_hex_digit(*num_p) && (!zpl_strchr("+-.eExX", *num_p))) { + skip_number = true; + break; + } + } while (*num_p++); + + if (!skip_number) { + zpl_adt_str_to_number(&row_item); + } + } + + if (colc >= zpl_array_count(root->nodes)) { + zpl_adt_inset_arr(root, NULL); + } + + zpl_array_append(root->nodes[colc].nodes, row_item); + + if (d == delim) { + colc++; + p++; + } + else if (d == '\n' || d == 0) { + /* check if number of rows is not mismatched */ + if (total_colc < colc) total_colc = colc; + else if (total_colc != colc) { + ZPL_CSV_ASSERT("mismatched rows"); + err = ZPL_CSV_ERROR_MISMATCHED_ROWS; + return err; + } + colc = 0; + if (d != 0) p++; + } + } while(*p); + + if (zpl_array_count(root->nodes) == 0) { + ZPL_CSV_ASSERT("unexpected end of input. stream is empty."); + err = ZPL_CSV_ERROR_UNEXPECTED_END_OF_INPUT; + return err; + } + + /* consider first row as a header. */ + if (has_header) { + for (zpl_isize i = 0; i < zpl_array_count(root->nodes); i++) { + zpl_csv_object *col = root->nodes + i; + zpl_csv_object *hdr = col->nodes; + col->name = hdr->string; + zpl_array_remove_at(col->nodes, 0); + } + } + + return err; +} +void zpl_csv_free(zpl_csv_object *obj) { + zpl_adt_destroy_branch(obj); +} + +void zpl__csv_write_record(zpl_file *file, zpl_csv_object *node) { + switch (node->type) { + case ZPL_ADT_TYPE_STRING: { + switch (node->name_style) { + case ZPL_ADT_NAME_STYLE_DOUBLE_QUOTE: { + zpl_fprintf(file, "\""); + zpl_adt_print_string(file, node, "\"", '"'); + zpl_fprintf(file, "\""); + } break; + + case ZPL_ADT_NAME_STYLE_NO_QUOTES: { + zpl_fprintf(file, "%s", node->string); + } break; + } + } break; + + case ZPL_ADT_TYPE_REAL: + case ZPL_ADT_TYPE_INTEGER: { + zpl_adt_print_number(file, node); + } break; + } +} + +void zpl__csv_write_header(zpl_file *file, zpl_csv_object *header) { + zpl_csv_object temp = *header; + temp.string = temp.name; + temp.type = ZPL_ADT_TYPE_STRING; + zpl__csv_write_record(file, &temp); +} + +void zpl_csv_write_delimiter(zpl_file *file, zpl_csv_object *obj, char delimiter) { + ZPL_ASSERT_NOT_NULL(file); + ZPL_ASSERT_NOT_NULL(obj); + ZPL_ASSERT(obj->nodes); + zpl_isize cols = zpl_array_count(obj->nodes); + if (cols == 0) return; + + zpl_isize rows = zpl_array_count(obj->nodes[0].nodes); + if (rows == 0) return; + + zpl_b32 has_headers = obj->nodes[0].name != NULL; + + if (has_headers) { + for (zpl_isize i = 0; i < cols; i++) { + zpl__csv_write_header(file, &obj->nodes[i]); + if (i+1 != cols) { + zpl_fprintf(file, ","); + } + } + zpl_fprintf(file, "\n"); + } + + for (zpl_isize r = 0; r < rows; r++) { + for (zpl_isize i = 0; i < cols; i++) { + zpl__csv_write_record(file, &obj->nodes[i].nodes[r]); + if (i+1 != cols) { + zpl_fprintf(file, ","); + } + } + zpl_fprintf(file, "\n"); + } +} + +zpl_string zpl_csv_write_string_delimiter(zpl_allocator a, zpl_csv_object *obj, char delimiter) { + zpl_file tmp; + zpl_file_stream_new(&tmp, a); + zpl_csv_write_delimiter(&tmp, obj, delimiter); + zpl_isize fsize; + zpl_u8* buf = zpl_file_stream_buf(&tmp, &fsize); + zpl_string output = zpl_string_make_length(a, (char *)buf, fsize+1); + zpl_file_close(&tmp); + return output; +} + +ZPL_END_C_DECLS #endif #if defined(ZPL_COMPILER_MSVC) @@ -18062,24 +18060,24 @@ License: #endif #if defined(ZPL_EXPOSE_TYPES) - typedef zpl_u8 u8; - typedef zpl_i8 i8; - typedef zpl_u16 u16; - typedef zpl_i16 i16; - typedef zpl_u32 u32; - typedef zpl_i32 i32; - typedef zpl_u64 u64; - typedef zpl_i64 i64; - typedef zpl_b8 b8; - typedef zpl_b16 b16; - typedef zpl_b32 b32; - typedef zpl_f32 f32; - typedef zpl_f64 f64; - typedef zpl_rune rune; - typedef zpl_usize usize; - typedef zpl_isize isize; - typedef zpl_uintptr uintptr; - typedef zpl_intptr intptr; +typedef zpl_u8 u8; +typedef zpl_i8 i8; +typedef zpl_u16 u16; +typedef zpl_i16 i16; +typedef zpl_u32 u32; +typedef zpl_i32 i32; +typedef zpl_u64 u64; +typedef zpl_i64 i64; +typedef zpl_b8 b8; +typedef zpl_b16 b16; +typedef zpl_b32 b32; +typedef zpl_f32 f32; +typedef zpl_f64 f64; +typedef zpl_rune rune; +typedef zpl_usize usize; +typedef zpl_isize isize; +typedef zpl_uintptr uintptr; +typedef zpl_intptr intptr; #endif // ZPL_EXPOSE_TYPES #endif // ZPL_H @@ -18164,3 +18162,4 @@ License: // source/opts.c // source/timer.c // source/math.c +