common.cpp 21 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037
  1. #if defined(GB_SYSTEM_UNIX)
  2. // Required for intrinsics on GCC
  3. #include <xmmintrin.h>
  4. #endif
  5. #if defined(GB_COMPILER_MSVC)
  6. #include <intrin.h>
  7. #endif
  8. #if defined(GB_SYSTEM_WINDOWS)
  9. #define NOMINMAX 1
  10. #include <windows.h>
  11. #undef NOMINMAX
  12. #endif
  13. #define GB_WINDOWS_H_INCLUDED
  14. #define GB_IMPLEMENTATION
  15. #include "gb/gb.h"
  16. #include <wchar.h>
  17. #include <stdio.h>
  18. #if defined(GB_COMPILER_MSVC)
  19. #include <psapi.h>
  20. #endif
  21. #include <math.h>
  22. #include <string.h>
  23. gb_inline void zero_size(void *ptr, isize len) {
  24. memset(ptr, 0, len);
  25. }
  26. #define zero_item(ptr) zero_size((ptr), gb_size_of(ptr))
  27. template <typename U, typename V>
  28. gb_inline U bit_cast(V &v) { return reinterpret_cast<U &>(v); }
  29. template <typename U, typename V>
  30. gb_inline U const &bit_cast(V const &v) { return reinterpret_cast<U const &>(v); }
  31. gb_inline i64 align_formula(i64 size, i64 align) {
  32. if (align > 0) {
  33. i64 result = size + align-1;
  34. return result - result%align;
  35. }
  36. return size;
  37. }
  38. gb_inline isize align_formula_isize(isize size, isize align) {
  39. if (align > 0) {
  40. isize result = size + align-1;
  41. return result - result%align;
  42. }
  43. return size;
  44. }
  45. GB_ALLOCATOR_PROC(heap_allocator_proc);
  46. gbAllocator heap_allocator(void) {
  47. gbAllocator a;
  48. a.proc = heap_allocator_proc;
  49. a.data = nullptr;
  50. return a;
  51. }
  52. GB_ALLOCATOR_PROC(heap_allocator_proc) {
  53. void *ptr = nullptr;
  54. gb_unused(allocator_data);
  55. gb_unused(old_size);
  56. // TODO(bill): Throughly test!
  57. switch (type) {
  58. #if defined(GB_COMPILER_MSVC)
  59. #if 0
  60. case gbAllocation_Alloc:
  61. ptr = _aligned_malloc(size, alignment);
  62. if (flags & gbAllocatorFlag_ClearToZero) {
  63. zero_size(ptr, size);
  64. }
  65. break;
  66. case gbAllocation_Free:
  67. _aligned_free(old_memory);
  68. break;
  69. case gbAllocation_Resize:
  70. ptr = _aligned_realloc(old_memory, size, alignment);
  71. break;
  72. #else
  73. case gbAllocation_Alloc: {
  74. isize aligned_size = align_formula_isize(size, alignment);
  75. // TODO(bill): Make sure this is aligned correctly
  76. ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, aligned_size);
  77. } break;
  78. case gbAllocation_Free:
  79. HeapFree(GetProcessHeap(), 0, old_memory);
  80. break;
  81. case gbAllocation_Resize: {
  82. isize aligned_size = align_formula_isize(size, alignment);
  83. ptr = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, old_memory, aligned_size);
  84. } break;
  85. #endif
  86. #elif defined(GB_SYSTEM_LINUX)
  87. // TODO(bill): *nix version that's decent
  88. case gbAllocation_Alloc: {
  89. ptr = aligned_alloc(alignment, size);
  90. // ptr = malloc(size+alignment);
  91. if (flags & gbAllocatorFlag_ClearToZero) {
  92. zero_size(ptr, size);
  93. }
  94. break;
  95. }
  96. case gbAllocation_Free: {
  97. free(old_memory);
  98. break;
  99. }
  100. case gbAllocation_Resize: {
  101. // ptr = realloc(old_memory, size);
  102. ptr = gb_default_resize_align(heap_allocator(), old_memory, old_size, size, alignment);
  103. break;
  104. }
  105. #else
  106. // TODO(bill): *nix version that's decent
  107. case gbAllocation_Alloc: {
  108. posix_memalign(&ptr, alignment, size);
  109. if (flags & gbAllocatorFlag_ClearToZero) {
  110. zero_size(ptr, size);
  111. }
  112. break;
  113. }
  114. case gbAllocation_Free: {
  115. free(old_memory);
  116. break;
  117. }
  118. case gbAllocation_Resize: {
  119. ptr = gb_default_resize_align(heap_allocator(), old_memory, old_size, size, alignment);
  120. break;
  121. }
  122. #endif
  123. case gbAllocation_FreeAll:
  124. break;
  125. }
  126. return ptr;
  127. }
  128. #include "unicode.cpp"
  129. #include "array.cpp"
  130. #include "string.cpp"
  131. #include "murmurhash3.cpp"
  132. #define for_array(index_, array_) for (isize index_ = 0; index_ < (array_).count; index_++)
  133. #include "range_cache.cpp"
  134. u32 fnv32a(void const *data, isize len) {
  135. u8 const *bytes = cast(u8 const *)data;
  136. u32 h = 0x811c9dc5;
  137. for (isize i = 0; i < len; i++) {
  138. u32 b = cast(u32)bytes[i];
  139. h = (h ^ b) * 0x01000193;
  140. }
  141. return h;
  142. }
  143. u64 fnv64a(void const *data, isize len) {
  144. u8 const *bytes = cast(u8 const *)data;
  145. u64 h = 0xcbf29ce484222325ull;
  146. for (isize i = 0; i < len; i++) {
  147. u64 b = cast(u64)bytes[i];
  148. h = (h ^ b) * 0x100000001b3ull;
  149. }
  150. return h;
  151. }
  152. u64 u64_digit_value(Rune r) {
  153. if ('0' <= r && r <= '9') {
  154. return r - '0';
  155. } else if ('a' <= r && r <= 'f') {
  156. return r - 'a' + 10;
  157. } else if ('A' <= r && r <= 'F') {
  158. return r - 'A' + 10;
  159. }
  160. return 16; // NOTE(bill): Larger than highest possible
  161. }
  162. u64 u64_from_string(String string) {
  163. u64 base = 10;
  164. bool has_prefix = false;
  165. if (string.len > 2 && string[0] == '0') {
  166. switch (string[1]) {
  167. case 'b': base = 2; has_prefix = true; break;
  168. case 'o': base = 8; has_prefix = true; break;
  169. case 'd': base = 10; has_prefix = true; break;
  170. case 'z': base = 12; has_prefix = true; break;
  171. case 'x': base = 16; has_prefix = true; break;
  172. case 'h': base = 16; has_prefix = true; break;
  173. }
  174. }
  175. u8 *text = string.text;
  176. isize len = string.len;
  177. if (has_prefix) {
  178. text += 2;
  179. len -= 2;
  180. }
  181. u64 result = 0ull;
  182. for (isize i = 0; i < len; i++) {
  183. Rune r = cast(Rune)text[i];
  184. if (r == '_') {
  185. continue;
  186. }
  187. u64 v = u64_digit_value(r);
  188. if (v >= base) {
  189. break;
  190. }
  191. result *= base;
  192. result += v;
  193. }
  194. return result;
  195. }
  196. gb_global char const global_num_to_char_table[] =
  197. "0123456789"
  198. "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  199. "abcdefghijklmnopqrstuvwxyz"
  200. "@$";
  201. String u64_to_string(u64 v, char *out_buf, isize out_buf_len) {
  202. char buf[32] = {0};
  203. isize i = gb_size_of(buf);
  204. u64 b = 10;
  205. while (v >= b) {
  206. buf[--i] = global_num_to_char_table[v%b];
  207. v /= b;
  208. }
  209. buf[--i] = global_num_to_char_table[v%b];
  210. isize len = gb_min(gb_size_of(buf)-i, out_buf_len);
  211. gb_memmove(out_buf, &buf[i], len);
  212. return make_string(cast(u8 *)out_buf, len);
  213. }
  214. String i64_to_string(i64 a, char *out_buf, isize out_buf_len) {
  215. char buf[32] = {0};
  216. isize i = gb_size_of(buf);
  217. bool negative = false;
  218. if (a < 0) {
  219. negative = true;
  220. a = -a;
  221. }
  222. u64 v = cast(u64)a;
  223. u64 b = 10;
  224. while (v >= b) {
  225. buf[--i] = global_num_to_char_table[v%b];
  226. v /= b;
  227. }
  228. buf[--i] = global_num_to_char_table[v%b];
  229. if (negative) {
  230. buf[--i] = '-';
  231. }
  232. isize len = gb_min(gb_size_of(buf)-i, out_buf_len);
  233. gb_memmove(out_buf, &buf[i], len);
  234. return make_string(cast(u8 *)out_buf, len);
  235. }
  236. gb_global i64 const signed_integer_mins[] = {
  237. 0,
  238. -128ll,
  239. -32768ll,
  240. 0,
  241. -2147483648ll,
  242. 0,
  243. 0,
  244. 0,
  245. (-9223372036854775807ll - 1ll),
  246. };
  247. gb_global i64 const signed_integer_maxs[] = {
  248. 0,
  249. 127ll,
  250. 32767ll,
  251. 0,
  252. 2147483647ll,
  253. 0,
  254. 0,
  255. 0,
  256. 9223372036854775807ll,
  257. };
  258. gb_global u64 const unsigned_integer_maxs[] = {
  259. 0,
  260. 255ull,
  261. 65535ull,
  262. 0,
  263. 4294967295ull,
  264. 0,
  265. 0,
  266. 0,
  267. 18446744073709551615ull,
  268. };
  269. bool add_overflow_u64(u64 x, u64 y, u64 *result) {
  270. *result = x + y;
  271. return *result < x || *result < y;
  272. }
  273. bool sub_overflow_u64(u64 x, u64 y, u64 *result) {
  274. *result = x - y;
  275. return *result > x;
  276. }
  277. void mul_overflow_u64(u64 x, u64 y, u64 *lo, u64 *hi) {
  278. #if defined(GB_COMPILER_MSVC)
  279. *lo = _umul128(x, y, hi);
  280. #else
  281. // URL(bill): https://stackoverflow.com/questions/25095741/how-can-i-multiply-64-bit-operands-and-get-128-bit-result-portably#25096197
  282. u64 u1, v1, w1, t, w3, k;
  283. u1 = (x & 0xffffffff);
  284. v1 = (y & 0xffffffff);
  285. t = (u1 * v1);
  286. w3 = (t & 0xffffffff);
  287. k = (t >> 32);
  288. x >>= 32;
  289. t = (x * v1) + k;
  290. k = (t & 0xffffffff);
  291. w1 = (t >> 32);
  292. y >>= 32;
  293. t = (u1 * y) + k;
  294. k = (t >> 32);
  295. *hi = (x * y) + w1 + k;
  296. *lo = (t << 32) + w3;
  297. #endif
  298. }
  299. gb_global String global_module_path = {0};
  300. gb_global bool global_module_path_set = false;
  301. // Arena from Per Vognsen
  302. #define ALIGN_DOWN(n, a) ((n) & ~((a) - 1))
  303. #define ALIGN_UP(n, a) ALIGN_DOWN((n) + (a) - 1, (a))
  304. #define ALIGN_DOWN_PTR(p, a) (cast(void *)ALIGN_DOWN(cast(uintptr)(p), (a)))
  305. #define ALIGN_UP_PTR(p, a) (cast(void *)ALIGN_UP(cast(uintptr)(p), (a)))
  306. typedef struct Arena {
  307. u8 * ptr;
  308. u8 * end;
  309. u8 * prev;
  310. Array<u8 *> blocks;
  311. gbAllocator backing;
  312. isize block_size;
  313. gbMutex mutex;
  314. isize total_used;
  315. } Arena;
  316. #define ARENA_MIN_ALIGNMENT 16
  317. #define ARENA_DEFAULT_BLOCK_SIZE (8*1024*1024)
  318. void arena_init(Arena *arena, gbAllocator backing, isize block_size=ARENA_DEFAULT_BLOCK_SIZE) {
  319. arena->backing = backing;
  320. arena->block_size = block_size;
  321. array_init(&arena->blocks, backing, 0, 2);
  322. gb_mutex_init(&arena->mutex);
  323. }
  324. void arena_grow(Arena *arena, isize min_size) {
  325. // gb_mutex_lock(&arena->mutex);
  326. // defer (gb_mutex_unlock(&arena->mutex));
  327. isize size = gb_max(arena->block_size, min_size);
  328. size = ALIGN_UP(size, ARENA_MIN_ALIGNMENT);
  329. void *new_ptr = gb_alloc(arena->backing, size);
  330. arena->ptr = cast(u8 *)new_ptr;
  331. // zero_size(arena->ptr, size); // NOTE(bill): This should already be zeroed
  332. GB_ASSERT(arena->ptr == ALIGN_DOWN_PTR(arena->ptr, ARENA_MIN_ALIGNMENT));
  333. arena->end = arena->ptr + size;
  334. array_add(&arena->blocks, arena->ptr);
  335. }
  336. void *arena_alloc(Arena *arena, isize size, isize alignment) {
  337. // gb_mutex_lock(&arena->mutex);
  338. // defer (gb_mutex_unlock(&arena->mutex));
  339. arena->total_used += size;
  340. if (size > (arena->end - arena->ptr)) {
  341. arena_grow(arena, size);
  342. GB_ASSERT(size <= (arena->end - arena->ptr));
  343. }
  344. isize align = gb_max(alignment, ARENA_MIN_ALIGNMENT);
  345. void *ptr = arena->ptr;
  346. arena->prev = arena->ptr;
  347. arena->ptr = cast(u8 *)ALIGN_UP_PTR(arena->ptr + size, align);
  348. GB_ASSERT(arena->ptr <= arena->end);
  349. GB_ASSERT(ptr == ALIGN_DOWN_PTR(ptr, align));
  350. // zero_size(ptr, size);
  351. return ptr;
  352. }
  353. void arena_free_all(Arena *arena) {
  354. // gb_mutex_lock(&arena->mutex);
  355. // defer (gb_mutex_unlock(&arena->mutex));
  356. for_array(i, arena->blocks) {
  357. gb_free(arena->backing, arena->blocks[i]);
  358. }
  359. array_clear(&arena->blocks);
  360. arena->ptr = nullptr;
  361. arena->end = nullptr;
  362. }
  363. GB_ALLOCATOR_PROC(arena_allocator_proc);
  364. gbAllocator arena_allocator(Arena *arena) {
  365. gbAllocator a;
  366. a.proc = arena_allocator_proc;
  367. a.data = arena;
  368. return a;
  369. }
  370. GB_ALLOCATOR_PROC(arena_allocator_proc) {
  371. void *ptr = nullptr;
  372. Arena *arena = cast(Arena *)allocator_data;
  373. GB_ASSERT_NOT_NULL(arena);
  374. switch (type) {
  375. case gbAllocation_Alloc:
  376. ptr = arena_alloc(arena, size, alignment);
  377. break;
  378. case gbAllocation_Free:
  379. // GB_PANIC("gbAllocation_Free not supported");
  380. break;
  381. case gbAllocation_Resize:
  382. GB_PANIC("gbAllocation_Resize: not supported");
  383. break;
  384. case gbAllocation_FreeAll:
  385. arena_free_all(arena);
  386. break;
  387. }
  388. return ptr;
  389. }
  390. #include "string_map.cpp"
  391. #include "map.cpp"
  392. #include "ptr_set.cpp"
  393. #include "string_set.cpp"
  394. #include "priority_queue.cpp"
  395. #include "thread_pool.cpp"
  396. struct StringIntern {
  397. StringIntern *next;
  398. isize len;
  399. char str[1];
  400. };
  401. Map<StringIntern *> string_intern_map = {}; // Key: u64
  402. Arena string_intern_arena = {};
  403. char const *string_intern(char const *text, isize len) {
  404. u64 hash = gb_fnv64a(text, len);
  405. u64 key = hash ? hash : 1;
  406. StringIntern **found = map_get(&string_intern_map, hash_integer(key));
  407. if (found) {
  408. for (StringIntern *it = *found; it != nullptr; it = it->next) {
  409. if (it->len == len && gb_strncmp(it->str, (char *)text, len) == 0) {
  410. return it->str;
  411. }
  412. }
  413. }
  414. StringIntern *new_intern = cast(StringIntern *)arena_alloc(&string_intern_arena, gb_offset_of(StringIntern, str) + len + 1, gb_align_of(StringIntern));
  415. new_intern->len = len;
  416. new_intern->next = found ? *found : nullptr;
  417. gb_memmove(new_intern->str, text, len);
  418. new_intern->str[len] = 0;
  419. map_set(&string_intern_map, hash_integer(key), new_intern);
  420. return new_intern->str;
  421. }
  422. char const *string_intern(String const &string) {
  423. return string_intern(cast(char const *)string.text, string.len);
  424. }
  425. void init_string_interner(void) {
  426. map_init(&string_intern_map, heap_allocator());
  427. arena_init(&string_intern_arena, heap_allocator());
  428. }
  429. i32 next_pow2(i32 n) {
  430. if (n <= 0) {
  431. return 0;
  432. }
  433. n--;
  434. n |= n >> 1;
  435. n |= n >> 2;
  436. n |= n >> 4;
  437. n |= n >> 8;
  438. n |= n >> 16;
  439. n++;
  440. return n;
  441. }
  442. i64 next_pow2(i64 n) {
  443. if (n <= 0) {
  444. return 0;
  445. }
  446. n--;
  447. n |= n >> 1;
  448. n |= n >> 2;
  449. n |= n >> 4;
  450. n |= n >> 8;
  451. n |= n >> 16;
  452. n |= n >> 32;
  453. n++;
  454. return n;
  455. }
  456. i32 bit_set_count(u32 x) {
  457. x -= ((x >> 1) & 0x55555555);
  458. x = (((x >> 2) & 0x33333333) + (x & 0x33333333));
  459. x = (((x >> 4) + x) & 0x0f0f0f0f);
  460. x += (x >> 8);
  461. x += (x >> 16);
  462. return cast(i32)(x & 0x0000003f);
  463. }
  464. i64 bit_set_count(u64 x) {
  465. u32 a = *(cast(u32 *)&x);
  466. u32 b = *(cast(u32 *)&x + 1);
  467. return bit_set_count(a) + bit_set_count(b);
  468. }
  469. u32 floor_log2(u32 x) {
  470. x |= x >> 1;
  471. x |= x >> 2;
  472. x |= x >> 4;
  473. x |= x >> 8;
  474. x |= x >> 16;
  475. return cast(u32)(bit_set_count(x) - 1);
  476. }
  477. u64 floor_log2(u64 x) {
  478. x |= x >> 1;
  479. x |= x >> 2;
  480. x |= x >> 4;
  481. x |= x >> 8;
  482. x |= x >> 16;
  483. x |= x >> 32;
  484. return cast(u64)(bit_set_count(x) - 1);
  485. }
  486. u32 ceil_log2(u32 x) {
  487. i32 y = cast(i32)(x & (x-1));
  488. y |= -y;
  489. y >>= 32-1;
  490. x |= x >> 1;
  491. x |= x >> 2;
  492. x |= x >> 4;
  493. x |= x >> 8;
  494. x |= x >> 16;
  495. return cast(u32)(bit_set_count(x) - 1 - y);
  496. }
  497. u64 ceil_log2(u64 x) {
  498. i64 y = cast(i64)(x & (x-1));
  499. y |= -y;
  500. y >>= 64-1;
  501. x |= x >> 1;
  502. x |= x >> 2;
  503. x |= x >> 4;
  504. x |= x >> 8;
  505. x |= x >> 16;
  506. x |= x >> 32;
  507. return cast(u64)(bit_set_count(x) - 1 - y);
  508. }
  509. i32 prev_pow2(i32 n) {
  510. if (n <= 0) {
  511. return 0;
  512. }
  513. n |= n >> 1;
  514. n |= n >> 2;
  515. n |= n >> 4;
  516. n |= n >> 8;
  517. n |= n >> 16;
  518. return n - (n >> 1);
  519. }
  520. i64 prev_pow2(i64 n) {
  521. if (n <= 0) {
  522. return 0;
  523. }
  524. n |= n >> 1;
  525. n |= n >> 2;
  526. n |= n >> 4;
  527. n |= n >> 8;
  528. n |= n >> 16;
  529. n |= n >> 32;
  530. return n - (n >> 1);
  531. }
  532. i16 f32_to_f16(f32 value) {
  533. union { u32 i; f32 f; } v;
  534. i32 i, s, e, m;
  535. v.f = value;
  536. i = (i32)v.i;
  537. s = (i >> 16) & 0x00008000;
  538. e = ((i >> 23) & 0x000000ff) - (127 - 15);
  539. m = i & 0x007fffff;
  540. if (e <= 0) {
  541. if (e < -10) return cast(i16)s;
  542. m = (m | 0x00800000) >> (1 - e);
  543. if (m & 0x00001000)
  544. m += 0x00002000;
  545. return cast(i16)(s | (m >> 13));
  546. } else if (e == 0xff - (127 - 15)) {
  547. if (m == 0) {
  548. return cast(i16)(s | 0x7c00); /* NOTE(bill): infinity */
  549. } else {
  550. /* NOTE(bill): NAN */
  551. m >>= 13;
  552. return cast(i16)(s | 0x7c00 | m | (m == 0));
  553. }
  554. } else {
  555. if (m & 0x00001000) {
  556. m += 0x00002000;
  557. if (m & 0x00800000) {
  558. m = 0;
  559. e += 1;
  560. }
  561. }
  562. if (e > 30) {
  563. float volatile f = 1e12f;
  564. int j;
  565. for (j = 0; j < 10; j++) {
  566. f *= f; /* NOTE(bill): Cause overflow */
  567. }
  568. return cast(i16)(s | 0x7c00);
  569. }
  570. return cast(i16)(s | (e << 10) | (m >> 13));
  571. }
  572. }
  573. f64 gb_sqrt(f64 x) {
  574. return sqrt(x);
  575. }
  576. // Doubly Linked Lists
  577. #define DLIST_SET(curr_element, next_element) do { \
  578. (curr_element)->next = (next_element); \
  579. (curr_element)->next->prev = (curr_element); \
  580. (curr_element) = (curr_element)->next; \
  581. } while (0)
  582. #define DLIST_APPEND(root_element, curr_element, next_element) do { \
  583. if ((root_element) == nullptr) { \
  584. (root_element) = (curr_element) = (next_element); \
  585. } else { \
  586. DLIST_SET(curr_element, next_element); \
  587. } \
  588. } while (0)
  589. #if defined(GB_SYSTEM_WINDOWS)
  590. wchar_t **command_line_to_wargv(wchar_t *cmd_line, int *_argc) {
  591. u32 i, j;
  592. u32 len = cast(u32)string16_len(cmd_line);
  593. i = ((len+2)/2)*gb_size_of(void *) + gb_size_of(void *);
  594. wchar_t **argv = cast(wchar_t **)GlobalAlloc(GMEM_FIXED, i + (len+2)*gb_size_of(wchar_t));
  595. wchar_t *_argv = cast(wchar_t *)((cast(u8 *)argv)+i);
  596. u32 argc = 0;
  597. argv[argc] = _argv;
  598. bool in_quote = false;
  599. bool in_text = false;
  600. bool in_space = true;
  601. i = 0;
  602. j = 0;
  603. for (;;) {
  604. wchar_t a = cmd_line[i];
  605. if (a == 0) {
  606. break;
  607. }
  608. if (in_quote) {
  609. if (a == '\"') {
  610. in_quote = false;
  611. } else {
  612. _argv[j++] = a;
  613. }
  614. } else {
  615. switch (a) {
  616. case '\"':
  617. in_quote = true;
  618. in_text = true;
  619. if (in_space) argv[argc++] = _argv+j;
  620. in_space = false;
  621. break;
  622. case ' ':
  623. case '\t':
  624. case '\n':
  625. case '\r':
  626. if (in_text) _argv[j++] = '\0';
  627. in_text = false;
  628. in_space = true;
  629. break;
  630. default:
  631. in_text = true;
  632. if (in_space) argv[argc++] = _argv+j;
  633. _argv[j++] = a;
  634. in_space = false;
  635. break;
  636. }
  637. }
  638. i++;
  639. }
  640. _argv[j] = '\0';
  641. argv[argc] = nullptr;
  642. if (_argc) *_argc = argc;
  643. return argv;
  644. }
  645. #endif
  646. #if defined(GB_SYSTEM_WINDOWS)
  647. bool path_is_directory(String path) {
  648. gbAllocator a = heap_allocator();
  649. String16 wstr = string_to_string16(a, path);
  650. defer (gb_free(a, wstr.text));
  651. i32 attribs = GetFileAttributesW(wstr.text);
  652. if (attribs < 0) return false;
  653. return (attribs & FILE_ATTRIBUTE_DIRECTORY) != 0;
  654. }
  655. #else
  656. bool path_is_directory(String path) {
  657. gbAllocator a = heap_allocator();
  658. char *copy = cast(char *)copy_string(a, path).text;
  659. defer (gb_free(a, copy));
  660. struct stat s;
  661. if (stat(copy, &s) == 0) {
  662. return (s.st_mode & S_IFDIR) != 0;
  663. }
  664. return false;
  665. }
  666. #endif
  667. String path_to_full_path(gbAllocator a, String path) {
  668. gbAllocator ha = heap_allocator();
  669. char *path_c = gb_alloc_str_len(ha, cast(char *)path.text, path.len);
  670. defer (gb_free(ha, path_c));
  671. char *fullpath = gb_path_get_full_name(a, path_c);
  672. String res = string_trim_whitespace(make_string_c(fullpath));
  673. #if defined(GB_SYSTEM_WINDOWS)
  674. for (isize i = 0; i < res.len; i++) {
  675. if (res.text[i] == '\\') {
  676. res.text[i] = '/';
  677. }
  678. }
  679. #endif
  680. return res;
  681. }
  682. struct FileInfo {
  683. String name;
  684. String fullpath;
  685. i64 size;
  686. bool is_dir;
  687. };
  688. enum ReadDirectoryError {
  689. ReadDirectory_None,
  690. ReadDirectory_InvalidPath,
  691. ReadDirectory_NotExists,
  692. ReadDirectory_Permission,
  693. ReadDirectory_NotDir,
  694. ReadDirectory_Empty,
  695. ReadDirectory_Unknown,
  696. ReadDirectory_COUNT,
  697. };
  698. i64 get_file_size(String path) {
  699. char *c_str = alloc_cstring(heap_allocator(), path);
  700. defer (gb_free(heap_allocator(), c_str));
  701. gbFile f = {};
  702. gbFileError err = gb_file_open(&f, c_str);
  703. defer (gb_file_close(&f));
  704. if (err != gbFileError_None) {
  705. return -1;
  706. }
  707. return gb_file_size(&f);
  708. }
  709. #if defined(GB_SYSTEM_WINDOWS)
  710. ReadDirectoryError read_directory(String path, Array<FileInfo> *fi) {
  711. GB_ASSERT(fi != nullptr);
  712. gbAllocator a = heap_allocator();
  713. while (path.len > 0) {
  714. Rune end = path[path.len-1];
  715. if (end == '/') {
  716. path.len -= 1;
  717. } else if (end == '\\') {
  718. path.len -= 1;
  719. } else {
  720. break;
  721. }
  722. }
  723. if (path.len == 0) {
  724. return ReadDirectory_InvalidPath;
  725. }
  726. {
  727. char *c_str = alloc_cstring(a, path);
  728. defer (gb_free(a, c_str));
  729. gbFile f = {};
  730. gbFileError file_err = gb_file_open(&f, c_str);
  731. defer (gb_file_close(&f));
  732. switch (file_err) {
  733. case gbFileError_Invalid: return ReadDirectory_InvalidPath;
  734. case gbFileError_NotExists: return ReadDirectory_NotExists;
  735. // case gbFileError_Permission: return ReadDirectory_Permission;
  736. }
  737. }
  738. if (!path_is_directory(path)) {
  739. return ReadDirectory_NotDir;
  740. }
  741. char *new_path = gb_alloc_array(a, char, path.len+3);
  742. defer (gb_free(a, new_path));
  743. gb_memmove(new_path, path.text, path.len);
  744. gb_memmove(new_path+path.len, "/*", 2);
  745. new_path[path.len+2] = 0;
  746. String np = make_string(cast(u8 *)new_path, path.len+2);
  747. String16 wstr = string_to_string16(a, np);
  748. defer (gb_free(a, wstr.text));
  749. WIN32_FIND_DATAW file_data = {};
  750. HANDLE find_file = FindFirstFileW(wstr.text, &file_data);
  751. if (find_file == INVALID_HANDLE_VALUE) {
  752. return ReadDirectory_Unknown;
  753. }
  754. defer (FindClose(find_file));
  755. array_init(fi, a, 0, 100);
  756. do {
  757. wchar_t *filename_w = file_data.cFileName;
  758. i64 size = cast(i64)file_data.nFileSizeLow;
  759. size |= (cast(i64)file_data.nFileSizeHigh) << 32;
  760. String name = string16_to_string(a, make_string16_c(filename_w));
  761. if (name == "." || name == "..") {
  762. gb_free(a, name.text);
  763. continue;
  764. }
  765. String filepath = {};
  766. filepath.len = path.len+1+name.len;
  767. filepath.text = gb_alloc_array(a, u8, filepath.len+1);
  768. defer (gb_free(a, filepath.text));
  769. gb_memmove(filepath.text, path.text, path.len);
  770. gb_memmove(filepath.text+path.len, "/", 1);
  771. gb_memmove(filepath.text+path.len+1, name.text, name.len);
  772. FileInfo info = {};
  773. info.name = name;
  774. info.fullpath = path_to_full_path(a, filepath);
  775. info.size = size;
  776. info.is_dir = (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
  777. array_add(fi, info);
  778. } while (FindNextFileW(find_file, &file_data));
  779. if (fi->count == 0) {
  780. return ReadDirectory_Empty;
  781. }
  782. return ReadDirectory_None;
  783. }
  784. #elif defined(GB_SYSTEM_LINUX) || defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_FREEBSD)
  785. #include <dirent.h>
  786. ReadDirectoryError read_directory(String path, Array<FileInfo> *fi) {
  787. GB_ASSERT(fi != nullptr);
  788. gbAllocator a = heap_allocator();
  789. char *c_path = alloc_cstring(a, path);
  790. defer (gb_free(a, c_path));
  791. DIR *dir = opendir(c_path);
  792. if (!dir) {
  793. switch (errno) {
  794. case ENOENT:
  795. return ReadDirectory_NotExists;
  796. case EACCES:
  797. return ReadDirectory_Permission;
  798. case ENOTDIR:
  799. return ReadDirectory_NotDir;
  800. default:
  801. // ENOMEM: out of memory
  802. // EMFILE: per-process limit on open fds reached
  803. // ENFILE: system-wide limit on total open files reached
  804. return ReadDirectory_Unknown;
  805. }
  806. GB_PANIC("unreachable");
  807. }
  808. array_init(fi, a, 0, 100);
  809. for (;;) {
  810. struct dirent *entry = readdir(dir);
  811. if (entry == nullptr) {
  812. break;
  813. }
  814. String name = make_string_c(entry->d_name);
  815. if (name == "." || name == "..") {
  816. continue;
  817. }
  818. String filepath = {};
  819. filepath.len = path.len+1+name.len;
  820. filepath.text = gb_alloc_array(a, u8, filepath.len+1);
  821. defer (gb_free(a, filepath.text));
  822. gb_memmove(filepath.text, path.text, path.len);
  823. gb_memmove(filepath.text+path.len, "/", 1);
  824. gb_memmove(filepath.text+path.len+1, name.text, name.len);
  825. filepath.text[filepath.len] = 0;
  826. struct stat dir_stat = {};
  827. if (stat((char *)filepath.text, &dir_stat)) {
  828. continue;
  829. }
  830. if (S_ISDIR(dir_stat.st_mode)) {
  831. continue;
  832. }
  833. i64 size = dir_stat.st_size;
  834. FileInfo info = {};
  835. info.name = name;
  836. info.fullpath = path_to_full_path(a, filepath);
  837. info.size = size;
  838. array_add(fi, info);
  839. }
  840. if (fi->count == 0) {
  841. return ReadDirectory_Empty;
  842. }
  843. return ReadDirectory_None;
  844. }
  845. #else
  846. #error Implement read_directory
  847. #endif