From 85dbaa37b922258ae16385d31d8047b2fa765f62 Mon Sep 17 00:00:00 2001 From: Ed_ Date: Thu, 13 Feb 2025 19:12:13 -0500 Subject: [PATCH] updating to latest VEFontCache... tested 10k draw call target (worked) --- code/font/vefontcache/draw.odin | 4 +- code/font/vefontcache/parser.odin | 18 +- code/font/vefontcache/vefontcache.odin | 47 +- code/grime/virtual_arena.odin | 5 +- code/sectr/engine/client_api.odin | 11 +- code/sectr/font/render_sokol.odin | 4 +- code/sectr/ui/tests.odin | 4 +- examples/gencpp_singleheader.hpp | 10002 ++++++++++++++++++ scripts/build.ps1 | 4 +- thirdparty/stb/lib/stb_truetype.lib | Bin 380638 -> 945032 bytes thirdparty/stb/src/Makefile | 39 +- thirdparty/stb/src/gb/gb.h | 10824 -------------------- thirdparty/stb/src/stb_image.c | 2 - thirdparty/stb/src/stb_image.h | 7897 -------------- thirdparty/stb/src/stb_truetype.h | 14 +- thirdparty/stb/truetype/stb_truetype.odin | 10 +- 16 files changed, 10064 insertions(+), 18821 deletions(-) create mode 100644 examples/gencpp_singleheader.hpp delete mode 100644 thirdparty/stb/src/gb/gb.h delete mode 100644 thirdparty/stb/src/stb_image.c delete mode 100644 thirdparty/stb/src/stb_image.h diff --git a/code/font/vefontcache/draw.odin b/code/font/vefontcache/draw.odin index 80bd3f5..18e9e88 100644 --- a/code/font/vefontcache/draw.odin +++ b/code/font/vefontcache/draw.odin @@ -703,13 +703,13 @@ batch_generate_glyphs_draw_list :: proc ( draw_list : ^Draw_List, dst_glyph_pos := glyph.region_pos dst_glyph_size := bounds_size_scaled + atlas.glyph_padding - dst_glyph_size.x = ceil(dst_glyph_size.x) + dst_glyph_size.x = dst_glyph_size.x dst_glyph_size.y = max(dst_glyph_size.y, ceil(dst_glyph_size.y) * glyph_buffer.snap_glyph_height) // Note(Ed): Seems to improve hinting to_glyph_buffer_space( & dst_glyph_pos, & dst_glyph_size, atlas_size ) src_position := Vec2 { glyph.buffer_x, 0 } src_size := (bounds_size_scaled + atlas.glyph_padding) * glyph_buffer.over_sample - src_size.x = ceil(src_size.x) + src_size.x = src_size.x src_size.y = max(src_size.y, ceil(src_size.y) * glyph_buffer.snap_glyph_height) // Note(Ed): Seems to improve hinting to_target_space( & src_position, & src_size, glyph_buffer_size ) diff --git a/code/font/vefontcache/parser.odin b/code/font/vefontcache/parser.odin index 9223baf..878f390 100644 --- a/code/font/vefontcache/parser.odin +++ b/code/font/vefontcache/parser.odin @@ -10,9 +10,9 @@ Freetype isn't really supported and its not a high priority. ~~That interface is not exposed from this parser but could be added to parser_init.~~ STB_Truetype: -* Has macros for its allocation unfortuantely. -TODO(Ed): Just keep a local version of stb_truetype and modify it to support a sokol/odin compatible allocator. -Already wanted to do so anyway to evaluate the shape generation implementation. +* Added ability to set the stb_truetype allocator for STBTT_MALLOC and STBTT_FREE. +* Changed procedure signatures to pass the font_info struct by immutable ptr (#by_ptr) + when the C equivalent has their parameter as `const*`. */ import "core:c" @@ -27,10 +27,8 @@ Parser_Kind :: enum u32 { Parser_Font_Info :: struct { label : string, kind : Parser_Kind, - using _ : struct #raw_union { - stbtt_info : stbtt.fontinfo, - // freetype_info : freetype.Face - }, + stbtt_info : stbtt.fontinfo, + // freetype_info : freetype.Face data : []byte, } @@ -61,7 +59,7 @@ Parser_Context :: struct { parser_stbtt_allocator_proc :: proc( allocator_data : rawptr, - type : stbtt.gbAllocationType, + type : stbtt.zpl_allocator_type, size : c.ssize_t, alignment : c.ssize_t, old_memory : rawptr, @@ -86,13 +84,13 @@ parser_init :: proc( ctx : ^Parser_Context, kind : Parser_Kind, allocator := con ctx.kind = kind ctx.lib_backing = allocator - stbtt_allocator := stbtt.gbAllocator { parser_stbtt_allocator_proc, & ctx.lib_backing } + stbtt_allocator := stbtt.zpl_allocator { parser_stbtt_allocator_proc, & ctx.lib_backing } stbtt.SetAllocator( stbtt_allocator ) } parser_reload :: proc( ctx : ^Parser_Context, allocator := context.allocator) { ctx.lib_backing = allocator - stbtt_allocator := stbtt.gbAllocator { parser_stbtt_allocator_proc, & ctx.lib_backing } + stbtt_allocator := stbtt.zpl_allocator { parser_stbtt_allocator_proc, & ctx.lib_backing } stbtt.SetAllocator( stbtt_allocator ) } diff --git a/code/font/vefontcache/vefontcache.odin b/code/font/vefontcache/vefontcache.odin index 2cfd37d..6f233bd 100644 --- a/code/font/vefontcache/vefontcache.odin +++ b/code/font/vefontcache/vefontcache.odin @@ -81,9 +81,6 @@ Context :: struct { // debug_print : b32, // debug_print_verbose : b32, - // Will enforce even px_size when drawing. - even_size_only : f32, - // Whether or not to snap positioning to the pixel of the view // Helps with hinting snap_to_view_extent : b32, @@ -176,8 +173,8 @@ startup :: proc( ctx : ^Context, parser_kind : Parser_Kind = .STB_TrueType, // N glyph_draw_params := Init_Glyph_Draw_Params_Default, shape_cache_params := Init_Shape_Cache_Params_Default, shaper_params := Init_Shaper_Params_Default, - alpha_sharpen : f32 = 0.35, - px_scalar : f32 = 1.6, + alpha_sharpen : f32 = 0.1, + px_scalar : f32 = 1.4, zoom_px_interval : i32 = 2, // Curve quality to use for a font when unspecified, @@ -823,7 +820,7 @@ draw_text_normalized_space :: proc( ctx : ^Context, zoom : Will affect the scale similar to how the zoom on a canvas would behave. */ // @(optimization_mode="favor_size") -draw_shape_view_space :: #force_inline proc( ctx : ^Context, +draw_shape_view_space :: proc( ctx : ^Context, colour : RGBAN, view : Vec2, position : Vec2, @@ -849,10 +846,9 @@ draw_shape_view_space :: #force_inline proc( ctx : ^Context, resolved_size, zoom_scale := resolve_zoom_size_scale( zoom, px_size, scale, ctx.zoom_px_interval, 2, 999.0, view ) target_position, norm_scale := get_normalized_position_scale( position, zoom_scale, view ) - // Does nothing if px_scalar is 1.0 - target_px_size := resolved_size * ctx.px_scalar - target_scale := norm_scale * px_scalar_quotient - target_font_scale := parser_scale( entry.parser_info, target_px_size ) + target_px_size, + target_font_scale, + target_scale := resolve_px_scalar_size(entry.parser_info, resolved_size, ctx.px_scalar, norm_scale) ctx.cursor_pos = generate_shape_draw_list( & ctx.draw_list, shape, & ctx.atlas, & ctx.glyph_buffer, ctx.px_scalar, @@ -918,10 +914,9 @@ draw_text_view_space :: proc(ctx : ^Context, resolved_size, zoom_scale := resolve_zoom_size_scale( zoom, px_size, scale, ctx.zoom_px_interval, 2, 999.0, view ) target_position, norm_scale := get_normalized_position_scale( position, zoom_scale, view ) - // Does nothing if px_scalar is 1.0 - target_px_size := resolved_size * ctx.px_scalar - target_scale := norm_scale * (1 / ctx.px_scalar) - target_font_scale := parser_scale( entry.parser_info, target_px_size ) + target_px_size, + target_font_scale, + target_scale := resolve_px_scalar_size(entry.parser_info, resolved_size, ctx.px_scalar, norm_scale) shape := shaper_shape_text_cached( text_utf8, & ctx.shaper_ctx, & ctx.shape_cache, ctx.atlas, vec2(ctx.glyph_buffer.size), font, @@ -1002,11 +997,9 @@ draw_shape :: proc( ctx : ^Context, position, scale : Vec2, shape : Shaped_Text absolute_scale := peek(stack.scale) * zoom_scale target_position, norm_scale := get_normalized_position_scale( absolute_position, absolute_scale, view ) - - // Does nothing when px_scalar is 1.0 - target_px_size := resolved_size * ctx.px_scalar - target_scale := norm_scale * px_scalar_quotient - target_font_scale := parser_scale( entry.parser_info, target_px_size ) + target_px_size, + target_font_scale, + target_scale := resolve_px_scalar_size(entry.parser_info,resolved_size, ctx.px_scalar, norm_scale) ctx.cursor_pos = generate_shape_draw_list( & ctx.draw_list, shape, & ctx.atlas, & ctx.glyph_buffer, ctx.px_scalar, @@ -1082,11 +1075,9 @@ draw_text :: proc( ctx : ^Context, position, scale : Vec2, text_utf8 : string, absolute_scale := peek(stack.scale) * scale target_position, norm_scale := get_normalized_position_scale( absolute_position, absolute_scale, view ) - - // Does nothing when px_scalar is 1.0 - target_px_size := resolved_size * ctx.px_scalar - target_scale := norm_scale * (1 / ctx.px_scalar) - target_font_scale := parser_scale( entry.parser_info, target_px_size ) + target_px_size, + target_font_scale, + target_scale := resolve_px_scalar_size(entry.parser_info, resolved_size, ctx.px_scalar, norm_scale) shape := shaper_shape_text_cached( text_utf8, & ctx.shaper_ctx, & ctx.shape_cache, ctx.atlas, vec2(ctx.glyph_buffer.size), font, @@ -1150,7 +1141,8 @@ measure_shape_size :: #force_inline proc( ctx : Context, shape : Shaped_Text ) - } // Don't use this if you already have the shape instead use measure_shape_size -measure_text_size :: #force_inline proc( ctx : ^Context, font : Font_ID, px_size : f32, text_utf8 : string, +@(optimization_mode="favor_size") +measure_text_size :: proc( ctx : ^Context, font : Font_ID, px_size : f32, text_utf8 : string, shaper_proc : $Shaper_Shape_Text_Uncached_Proc = shaper_shape_harfbuzz ) -> (measured : Vec2) { @@ -1241,9 +1233,12 @@ resolve_zoom_size_scale :: #force_inline proc "contextless" ( return } +// Get the target pixel, font_scale, and scale for the given font pixel size, and scalar multiple to apply. (Normalized space with norm_scale) +// To derived norm_scale use: get_normalized_position_scale or just do (scale * (1 / view)) resolve_px_scalar_size :: #force_inline proc "contextless" ( parser_info : Parser_Font_Info, px_size, px_scalar : f32, norm_scale : Vec2 ) -> (target_px_size, target_font_scale : f32, target_scale : Vec2 ) { + // Does nothing when px_scalar is 1.0 target_px_size = px_size * px_scalar target_scale = norm_scale * (1 / px_scalar) target_font_scale = parser_scale( parser_info, target_px_size ) @@ -1276,7 +1271,7 @@ set_snap_glyph_render_height :: #force_inline proc( ctx : ^Context, should_snap ctx.glyph_buffer.snap_glyph_height = cast(f32) i32(should_snap) } -//#endregion("misc") +//#endregion("miscellaneous") //#region("scope stack") diff --git a/code/grime/virtual_arena.odin b/code/grime/virtual_arena.odin index 3539642..edf0f34 100644 --- a/code/grime/virtual_arena.odin +++ b/code/grime/virtual_arena.odin @@ -1,10 +1,11 @@ /* -Odin's virtual arena allocator doesn't do what I ideally want for allocation resizing. -(It was also a nice exercise along with making the other allocators) +~~Odin's virtual arena allocator doesn't do what I ideally want for allocation resizing.~~ +It was also a nice exercise along with making the other allocators) So this is a virtual memory backed arena allocator designed to take advantage of one large contigous reserve of memory. With the expectation that resizes with its interface will only occur using the last allocated block. +Note(Ed): Odin's mem allocator now has that feature All virtual address space memory for this application is managed by a virtual arena. No other part of the program will directly touch the vitual memory interface direclty other than it. diff --git a/code/sectr/engine/client_api.odin b/code/sectr/engine/client_api.odin index e01b38c..7b867db 100644 --- a/code/sectr/engine/client_api.odin +++ b/code/sectr/engine/client_api.odin @@ -90,6 +90,7 @@ startup :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem push( policy_ptr, SlabSizeClass { 64 * Megabyte, 64 * Megabyte, alignment }) push( policy_ptr, SlabSizeClass { 128 * Megabyte, 128 * Megabyte, alignment }) push( policy_ptr, SlabSizeClass { 256 * Megabyte, 256 * Megabyte, alignment }) + push( policy_ptr, SlabSizeClass { 512 * Megabyte, 512 * Megabyte, alignment }) // Anything above 128 meg needs to have its own setup looked into. alloc_error : AllocatorError @@ -355,19 +356,21 @@ startup :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem // } // Setup workspace UI state - ui_startup( & workspace.ui, cache_table_size = 8 * Kilo, cache_allocator = persistent_slab_allocator() ) + ui_startup( & workspace.ui, cache_table_size = 64 * Kilo, cache_allocator = persistent_slab_allocator() ) } // debug.path_lorem = str_fmt("C:/projects/SectrPrototype/examples/Lorem Ipsum (197).txt", allocator = persistent_slab_allocator()) // debug.path_lorem = str_fmt("C:/projects/SectrPrototype/examples/Lorem Ipsum (1022).txt", allocator = persistent_slab_allocator()) // debug.path_lorem = str_fmt("C:/projects/SectrPrototype/examples/ve_fontcache.h", allocator = persistent_slab_allocator()) - debug.path_lorem = str_fmt("C:/projects/SectrPrototype/examples/sokol_gp.h", allocator = persistent_slab_allocator()) + // debug.path_lorem = str_fmt("C:/projects/SectrPrototype/examples/sokol_gp.h", allocator = persistent_slab_allocator()) // debug.path_lorem = str_fmt("C:/projects/SectrPrototype/examples/sokol_gl.h", allocator = persistent_slab_allocator()) + debug.path_lorem = str_fmt("C:\\projects\\SectrPrototype\\examples\\gencpp_singleheader.hpp", allocator = persistent_slab_allocator()) alloc_error : AllocatorError; success : bool - debug.lorem_content, success = os.read_entire_file( debug.path_lorem, persistent_slab_allocator() ) + debug.lorem_content, success = os.read_entire_file( debug.path_lorem, persistent_allocator() ) + assert(success) - debug.lorem_parse, alloc_error = pws_parser_parse( transmute(string) debug.lorem_content, persistent_slab_allocator() ) + debug.lorem_parse, alloc_error = pws_parser_parse( transmute(string) debug.lorem_content, persistent_allocator() ) verify( alloc_error == .None, "Faield to parse due to allocation failure" ) // Render texture test diff --git a/code/sectr/font/render_sokol.odin b/code/sectr/font/render_sokol.odin index 8be637a..88fd8eb 100644 --- a/code/sectr/font/render_sokol.odin +++ b/code/sectr/font/render_sokol.odin @@ -67,14 +67,14 @@ font_provider_setup_sokol_gfx_objects :: proc( ctx : ^VE_RenderData, ve_ctx : ve screen_shader = sokol_gfx.make_shader(ve_draw_text_shader_desc(backend) ) draw_list_vbuf = sokol_gfx.make_buffer( BufferDesciption { - size = size_of([4]f32) * 2 * Mega, + size = size_of([4]f32) * 4 * Mega, usage = BufferUsage.STREAM, type = BufferType.VERTEXBUFFER, }) verify( sokol_gfx.query_buffer_state( draw_list_vbuf) < ResourceState.FAILED, "Failed to make draw_list_vbuf" ) draw_list_ibuf = sokol_gfx.make_buffer( BufferDesciption { - size = size_of(u32) * 3 * Mega, + size = size_of(u32) * 6 * Mega, usage = BufferUsage.STREAM, type = BufferType.INDEXBUFFER, }) diff --git a/code/sectr/ui/tests.odin b/code/sectr/ui/tests.odin index 09f5bfd..7d0903c 100644 --- a/code/sectr/ui/tests.odin +++ b/code/sectr/ui/tests.odin @@ -190,13 +190,13 @@ test_whitespace_ast :: proc( default_layout : ^UI_Layout, frame_style_default : // index := 0 widgets : Array(UI_Widget) // widgets, alloc_error = array_init_reserve( UI_Widget, frame_slab_allocator(), 8 ) - widgets, alloc_error = make( Array(UI_Widget), 8 * Kilobyte ) + widgets, alloc_error = make( Array(UI_Widget), 64 * Kilobyte ) widgets_ptr := & widgets label_id := 0 builder : StringBuilder - str.builder_init_len_cap( & builder, len = 0, cap = 16 * Kilobyte ) + str.builder_init_len_cap( & builder, len = 0, cap = 64 * Kilobyte ) line_id := 0 for line in array_to_slice( debug.lorem_parse.lines ) diff --git a/examples/gencpp_singleheader.hpp b/examples/gencpp_singleheader.hpp new file mode 100644 index 0000000..a8ce3c4 --- /dev/null +++ b/examples/gencpp_singleheader.hpp @@ -0,0 +1,10002 @@ +// This file was generated automatially by gencpp's singleheader.cpp(See: https://github.com/Ed94/gencpp) + +#pragma once + +#ifdef __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wunused-const-variable" +# pragma clang diagnostic ignored "-Wunused-but-set-variable" +# pragma clang diagnostic ignored "-Wswitch" +# pragma clang diagnostic ignored "-Wunused-variable" +# pragma clang diagnostic ignored "-Wunknown-pragmas" +# pragma clang diagnostic ignored "-Wvarargs" +# pragma clang diagnostic ignored "-Wunused-function" +# pragma clang diagnostic ignored "-Wbraced-scalar-init" +# pragma clang diagnostic ignored "-W#pragma-messages" +# pragma clang diagnostic ignored "-Wstatic-in-inline" +#endif + +#ifdef __GNUC__ +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wunknown-pragmas" +# pragma GCC diagnostic ignored "-Wcomment" +# pragma GCC diagnostic ignored "-Wswitch" +# pragma GCC diagnostic ignored "-Wunused-variable" +#endif +/* + gencpp: An attempt at "simple" staged metaprogramming for c/c++. + + See Readme.md for more information from the project repository. + + Define GEN_IMPLEMENTATION before including this file in a single compilation unit. + + Public Address: + https://github.com/Ed94/gencpp --------------------------------------------------------------. + | _____ _____ _ _ | + | / ____) / ____} | | | | + | | / ___ ___ _ __ ___ _ __ _ __ | {___ | |__ _ _, __ _, ___ __| | | + | | |{_ |/ _ \ '_ \ / __} '_ l| '_ l `\___ \| __/ _` |/ _` |/ _ \/ _` | | + | | l__j | ___/ | | | {__; |+l } |+l | ____) | l| (_| | {_| | ___/ (_| | | + | \_____|\___}_l |_|\___} ,__/| ,__/ (_____/ \__\__/_|\__, |\___}\__,_l | + | Singleheader | | | | __} | | + | l_l l_l {___/ | + ! ----------------------------------------------------------------------- VERSION: v0.25-Alpha | + ! ============================================================================================ | + ! WARNING: THIS IS AN ALPHA VERSION OF THE LIBRARY, USE AT YOUR OWN DISCRETION | + ! NEVER DO CODE GENERATION WITHOUT AT LEAST HAVING CONTENT IN A CODEBASE UNDER VERSION CONTROL | + ! ============================================================================================ / +*/ +#if ! defined(GEN_DONT_ENFORCE_GEN_TIME_GUARD) && ! defined(GEN_TIME) +# error Gen.hpp : GEN_TIME not defined +#endif + +//! If its desired to roll your own dependencies, define GEN_ROLL_OWN_DEPENDENCIES before including this file. +// Dependencies are derived from the c-zpl library: https://github.com/zpl-c/zpl +#ifndef GEN_ROLL_OWN_DEPENDENCIES + +#pragma region Platform Detection + +/* Platform architecture */ + +#if defined( _WIN64 ) || defined( __x86_64__ ) || defined( _M_X64 ) || defined( __64BIT__ ) || defined( __powerpc64__ ) || defined( __ppc64__ ) || defined( __aarch64__ ) +# ifndef GEN_ARCH_64_BIT +# define GEN_ARCH_64_BIT 1 +# endif +#else +# ifndef GEN_ARCH_32_BItxt_StrCaT +# define GEN_ARCH_32_BIT 1 +# endif +#endif + +/* Platform OS */ + +#if defined( _WIN32 ) || defined( _WIN64 ) +# ifndef GEN_SYSTEM_WINDOWS +# define GEN_SYSTEM_WINDOWS 1 +# endif +#elif defined( __APPLE__ ) && defined( __MACH__ ) +# ifndef GEN_SYSTEM_OSX +# define GEN_SYSTEM_OSX 1 +# endif +# ifndef GEN_SYSTEM_MACOS +# define GEN_SYSTEM_MACOS 1 +# endif +#elif defined( __unix__ ) +# ifndef GEN_SYSTEM_UNIX +# define GEN_SYSTEM_UNIX 1 +# endif +# if defined( ANDROID ) || defined( __ANDROID__ ) +# ifndef GEN_SYSTEM_ANDROID +# define GEN_SYSTEM_ANDROID 1 +# endif +# ifndef GEN_SYSTEM_LINUX +# define GEN_SYSTEM_LINUX 1 +# endif +# elif defined( __linux__ ) +# ifndef GEN_SYSTEM_LINUX +# define GEN_SYSTEM_LINUX 1 +# endif +# elif defined( __FreeBSD__ ) || defined( __FreeBSD_kernel__ ) +# ifndef GEN_SYSTEM_FREEBSD +# define GEN_SYSTEM_FREEBSD 1 +# endif +# elif defined( __OpenBSD__ ) +# ifndef GEN_SYSTEM_OPENBSD +# define GEN_SYSTEM_OPENBSD 1 +# endif +# elif defined( __EMSCRIPTEN__ ) +# ifndef GEN_SYSTEM_EMSCRIPTEN +# define GEN_SYSTEM_EMSCRIPTEN 1 +# endif +# elif defined( __CYGWIN__ ) +# ifndef GEN_SYSTEM_CYGWIN +# define GEN_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 ) +# pragma message("Detected MSVC") +// # define GEN_COMPILER_CLANG 0 +# define GEN_COMPILER_MSVC 1 +// # define GEN_COMPILER_GCC 0 +#elif defined( __GNUC__ ) +# pragma message("Detected GCC") +// # define GEN_COMPILER_CLANG 0 +// # define GEN_COMPILER_MSVC 0 +# define GEN_COMPILER_GCC 1 +#elif defined( __clang__ ) +# pragma message("Detected CLANG") +# define GEN_COMPILER_CLANG 1 +// # define GEN_COMPILER_MSVC 0 +// # define GEN_COMPILER_GCC 0 +#else +# error Unknown compiler +#endif + +#if defined( __has_attribute ) +# define GEN_HAS_ATTRIBUTE( attribute ) __has_attribute( attribute ) +#else +# define GEN_HAS_ATTRIBUTE( attribute ) ( 0 ) +#endif + +#if defined(GEN_GCC_VERSION_CHECK) +# undef GEN_GCC_VERSION_CHECK +#endif +#if defined(GEN_GCC_VERSION) +# define GEN_GCC_VERSION_CHECK(major,minor,patch) (GEN_GCC_VERSION >= GEN_VERSION_ENCODE(major, minor, patch)) +#else +# define GEN_GCC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if !defined(GEN_COMPILER_C) +# ifdef __cplusplus +# define GEN_COMPILER_C 0 +# define GEN_COMPILER_CPP 1 +# else +# if defined(__STDC__) +# define GEN_COMPILER_C 1 +# define GEN_COMPILER_CPP 0 +# else + // Fallback for very old C compilers +# define GEN_COMPILER_C 1 +# define GEN_COMPILER_CPP 0 +# endif +# endif +#endif + +#if GEN_COMPILER_C +#pragma message("GENCPP: Detected C") +#endif + +#pragma endregion Platform Detection + +#pragma region Mandatory Includes + +# include +# include + +# if defined( GEN_SYSTEM_WINDOWS ) +# include +# endif + +#if GEN_COMPILER_C +#include +#include +#endif + +#pragma endregion Mandatory Includes + +#if GEN_DONT_USE_NAMESPACE || GEN_COMPILER_C +# if GEN_COMPILER_C +# define GEN_NS +# define GEN_NS_BEGIN +# define GEN_NS_END +# else +# define GEN_NS :: +# define GEN_NS_BEGIN +# define GEN_NS_END +# endif +#else +# define GEN_NS gen:: +# define GEN_NS_BEGIN namespace gen { +# define GEN_NS_END } +#endif + +GEN_NS_BEGIN + +#pragma region Macros + +#ifndef GEN_API +#if GEN_COMPILER_MSVC + #ifdef GEN_DYN_LINK + #ifdef GEN_DYN_EXPORT + #define GEN_API __declspec(dllexport) + #else + #define GEN_API __declspec(dllimport) + #endif + #else + #define GEN_API // Empty for static builds + #endif +#else + #ifdef GEN_DYN_LINK + #define GEN_API __attribute__((visibility("default"))) + #else + #define GEN_API // Empty for static builds + #endif +#endif +#endif // GEN_API + +#ifndef global // Global variables +# if defined(GEN_STATIC_LINK) || defined(GEN_DYN_LINK) +# define global +# else +# define global static +# endif +#endif +#ifndef internal +#define internal static // Internal linkage +#endif +#ifndef local_persist +#define local_persist static // Local Persisting variables +#endif + +#ifndef bit +#define bit( Value ) ( 1 << Value ) +#endif + +#ifndef bitfield_is_set +#define bitfield_is_set( Type, Field, Mask ) ( (scast(Type, Mask) & scast(Type, Field)) == scast(Type, Mask) ) +#endif + +// Mainly intended for forcing the base library to utilize only C-valid constructs or type coercion +#ifndef GEN_C_LIKE_CPP +#define GEN_C_LIKE_CPP 0 +#endif + +#if GEN_COMPILER_CPP +# ifndef cast +# define cast( type, value ) (tmpl_cast( value )) +# endif +#else +# ifndef cast +# define cast( type, value ) ( (type)(value) ) +# endif +#endif + +#if GEN_COMPILER_CPP +# ifndef ccast +# define ccast( type, value ) ( const_cast< type >( (value) ) ) +# endif +# ifndef pcast +# define pcast( type, value ) ( * reinterpret_cast< type* >( & ( value ) ) ) +# endif +# ifndef rcast +# define rcast( type, value ) reinterpret_cast< type >( value ) +# endif +# ifndef scast +# define scast( type, value ) static_cast< type >( value ) +# endif +#else +# ifndef ccast +# define ccast( type, value ) ( (type)(value) ) +# endif +# ifndef pcast +# define pcast( type, value ) ( * (type*)(& value) ) +# endif +# ifndef rcast +# define rcast( type, value ) ( (type)(value) ) +# endif +# ifndef scast +# define scast( type, value ) ( (type)(value) ) +# endif +#endif + +#ifndef stringize +#define stringize_va( ... ) #__VA_ARGS__ +#define stringize( ... ) stringize_va( __VA_ARGS__ ) +#endif + +#define src_line_str stringize(__LINE__) + +#ifndef do_once +#define do_once() \ + local_persist int __do_once_counter_##src_line_str = 0; \ + for(; __do_once_counter_##src_line_str != 1; __do_once_counter_##src_line_str = 1 ) \ + +#define do_once_defer( expression ) \ + local_persist int __do_once_counter_##src_line_str = 0; \ + for(;__do_once_counter_##src_line_str != 1; __do_once_counter_##src_line_str = 1, (expression)) \ + +#define do_once_start \ + do \ + { \ + local_persist \ + bool done = false; \ + if ( done ) \ + break; \ + done = true; + +#define do_once_end \ + } \ + while(0); +#endif + +#ifndef labeled_scope_start +#define labeled_scope_start if ( false ) { +#define labeled_scope_end } +#endif + +#ifndef compiler_decorated_func_name +# ifdef COMPILER_CLANG +# define compiler_decorated_func_name __PRETTY_NAME__ +# elif defined(COMPILER_MSVC) +# define compiler_decorated_func_name __FUNCDNAME__ +# endif +#endif + +#ifndef num_args_impl + +// This is essentially an arg couneter version of GEN_SELECT_ARG macros +// See section : _Generic function overloading for that usage (explains this heavier case) + +#define num_args_impl( _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, _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, _52, _53, _54, _55, _56, _57, _58, _59, _60, \ + _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, \ + _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, \ + _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, \ + _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, \ + N, ... \ + ) N + +// ## deletes preceding comma if _VA_ARGS__ is empty (GCC, Clang) +#define num_args(...) \ + num_args_impl(_, ## __VA_ARGS__, \ + 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, \ + 90, 89, 88, 87, 86, 85, 84, 83, 82, 81, \ + 80, 79, 78, 77, 76, 75, 74, 73, 72, 71, \ + 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, \ + 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, \ + 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, \ + 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, \ + 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, \ + 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, \ + 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, \ + 0 \ + ) +#endif + +#ifndef clamp +#define clamp( x, lower, upper ) min( max( ( x ), ( lower ) ), ( upper ) ) +#endif +#ifndef count_of +#define count_of( x ) ( ( size_of( x ) / size_of( 0 [ x ] ) ) / ( ( ssize )( ! ( size_of( x ) % size_of( 0 [ x ] ) ) ) ) ) +#endif +#ifndef is_between +#define is_between( x, lower, upper ) ( ( ( lower ) <= ( x ) ) && ( ( x ) <= ( upper ) ) ) +#endif +#ifndef size_of +#define size_of( x ) ( ssize )( sizeof( x ) ) +#endif + +#ifndef max +#define max( a, b ) ( (a > b) ? (a) : (b) ) +#endif +#ifndef min +#define min( a, b ) ( (a < b) ? (a) : (b) ) +#endif + +#if GEN_COMPILER_MSVC || GEN_COMPILER_TINYC +# define offset_of( Type, element ) ( ( GEN_NS( ssize ) ) & ( ( ( Type* )0 )->element ) ) +#else +# define offset_of( Type, element ) __builtin_offsetof( Type, element ) +#endif + +#ifndef forceinline +# if GEN_COMPILER_MSVC +# define forceinline __forceinline +# elif GEN_COMPILER_GCC +# define forceinline inline __attribute__((__always_inline__)) +# elif GEN_COMPILER_CLANG +# if __has_attribute(__always_inline__) +# define forceinline inline __attribute__((__always_inline__)) +# else +# define forceinline +# endif +# else +# define forceinline +# endif +#endif + +#ifndef neverinline +# if GEN_COMPILER_MSVC +# define neverinline __declspec( noinline ) +# elif GEN_COMPILER_GCC +# define neverinline __attribute__( ( __noinline__ ) ) +# elif GEN_COMPILER_CLANG +# if __has_attribute(__always_inline__) +# define neverinline __attribute__( ( __noinline__ ) ) +# else +# define neverinline +# endif +# else +# define neverinline +# endif +#endif + +#if GEN_COMPILER_C +#ifndef static_assert +#undef static_assert + #if GEN_COMPILER_C && __STDC_VERSION__ >= 201112L + #define static_assert(condition, message) _Static_assert(condition, message) + #else + #define static_assert(condition, message) typedef char static_assertion_##__LINE__[(condition)?1:-1] + #endif +#endif +#endif + +#if GEN_COMPILER_CPP +// Already Defined +#elif GEN_COMPILER_C && __STDC_VERSION__ >= 201112L +# define thread_local _Thread_local +#elif GEN_COMPILER_MSVC +# define thread_local __declspec(thread) +#elif GEN_COMPILER_CLANG +# define thread_local __thread +#else +# error "No thread local support" +#endif + +#if ! defined(typeof) && (!GEN_COMPILER_C || __STDC_VERSION__ < 202311L) +# if ! GEN_COMPILER_C +# define typeof decltype +# elif defined(_MSC_VER) +# define typeof __typeof__ +# elif defined(__GNUC__) || defined(__clang__) +# define typeof __typeof__ +# else +# error "Compiler not supported" +# endif +#endif + +#ifndef GEN_API_C_BEGIN +# if GEN_COMPILER_C +# define GEN_API_C_BEGIN +# define GEN_API_C_END +# else +# define GEN_API_C_BEGIN extern "C" { +# define GEN_API_C_END } +# endif +#endif + +#if GEN_COMPILER_C +# if __STDC_VERSION__ >= 202311L +# define enum_underlying(type) : type +# else +# define enum_underlying(type) +# endif +#else +# define enum_underlying(type) : type +#endif + +#if GEN_COMPILER_C +# ifndef nullptr +# define nullptr NULL +# endif + +# ifndef GEN_REMOVE_PTR +# define GEN_REMOVE_PTR(type) typeof(* ( (type) NULL) ) +# endif +#endif + +#if ! defined(GEN_PARAM_DEFAULT) && GEN_COMPILER_CPP +# define GEN_PARAM_DEFAULT = {} +#else +# define GEN_PARAM_DEFAULT +#endif + +#if GEN_COMPILER_CPP + #define struct_init(type, value) {value} +#else + #define struct_init(type, value) {value} +#endif + +#if 0 +#ifndef GEN_OPTIMIZE_MAPPINGS_BEGIN +# define GEN_OPTIMIZE_MAPPINGS_BEGIN _pragma(optimize("gt", on)) +# define GEN_OPITMIZE_MAPPINGS_END _pragma(optimize("", on)) +#endif +#else +# define GEN_OPTIMIZE_MAPPINGS_BEGIN +# define GEN_OPITMIZE_MAPPINGS_END +#endif + +#ifndef get_optional +# if GEN_COMPILER_C +# define get_optional(opt) opt ? *opt : (typeof(*opt)){0} +# else +# define get_optional(opt) opt +# endif +#endif + +#pragma endregion Macros + +#pragma region Basic Types + +#define GEN_U8_MIN 0u +#define GEN_U8_MAX 0xffu +#define GEN_I8_MIN ( -0x7f - 1 ) +#define GEN_I8_MAX 0x7f + +#define GEN_U16_MIN 0u +#define GEN_U16_MAX 0xffffu +#define GEN_I16_MIN ( -0x7fff - 1 ) +#define GEN_I16_MAX 0x7fff + +#define GEN_U32_MIN 0u +#define GEN_U32_MAX 0xffffffffu +#define GEN_I32_MIN ( -0x7fffffff - 1 ) +#define GEN_I32_MAX 0x7fffffff + +#define GEN_U64_MIN 0ull +#define GEN_U64_MAX 0xffffffffffffffffull +#define GEN_I64_MIN ( -0x7fffffffffffffffll - 1 ) +#define GEN_I64_MAX 0x7fffffffffffffffll + +#if defined( GEN_ARCH_32_BIT ) +# define GEN_USIZE_MIN GEN_U32_MIN +# define GEN_USIZE_MAX GEN_U32_MAX +# define GEN_ISIZE_MIN GEN_S32_MIN +# define GEN_ISIZE_MAX GEN_S32_MAX +#elif defined( GEN_ARCH_64_BIT ) +# define GEN_USIZE_MIN GEN_U64_MIN +# define GEN_USIZE_MAX GEN_U64_MAX +# define GEN_ISIZE_MIN GEN_I64_MIN +# define GEN_ISIZE_MAX GEN_I64_MAX +#else +# error Unknown architecture size. This library only supports 32 bit and 64 bit architectures. +#endif + +#define GEN_F32_MIN 1.17549435e-38f +#define GEN_F32_MAX 3.40282347e+38f +#define GEN_F64_MIN 2.2250738585072014e-308 +#define GEN_F64_MAX 1.7976931348623157e+308 + +#if defined( GEN_COMPILER_MSVC ) +# if _MSC_VER < 1300 +typedef unsigned char u8; +typedef signed char s8; +typedef unsigned short u16; +typedef signed short s16; +typedef unsigned int u32; +typedef signed int s32; +# else +typedef unsigned __int8 u8; +typedef signed __int8 s8; +typedef unsigned __int16 u16; +typedef signed __int16 s16; +typedef unsigned __int32 u32; +typedef signed __int32 s32; +# endif +typedef unsigned __int64 u64; +typedef signed __int64 s64; +#else +# include + +typedef uint8_t u8; +typedef int8_t s8; +typedef uint16_t u16; +typedef int16_t s16; +typedef uint32_t u32; +typedef int32_t s32; +typedef uint64_t u64; +typedef int64_t s64; +#endif + +static_assert( sizeof( u8 ) == sizeof( s8 ), "sizeof(u8) != sizeof(s8)" ); +static_assert( sizeof( u16 ) == sizeof( s16 ), "sizeof(u16) != sizeof(s16)" ); +static_assert( sizeof( u32 ) == sizeof( s32 ), "sizeof(u32) != sizeof(s32)" ); +static_assert( sizeof( u64 ) == sizeof( s64 ), "sizeof(u64) != sizeof(s64)" ); + +static_assert( sizeof( u8 ) == 1, "sizeof(u8) != 1" ); +static_assert( sizeof( u16 ) == 2, "sizeof(u16) != 2" ); +static_assert( sizeof( u32 ) == 4, "sizeof(u32) != 4" ); +static_assert( sizeof( u64 ) == 8, "sizeof(u64) != 8" ); + +typedef size_t usize; +typedef ptrdiff_t ssize; + +static_assert( sizeof( usize ) == sizeof( ssize ), "sizeof(usize) != sizeof(ssize)" ); + +// 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 sptr; +typedef unsigned __int64 uptr; +#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 sptr; +typedef _W64 unsigned int uptr; +#else +typedef uintptr_t uptr; +typedef intptr_t sptr; +#endif + +static_assert( sizeof( uptr ) == sizeof( sptr ), "sizeof(uptr) != sizeof(sptr)" ); + +typedef float f32; +typedef double f64; + +static_assert( sizeof( f32 ) == 4, "sizeof(f32) != 4" ); +static_assert( sizeof( f64 ) == 8, "sizeof(f64) != 8" ); + +typedef s8 b8; +typedef s16 b16; +typedef s32 b32; + +typedef void* mem_ptr; +typedef void const* mem_ptr_const ; + +#if GEN_COMPILER_CPP +template uptr to_uptr( Type* ptr ) { return (uptr)ptr; } +template sptr to_sptr( Type* ptr ) { return (sptr)ptr; } + +template mem_ptr to_mem_ptr ( Type ptr ) { return (mem_ptr) ptr; } +template mem_ptr_const to_mem_ptr_const( Type ptr ) { return (mem_ptr_const)ptr; } +#else +#define to_uptr( ptr ) ((uptr)(ptr)) +#define to_sptr( ptr ) ((sptr)(ptr)) + +#define to_mem_ptr( ptr) ((mem_ptr)ptr) +#define to_mem_ptr_const( ptr) ((mem_ptr)ptr) +#endif + +#pragma endregion Basic Types + +#pragma region Debug + +#if GEN_BUILD_DEBUG +# if defined( GEN_COMPILER_MSVC ) +# if _MSC_VER < 1300 +// #pragma message("GEN_BUILD_DEBUG: __asm int 3") +# define GEN_DEBUG_TRAP() __asm int 3 /* Trap to debugger! */ +# else +// #pragma message("GEN_BUILD_DEBUG: __debugbreak()") +# define GEN_DEBUG_TRAP() __debugbreak() +# endif +# elif defined( GEN_COMPILER_TINYC ) +# define GEN_DEBUG_TRAP() process_exit( 1 ) +# else +# define GEN_DEBUG_TRAP() __builtin_trap() +# endif +#else +// #pragma message("GEN_BUILD_DEBUG: omitted") +# define GEN_DEBUG_TRAP() +#endif + +#define GEN_ASSERT( cond ) GEN_ASSERT_MSG( cond, NULL ) + +#define GEN_ASSERT_MSG( cond, msg, ... ) \ + do \ + { \ + if ( ! ( cond ) ) \ + { \ + assert_handler( #cond, __FILE__, __func__, scast( s64, __LINE__ ), msg, ##__VA_ARGS__ ); \ + GEN_DEBUG_TRAP(); \ + } \ + } while ( 0 ) + +#define GEN_ASSERT_NOT_NULL( ptr ) GEN_ASSERT_MSG( ( ptr ) != NULL, #ptr " must not be NULL" ) + +// NOTE: Things that shouldn't happen with a message! +#define GEN_PANIC( msg, ... ) GEN_ASSERT_MSG( 0, msg, ##__VA_ARGS__ ) + +#if GEN_BUILD_DEBUG + #define GEN_FATAL( ... ) \ + do \ + { \ + local_persist thread_local \ + char buf[GEN_PRINTF_MAXLEN] = { 0 }; \ + \ + c_str_fmt(buf, GEN_PRINTF_MAXLEN, __VA_ARGS__); \ + GEN_PANIC(buf); \ + } \ + while (0) +#else + +# define GEN_FATAL( ... ) \ + do \ + { \ + c_str_fmt_out_err( __VA_ARGS__ ); \ + GEN_DEBUG_TRAP(); \ + process_exit(1); \ + } \ + while (0) +#endif + +GEN_API void assert_handler( char const* condition, char const* file, char const* function, s32 line, char const* msg, ... ); +GEN_API s32 assert_crash( char const* condition ); +GEN_API void process_exit( u32 code ); + +#pragma endregion Debug + +#pragma region Memory + +#define kilobytes( x ) ( ( x ) * ( s64 )( 1024 ) ) +#define megabytes( x ) ( kilobytes( x ) * ( s64 )( 1024 ) ) +#define gigabytes( x ) ( megabytes( x ) * ( s64 )( 1024 ) ) +#define terabytes( x ) ( gigabytes( x ) * ( s64 )( 1024 ) ) + +#define GEN__ONES ( scast( GEN_NS usize, - 1) / GEN_U8_MAX ) +#define GEN__HIGHS ( GEN__ONES * ( GEN_U8_MAX / 2 + 1 ) ) +#define GEN__HAS_ZERO( x ) ( ( ( x ) - GEN__ONES ) & ~( x ) & GEN__HIGHS ) + +template< class Type > +void swap( Type& a, Type& b ) +{ + Type tmp = a; + a = b; + b = tmp; +} + +//! Checks if value is power of 2. +b32 is_power_of_two( ssize x ); + +//! Aligns address to specified alignment. +void* align_forward( void* ptr, ssize alignment ); + +//! Aligns value to a specified alignment. +s64 align_forward_by_value( s64 value, ssize alignment ); + +//! Moves pointer forward by bytes. +void* pointer_add( void* ptr, ssize bytes ); + +//! Moves pointer forward by bytes. +void const* pointer_add_const( void const* ptr, ssize bytes ); + +//! Calculates difference between two addresses. +ssize pointer_diff( void const* begin, void const* end ); + +//! Copy non-overlapping memory from source to destination. +GEN_API void* mem_copy( void* dest, void const* source, ssize size ); + +//! Search for a constant value within the size limit at memory location. +GEN_API void const* mem_find( void const* data, u8 byte_value, ssize size ); + +//! Copy memory from source to destination. +void* mem_move( void* dest, void const* source, ssize size ); + +//! Set constant value at memory location with specified size. +void* mem_set( void* data, u8 byte_value, ssize size ); + +//! @param ptr Memory location to clear up. +//! @param size The size to clear up with. +void zero_size( void* ptr, ssize size ); + +//! Clears up an item. +#define zero_item( t ) zero_size( ( t ), size_of( *( t ) ) ) // NOTE: Pass pointer of struct + +//! Clears up an array. +#define zero_array( a, count ) zero_size( ( a ), size_of( *( a ) ) * count ) + +enum AllocType : u8 +{ + EAllocation_ALLOC, + EAllocation_FREE, + EAllocation_FREE_ALL, + EAllocation_RESIZE, +}; + +typedef void*(AllocatorProc)( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags ); + +struct AllocatorInfo +{ + AllocatorProc* Proc; + void* Data; +}; + +enum AllocFlag +{ + ALLOCATOR_FLAG_CLEAR_TO_ZERO = bit( 0 ), +}; + +#ifndef GEN_DEFAULT_MEMORY_ALIGNMENT +# define GEN_DEFAULT_MEMORY_ALIGNMENT ( 2 * size_of( void* ) ) +#endif + +#ifndef GEN_DEFAULT_ALLOCATOR_FLAGS +# define GEN_DEFAULT_ALLOCATOR_FLAGS ( ALLOCATOR_FLAG_CLEAR_TO_ZERO ) +#endif + +//! Allocate memory with default alignment. +void* alloc( AllocatorInfo a, ssize size ); + +//! Allocate memory with specified alignment. +void* alloc_align( AllocatorInfo a, ssize size, ssize alignment ); + +//! Free allocated memory. +void allocator_free( AllocatorInfo a, void* ptr ); + +//! Free all memory allocated by an allocator. +void free_all( AllocatorInfo a ); + +//! Resize an allocated memory. +void* resize( AllocatorInfo a, void* ptr, ssize old_size, ssize new_size ); + +//! Resize an allocated memory with specified alignment. +void* resize_align( AllocatorInfo a, void* ptr, ssize old_size, ssize new_size, ssize alignment ); + +//! Allocate memory for an item. +#define alloc_item( allocator_, Type ) ( Type* )alloc( allocator_, size_of( Type ) ) + +//! Allocate memory for an array of items. +#define alloc_array( allocator_, Type, count ) ( Type* )alloc( allocator_, size_of( Type ) * ( count ) ) + +/* heap memory analysis tools */ +/* define GEN_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 */ +GEN_API void heap_stats_init( void ); +GEN_API ssize heap_stats_used_memory( void ); +GEN_API ssize heap_stats_alloc_count( void ); +GEN_API void heap_stats_check( void ); + +//! Allocate/Resize memory using default options. + +//! Use this if you don't need a "fancy" resize allocation +void* default_resize_align( AllocatorInfo a, void* ptr, ssize old_size, ssize new_size, ssize alignment ); + +GEN_API void* heap_allocator_proc( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags ); + +//! The heap allocator backed by operating system's memory manager. +constexpr AllocatorInfo heap( void ) { AllocatorInfo allocator = { heap_allocator_proc, nullptr }; return allocator; } + +//! Helper to allocate memory using heap allocator. +#define malloc( sz ) alloc( heap(), sz ) + +//! Helper to free memory allocated by heap allocator. +#define mfree( ptr ) allocator_free( heap(), ptr ) + +struct VirtualMemory +{ + void* data; + ssize size; +}; + +//! Initialize virtual memory from existing data. +GEN_API VirtualMemory vm_from_memory( void* data, ssize 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 serve. +GEN_API VirtualMemory vm_alloc( void* addr, ssize size ); + +//! Release the virtual memory. +GEN_API b32 vm_free( VirtualMemory vm ); + +//! Trim virtual memory. +GEN_API VirtualMemory vm_trim( VirtualMemory vm, ssize lead_size, ssize size ); + +//! Purge virtual memory. +GEN_API b32 vm_purge( VirtualMemory vm ); + +//! Retrieve VM's page size and alignment. +GEN_API ssize virtual_memory_page_size( ssize* alignment_out ); + +#pragma region Arena +struct Arena; + +AllocatorInfo arena_allocator_info( Arena* arena ); + +// Remove static keyword and rename allocator_proc +GEN_API void* arena_allocator_proc(void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags); + +// Add these declarations after the Arena struct +Arena arena_init_from_allocator(AllocatorInfo backing, ssize size); +Arena arena_init_from_memory ( void* start, ssize size ); + +Arena arena_init_sub (Arena* parent, ssize size); +ssize arena_alignment_of (Arena* arena, ssize alignment); +void arena_check (Arena* arena); +void arena_free (Arena* arena); +ssize arena_size_remaining(Arena* arena, ssize alignment); + +struct Arena +{ + AllocatorInfo Backing; + void* PhysicalStart; + ssize TotalSize; + ssize TotalUsed; + ssize TempCount; + +#if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP +#pragma region Member Mapping + forceinline operator AllocatorInfo() { return arena_allocator_info(this); } + + forceinline static void* allocator_proc( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags ) { return arena_allocator_proc( allocator_data, type, size, alignment, old_memory, old_size, flags ); } + forceinline static Arena init_from_memory( void* start, ssize size ) { return arena_init_from_memory( start, size ); } + forceinline static Arena init_from_allocator( AllocatorInfo backing, ssize size ) { return arena_init_from_allocator( backing, size ); } + forceinline static Arena init_sub( Arena& parent, ssize size ) { return arena_init_from_allocator( parent.Backing, size ); } + forceinline ssize alignment_of( ssize alignment ) { return arena_alignment_of(this, alignment); } + forceinline void free() { return arena_free(this); } + forceinline ssize size_remaining( ssize alignment ) { return arena_size_remaining(this, alignment); } + +// This id is defined by Unreal for asserts +#pragma push_macro("check") +#undef check + forceinline void check() { arena_check(this); } +#pragma pop_macro("check") + +#pragma endregion Member Mapping +#endif +}; + +#if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP +forceinline AllocatorInfo allocator_info(Arena& arena ) { return arena_allocator_info(& arena); } +forceinline Arena init_sub (Arena& parent, ssize size) { return arena_init_sub( & parent, size); } +forceinline ssize alignment_of (Arena& arena, ssize alignment) { return arena_alignment_of( & arena, alignment); } +forceinline void free (Arena& arena) { return arena_free(& arena); } +forceinline ssize size_remaining(Arena& arena, ssize alignment) { return arena_size_remaining(& arena, alignment); } + +// This id is defined by Unreal for asserts +#pragma push_macro("check") +#undef check +forceinline void check(Arena& arena) { return arena_check(& arena); } +#pragma pop_macro("check") +#endif + +inline +AllocatorInfo arena_allocator_info( Arena* arena ) { + GEN_ASSERT(arena != nullptr); + AllocatorInfo info = { arena_allocator_proc, arena }; + return info; +} + +inline +Arena arena_init_from_memory( void* start, ssize size ) +{ + Arena arena = { + { nullptr, nullptr }, + start, + size, + 0, + 0 + }; + return arena; +} + +inline +Arena arena_init_from_allocator(AllocatorInfo backing, ssize size) { + Arena result = { + backing, + alloc(backing, size), + size, + 0, + 0 + }; + return result; +} + +inline +Arena arena_init_sub(Arena* parent, ssize size) { + GEN_ASSERT(parent != nullptr); + return arena_init_from_allocator(parent->Backing, size); +} + +inline +ssize arena_alignment_of(Arena* arena, ssize alignment) +{ + GEN_ASSERT(arena != nullptr); + ssize alignment_offset, result_pointer, mask; + GEN_ASSERT(is_power_of_two(alignment)); + + alignment_offset = 0; + result_pointer = (ssize)arena->PhysicalStart + arena->TotalUsed; + mask = alignment - 1; + + if (result_pointer & mask) + alignment_offset = alignment - (result_pointer & mask); + + return alignment_offset; +} + +inline +void arena_check(Arena* arena) +{ + GEN_ASSERT(arena != nullptr ); + GEN_ASSERT(arena->TempCount == 0); +} + +inline +void arena_free(Arena* arena) +{ + GEN_ASSERT(arena != nullptr); + if (arena->Backing.Proc) + { + allocator_free(arena->Backing, arena->PhysicalStart); + arena->PhysicalStart = nullptr; + } +} + +inline +ssize arena_size_remaining(Arena* arena, ssize alignment) +{ + GEN_ASSERT(arena != nullptr); + ssize result = arena->TotalSize - (arena->TotalUsed + arena_alignment_of(arena, alignment)); + return result; +} +#pragma endregion Arena + +#pragma region FixedArena +template +struct FixedArena; + +template FixedArena fixed_arena_init(); +template AllocatorInfo fixed_arena_allocator_info(FixedArena* fixed_arena ); +template ssize fixed_arena_size_remaining(FixedArena* fixed_arena, ssize alignment); +template void fixed_arena_free(FixedArena* fixed_arena); + +#if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP +template AllocatorInfo allocator_info( FixedArena& fixed_arena ) { return allocator_info(& fixed_arena); } +template ssize size_remaining(FixedArena& fixed_arena, ssize alignment) { return size_remaining( & fixed_arena, alignment); } +#endif + +// Just a wrapper around using an arena with memory associated with its scope instead of from an allocator. +// Used for static segment or stack allocations. +template< s32 Size > +struct FixedArena +{ + char memory[Size]; + Arena arena; + +#if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP +#pragma region Member Mapping + forceinline operator AllocatorInfo() { return fixed_arena_allocator_info(this); } + + forceinline static FixedArena init() { FixedArena result; fixed_arena_init(result); return result; } + forceinline ssize size_remaining(ssize alignment) { fixed_arena_size_remaining(this, alignment); } +#pragma endregion Member Mapping +#endif +}; + +template inline +AllocatorInfo fixed_arena_allocator_info( FixedArena* fixed_arena ) { + GEN_ASSERT(fixed_arena); + return { arena_allocator_proc, & fixed_arena->arena }; +} + +template inline +void fixed_arena_init(FixedArena* result) { + zero_size(& result->memory[0], Size); + result->arena = arena_init_from_memory(& result->memory[0], Size); +} + +template inline +void fixed_arena_free(FixedArena* fixed_arena) { + arena_free( & fixed_arena->arena); +} + +template inline +ssize fixed_arena_size_remaining(FixedArena* fixed_arena, ssize alignment) { + return size_remaining(fixed_arena->arena, alignment); +} + +using FixedArena_1KB = FixedArena< kilobytes( 1 ) >; +using FixedArena_4KB = FixedArena< kilobytes( 4 ) >; +using FixedArena_8KB = FixedArena< kilobytes( 8 ) >; +using FixedArena_16KB = FixedArena< kilobytes( 16 ) >; +using FixedArena_32KB = FixedArena< kilobytes( 32 ) >; +using FixedArena_64KB = FixedArena< kilobytes( 64 ) >; +using FixedArena_128KB = FixedArena< kilobytes( 128 ) >; +using FixedArena_256KB = FixedArena< kilobytes( 256 ) >; +using FixedArena_512KB = FixedArena< kilobytes( 512 ) >; +using FixedArena_1MB = FixedArena< megabytes( 1 ) >; +using FixedArena_2MB = FixedArena< megabytes( 2 ) >; +using FixedArena_4MB = FixedArena< megabytes( 4 ) >; +#pragma endregion FixedArena + +#pragma region Pool +struct Pool; + +GEN_API void* pool_allocator_proc(void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags); + + Pool pool_init(AllocatorInfo backing, ssize num_blocks, ssize block_size); + Pool pool_init_align(AllocatorInfo backing, ssize num_blocks, ssize block_size, ssize block_align); + AllocatorInfo pool_allocator_info(Pool* pool); +GEN_API void pool_clear(Pool* pool); + void pool_free(Pool* pool); + +#if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP +forceinline AllocatorInfo allocator_info(Pool& pool) { return pool_allocator_info(& pool); } +forceinline void clear(Pool& pool) { return pool_clear(& pool); } +forceinline void free(Pool& pool) { return pool_free(& pool); } +#endif + +struct Pool +{ + AllocatorInfo Backing; + void* PhysicalStart; + void* FreeList; + ssize BlockSize; + ssize BlockAlign; + ssize TotalSize; + ssize NumBlocks; + +#if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP +#pragma region Member Mapping + forceinline operator AllocatorInfo() { return pool_allocator_info(this); } + + forceinline static void* allocator_proc(void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags) { return pool_allocator_proc(allocator_data, type, size, alignment, old_memory, old_size, flags); } + forceinline static Pool init(AllocatorInfo backing, ssize num_blocks, ssize block_size) { return pool_init(backing, num_blocks, block_size); } + forceinline static Pool init_align(AllocatorInfo backing, ssize num_blocks, ssize block_size, ssize block_align) { return pool_init_align(backing, num_blocks, block_size, block_align); } + forceinline void clear() { pool_clear( this); } + forceinline void free() { pool_free( this); } +#pragma endregion +#endif +}; + +inline +AllocatorInfo pool_allocator_info(Pool* pool) { + AllocatorInfo info = { pool_allocator_proc, pool }; + return info; +} + +inline +Pool pool_init(AllocatorInfo backing, ssize num_blocks, ssize block_size) { + return pool_init_align(backing, num_blocks, block_size, GEN_DEFAULT_MEMORY_ALIGNMENT); +} + +inline +void pool_free(Pool* pool) { + if(pool->Backing.Proc) { + allocator_free(pool->Backing, pool->PhysicalStart); + } +} +#pragma endregion Pool + +inline +b32 is_power_of_two( ssize x ) { + if ( x <= 0 ) + return false; + return ! ( x & ( x - 1 ) ); +} + +inline +mem_ptr align_forward( void* ptr, ssize alignment ) +{ + GEN_ASSERT( is_power_of_two( alignment ) ); + uptr p = to_uptr(ptr); + uptr forward = (p + ( alignment - 1 ) ) & ~( alignment - 1 ); + + return to_mem_ptr(forward); +} + +inline s64 align_forward_s64( s64 value, ssize alignment ) { return value + ( alignment - value % alignment ) % alignment; } + +inline void* pointer_add ( void* ptr, ssize bytes ) { return rcast(void*, rcast( u8*, ptr) + bytes ); } +inline void const* pointer_add_const( void const* ptr, ssize bytes ) { return rcast(void const*, rcast( u8 const*, ptr) + bytes ); } + +inline sptr pointer_diff( mem_ptr_const begin, mem_ptr_const end ) { + return scast( ssize, rcast( u8 const*, end) - rcast(u8 const*, begin) ); +} + +inline +void* mem_move( void* destination, void const* source, ssize byte_count ) +{ + if ( destination == NULL ) + { + return NULL; + } + + u8* dest_ptr = rcast( u8*, destination); + u8 const* src_ptr = rcast( u8 const*, source); + + if ( dest_ptr == src_ptr ) + return dest_ptr; + + if ( src_ptr + byte_count <= dest_ptr || dest_ptr + byte_count <= src_ptr ) // NOTE: Non-overlapping + return mem_copy( dest_ptr, src_ptr, byte_count ); + + if ( dest_ptr < src_ptr ) + { + if ( to_uptr(src_ptr) % size_of( ssize ) == to_uptr(dest_ptr) % size_of( ssize ) ) + { + while ( pcast( uptr, dest_ptr) % size_of( ssize ) ) + { + if ( ! byte_count-- ) + return destination; + + *dest_ptr++ = *src_ptr++; + } + while ( byte_count >= size_of( ssize ) ) + { + * rcast(ssize*, dest_ptr) = * rcast(ssize const*, src_ptr); + byte_count -= size_of( ssize ); + dest_ptr += size_of( ssize ); + src_ptr += size_of( ssize ); + } + } + for ( ; byte_count; byte_count-- ) + *dest_ptr++ = *src_ptr++; + } + else + { + if ( ( to_uptr(src_ptr) % size_of( ssize ) ) == ( to_uptr(dest_ptr) % size_of( ssize ) ) ) + { + while ( to_uptr( dest_ptr + byte_count ) % size_of( ssize ) ) + { + if ( ! byte_count-- ) + return destination; + + dest_ptr[ byte_count ] = src_ptr[ byte_count ]; + } + while ( byte_count >= size_of( ssize ) ) + { + byte_count -= size_of( ssize ); + * rcast(ssize*, dest_ptr + byte_count ) = * rcast( ssize const*, src_ptr + byte_count ); + } + } + while ( byte_count ) + byte_count--, dest_ptr[ byte_count ] = src_ptr[ byte_count ]; + } + + return destination; +} + +inline +void* mem_set( void* destination, u8 fill_byte, ssize byte_count ) +{ + if ( destination == NULL ) + { + return NULL; + } + + ssize align_offset; + u8* dest_ptr = rcast( u8*, destination); + u32 fill_word = ( ( u32 )-1 ) / 255 * fill_byte; + + if ( byte_count == 0 ) + return destination; + + dest_ptr[ 0 ] = dest_ptr[ byte_count - 1 ] = fill_byte; + if ( byte_count < 3 ) + return destination; + + dest_ptr[ 1 ] = dest_ptr[ byte_count - 2 ] = fill_byte; + dest_ptr[ 2 ] = dest_ptr[ byte_count - 3 ] = fill_byte; + if ( byte_count < 7 ) + return destination; + + dest_ptr[ 3 ] = dest_ptr[ byte_count - 4 ] = fill_byte; + if ( byte_count < 9 ) + return destination; + + align_offset = -to_sptr( dest_ptr ) & 3; + dest_ptr += align_offset; + byte_count -= align_offset; + byte_count &= -4; + + * rcast( u32*, ( dest_ptr + 0 ) ) = fill_word; + * rcast( u32*, ( dest_ptr + byte_count - 4 ) ) = fill_word; + if ( byte_count < 9 ) + return destination; + + * rcast( u32*, dest_ptr + 4 ) = fill_word; + * rcast( u32*, dest_ptr + 8 ) = fill_word; + * rcast( u32*, dest_ptr + byte_count - 12 ) = fill_word; + * rcast( u32*, dest_ptr + byte_count - 8 ) = fill_word; + if ( byte_count < 25 ) + return destination; + + * rcast( u32*, dest_ptr + 12 ) = fill_word; + * rcast( u32*, dest_ptr + 16 ) = fill_word; + * rcast( u32*, dest_ptr + 20 ) = fill_word; + * rcast( u32*, dest_ptr + 24 ) = fill_word; + * rcast( u32*, dest_ptr + byte_count - 28 ) = fill_word; + * rcast( u32*, dest_ptr + byte_count - 24 ) = fill_word; + * rcast( u32*, dest_ptr + byte_count - 20 ) = fill_word; + * rcast( u32*, dest_ptr + byte_count - 16 ) = fill_word; + + align_offset = 24 + to_uptr( dest_ptr ) & 4; + dest_ptr += align_offset; + byte_count -= align_offset; + + { + u64 fill_doubleword = ( scast( u64, fill_word) << 32 ) | fill_word; + while ( byte_count > 31 ) + { + * rcast( u64*, dest_ptr + 0 ) = fill_doubleword; + * rcast( u64*, dest_ptr + 8 ) = fill_doubleword; + * rcast( u64*, dest_ptr + 16 ) = fill_doubleword; + * rcast( u64*, dest_ptr + 24 ) = fill_doubleword; + + byte_count -= 32; + dest_ptr += 32; + } + } + + return destination; +} + +inline +void* alloc_align( AllocatorInfo a, ssize size, ssize alignment ) { + return a.Proc( a.Data, EAllocation_ALLOC, size, alignment, nullptr, 0, GEN_DEFAULT_ALLOCATOR_FLAGS ); +} + +inline +void* alloc( AllocatorInfo a, ssize size ) { + return alloc_align( a, size, GEN_DEFAULT_MEMORY_ALIGNMENT ); +} + +inline +void allocator_free( AllocatorInfo a, void* ptr ) { + if ( ptr != nullptr ) + a.Proc( a.Data, EAllocation_FREE, 0, 0, ptr, 0, GEN_DEFAULT_ALLOCATOR_FLAGS ); +} + +inline +void free_all( AllocatorInfo a ) { + a.Proc( a.Data, EAllocation_FREE_ALL, 0, 0, nullptr, 0, GEN_DEFAULT_ALLOCATOR_FLAGS ); +} + +inline +void* resize( AllocatorInfo a, void* ptr, ssize old_size, ssize new_size ) { + return resize_align( a, ptr, old_size, new_size, GEN_DEFAULT_MEMORY_ALIGNMENT ); +} + +inline +void* resize_align( AllocatorInfo a, void* ptr, ssize old_size, ssize new_size, ssize alignment ) { + return a.Proc( a.Data, EAllocation_RESIZE, new_size, alignment, ptr, old_size, GEN_DEFAULT_ALLOCATOR_FLAGS ); +} + +inline +void* default_resize_align( AllocatorInfo a, void* old_memory, ssize old_size, ssize new_size, ssize alignment ) +{ + if ( ! old_memory ) + return alloc_align( a, new_size, alignment ); + + if ( new_size == 0 ) + { + allocator_free( a, old_memory ); + return nullptr; + } + + if ( new_size < old_size ) + new_size = old_size; + + if ( old_size == new_size ) + { + return old_memory; + } + else + { + void* new_memory = alloc_align( a, new_size, alignment ); + if ( ! new_memory ) + return nullptr; + + mem_move( new_memory, old_memory, min( new_size, old_size ) ); + allocator_free( a, old_memory ); + return new_memory; + } +} + +inline +void zero_size( void* ptr, ssize size ) { + mem_set( ptr, 0, size ); +} + +#pragma endregion Memory + +#pragma region String Ops + +const char* char_first_occurence( const char* str, char c ); + +b32 char_is_alpha( char c ); +b32 char_is_alphanumeric( char c ); +b32 char_is_digit( char c ); +b32 char_is_hex_digit( char c ); +b32 char_is_space( char c ); +char char_to_lower( char c ); +char char_to_upper( char c ); + +s32 digit_to_int( char c ); +s32 hex_digit_to_int( char c ); + +s32 c_str_compare( const char* s1, const char* s2 ); +s32 c_str_compare_len( const char* s1, const char* s2, ssize len ); +char* c_str_copy( char* dest, const char* source, ssize len ); +ssize c_str_copy_nulpad( char* dest, const char* source, ssize len ); +ssize c_str_len( const char* str ); +ssize c_str_len_capped( const char* str, ssize max_len ); +char* c_str_reverse( char* str ); // NOTE: ASCII only +char const* c_str_skip( char const* str, char c ); +char const* c_str_skip_any( char const* str, char const* char_list ); +char const* c_str_trim( char const* str, b32 catch_newline ); + +// NOTE: ASCII only +void c_str_to_lower( char* str ); +void c_str_to_upper( char* str ); + +GEN_API s64 c_str_to_i64( const char* str, char** end_ptr, s32 base ); +GEN_API void i64_to_str( s64 value, char* string, s32 base ); +GEN_API void u64_to_str( u64 value, char* string, s32 base ); +GEN_API f64 c_str_to_f64( const char* str, char** end_ptr ); + +inline +const char* char_first_occurence( const char* s, char c ) +{ + char ch = c; + for ( ; *s != ch; s++ ) + { + if ( *s == '\0' ) + return NULL; + } + return s; +} + +inline +b32 char_is_alpha( char c ) +{ + if ( ( c >= 'A' && c <= 'Z' ) || ( c >= 'a' && c <= 'z' ) ) + return true; + return false; +} + +inline +b32 char_is_alphanumeric( char c ) +{ + return char_is_alpha( c ) || char_is_digit( c ); +} + +inline +b32 char_is_digit( char c ) +{ + if ( c >= '0' && c <= '9' ) + return true; + return false; +} + +inline +b32 char_is_hex_digit( char c ) +{ + if ( char_is_digit( c ) || ( c >= 'a' && c <= 'f' ) || ( c >= 'A' && c <= 'F' ) ) + return true; + return false; +} + +inline +b32 char_is_space( char c ) +{ + if ( c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v' ) + return true; + return false; +} + +inline +char char_to_lower( char c ) +{ + if ( c >= 'A' && c <= 'Z' ) + return 'a' + ( c - 'A' ); + return c; +} + +inline char char_to_upper( char c ) +{ + if ( c >= 'a' && c <= 'z' ) + return 'A' + ( c - 'a' ); + return c; +} + +inline +s32 digit_to_int( char c ) +{ + return char_is_digit( c ) ? c - '0' : c - 'W'; +} + +inline +s32 hex_digit_to_int( char c ) +{ + if ( char_is_digit( c ) ) + return digit_to_int( c ); + else if ( is_between( c, 'a', 'f' ) ) + return c - 'a' + 10; + else if ( is_between( c, 'A', 'F' ) ) + return c - 'A' + 10; + return -1; +} + +inline +s32 c_str_compare( const char* s1, const char* s2 ) +{ + while ( *s1 && ( *s1 == *s2 ) ) + { + s1++, s2++; + } + return *( u8* )s1 - *( u8* )s2; +} + +inline +s32 c_str_compare_len( const char* s1, const char* s2, ssize len ) +{ + for ( ; len > 0; s1++, s2++, len-- ) + { + if ( *s1 != *s2 ) + return ( ( s1 < s2 ) ? -1 : +1 ); + else if ( *s1 == '\0' ) + return 0; + } + return 0; +} + +inline +char* c_str_copy( char* dest, const char* source, ssize len ) +{ + GEN_ASSERT_NOT_NULL( dest ); + if ( source ) + { + char* str = dest; + while ( len > 0 && *source ) + { + *str++ = *source++; + len--; + } + while ( len > 0 ) + { + *str++ = '\0'; + len--; + } + } + return dest; +} + +inline +ssize c_str_copy_nulpad( char* dest, const char* source, ssize len ) +{ + ssize result = 0; + GEN_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; +} + +inline +ssize c_str_len( const char* str ) +{ + if ( str == NULL ) + { + return 0; + } + const char* p = str; + while ( *str ) + str++; + return str - p; +} + +inline +ssize c_str_len_capped( const char* str, ssize max_len ) +{ + const char* end = rcast(const char*, mem_find( str, 0, max_len )); + if ( end ) + return end - str; + return max_len; +} + +inline +char* c_str_reverse( char* str ) +{ + ssize len = c_str_len( str ); + char* a = str + 0; + char* b = str + len - 1; + len /= 2; + while ( len-- ) + { + swap( *a, *b ); + a++, b--; + } + return str; +} + +inline +char const* c_str_skip( char const* str, char c ) +{ + while ( *str && *str != c ) + { + ++str; + } + return str; +} + +inline +char const* c_str_skip_any( char const* str, char const* char_list ) +{ + char const* closest_ptr = rcast( char const*, pointer_add_const( rcast(mem_ptr_const, str), c_str_len( str ) )); + ssize char_list_count = c_str_len( char_list ); + for ( ssize i = 0; i < char_list_count; i++ ) + { + char const* p = c_str_skip( str, char_list[ i ] ); + closest_ptr = min( closest_ptr, p ); + } + return closest_ptr; +} + +inline +char const* c_str_trim( char const* str, b32 catch_newline ) +{ + while ( *str && char_is_space( *str ) && ( ! catch_newline || ( catch_newline && *str != '\n' ) ) ) + { + ++str; + } + return str; +} + +inline +void c_str_to_lower( char* str ) +{ + if ( ! str ) + return; + while ( *str ) + { + *str = char_to_lower( *str ); + str++; + } +} + +inline +void c_str_to_upper( char* str ) +{ + if ( ! str ) + return; + while ( *str ) + { + *str = char_to_upper( *str ); + str++; + } +} + +#pragma endregion String Ops + +#pragma region Printing + +typedef struct FileInfo FileInfo; + +#ifndef GEN_PRINTF_MAXLEN +# define GEN_PRINTF_MAXLEN kilobytes(128) +#endif +typedef char PrintF_Buffer[GEN_PRINTF_MAXLEN]; + +// NOTE: A locally persisting buffer is used internally +GEN_API char* c_str_fmt_buf ( char const* fmt, ... ); +GEN_API char* c_str_fmt_buf_va ( char const* fmt, va_list va ); +GEN_API ssize c_str_fmt ( char* str, ssize n, char const* fmt, ... ); +GEN_API ssize c_str_fmt_va ( char* str, ssize n, char const* fmt, va_list va ); +GEN_API ssize c_str_fmt_out_va ( char const* fmt, va_list va ); +GEN_API ssize c_str_fmt_out_err ( char const* fmt, ... ); +GEN_API ssize c_str_fmt_out_err_va( char const* fmt, va_list va ); +GEN_API ssize c_str_fmt_file ( FileInfo* f, char const* fmt, ... ); +GEN_API ssize c_str_fmt_file_va ( FileInfo* f, char const* fmt, va_list va ); + +constexpr +char const* Msg_Invalid_Value = "INVALID VALUE PROVIDED"; + +inline +ssize log_fmt(char const* fmt, ...) +{ + ssize res; + va_list va; + + va_start(va, fmt); + res = c_str_fmt_out_va(fmt, va); + va_end(va); + + return res; +} + +#pragma endregion Printing + +#pragma region Containers + +template struct RemoveConst { typedef TType Type; }; +template struct RemoveConst { typedef TType Type; }; +template struct RemoveConst { typedef TType Type[]; }; +template struct RemoveConst { typedef TType Type[Size]; }; + +template using TRemoveConst = typename RemoveConst::Type; + +template struct RemovePtr { typedef TType Type; }; +template struct RemovePtr { typedef TType Type; }; + +template using TRemovePtr = typename RemovePtr::Type; + + +#pragma region Array +#define Array(Type) Array + +// #define array_init(Type, ...) array_init (__VA_ARGS__) +// #define array_init_reserve(Type, ...) array_init_reserve(__VA_ARGS__) + +struct ArrayHeader; + +#if GEN_COMPILER_CPP + template struct Array; +# define get_array_underlying_type(array) typename TRemovePtr:: DataType +#endif + +usize array_grow_formula(ssize value); + +template Array array_init (AllocatorInfo allocator); +template Array array_init_reserve (AllocatorInfo allocator, ssize capacity); +template bool array_append_array (Array* array, Array other); +template bool array_append (Array* array, Type value); +template bool array_append_items (Array* array, Type* items, usize item_num); +template bool array_append_at (Array* array, Type item, usize idx); +template bool array_append_items_at(Array* array, Type* items, usize item_num, usize idx); +template Type* array_back (Array array); +template void array_clear (Array array); +template bool array_fill (Array array, usize begin, usize end, Type value); +template void array_free (Array* array); +template bool arary_grow (Array* array, usize min_capacity); +template usize array_num (Array array); +template void arary_pop (Array array); +template void arary_remove_at (Array array, usize idx); +template bool arary_reserve (Array* array, usize new_capacity); +template bool arary_resize (Array* array, usize num); +template bool arary_set_capacity (Array* array, usize new_capacity); +template ArrayHeader* arary_get_header (Array array); + +struct ArrayHeader { + AllocatorInfo Allocator; + usize Capacity; + usize Num; +}; + +#if GEN_COMPILER_CPP +template +struct Array +{ + Type* Data; + +#pragma region Member Mapping + forceinline static Array init(AllocatorInfo allocator) { return array_init(allocator); } + forceinline static Array init_reserve(AllocatorInfo allocator, ssize capacity) { return array_init_reserve(allocator, capacity); } + forceinline static usize grow_formula(ssize value) { return array_grow_formula(value); } + + forceinline bool append(Array other) { return array_append_array(this, other); } + forceinline bool append(Type value) { return array_append(this, value); } + forceinline bool append(Type* items, usize item_num) { return array_append_items(this, items, item_num); } + forceinline bool append_at(Type item, usize idx) { return array_append_at(this, item, idx); } + forceinline bool append_at(Type* items, usize item_num, usize idx) { return array_append_items_at(this, items, item_num, idx); } + forceinline Type* back() { return array_back(* this); } + forceinline void clear() { array_clear(* this); } + forceinline bool fill(usize begin, usize end, Type value) { return array_fill(* this, begin, end, value); } + forceinline void free() { array_free(this); } + forceinline ArrayHeader* get_header() { return array_get_header(* this); } + forceinline bool grow(usize min_capacity) { return array_grow(this, min_capacity); } + forceinline usize num() { return array_num(*this); } + forceinline void pop() { array_pop(* this); } + forceinline void remove_at(usize idx) { array_remove_at(* this, idx); } + forceinline bool reserve(usize new_capacity) { return array_reserve(this, new_capacity); } + forceinline bool resize(usize num) { return array_resize(this, num); } + forceinline bool set_capacity(usize new_capacity) { return array_set_capacity(this, new_capacity); } +#pragma endregion Member Mapping + + forceinline operator Type*() { return Data; } + forceinline operator Type const*() const { return Data; } + forceinline Type* begin() { return Data; } + forceinline Type* end() { return Data + get_header()->Num; } + + forceinline Type& operator[](ssize index) { return Data[index]; } + forceinline Type const& operator[](ssize index) const { return Data[index]; } + + using DataType = Type; +}; +#endif + +#if GEN_COMPILER_CPP && 0 +template bool append(Array& array, Array other) { return append( & array, other ); } +template bool append(Array& array, Type value) { return append( & array, value ); } +template bool append(Array& array, Type* items, usize item_num) { return append( & array, items, item_num ); } +template bool append_at(Array& array, Type item, usize idx) { return append_at( & array, item, idx ); } +template bool append_at(Array& array, Type* items, usize item_num, usize idx) { return append_at( & array, items, item_num, idx ); } +template void free(Array& array) { return free( & array ); } +template bool grow(Array& array, usize min_capacity) { return grow( & array, min_capacity); } +template bool reserve(Array& array, usize new_capacity) { return reserve( & array, new_capacity); } +template bool resize(Array& array, usize num) { return resize( & array, num); } +template bool set_capacity(Array& array, usize new_capacity) { return set_capacity( & array, new_capacity); } + +template forceinline Type* begin(Array& array) { return array; } +template forceinline Type* end(Array& array) { return array + array_get_header(array)->Num; } +template forceinline Type* next(Array& array, Type* entry) { return entry + 1; } +#endif + +template forceinline Type* array_begin(Array array) { return array; } +template forceinline Type* array_end(Array array) { return array + array_get_header(array)->Num; } +template forceinline Type* array_next(Array array, Type* entry) { return ++ entry; } + +template inline +Array array_init(AllocatorInfo allocator) { + return array_init_reserve(allocator, array_grow_formula(0)); +} + +template inline +Array array_init_reserve(AllocatorInfo allocator, ssize capacity) +{ + GEN_ASSERT(capacity > 0); + ArrayHeader* header = rcast(ArrayHeader*, alloc(allocator, sizeof(ArrayHeader) + sizeof(Type) * capacity)); + + if (header == nullptr) + return {nullptr}; + + header->Allocator = allocator; + header->Capacity = capacity; + header->Num = 0; + + return {rcast(Type*, header + 1)}; +} + +forceinline +usize array_grow_formula(ssize value) { + return 2 * value + 8; +} + +template inline +bool array_append_array(Array* array, Array other) { + return array_append_items(array, (Type*)other, array_num(other)); +} + +template inline +bool array_append(Array* array, Type value) +{ + GEN_ASSERT( array != nullptr); + GEN_ASSERT(* array != nullptr); + ArrayHeader* header = array_get_header(* array); + + if (header->Num == header->Capacity) + { + if ( ! array_grow(array, header->Capacity)) + return false; + header = array_get_header(* array); + } + + (*array)[ header->Num] = value; + header->Num++; + + return true; +} + +template inline +bool array_append_items(Array* array, Type* items, usize item_num) +{ + GEN_ASSERT( array != nullptr); + GEN_ASSERT(* array != nullptr); + GEN_ASSERT(items != nullptr); + GEN_ASSERT(item_num > 0); + ArrayHeader* header = array_get_header(* array); + + if (header->Num + item_num > header->Capacity) + { + if ( ! array_grow(array, header->Capacity + item_num)) + return false; + header = array_get_header(* array); + } + + mem_copy((Type*)array + header->Num, items, item_num * sizeof(Type)); + header->Num += item_num; + + return true; +} + +template inline +bool array_append_at(Array* array, Type item, usize idx) +{ + GEN_ASSERT( array != nullptr); + GEN_ASSERT(* array != nullptr); + ArrayHeader* header = array_get_header(* array); + + ssize slot = idx; + if (slot >= (ssize)(header->Num)) + slot = header->Num - 1; + + if (slot < 0) + slot = 0; + + if (header->Capacity < header->Num + 1) + { + if ( ! array_grow(array, header->Capacity + 1)) + return false; + + header = array_get_header(* array); + } + + Type* target = &(*array)[slot]; + + mem_move(target + 1, target, (header->Num - slot) * sizeof(Type)); + header->Num++; + + return true; +} + +template inline +bool array_append_items_at(Array* array, Type* items, usize item_num, usize idx) +{ + GEN_ASSERT( array != nullptr); + GEN_ASSERT(* array != nullptr); + ArrayHeader* header = get_header(array); + + if (idx >= header->Num) + { + return array_append_items(array, items, item_num); + } + + if (item_num > header->Capacity) + { + if (! grow(array, header->Capacity + item_num)) + return false; + + header = get_header(array); + } + + Type* target = array.Data + idx + item_num; + Type* src = array.Data + idx; + + mem_move(target, src, (header->Num - idx) * sizeof(Type)); + mem_copy(src, items, item_num * sizeof(Type)); + header->Num += item_num; + + return true; +} + +template inline +Type* array_back(Array array) +{ + GEN_ASSERT(array != nullptr); + + ArrayHeader* header = array_get_header(array); + if (header->Num <= 0) + return nullptr; + + return & (array)[header->Num - 1]; +} + +template inline +void array_clear(Array array) { + GEN_ASSERT(array != nullptr); + ArrayHeader* header = array_get_header(array); + header->Num = 0; +} + +template inline +bool array_fill(Array array, usize begin, usize end, Type value) +{ + GEN_ASSERT(array != nullptr); + GEN_ASSERT(begin <= end); + ArrayHeader* header = array_get_header(array); + + if (begin < 0 || end > header->Num) + return false; + + for (ssize idx = ssize(begin); idx < ssize(end); idx++) { + array[idx] = value; + } + + return true; +} + +template forceinline +void array_free(Array* array) { + GEN_ASSERT( array != nullptr); + GEN_ASSERT(* array != nullptr); + ArrayHeader* header = array_get_header(* array); + allocator_free(header->Allocator, header); + Type** Data = (Type**)array; + *Data = nullptr; +} + +template forceinline +ArrayHeader* array_get_header(Array array) { + GEN_ASSERT(array != nullptr); + Type* Data = array; + + using NonConstType = TRemoveConst; + return rcast(ArrayHeader*, const_cast(Data)) - 1; +} + +template forceinline +bool array_grow(Array* array, usize min_capacity) +{ + GEN_ASSERT( array != nullptr); + GEN_ASSERT(* array != nullptr); + GEN_ASSERT( min_capacity > 0 ); + ArrayHeader* header = array_get_header(* array); + usize new_capacity = array_grow_formula(header->Capacity); + + if (new_capacity < min_capacity) + new_capacity = min_capacity; + + return array_set_capacity(array, new_capacity); +} + +template forceinline +usize array_num(Array array) { + GEN_ASSERT(array != nullptr); + return array_get_header(array)->Num; +} + +template forceinline +void array_pop(Array array) { + GEN_ASSERT(array != nullptr); + ArrayHeader* header = array_get_header(array); + GEN_ASSERT(header->Num > 0); + header->Num--; +} + +template inline +void array_remove_at(Array array, usize idx) +{ + GEN_ASSERT(array != nullptr); + ArrayHeader* header = array_get_header(array); + GEN_ASSERT(idx < header->Num); + + mem_move(array + idx, array + idx + 1, sizeof(Type) * (header->Num - idx - 1)); + header->Num--; +} + +template inline +bool array_reserve(Array* array, usize new_capacity) +{ + GEN_ASSERT( array != nullptr); + GEN_ASSERT(* array != nullptr); + ArrayHeader* header = array_get_header(array); + + if (header->Capacity < new_capacity) + return set_capacity(array, new_capacity); + + return true; +} + +template inline +bool array_resize(Array* array, usize num) +{ + GEN_ASSERT( array != nullptr); + GEN_ASSERT(* array != nullptr); + ArrayHeader* header = array_get_header(* array); + + if (header->Capacity < num) { + if (! array_grow( array, num)) + return false; + header = array_get_header(* array); + } + + header->Num = num; + return true; +} + +template inline +bool array_set_capacity(Array* array, usize new_capacity) +{ + GEN_ASSERT( array != nullptr); + GEN_ASSERT(* array != nullptr); + ArrayHeader* header = array_get_header(* array); + + if (new_capacity == header->Capacity) + return true; + + if (new_capacity < header->Num) + { + header->Num = new_capacity; + return true; + } + + ssize size = sizeof(ArrayHeader) + sizeof(Type) * new_capacity; + ArrayHeader* new_header = rcast(ArrayHeader*, alloc(header->Allocator, size)); + + if (new_header == nullptr) + return false; + + mem_move(new_header, header, sizeof(ArrayHeader) + sizeof(Type) * header->Num); + + new_header->Capacity = new_capacity; + + allocator_free(header->Allocator, header); + + Type** Data = (Type**)array; + * Data = rcast(Type*, new_header + 1); + return true; +} + +// These are intended for use in the base library of gencpp and the C-variant of the library +// It provides a interoperability between the C++ and C implementation of arrays. (not letting these do any crazy substiution though) +// They are undefined in gen.hpp and gen.cpp at the end of the files. +// The cpp library expects the user to use the regular calls as they can resolve the type fine. + +#define array_init(type, allocator) array_init (allocator ) +#define array_init_reserve(type, allocator, cap) array_init_reserve (allocator, cap) +#define array_append_array(array, other) array_append_array < get_array_underlying_type(array) > (& array, other ) +#define array_append(array, value) array_append < get_array_underlying_type(array) > (& array, value ) +#define array_append_items(array, items, item_num) array_append_items < get_array_underlying_type(array) > (& array, items, item_num ) +#define array_append_at(array, item, idx ) array_append_at < get_array_underlying_type(array) > (& array, item, idx ) +#define array_append_at_items(array, items, item_num, idx) array_append_at_items< get_array_underlying_type(array) > (& items, item_num, idx ) +#define array_back(array) array_back < get_array_underlying_type(array) > (array ) +#define array_clear(array) array_clear < get_array_underlying_type(array) > (array ) +#define array_fill(array, begin, end, value) array_fill < get_array_underlying_type(array) > (array, begin, end, value ) +#define array_free(array) array_free < get_array_underlying_type(array) > (& array ) +#define arary_grow(array, min_capacity) arary_grow < get_array_underlying_type(array) > (& array, min_capacity) +#define array_num(array) array_num < get_array_underlying_type(array) > (array ) +#define arary_pop(array) arary_pop < get_array_underlying_type(array) > (array ) +#define arary_remove_at(array, idx) arary_remove_at < get_array_underlying_type(array) > (idx) +#define arary_reserve(array, new_capacity) arary_reserve < get_array_underlying_type(array) > (& array, new_capacity ) +#define arary_resize(array, num) arary_resize < get_array_underlying_type(array) > (& array, num) +#define arary_set_capacity(new_capacity) arary_set_capacity < get_array_underlying_type(array) > (& array, new_capacity ) +#define arary_get_header(array) arary_get_header < get_array_underlying_type(array) > (array ) + +#pragma endregion Array + +#pragma region HashTable +#define HashTable(Type) HashTable + +template struct HashTable; + +#ifndef get_hashtable_underlying_type +#define get_hashtable_underlying_type(table) typename TRemovePtr:: DataType +#endif + +struct HashTableFindResult { + ssize HashIndex; + ssize PrevIndex; + ssize EntryIndex; +}; + +template +struct HashTableEntry { + u64 Key; + ssize Next; + Type Value; +}; + +#define HashTableEntry(Type) HashTableEntry + +template HashTable hashtable_init (AllocatorInfo allocator); +template HashTable hashtable_init_reserve(AllocatorInfo allocator, usize num); +template void hashtable_clear (HashTable table); +template void hashtable_destroy (HashTable* table); +template Type* hashtable_get (HashTable table, u64 key); +template void hashtable_grow (HashTable* table); +template void hashtable_rehash (HashTable* table, ssize new_num); +template void hashtable_rehash_fast (HashTable table); +template void hashtable_remove (HashTable table, u64 key); +template void hashtable_remove_entry(HashTable table, ssize idx); +template void hashtable_set (HashTable* table, u64 key, Type value); +template ssize hashtable_slot (HashTable table, u64 key); +template void hashtable_map (HashTable table, void (*map_proc)(u64 key, Type value)); +template void hashtable_map_mut (HashTable table, void (*map_proc)(u64 key, Type* value)); + +template ssize hashtable__add_entry (HashTable* table, u64 key); +template HashTableFindResult hashtable__find (HashTable table, u64 key); +template bool hashtable__full (HashTable table); + +static constexpr f32 HashTable_CriticalLoadScale = 0.7f; + +template +struct HashTable +{ + Array Hashes; + Array> Entries; + +#if ! GEN_C_LIKE_CPP +#pragma region Member Mapping + forceinline static HashTable init(AllocatorInfo allocator) { return hashtable_init(allocator); } + forceinline static HashTable init_reserve(AllocatorInfo allocator, usize num) { return hashtable_init_reserve(allocator, num); } + + forceinline void clear() { clear(*this); } + forceinline void destroy() { destroy(*this); } + forceinline Type* get(u64 key) { return get(*this, key); } + forceinline void grow() { grow(*this); } + forceinline void rehash(ssize new_num) { rehash(*this, new_num); } + forceinline void rehash_fast() { rehash_fast(*this); } + forceinline void remove(u64 key) { remove(*this, key); } + forceinline void remove_entry(ssize idx) { remove_entry(*this, idx); } + forceinline void set(u64 key, Type value) { set(*this, key, value); } + forceinline ssize slot(u64 key) { return slot(*this, key); } + forceinline void map(void (*proc)(u64, Type)) { map(*this, proc); } + forceinline void map_mut(void (*proc)(u64, Type*)) { map_mut(*this, proc); } +#pragma endregion Member Mapping +#endif + + using DataType = Type; +}; + +#if GEN_SUPPORT_CPP_REFERENCES +template void destroy (HashTable& table) { destroy(& table); } +template void grow (HashTable& table) { grow(& table); } +template void rehash (HashTable& table, ssize new_num) { rehash(& table, new_num); } +template void set (HashTable& table, u64 key, Type value) { set(& table, key, value); } +template ssize add_entry(HashTable& table, u64 key) { add_entry(& table, key); } +#endif + +template inline +HashTable hashtable_init(AllocatorInfo allocator) { + HashTable result = hashtable_init_reserve(allocator, 8); + return result; +} + +template inline +HashTable hashtable_init_reserve(AllocatorInfo allocator, usize num) +{ + HashTable result = { { nullptr }, { nullptr } }; + + result.Hashes = array_init_reserve(allocator, num); + array_get_header(result.Hashes)->Num = num; + array_resize(& result.Hashes, num); + array_fill(result.Hashes, 0, num, (ssize)-1); + + result.Entries = array_init_reserve>(allocator, num); + return result; +} + +template forceinline +void hashtable_clear(HashTable table) { + GEN_ASSERT_NOT_NULL(table.Hashes); + GEN_ASSERT_NOT_NULL(table.Entries); + array_clear(table.Entries); + array_fill(table.Hashes, 0, array_num(table.Hashes), (ssize)-1); +} + +template forceinline +void hashtable_destroy(HashTable* table) { + GEN_ASSERT_NOT_NULL(table->Hashes); + GEN_ASSERT_NOT_NULL(table->Entries); + if (table->Hashes && array_get_header(table->Hashes)->Capacity) { + array_free(table->Hashes); + array_free(table->Entries); + } +} + +template forceinline +Type* hashtable_get(HashTable table, u64 key) { + GEN_ASSERT_NOT_NULL(table.Hashes); + GEN_ASSERT_NOT_NULL(table.Entries); + ssize idx = hashtable__find(table, key).EntryIndex; + if (idx >= 0) + return & table.Entries[idx].Value; + + return nullptr; +} + +template forceinline +void hashtable_map(HashTable table, void (*map_proc)(u64 key, Type value)) { + GEN_ASSERT_NOT_NULL(table.Hashes); + GEN_ASSERT_NOT_NULL(table.Entries); + GEN_ASSERT_NOT_NULL(map_proc); + + for (ssize idx = 0; idx < ssize(num(table.Entries)); ++idx) { + map_proc(table.Entries[idx].Key, table.Entries[idx].Value); + } +} + +template forceinline +void hashtable_map_mut(HashTable table, void (*map_proc)(u64 key, Type* value)) { + GEN_ASSERT_NOT_NULL(table.Hashes); + GEN_ASSERT_NOT_NULL(table.Entries); + GEN_ASSERT_NOT_NULL(map_proc); + + for (ssize idx = 0; idx < ssize(num(table.Entries)); ++idx) { + map_proc(table.Entries[idx].Key, & table.Entries[idx].Value); + } +} + +template forceinline +void hashtable_grow(HashTable* table) { + GEN_ASSERT_NOT_NULL(table); + GEN_ASSERT_NOT_NULL(table->Hashes); + GEN_ASSERT_NOT_NULL(table->Entries); + ssize new_num = array_grow_formula( array_num(table->Entries)); + hashtable_rehash(table, new_num); +} + +template inline +void hashtable_rehash(HashTable* table, ssize new_num) +{ + GEN_ASSERT_NOT_NULL(table); + GEN_ASSERT_NOT_NULL(table->Hashes); + GEN_ASSERT_NOT_NULL(table->Entries); + ssize last_added_index; + HashTable new_ht = hashtable_init_reserve( array_get_header(table->Hashes)->Allocator, new_num); + + for (ssize idx = 0; idx < ssize( array_num(table->Entries)); ++idx) + { + HashTableFindResult find_result; + HashTableEntry& entry = table->Entries[idx]; + + find_result = hashtable__find(new_ht, entry.Key); + last_added_index = hashtable__add_entry(& new_ht, entry.Key); + + if (find_result.PrevIndex < 0) + new_ht.Hashes[find_result.HashIndex] = last_added_index; + else + new_ht.Entries[find_result.PrevIndex].Next = last_added_index; + + new_ht.Entries[last_added_index].Next = find_result.EntryIndex; + new_ht.Entries[last_added_index].Value = entry.Value; + } + + hashtable_destroy(table); + * table = new_ht; +} + +template inline +void hashtable_rehash_fast(HashTable table) +{ + GEN_ASSERT_NOT_NULL(table.Hashes); + GEN_ASSERT_NOT_NULL(table.Entries); + ssize idx; + + for (idx = 0; idx < ssize(num(table.Entries)); idx++) + table.Entries[idx].Next = -1; + + for (idx = 0; idx < ssize(num(table.Hashes)); idx++) + table.Hashes[idx] = -1; + + for (idx = 0; idx < ssize(num(table.Entries)); idx++) + { + HashTableEntry* entry; + HashTableFindResult find_result; + + entry = &table.Entries[idx]; + find_result = find(table, entry->Key); + + if (find_result.PrevIndex < 0) + table.Hashes[find_result.HashIndex] = idx; + else + table.Entries[find_result.PrevIndex].Next = idx; + } +} + +template forceinline +void hashtable_remove(HashTable table, u64 key) { + GEN_ASSERT_NOT_NULL(table.Hashes); + GEN_ASSERT_NOT_NULL(table.Entries); + HashTableFindResult find_result = find(table, key); + + if (find_result.EntryIndex >= 0) { + remove_at(table.Entries, find_result.EntryIndex); + rehash_fast(table); + } +} + +template forceinline +void hashtable_remove_entry(HashTable table, ssize idx) { + GEN_ASSERT_NOT_NULL(table.Hashes); + GEN_ASSERT_NOT_NULL(table.Entries); + remove_at(table.Entries, idx); +} + +template inline +void hashtable_set(HashTable* table, u64 key, Type value) +{ + GEN_ASSERT_NOT_NULL(table); + GEN_ASSERT_NOT_NULL(table->Hashes); + GEN_ASSERT_NOT_NULL(table->Entries); + ssize idx; + HashTableFindResult find_result; + + if (hashtable_full(* table)) + hashtable_grow(table); + + find_result = hashtable__find(* table, key); + if (find_result.EntryIndex >= 0) { + idx = find_result.EntryIndex; + } + else + { + idx = hashtable__add_entry(table, key); + + if (find_result.PrevIndex >= 0) { + table->Entries[find_result.PrevIndex].Next = idx; + } + else { + table->Hashes[find_result.HashIndex] = idx; + } + } + + table->Entries[idx].Value = value; + + if (hashtable_full(* table)) + hashtable_grow(table); +} + +template forceinline +ssize hashtable_slot(HashTable table, u64 key) { + GEN_ASSERT_NOT_NULL(table.Hashes); + GEN_ASSERT_NOT_NULL(table.Entries); + for (ssize idx = 0; idx < ssize(num(table.Hashes)); ++idx) + if (table.Hashes[idx] == key) + return idx; + + return -1; +} + +template forceinline +ssize hashtable__add_entry(HashTable* table, u64 key) { + GEN_ASSERT_NOT_NULL(table); + GEN_ASSERT_NOT_NULL(table->Hashes); + GEN_ASSERT_NOT_NULL(table->Entries); + ssize idx; + HashTableEntry entry = { key, -1 }; + + idx = array_num(table->Entries); + array_append( table->Entries, entry); + return idx; +} + +template inline +HashTableFindResult hashtable__find(HashTable table, u64 key) +{ + GEN_ASSERT_NOT_NULL(table.Hashes); + GEN_ASSERT_NOT_NULL(table.Entries); + HashTableFindResult result = { -1, -1, -1 }; + + if (array_num(table.Hashes) > 0) + { + result.HashIndex = key % array_num(table.Hashes); + result.EntryIndex = table.Hashes[result.HashIndex]; + + while (result.EntryIndex >= 0) + { + if (table.Entries[result.EntryIndex].Key == key) + break; + + result.PrevIndex = result.EntryIndex; + result.EntryIndex = table.Entries[result.EntryIndex].Next; + } + } + + return result; +} + +template forceinline +b32 hashtable_full(HashTable table) { + GEN_ASSERT_NOT_NULL(table.Hashes); + GEN_ASSERT_NOT_NULL(table.Entries); + usize critical_load = usize(HashTable_CriticalLoadScale * f32(array_num(table.Hashes))); + b32 result = array_num(table.Entries) > critical_load; + return result; +} + +#define hashtable_init(type, allocator) hashtable_init (allocator) +#define hashtable_init_reserve(type, allocator, num) hashtable_init_reserve(allocator, num) +#define hashtable_clear(table) hashtable_clear < get_hashtable_underlying_type(table) >(table) +#define hashtable_destroy(table) hashtable_destroy < get_hashtable_underlying_type(table) >(& table) +#define hashtable_get(table, key) hashtable_get < get_hashtable_underlying_type(table) >(table, key) +#define hashtable_grow(table) hashtable_grow < get_hashtable_underlying_type(table) >(& table) +#define hashtable_rehash(table, new_num) hashtable_rehash < get_hashtable_underlying_type(table) >(& table, new_num) +#define hashtable_rehash_fast(table) hashtable_rehash_fast < get_hashtable_underlying_type(table) >(table) +#define hashtable_remove(table, key) hashtable_remove < get_hashtable_underlying_type(table) >(table, key) +#define hashtable_remove_entry(table, idx) hashtable_remove_entry< get_hashtable_underlying_type(table) >(table, idx) +#define hashtable_set(table, key, value) hashtable_set < get_hashtable_underlying_type(table) >(& table, key, value) +#define hashtable_slot(table, key) hashtable_slot < get_hashtable_underlying_type(table) >(table, key) +#define hashtable_map(table, map_proc) hashtable_map < get_hashtable_underlying_type(table) >(table, map_proc) +#define hashtable_map_mut(table, map_proc) hashtable_map_mut < get_hashtable_underlying_type(table) >(table, map_proc) + +//#define hashtable_add_entry(table, key) hashtable_add_entry < get_hashtable_underlying_type(table) >(& table, key) +//#define hashtable_find(table, key) hashtable_find < get_hashtable_underlying_type(table) >(table, key) +//#define hashtable_full(table) hashtable_full < get_hashtable_underlying_type(table) >(table) + +#pragma endregion HashTable + +#pragma endregion Containers + +#pragma region Hashing + +GEN_API u32 crc32( void const* data, ssize len ); +GEN_API u64 crc64( void const* data, ssize len ); + +#pragma endregion Hashing + +#pragma region Strings + +struct Str; + +Str to_str_from_c_str (char const* bad_string); +bool str_are_equal (Str lhs, Str rhs); +char const* str_back (Str str); +bool str_contains (Str str, Str substring); +Str str_duplicate (Str str, AllocatorInfo allocator); +b32 str_starts_with (Str str, Str substring); +Str str_visualize_whitespace(Str str, AllocatorInfo allocator); + +// Constant string with length. +struct Str +{ + char const* Ptr; + ssize Len; + +#if GEN_COMPILER_CPP + forceinline operator char const* () const { return Ptr; } + forceinline char const& operator[]( ssize index ) const { return Ptr[index]; } + +#if ! GEN_C_LIKE_CPP + forceinline bool is_equal (Str rhs) const { return str_are_equal(* this, rhs); } + forceinline char const* back () const { return str_back(* this); } + forceinline bool contains (Str substring) const { return str_contains(* this, substring); } + forceinline Str duplicate (AllocatorInfo allocator) const { return str_duplicate(* this, allocator); } + forceinline b32 starts_with (Str substring) const { return str_starts_with(* this, substring); } + forceinline Str visualize_whitespace(AllocatorInfo allocator) const { return str_visualize_whitespace(* this, allocator); } +#endif +#endif +}; + +#define cast_to_str( str ) * rcast( Str*, (str) - sizeof(ssize) ) + +#ifndef txt +# if GEN_COMPILER_CPP +# define txt( text ) GEN_NS Str { ( text ), sizeof( text ) - 1 } +# else +# define txt( text ) (GEN_NS Str){ ( text ), sizeof( text ) - 1 } +# endif +#endif + +GEN_API_C_BEGIN +forceinline char const* str_begin(Str str) { return str.Ptr; } +forceinline char const* str_end (Str str) { return str.Ptr + str.Len; } +forceinline char const* str_next (Str str, char const* iter) { return iter + 1; } +GEN_API_C_END + +#if GEN_COMPILER_CPP +forceinline char const* begin(Str str) { return str.Ptr; } +forceinline char const* end (Str str) { return str.Ptr + str.Len; } +forceinline char const* next (Str str, char const* iter) { return iter + 1; } +#endif + +inline +bool str_are_equal(Str lhs, Str rhs) +{ + if (lhs.Len != rhs.Len) + return false; + + for (ssize idx = 0; idx < lhs.Len; ++idx) + if (lhs.Ptr[idx] != rhs.Ptr[idx]) + return false; + + return true; +} + +inline +char const* str_back(Str str) { + return & str.Ptr[str.Len - 1]; +} + +inline +bool str_contains(Str str, Str substring) +{ + if (substring.Len > str.Len) + return false; + + ssize main_len = str.Len; + ssize sub_len = substring.Len; + for (ssize idx = 0; idx <= main_len - sub_len; ++idx) + { + if (c_str_compare_len(str.Ptr + idx, substring.Ptr, sub_len) == 0) + return true; + } + return false; +} + +inline +b32 str_starts_with(Str str, Str substring) { + if (substring.Len > str.Len) + return false; + + b32 result = c_str_compare_len(str.Ptr, substring.Ptr, substring.Len) == 0; + return result; +} + +inline +Str to_str_from_c_str( char const* bad_str ) { + Str result = { bad_str, c_str_len( bad_str ) }; + return result; +} + +// Dynamic StrBuilder +// This is directly based off the ZPL string api. +// They used a header pattern +// I kept it for simplicty of porting but its not necessary to keep it that way. +#pragma region StrBuilder +struct StrBuilderHeader; + +#if GEN_COMPILER_C +typedef char* StrBuilder; +#else +struct StrBuilder; +#endif + +forceinline usize strbuilder_grow_formula(usize value); + +GEN_API StrBuilder strbuilder_make_reserve (AllocatorInfo allocator, ssize capacity); +GEN_API StrBuilder strbuilder_make_length (AllocatorInfo allocator, char const* str, ssize length); +GEN_API bool strbuilder_make_space_for (StrBuilder* str, char const* to_append, ssize add_len); +GEN_API bool strbuilder_append_c_str_len (StrBuilder* str, char const* c_str_to_append, ssize length); +GEN_API void strbuilder_trim (StrBuilder str, char const* cut_set); +GEN_API StrBuilder strbuilder_visualize_whitespace(StrBuilder const str); + +StrBuilder strbuilder_make_c_str (AllocatorInfo allocator, char const* str); +StrBuilder strbuilder_make_str (AllocatorInfo allocator, Str str); +StrBuilder strbuilder_fmt (AllocatorInfo allocator, char* buf, ssize buf_size, char const* fmt, ...); +StrBuilder strbuilder_fmt_buf (AllocatorInfo allocator, char const* fmt, ...); +StrBuilder strbuilder_join (AllocatorInfo allocator, char const** parts, ssize num_parts, char const* glue); +bool strbuilder_are_equal (StrBuilder const lhs, StrBuilder const rhs); +bool strbuilder_are_equal_str (StrBuilder const lhs, Str rhs); +bool strbuilder_append_char (StrBuilder* str, char c); +bool strbuilder_append_c_str (StrBuilder* str, char const* c_str_to_append); +bool strbuilder_append_str (StrBuilder* str, Str c_str_to_append); +bool strbuilder_append_string (StrBuilder* str, StrBuilder const other); +bool strbuilder_append_fmt (StrBuilder* str, char const* fmt, ...); +ssize strbuilder_avail_space (StrBuilder const str); +char* strbuilder_back (StrBuilder str); +bool strbuilder_contains_str (StrBuilder const str, Str substring); +bool strbuilder_contains_string (StrBuilder const str, StrBuilder const substring); +ssize strbuilder_capacity (StrBuilder const str); +void strbuilder_clear (StrBuilder str); +StrBuilder strbuilder_duplicate (StrBuilder const str, AllocatorInfo allocator); +void strbuilder_free (StrBuilder* str); +StrBuilderHeader* strbuilder_get_header (StrBuilder str); +ssize strbuilder_length (StrBuilder const str); +b32 strbuilder_starts_with_str (StrBuilder const str, Str substring); +b32 strbuilder_starts_with_string (StrBuilder const str, StrBuilder substring); +void strbuilder_skip_line (StrBuilder str); +void strbuilder_strip_space (StrBuilder str); +Str strbuilder_to_str (StrBuilder str); +void strbuilder_trim_space (StrBuilder str); + +struct StrBuilderHeader { + AllocatorInfo Allocator; + ssize Capacity; + ssize Length; +}; + +#if GEN_COMPILER_CPP +struct StrBuilder +{ + char* Data; + + forceinline operator char*() { return Data; } + forceinline operator char const*() const { return Data; } + forceinline operator Str() const { return { Data, strbuilder_length(* this) }; } + + StrBuilder const& operator=(StrBuilder const& other) const { + if (this == &other) + return *this; + + StrBuilder* this_ = ccast(StrBuilder*, this); + this_->Data = other.Data; + + return *this; + } + + forceinline char& operator[](ssize index) { return Data[index]; } + forceinline char const& operator[](ssize index) const { return Data[index]; } + + forceinline bool operator==(std::nullptr_t) const { return Data == nullptr; } + forceinline bool operator!=(std::nullptr_t) const { return Data != nullptr; } + friend forceinline bool operator==(std::nullptr_t, const StrBuilder str) { return str.Data == nullptr; } + friend forceinline bool operator!=(std::nullptr_t, const StrBuilder str) { return str.Data != nullptr; } + +#if ! GEN_C_LIKE_CPP + forceinline char* begin() const { return Data; } + forceinline char* end() const { return Data + strbuilder_length(* this); } + +#pragma region Member Mapping + forceinline static StrBuilder make(AllocatorInfo allocator, char const* str) { return strbuilder_make_c_str(allocator, str); } + forceinline static StrBuilder make(AllocatorInfo allocator, Str str) { return strbuilder_make_str(allocator, str); } + forceinline static StrBuilder make_reserve(AllocatorInfo allocator, ssize cap) { return strbuilder_make_reserve(allocator, cap); } + forceinline static StrBuilder make_length(AllocatorInfo a, char const* s, ssize l) { return strbuilder_make_length(a, s, l); } + forceinline static StrBuilder join(AllocatorInfo a, char const** p, ssize n, char const* g) { return strbuilder_join(a, p, n, g); } + forceinline static usize grow_formula(usize value) { return strbuilder_grow_formula(value); } + + static + StrBuilder fmt(AllocatorInfo allocator, char* buf, ssize buf_size, char const* fmt, ...) { + va_list va; + va_start(va, fmt); + ssize res = c_str_fmt_va(buf, buf_size, fmt, va) - 1; + va_end(va); + return strbuilder_make_length(allocator, buf, res); + } + + static + StrBuilder fmt_buf(AllocatorInfo allocator, char const* fmt, ...) { + local_persist thread_local + char buf[GEN_PRINTF_MAXLEN] = { 0 }; + va_list va; + va_start(va, fmt); + ssize res = c_str_fmt_va(buf, GEN_PRINTF_MAXLEN, fmt, va) - 1; + va_end(va); + return strbuilder_make_length(allocator, buf, res); + } + + forceinline bool make_space_for(char const* str, ssize add_len) { return strbuilder_make_space_for(this, str, add_len); } + forceinline bool append(char c) { return strbuilder_append_char(this, c); } + forceinline bool append(char const* str) { return strbuilder_append_c_str(this, str); } + forceinline bool append(char const* str, ssize length) { return strbuilder_append_c_str_len(this, str, length); } + forceinline bool append(Str str) { return strbuilder_append_str(this, str); } + forceinline bool append(const StrBuilder other) { return strbuilder_append_string(this, other); } + forceinline ssize avail_space() const { return strbuilder_avail_space(* this); } + forceinline char* back() { return strbuilder_back(* this); } + forceinline bool contains(Str substring) const { return strbuilder_contains_str(* this, substring); } + forceinline bool contains(StrBuilder const& substring) const { return strbuilder_contains_string(* this, substring); } + forceinline ssize capacity() const { return strbuilder_capacity(* this); } + forceinline void clear() { strbuilder_clear(* this); } + forceinline StrBuilder duplicate(AllocatorInfo allocator) const { return strbuilder_duplicate(* this, allocator); } + forceinline void free() { strbuilder_free(this); } + forceinline bool is_equal(StrBuilder const& other) const { return strbuilder_are_equal(* this, other); } + forceinline bool is_equal(Str other) const { return strbuilder_are_equal_str(* this, other); } + forceinline ssize length() const { return strbuilder_length(* this); } + forceinline b32 starts_with(Str substring) const { return strbuilder_starts_with_str(* this, substring); } + forceinline b32 starts_with(StrBuilder substring) const { return strbuilder_starts_with_string(* this, substring); } + forceinline void skip_line() { strbuilder_skip_line(* this); } + forceinline void strip_space() { strbuilder_strip_space(* this); } + forceinline Str to_str() { return { Data, strbuilder_length(*this) }; } + forceinline void trim(char const* cut_set) { strbuilder_trim(* this, cut_set); } + forceinline void trim_space() { strbuilder_trim_space(* this); } + forceinline StrBuilder visualize_whitespace() const { return strbuilder_visualize_whitespace(* this); } + forceinline StrBuilderHeader& get_header() { return * strbuilder_get_header(* this); } + + bool append_fmt(char const* fmt, ...) { + ssize res; + char buf[GEN_PRINTF_MAXLEN] = { 0 }; + + va_list va; + va_start(va, fmt); + res = c_str_fmt_va(buf, count_of(buf) - 1, fmt, va) - 1; + va_end(va); + + return strbuilder_append_c_str_len(this, buf, res); + } +#pragma endregion Member Mapping +#endif +}; +#endif + +forceinline char* strbuilder_begin(StrBuilder str) { return ((char*) str); } +forceinline char* strbuilder_end (StrBuilder str) { return ((char*) str + strbuilder_length(str)); } +forceinline char* strbuilder_next (StrBuilder str, char const* iter) { return ((char*) iter + 1); } + +#if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP +forceinline char* begin(StrBuilder str) { return ((char*) str); } +forceinline char* end (StrBuilder str) { return ((char*) str + strbuilder_length(str)); } +forceinline char* next (StrBuilder str, char* iter) { return ((char*) iter + 1); } +#endif + +#if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP +forceinline bool make_space_for(StrBuilder& str, char const* to_append, ssize add_len); +forceinline bool append(StrBuilder& str, char c); +forceinline bool append(StrBuilder& str, char const* c_str_to_append); +forceinline bool append(StrBuilder& str, char const* c_str_to_append, ssize length); +forceinline bool append(StrBuilder& str, Str c_str_to_append); +forceinline bool append(StrBuilder& str, const StrBuilder other); +forceinline bool append_fmt(StrBuilder& str, char const* fmt, ...); +forceinline char& back(StrBuilder& str); +forceinline void clear(StrBuilder& str); +forceinline void free(StrBuilder& str); +#endif + +forceinline +usize strbuilder_grow_formula(usize value) { + // Using a very aggressive growth formula to reduce time mem_copying with recursive calls to append in this library. + return 4 * value + 8; +} + +forceinline +StrBuilder strbuilder_make_c_str(AllocatorInfo allocator, char const* str) { + ssize length = str ? c_str_len(str) : 0; + return strbuilder_make_length(allocator, str, length); +} + +forceinline +StrBuilder strbuilder_make_str(AllocatorInfo allocator, Str str) { + return strbuilder_make_length(allocator, str.Ptr, str.Len); +} + +inline +StrBuilder strbuilder_fmt(AllocatorInfo allocator, char* buf, ssize buf_size, char const* fmt, ...) { + va_list va; + va_start(va, fmt); + ssize res = c_str_fmt_va(buf, buf_size, fmt, va) - 1; + va_end(va); + + return strbuilder_make_length(allocator, buf, res); +} + +inline +StrBuilder strbuilder_fmt_buf(AllocatorInfo allocator, char const* fmt, ...) +{ + local_persist thread_local + PrintF_Buffer buf = struct_init(PrintF_Buffer, {0}); + + va_list va; + va_start(va, fmt); + ssize res = c_str_fmt_va(buf, GEN_PRINTF_MAXLEN, fmt, va) -1; + va_end(va); + + return strbuilder_make_length(allocator, buf, res); +} + +inline +StrBuilder strbuilder_join(AllocatorInfo allocator, char const** parts, ssize num_parts, char const* glue) +{ + StrBuilder result = strbuilder_make_c_str(allocator, ""); + + for (ssize idx = 0; idx < num_parts; ++idx) + { + strbuilder_append_c_str(& result, parts[idx]); + + if (idx < num_parts - 1) + strbuilder_append_c_str(& result, glue); + } + + return result; +} + +forceinline +bool strbuilder_append_char(StrBuilder* str, char c) { + GEN_ASSERT(str != nullptr); + return strbuilder_append_c_str_len( str, (char const*)& c, (ssize)1); +} + +forceinline +bool strbuilder_append_c_str(StrBuilder* str, char const* c_str_to_append) { + GEN_ASSERT(str != nullptr); + return strbuilder_append_c_str_len(str, c_str_to_append, c_str_len(c_str_to_append)); +} + +forceinline +bool strbuilder_append_str(StrBuilder* str, Str c_str_to_append) { + GEN_ASSERT(str != nullptr); + return strbuilder_append_c_str_len(str, c_str_to_append.Ptr, c_str_to_append.Len); +} + +forceinline +bool strbuilder_append_string(StrBuilder* str, StrBuilder const other) { + GEN_ASSERT(str != nullptr); + return strbuilder_append_c_str_len(str, (char const*)other, strbuilder_length(other)); +} + +inline +bool strbuilder_append_fmt(StrBuilder* str, char const* fmt, ...) { + GEN_ASSERT(str != nullptr); + ssize res; + char buf[GEN_PRINTF_MAXLEN] = { 0 }; + + va_list va; + va_start(va, fmt); + res = c_str_fmt_va(buf, count_of(buf) - 1, fmt, va) - 1; + va_end(va); + + return strbuilder_append_c_str_len(str, (char const*)buf, res); +} + +inline +bool strbuilder_are_equal_string(StrBuilder const lhs, StrBuilder const rhs) +{ + if (strbuilder_length(lhs) != strbuilder_length(rhs)) + return false; + + for (ssize idx = 0; idx < strbuilder_length(lhs); ++idx) + if (lhs[idx] != rhs[idx]) + return false; + + return true; +} + +inline +bool strbuilder_are_equal_str(StrBuilder const lhs, Str rhs) +{ + if (strbuilder_length(lhs) != (rhs.Len)) + return false; + + for (ssize idx = 0; idx < strbuilder_length(lhs); ++idx) + if (lhs[idx] != rhs.Ptr[idx]) + return false; + + return true; +} + +forceinline +ssize strbuilder_avail_space(StrBuilder const str) { + StrBuilderHeader const* header = rcast(StrBuilderHeader const*, scast(char const*, str) - sizeof(StrBuilderHeader)); + return header->Capacity - header->Length; +} + +forceinline +char* strbuilder_back(StrBuilder str) { + return & (str)[strbuilder_length(str) - 1]; +} + +inline +bool strbuilder_contains_StrC(StrBuilder const str, Str substring) +{ + StrBuilderHeader const* header = rcast(StrBuilderHeader const*, scast(char const*, str) - sizeof(StrBuilderHeader)); + + if (substring.Len > header->Length) + return false; + + ssize main_len = header->Length; + ssize sub_len = substring.Len; + + for (ssize idx = 0; idx <= main_len - sub_len; ++idx) + { + if (c_str_compare_len(str + idx, substring.Ptr, sub_len) == 0) + return true; + } + + return false; +} + +inline +bool strbuilder_contains_string(StrBuilder const str, StrBuilder const substring) +{ + StrBuilderHeader const* header = rcast(StrBuilderHeader const*, scast(char const*, str) - sizeof(StrBuilderHeader)); + + if (strbuilder_length(substring) > header->Length) + return false; + + ssize main_len = header->Length; + ssize sub_len = strbuilder_length(substring); + + for (ssize idx = 0; idx <= main_len - sub_len; ++idx) + { + if (c_str_compare_len(str + idx, substring, sub_len) == 0) + return true; + } + + return false; +} + +forceinline +ssize strbuilder_capacity(StrBuilder const str) { + StrBuilderHeader const* header = rcast(StrBuilderHeader const*, scast(char const*, str) - sizeof(StrBuilderHeader)); + return header->Capacity; +} + +forceinline +void strbuilder_clear(StrBuilder str) { + strbuilder_get_header(str)->Length = 0; +} + +forceinline +StrBuilder strbuilder_duplicate(StrBuilder const str, AllocatorInfo allocator) { + return strbuilder_make_length(allocator, str, strbuilder_length(str)); +} + +forceinline +void strbuilder_free(StrBuilder* str) { + GEN_ASSERT(str != nullptr); + if (! (* str)) + return; + + StrBuilderHeader* header = strbuilder_get_header(* str); + allocator_free(header->Allocator, header); +} + +forceinline +StrBuilderHeader* strbuilder_get_header(StrBuilder str) { + return (StrBuilderHeader*)(scast(char*, str) - sizeof(StrBuilderHeader)); +} + +forceinline +ssize strbuilder_length(StrBuilder const str) +{ + StrBuilderHeader const* header = rcast(StrBuilderHeader const*, scast(char const*, str) - sizeof(StrBuilderHeader)); + return header->Length; +} + +forceinline +b32 strbuilder_starts_with_str(StrBuilder const str, Str substring) { + if (substring.Len > strbuilder_length(str)) + return false; + + b32 result = c_str_compare_len(str, substring.Ptr, substring.Len) == 0; + return result; +} + +forceinline +b32 strbuilder_starts_with_string(StrBuilder const str, StrBuilder substring) { + if (strbuilder_length(substring) > strbuilder_length(str)) + return false; + + b32 result = c_str_compare_len(str, substring, strbuilder_length(substring) - 1) == 0; + return result; +} + +inline +void strbuilder_skip_line(StrBuilder str) +{ +#define current (*scanner) + char* scanner = str; + while (current != '\r' && current != '\n') { + ++scanner; + } + + s32 new_length = scanner - str; + + if (current == '\r') { + new_length += 1; + } + + mem_move((char*)str, scanner, new_length); + + StrBuilderHeader* header = strbuilder_get_header(str); + header->Length = new_length; +#undef current +} + +inline +void strbuilder_strip_space(StrBuilder str) +{ + char* write_pos = str; + char* read_pos = str; + + while (* read_pos) + { + if (! char_is_space(* read_pos)) + { + * write_pos = * read_pos; + write_pos++; + } + read_pos++; + } + write_pos[0] = '\0'; // Null-terminate the modified string + + // Update the length if needed + strbuilder_get_header(str)->Length = write_pos - str; +} + +forceinline +Str strbuilder_to_str(StrBuilder str) { + Str result = { (char const*)str, strbuilder_length(str) }; + return result; +} + +forceinline +void strbuilder_trim_space(StrBuilder str) { + strbuilder_trim(str, " \t\r\n\v\f"); +} + +#pragma endregion StrBuilder + +#if GEN_COMPILER_CPP +struct StrBuilder_POD { + char* Data; +}; +static_assert( sizeof( StrBuilder_POD ) == sizeof( StrBuilder ), "StrBuilder is not a POD" ); +#endif + +forceinline +Str str_duplicate(Str str, AllocatorInfo allocator) { + Str result = strbuilder_to_str( strbuilder_make_length(allocator, str.Ptr, str.Len)); + return result; +} + +inline +Str str_visualize_whitespace(Str str, AllocatorInfo allocator) +{ + StrBuilder result = strbuilder_make_reserve(allocator, str.Len * 2); // Assume worst case for space requirements. + for (char const* c = str_begin(str); c != str_end(str); c = str_next(str, c)) + switch ( * c ) + { + case ' ': + strbuilder_append_str(& result, txt("·")); + break; + case '\t': + strbuilder_append_str(& result, txt("→")); + break; + case '\n': + strbuilder_append_str(& result, txt("↵")); + break; + case '\r': + strbuilder_append_str(& result, txt("⏎")); + break; + case '\v': + strbuilder_append_str(& result, txt("⇕")); + break; + case '\f': + strbuilder_append_str(& result, txt("⌂")); + break; + default: + strbuilder_append_char(& result, * c); + break; +} + return strbuilder_to_str(result); +} + +// Represents strings cached with the string table. +// Should never be modified, if changed string is desired, cache_string( str ) another. +typedef Str StrCached; + +// Implements basic string interning. Data structure is based off the ZPL Hashtable. +typedef HashTable(StrCached) StringTable; +#pragma endregion Strings + +#pragma region File Handling + +enum FileModeFlag +{ + EFileMode_READ = bit( 0 ), + EFileMode_WRITE = bit( 1 ), + EFileMode_APPEND = bit( 2 ), + EFileMode_RW = bit( 3 ), + GEN_FILE_MODES = EFileMode_READ | EFileMode_WRITE | EFileMode_APPEND | EFileMode_RW, +}; + +// NOTE: Only used internally and for the file operations +enum SeekWhenceType +{ + ESeekWhence_BEGIN = 0, + ESeekWhence_CURRENT = 1, + ESeekWhence_END = 2, +}; + +enum FileError +{ + EFileError_NONE, + EFileError_INVALID, + EFileError_INVALID_FILENAME, + EFileError_EXISTS, + EFileError_NOT_EXISTS, + EFileError_PERMISSION, + EFileError_TRUNCATION_FAILURE, + EFileError_NOT_EMPTY, + EFileError_NAME_TOO_LONG, + EFileError_UNKNOWN, +}; + +union FileDescriptor +{ + void* p; + sptr i; + uptr u; +}; + +typedef u32 FileMode; +typedef struct FileOperations FileOperations; + +#define GEN_FILE_OPEN_PROC( name ) FileError name( FileDescriptor* fd, FileOperations* ops, FileMode mode, char const* filename ) +#define GEN_FILE_READ_AT_PROC( name ) b32 name( FileDescriptor fd, void* buffer, ssize size, s64 offset, ssize* bytes_read, b32 stop_at_newline ) +#define GEN_FILE_WRITE_AT_PROC( name ) b32 name( FileDescriptor fd, mem_ptr_const buffer, ssize size, s64 offset, ssize* bytes_written ) +#define GEN_FILE_SEEK_PROC( name ) b32 name( FileDescriptor fd, s64 offset, SeekWhenceType whence, s64* new_offset ) +#define GEN_FILE_CLOSE_PROC( name ) void name( FileDescriptor fd ) + +typedef GEN_FILE_OPEN_PROC( file_open_proc ); +typedef GEN_FILE_READ_AT_PROC( FileReadProc ); +typedef GEN_FILE_WRITE_AT_PROC( FileWriteProc ); +typedef GEN_FILE_SEEK_PROC( FileSeekProc ); +typedef GEN_FILE_CLOSE_PROC( FileCloseProc ); + +struct FileOperations +{ + FileReadProc* read_at; + FileWriteProc* write_at; + FileSeekProc* seek; + FileCloseProc* close; +}; + +extern FileOperations const default_file_operations; + +typedef u64 FileTime; + +enum DirType +{ + GEN_DIR_TYPE_FILE, + GEN_DIR_TYPE_FOLDER, + GEN_DIR_TYPE_UNKNOWN, +}; + +struct DirInfo; + +struct DirEntry +{ + char const* filename; + DirInfo* dir_info; + u8 type; +}; + +struct DirInfo +{ + char const* fullpath; + DirEntry* entries; // zpl_array + + // Internals + char** filenames; // zpl_array + StrBuilder buf; +}; + +struct FileInfo +{ + FileOperations ops; + FileDescriptor fd; + b32 is_temp; + + char const* filename; + FileTime last_write_time; + DirEntry* dir; +}; + +enum FileStandardType +{ + EFileStandard_INPUT, + EFileStandard_OUTPUT, + EFileStandard_ERROR, + + EFileStandard_COUNT, +}; + +/** + * Get standard file I/O. + * @param std Check zpl_file_standard_type + * @return File handle to standard I/O + */ +GEN_API FileInfo* file_get_standard( FileStandardType std ); + +/** + * Closes the file + * @param file + */ +GEN_API FileError file_close( FileInfo* file ); + +/** + * Returns the currently opened file's name + * @param file + */ +inline +char const* file_name( FileInfo* file ) +{ + return file->filename ? file->filename : ""; +} + +/** + * Opens a file + * @param file + * @param filename + */ +GEN_API FileError file_open( FileInfo* file, char const* filename ); + +/** + * Opens a file using a specified mode + * @param file + * @param mode Access mode to use + * @param filename + */ +GEN_API FileError file_open_mode( FileInfo* file, FileMode mode, char const* filename ); + +/** + * Reads from a file + * @param file + * @param buffer Buffer to read to + * @param size Size to read + */ +b32 file_read( FileInfo* file, void* buffer, ssize size ); + +/** + * 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 + */ +b32 file_read_at( FileInfo* file, void* buffer, ssize size, s64 offset ); + +/** + * 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 + */ +b32 file_read_at_check( FileInfo* file, void* buffer, ssize size, s64 offset, ssize* bytes_read ); + +typedef struct FileContents FileContents; +struct FileContents +{ + AllocatorInfo allocator; + void* data; + ssize size; +}; + +constexpr b32 file_zero_terminate = true; +constexpr b32 file_no_zero_terminate = false; + +/** + * 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 + */ +GEN_API FileContents file_read_contents( AllocatorInfo a, b32 zero_terminate, char const* filepath ); + +/** + * Returns a size of the file + * @param file + * @return File size + */ +GEN_API s64 file_size( FileInfo* file ); + +/** + * Seeks the file cursor from the beginning of file to a specific position + * @param file + * @param offset Offset to seek to + */ +s64 file_seek( FileInfo* file, s64 offset ); + +/** + * Seeks the file cursor to the end of the file + * @param file + */ +s64 file_seek_to_end( FileInfo* file ); + +/** + * Returns the length from the beginning of the file we've read so far + * @param file + * @return Our current position in file + */ +s64 file_tell( FileInfo* file ); + +/** + * Writes to a file + * @param file + * @param buffer Buffer to read from + * @param size Size to read + */ +b32 file_write( FileInfo* file, void const* buffer, ssize size ); + +/** + * 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 + */ +b32 file_write_at( FileInfo* file, void const* buffer, ssize size, s64 offset ); + +/** + * 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 + */ +b32 file_write_at_check( FileInfo* file, void const* buffer, ssize size, s64 offset, ssize* bytes_written ); + +enum FileStreamFlags : u32 +{ + /* Allows us to write to the buffer directly. Beware: you can not append a new data! */ + EFileStream_WRITABLE = 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. */ + EFileStream_CLONE_WRITABLE = bit( 1 ), + + EFileStream_UNDERLYING = GEN_U32_MAX, +}; + +/** + * Opens a new memory stream + * @param file + * @param allocator + */ +GEN_API b8 file_stream_new( FileInfo* file, AllocatorInfo 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 + */ +GEN_API b8 file_stream_open( FileInfo* file, AllocatorInfo allocator, u8* buffer, ssize size, FileStreamFlags flags ); + +/** + * Retrieves the stream's underlying buffer and buffer size. + * @param file memory stream + * @param size (Optional) buffer size + */ +GEN_API u8* file_stream_buf( FileInfo* file, ssize* size ); + +extern FileOperations const memory_file_operations; + +inline +s64 file_seek( FileInfo* f, s64 offset ) +{ + s64 new_offset = 0; + + if ( ! f->ops.read_at ) + f->ops = default_file_operations; + + f->ops.seek( f->fd, offset, ESeekWhence_BEGIN, &new_offset ); + + return new_offset; +} + +inline +s64 file_seek_to_end( FileInfo* f ) +{ + s64 new_offset = 0; + + if ( ! f->ops.read_at ) + f->ops = default_file_operations; + + f->ops.seek( f->fd, 0, ESeekWhence_END, &new_offset ); + + return new_offset; +} + +inline +s64 file_tell( FileInfo* f ) +{ + s64 new_offset = 0; + + if ( ! f->ops.read_at ) + f->ops = default_file_operations; + + f->ops.seek( f->fd, 0, ESeekWhence_CURRENT, &new_offset ); + + return new_offset; +} + +inline +b32 file_read( FileInfo* f, void* buffer, ssize size ) +{ + s64 cur_offset = file_tell( f ); + b32 result = file_read_at( f, buffer, size, file_tell( f ) ); + file_seek( f, cur_offset + size ); + return result; +} + +inline +b32 file_read_at( FileInfo* f, void* buffer, ssize size, s64 offset ) +{ + return file_read_at_check( f, buffer, size, offset, NULL ); +} + +inline +b32 file_read_at_check( FileInfo* f, void* buffer, ssize size, s64 offset, ssize* bytes_read ) +{ + if ( ! f->ops.read_at ) + f->ops = default_file_operations; + return f->ops.read_at( f->fd, buffer, size, offset, bytes_read, false ); +} + +inline +b32 file_write( FileInfo* f, void const* buffer, ssize size ) +{ + s64 cur_offset = file_tell( f ); + b32 result = file_write_at( f, buffer, size, file_tell( f ) ); + + file_seek( f, cur_offset + size ); + + return result; +} + +inline +b32 file_write_at( FileInfo* f, void const* buffer, ssize size, s64 offset ) +{ + return file_write_at_check( f, buffer, size, offset, NULL ); +} + +inline +b32 file_write_at_check( FileInfo* f, void const* buffer, ssize size, s64 offset, ssize* bytes_written ) +{ + if ( ! f->ops.read_at ) + f->ops = default_file_operations; + + return f->ops.write_at( f->fd, buffer, size, offset, bytes_written ); +} + +#pragma endregion File Handling + +#pragma region Timing + +#ifdef GEN_BENCHMARK +//! Return CPU timestamp. +GEN_API u64 read_cpu_time_stamp_counter( void ); + +//! Return relative time (in seconds) since the application start. +GEN_API f64 time_rel( void ); + +//! Return relative time since the application start. +GEN_API u64 time_rel_ms( void ); +#endif + +#pragma endregion Timing + +#pragma region ADT + +enum ADT_Type : u32 +{ + EADT_TYPE_UNINITIALISED, /* node was not initialised, this is a programming error! */ + EADT_TYPE_ARRAY, + EADT_TYPE_OBJECT, + EADT_TYPE_STRING, + EADT_TYPE_MULTISTRING, + EADT_TYPE_INTEGER, + EADT_TYPE_REAL, +}; + +enum ADT_Props : u32 +{ + EADT_PROPS_NONE, + EADT_PROPS_NAN, + EADT_PROPS_NAN_NEG, + EADT_PROPS_INFINITY, + EADT_PROPS_INFINITY_NEG, + EADT_PROPS_FALSE, + EADT_PROPS_TRUE, + EADT_PROPS_NULL, + EADT_PROPS_IS_EXP, + EADT_PROPS_IS_HEX, + + // Used internally so that people can fill in real numbers they plan to write. + EADT_PROPS_IS_PARSED_REAL, +}; + +enum ADT_NamingStyle : u32 +{ + EADT_NAME_STYLE_DOUBLE_QUOTE, + EADT_NAME_STYLE_SINGLE_QUOTE, + EADT_NAME_STYLE_NO_QUOTES, +}; + +enum ADT_AssignStyle : u32 +{ + EADT_ASSIGN_STYLE_COLON, + EADT_ASSIGN_STYLE_EQUALS, + EADT_ASSIGN_STYLE_LINE, +}; + +enum ADT_DelimStyle : u32 +{ + EADT_DELIM_STYLE_COMMA, + EADT_DELIM_STYLE_LINE, + EADT_DELIM_STYLE_NEWLINE, +}; + +enum ADT_Error : u32 +{ + EADT_ERROR_NONE, + EADT_ERROR_INTERNAL, + EADT_ERROR_ALREADY_CONVERTED, + EADT_ERROR_INVALID_TYPE, + EADT_ERROR_OUT_OF_MEMORY, +}; + +struct ADT_Node +{ + char const* name; + struct ADT_Node* parent; + + /* properties */ + ADT_Type type : 4; + u8 props : 4; +#ifndef GEN_PARSER_DISABLE_ANALYSIS + u8 cfg_mode : 1; + u8 name_style : 2; + u8 assign_style : 2; + u8 delim_style : 2; + u8 delim_line_width : 4; + u8 assign_line_width : 4; +#endif + + /* adt data */ + union + { + char const* string; + Array(ADT_Node) nodes; ///< zpl_array + + struct + { + union + { + f64 real; + s64 integer; + }; + +#ifndef GEN_PARSER_DISABLE_ANALYSIS + /* number analysis */ + s32 base; + s32 base2; + u8 base2_offset : 4; + s8 exp : 4; + u8 neg_zero : 1; + u8 lead_digit : 1; +#endif + }; + }; +}; + +/* 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. + */ + +/** + * @brief Initialise an ADT object or array + * + * @param node + * @param backing Memory allocator used for descendants + * @param name Node's name + * @param is_array + * @return error code + */ +GEN_API u8 adt_make_branch( ADT_Node* node, AllocatorInfo backing, char const* name, b32 is_array ); + +/** + * @brief Destroy an ADT branch and its descendants + * + * @param node + * @return error code + */ +GEN_API u8 adt_destroy_branch( ADT_Node* node ); + +/** + * @brief Initialise an ADT leaf + * + * @param node + * @param name Node's name + * @param type Node's type (use zpl_adt_make_branch for container nodes) + * @return error code + */ +GEN_API u8 adt_make_leaf( ADT_Node* node, char const* name, ADT_Type type ); + + +/** + * @brief Fetch a node using provided URI string. + * + * This method uses a basic syntax to fetch a node from the ADT. The following features are available + * to retrieve the data: + * + * - "a/b/c" navigates through objects "a" and "b" to get to "c" + * - "arr/[foo=123]/bar" iterates over "arr" to find any object with param "foo" that matches the value "123", then gets its field called "bar" + * - "arr/3" retrieves the 4th element in "arr" + * - "arr/[apple]" retrieves the first element of value "apple" in "arr" + * + * @param node ADT node + * @param uri Locator string as described above + * @return zpl_adt_node* + * + * @see code/apps/examples/json_get.c + */ +GEN_API ADT_Node* adt_query( ADT_Node* node, char const* uri ); + +/** + * @brief Find a field node within an object by the given name. + * + * @param node + * @param name + * @param deep_search Perform search recursively + * @return zpl_adt_node * node + */ +GEN_API ADT_Node* adt_find( ADT_Node* node, char const* name, b32 deep_search ); + +/** + * @brief Allocate an unitialised node within a container at a specified index. + * + * @param parent + * @param index + * @return zpl_adt_node * node + */ +GEN_API ADT_Node* adt_alloc_at( ADT_Node* parent, ssize index ); + +/** + * @brief Allocate an unitialised node within a container. + * + * @param parent + * @return zpl_adt_node * node + */ +GEN_API ADT_Node* adt_alloc( ADT_Node* parent ); + +/** + * @brief Move an existing node to a new container at a specified index. + * + * @param node + * @param new_parent + * @param index + * @return zpl_adt_node * node + */ +GEN_API ADT_Node* adt_move_node_at( ADT_Node* node, ADT_Node* new_parent, ssize index ); + +/** + * @brief Move an existing node to a new container. + * + * @param node + * @param new_parent + * @return zpl_adt_node * node + */ +GEN_API ADT_Node* adt_move_node( ADT_Node* node, ADT_Node* new_parent ); + +/** + * @brief Swap two nodes. + * + * @param node + * @param other_node + * @return + */ +GEN_API void adt_swap_nodes( ADT_Node* node, ADT_Node* other_node ); + +/** + * @brief Remove node from container. + * + * @param node + * @return + */ +GEN_API void adt_remove_node( ADT_Node* node ); + +/** + * @brief Initialise a node as an object + * + * @param obj + * @param name + * @param backing + * @return + */ +GEN_API b8 adt_set_obj( ADT_Node* obj, char const* name, AllocatorInfo backing ); + +/** + * @brief Initialise a node as an array + * + * @param obj + * @param name + * @param backing + * @return + */ +GEN_API b8 adt_set_arr( ADT_Node* obj, char const* name, AllocatorInfo backing ); + +/** + * @brief Initialise a node as a string + * + * @param obj + * @param name + * @param value + * @return + */ +GEN_API b8 adt_set_str( ADT_Node* obj, char const* name, char const* value ); + +/** + * @brief Initialise a node as a float + * + * @param obj + * @param name + * @param value + * @return + */ +GEN_API b8 adt_set_flt( ADT_Node* obj, char const* name, f64 value ); + +/** + * @brief Initialise a node as a signed integer + * + * @param obj + * @param name + * @param value + * @return + */ +GEN_API b8 adt_set_int( ADT_Node* obj, char const* name, s64 value ); + +/** + * @brief Append a new node to a container as an object + * + * @param parent + * @param name + * @return* + */ +GEN_API ADT_Node* adt_append_obj( ADT_Node* parent, char const* name ); + +/** + * @brief Append a new node to a container as an array + * + * @param parent + * @param name + * @return* + */ +GEN_API ADT_Node* adt_append_arr( ADT_Node* parent, char const* name ); + +/** + * @brief Append a new node to a container as a string + * + * @param parent + * @param name + * @param value + * @return* + */ +GEN_API ADT_Node* adt_append_str( ADT_Node* parent, char const* name, char const* value ); + +/** + * @brief Append a new node to a container as a float + * + * @param parent + * @param name + * @param value + * @return* + */ +GEN_API ADT_Node* adt_append_flt( ADT_Node* parent, char const* name, f64 value ); + +/** + * @brief Append a new node to a container as a signed integer + * + * @param parent + * @param name + * @param value + * @return* + */ +GEN_API ADT_Node* adt_append_int( ADT_Node* parent, char const* name, s64 value ); + +/* parser helpers */ + +/** + * @brief Parses a text and stores the result into an unitialised node. + * + * @param node + * @param base + * @return* + */ +GEN_API char* adt_parse_number( ADT_Node* node, char* base ); + +/** + * @brief Parses a text and stores the result into an unitialised node. + * This function expects the entire input to be a number. + * + * @param node + * @param base + * @return* + */ +GEN_API char* adt_parse_number_strict( ADT_Node* node, char* base_str ); + +/** + * @brief Parses and converts an existing string node into a number. + * + * @param node + * @return + */ +GEN_API ADT_Error adt_c_str_to_number( ADT_Node* node ); + +/** + * @brief Parses and converts an existing string node into a number. + * This function expects the entire input to be a number. + * + * @param node + * @return + */ +GEN_API ADT_Error adt_c_str_to_number_strict( ADT_Node* node ); + +/** + * @brief Prints a number into a file stream. + * + * The provided file handle can also be a memory mapped stream. + * + * @see zpl_file_stream_new + * @param file + * @param node + * @return + */ +GEN_API ADT_Error adt_print_number( FileInfo* file, ADT_Node* node ); + +/** + * @brief Prints a string into a file stream. + * + * The provided file handle can also be a memory mapped stream. + * + * @see zpl_file_stream_new + * @param file + * @param node + * @param escaped_chars + * @param escape_symbol + * @return + */ +GEN_API ADT_Error adt_print_string( FileInfo* file, ADT_Node* node, char const* escaped_chars, char const* escape_symbol ); + +#pragma endregion ADT + +#pragma region CSV + +enum CSV_Error : u32 +{ + ECSV_Error__NONE, + ECSV_Error__INTERNAL, + ECSV_Error__UNEXPECTED_END_OF_INPUT, + ECSV_Error__MISMATCHED_ROWS, +}; + +typedef ADT_Node CSV_Object; + + u8 csv_parse( CSV_Object* root, char* text, AllocatorInfo allocator, b32 has_header ); +GEN_API u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b32 has_header, char delim ); + void csv_free( CSV_Object* obj ); + + void csv_write( FileInfo* file, CSV_Object* obj ); + StrBuilder csv_write_string( AllocatorInfo a, CSV_Object* obj ); +GEN_API void csv_write_delimiter( FileInfo* file, CSV_Object* obj, char delim ); +GEN_API StrBuilder csv_write_strbuilder_delimiter( AllocatorInfo a, CSV_Object* obj, char delim ); + +/* inline */ + +inline +u8 csv_parse( CSV_Object* root, char* text, AllocatorInfo allocator, b32 has_header ) +{ + return csv_parse_delimiter( root, text, allocator, has_header, ',' ); +} + +inline +void csv_write( FileInfo* file, CSV_Object* obj ) +{ + csv_write_delimiter( file, obj, ',' ); +} + +inline +StrBuilder csv_write_string( AllocatorInfo a, CSV_Object* obj ) +{ + return csv_write_strbuilder_delimiter( a, obj, ',' ); +} + +#pragma endregion CSV + +GEN_NS_END + +// GEN_ROLL_OWN_DEPENDENCIES +#endif + +GEN_NS_BEGIN + +#pragma region Types + +/* + ________ __ __ ________ +| \ | \ | \ | \ +| ▓▓▓▓▓▓▓▓_______ __ __ ______ ____ _______ | ▓▓\ | ▓▓ \▓▓▓▓▓▓▓▓__ __ ______ ______ _______ +| ▓▓__ | \| \ | \ \ \ / \ | ▓▓▓\| ▓▓ | ▓▓ | \ | \/ \ / \ / \ +| ▓▓ \ | ▓▓▓▓▓▓▓\ ▓▓ | ▓▓ ▓▓▓▓▓▓\▓▓▓▓\ ▓▓▓▓▓▓▓ | ▓▓▓▓\ ▓▓ | ▓▓ | ▓▓ | ▓▓ ▓▓▓▓▓▓\ ▓▓▓▓▓▓\ ▓▓▓▓▓▓▓ +| ▓▓▓▓▓ | ▓▓ | ▓▓ ▓▓ | ▓▓ ▓▓ | ▓▓ | ▓▓\▓▓ \ | ▓▓\▓▓ ▓▓ | ▓▓ | ▓▓ | ▓▓ ▓▓ | ▓▓ ▓▓ ▓▓\▓▓ \ +| ▓▓_____| ▓▓ | ▓▓ ▓▓__/ ▓▓ ▓▓ | ▓▓ | ▓▓_\▓▓▓▓▓▓\ | ▓▓ \▓▓▓▓ | ▓▓ | ▓▓__/ ▓▓ ▓▓__/ ▓▓ ▓▓▓▓▓▓▓▓_\▓▓▓▓▓▓\ +| ▓▓ \ ▓▓ | ▓▓\▓▓ ▓▓ ▓▓ | ▓▓ | ▓▓ ▓▓ | ▓▓ \▓▓▓ | ▓▓ \▓▓ ▓▓ ▓▓ ▓▓\▓▓ \ ▓▓ + \▓▓▓▓▓▓▓▓\▓▓ \▓▓ \▓▓▓▓▓▓ \▓▓ \▓▓ \▓▓\▓▓▓▓▓▓▓ \▓▓ \▓▓ \▓▓ _\▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓\▓▓▓▓▓▓▓ + | \__| ▓▓ ▓▓ + \▓▓ ▓▓ ▓▓ + \▓▓▓▓▓▓ \▓▓ + +*/ + +using LogFailType = ssize(*)(char const*, ...); + +// By default this library will either crash or exit if an error is detected while generating codes. +// Even if set to not use GEN_FATAL, GEN_FATAL will still be used for memory failures as the library is unusable when they occur. +#ifdef GEN_DONT_USE_FATAL + #define log_failure log_fmt +#else + #define log_failure GEN_FATAL +#endif + +enum AccessSpec : u32 +{ + AccessSpec_Default, + AccessSpec_Private, + AccessSpec_Protected, + AccessSpec_Public, + + AccessSpec_Num_AccessSpec, + AccessSpec_Invalid, + + AccessSpec_SizeDef = GEN_U32_MAX, +}; +static_assert( size_of(AccessSpec) == size_of(u32), "AccessSpec not u32 size" ); + +inline +Str access_spec_to_str( AccessSpec type ) +{ + local_persist + Str lookup[ (u32)AccessSpec_Num_AccessSpec ] = { + { "", sizeof( "" ) - 1 }, + { "private", sizeof("prviate") - 1 }, + { "private", sizeof("protected") - 1 }, + { "public", sizeof("public") - 1 }, + }; + + Str invalid = { "Invalid", sizeof("Invalid") - 1 }; + if ( type > AccessSpec_Public ) + return invalid; + + return lookup[ (u32)type ]; +} + +enum CodeFlag : u32 +{ + CodeFlag_None = 0, + CodeFlag_FunctionType = bit(0), + CodeFlag_ParamPack = bit(1), + CodeFlag_Module_Export = bit(2), + CodeFlag_Module_Import = bit(3), + + CodeFlag_SizeDef = GEN_U32_MAX, +}; +static_assert( size_of(CodeFlag) == size_of(u32), "CodeFlag not u32 size" ); + +// Used to indicate if enum definitoin is an enum class or regular enum. +enum EnumDecl : u8 +{ + EnumDecl_Regular, + EnumDecl_Class, + + EnumT_SizeDef = GEN_U8_MAX, +}; +typedef u8 EnumT; + +enum ModuleFlag : u32 +{ + ModuleFlag_None = 0, + ModuleFlag_Export = bit(0), + ModuleFlag_Import = bit(1), + + Num_ModuleFlags, + ModuleFlag_Invalid, + + ModuleFlag_SizeDef = GEN_U32_MAX, +}; +static_assert( size_of(ModuleFlag) == size_of(u32), "ModuleFlag not u32 size" ); + +inline +Str module_flag_to_str( ModuleFlag flag ) +{ + local_persist + Str lookup[ (u32)Num_ModuleFlags ] = { + { "__none__", sizeof("__none__") - 1 }, + { "export", sizeof("export") - 1 }, + { "import", sizeof("import") - 1 }, + }; + + local_persist + Str invalid_flag = { "invalid", sizeof("invalid") }; + if ( flag > ModuleFlag_Import ) + return invalid_flag; + + return lookup[ (u32)flag ]; +} + +enum EPreprocessCond : u32 +{ + PreprocessCond_If, + PreprocessCond_IfDef, + PreprocessCond_IfNotDef, + PreprocessCond_ElIf, + + EPreprocessCond_SizeDef = GEN_U32_MAX, +}; +static_assert( size_of(EPreprocessCond) == size_of(u32), "EPreprocessCond not u32 size" ); + +enum ETypenameTag : u16 +{ + Tag_None, + Tag_Class, + Tag_Enum, + Tag_Struct, + Tag_Union, + + Tag_UnderlyingType = GEN_U16_MAX, +}; +static_assert( size_of(ETypenameTag) == size_of(u16), "ETypenameTag is not u16 size"); + +enum CodeType : u32 +{ + CT_Invalid, + CT_Untyped, + CT_NewLine, + CT_Comment, + CT_Access_Private, + CT_Access_Protected, + CT_Access_Public, + CT_PlatformAttributes, + CT_Class, + CT_Class_Fwd, + CT_Class_Body, + CT_Constructor, + CT_Constructor_Fwd, + CT_Destructor, + CT_Destructor_Fwd, + CT_Enum, + CT_Enum_Fwd, + CT_Enum_Body, + CT_Enum_Class, + CT_Enum_Class_Fwd, + CT_Execution, + CT_Export_Body, + CT_Extern_Linkage, + CT_Extern_Linkage_Body, + CT_Friend, + CT_Function, + CT_Function_Fwd, + CT_Function_Body, + CT_Global_Body, + CT_Module, + CT_Namespace, + CT_Namespace_Body, + CT_Operator, + CT_Operator_Fwd, + CT_Operator_Member, + CT_Operator_Member_Fwd, + CT_Operator_Cast, + CT_Operator_Cast_Fwd, + CT_Parameters, + CT_Parameters_Define, + CT_Preprocess_Define, + CT_Preprocess_Include, + CT_Preprocess_If, + CT_Preprocess_IfDef, + CT_Preprocess_IfNotDef, + CT_Preprocess_ElIf, + CT_Preprocess_Else, + CT_Preprocess_EndIf, + CT_Preprocess_Pragma, + CT_Specifiers, + CT_Struct, + CT_Struct_Fwd, + CT_Struct_Body, + CT_Template, + CT_Typedef, + CT_Typename, + CT_Union, + CT_Union_Fwd, + CT_Union_Body, + CT_Using, + CT_Using_Namespace, + CT_Variable, + CT_NumTypes, + CT_UnderlyingType = GEN_U32_MAX +}; + +inline Str codetype_to_str(CodeType type) +{ + local_persist Str lookup[] = { + { "Invalid", sizeof("Invalid") - 1 }, + { "Untyped", sizeof("Untyped") - 1 }, + { "NewLine", sizeof("NewLine") - 1 }, + { "Comment", sizeof("Comment") - 1 }, + { "Access_Private", sizeof("Access_Private") - 1 }, + { "Access_Protected", sizeof("Access_Protected") - 1 }, + { "Access_Public", sizeof("Access_Public") - 1 }, + { "PlatformAttributes", sizeof("PlatformAttributes") - 1 }, + { "Class", sizeof("Class") - 1 }, + { "Class_Fwd", sizeof("Class_Fwd") - 1 }, + { "Class_Body", sizeof("Class_Body") - 1 }, + { "Constructor", sizeof("Constructor") - 1 }, + { "Constructor_Fwd", sizeof("Constructor_Fwd") - 1 }, + { "Destructor", sizeof("Destructor") - 1 }, + { "Destructor_Fwd", sizeof("Destructor_Fwd") - 1 }, + { "Enum", sizeof("Enum") - 1 }, + { "Enum_Fwd", sizeof("Enum_Fwd") - 1 }, + { "Enum_Body", sizeof("Enum_Body") - 1 }, + { "Enum_Class", sizeof("Enum_Class") - 1 }, + { "Enum_Class_Fwd", sizeof("Enum_Class_Fwd") - 1 }, + { "Execution", sizeof("Execution") - 1 }, + { "Export_Body", sizeof("Export_Body") - 1 }, + { "Extern_Linkage", sizeof("Extern_Linkage") - 1 }, + { "Extern_Linkage_Body", sizeof("Extern_Linkage_Body") - 1 }, + { "Friend", sizeof("Friend") - 1 }, + { "Function", sizeof("Function") - 1 }, + { "Function_Fwd", sizeof("Function_Fwd") - 1 }, + { "Function_Body", sizeof("Function_Body") - 1 }, + { "Global_Body", sizeof("Global_Body") - 1 }, + { "Module", sizeof("Module") - 1 }, + { "Namespace", sizeof("Namespace") - 1 }, + { "Namespace_Body", sizeof("Namespace_Body") - 1 }, + { "Operator", sizeof("Operator") - 1 }, + { "Operator_Fwd", sizeof("Operator_Fwd") - 1 }, + { "Operator_Member", sizeof("Operator_Member") - 1 }, + { "Operator_Member_Fwd", sizeof("Operator_Member_Fwd") - 1 }, + { "Operator_Cast", sizeof("Operator_Cast") - 1 }, + { "Operator_Cast_Fwd", sizeof("Operator_Cast_Fwd") - 1 }, + { "Parameters", sizeof("Parameters") - 1 }, + { "Parameters_Define", sizeof("Parameters_Define") - 1 }, + { "Preprocess_Define", sizeof("Preprocess_Define") - 1 }, + { "Preprocess_Include", sizeof("Preprocess_Include") - 1 }, + { "Preprocess_If", sizeof("Preprocess_If") - 1 }, + { "Preprocess_IfDef", sizeof("Preprocess_IfDef") - 1 }, + { "Preprocess_IfNotDef", sizeof("Preprocess_IfNotDef") - 1 }, + { "Preprocess_ElIf", sizeof("Preprocess_ElIf") - 1 }, + { "Preprocess_Else", sizeof("Preprocess_Else") - 1 }, + { "Preprocess_EndIf", sizeof("Preprocess_EndIf") - 1 }, + { "Preprocess_Pragma", sizeof("Preprocess_Pragma") - 1 }, + { "Specifiers", sizeof("Specifiers") - 1 }, + { "Struct", sizeof("Struct") - 1 }, + { "Struct_Fwd", sizeof("Struct_Fwd") - 1 }, + { "Struct_Body", sizeof("Struct_Body") - 1 }, + { "Template", sizeof("Template") - 1 }, + { "Typedef", sizeof("Typedef") - 1 }, + { "Typename", sizeof("Typename") - 1 }, + { "Union", sizeof("Union") - 1 }, + { "Union_Fwd", sizeof("Union_Fwd") - 1 }, + { "Union_Body", sizeof("Union_Body") - 1 }, + { "Using", sizeof("Using") - 1 }, + { "Using_Namespace", sizeof("Using_Namespace") - 1 }, + { "Variable", sizeof("Variable") - 1 }, + }; + return lookup[type]; +} + +inline Str codetype_to_keyword_str(CodeType type) +{ + local_persist Str lookup[] = { + { "__NA__", sizeof("__NA__") - 1 }, + { "__NA__", sizeof("__NA__") - 1 }, + { "__NA__", sizeof("__NA__") - 1 }, + { "//", sizeof("//") - 1 }, + { "private", sizeof("private") - 1 }, + { "protected", sizeof("protected") - 1 }, + { "public", sizeof("public") - 1 }, + { "__NA__", sizeof("__NA__") - 1 }, + { "class", sizeof("class") - 1 }, + { "clsss", sizeof("clsss") - 1 }, + { "__NA__", sizeof("__NA__") - 1 }, + { "__NA__", sizeof("__NA__") - 1 }, + { "__NA__", sizeof("__NA__") - 1 }, + { "__NA__", sizeof("__NA__") - 1 }, + { "__NA__", sizeof("__NA__") - 1 }, + { "enum", sizeof("enum") - 1 }, + { "enum", sizeof("enum") - 1 }, + { "__NA__", sizeof("__NA__") - 1 }, + { "enum class", sizeof("enum class") - 1 }, + { "enum class", sizeof("enum class") - 1 }, + { "__NA__", sizeof("__NA__") - 1 }, + { "__NA__", sizeof("__NA__") - 1 }, + { "extern", sizeof("extern") - 1 }, + { "extern", sizeof("extern") - 1 }, + { "friend", sizeof("friend") - 1 }, + { "__NA__", sizeof("__NA__") - 1 }, + { "__NA__", sizeof("__NA__") - 1 }, + { "__NA__", sizeof("__NA__") - 1 }, + { "__NA__", sizeof("__NA__") - 1 }, + { "module", sizeof("module") - 1 }, + { "namespace", sizeof("namespace") - 1 }, + { "__NA__", sizeof("__NA__") - 1 }, + { "operator", sizeof("operator") - 1 }, + { "operator", sizeof("operator") - 1 }, + { "operator", sizeof("operator") - 1 }, + { "operator", sizeof("operator") - 1 }, + { "operator", sizeof("operator") - 1 }, + { "operator", sizeof("operator") - 1 }, + { "__NA__", sizeof("__NA__") - 1 }, + { "__NA__", sizeof("__NA__") - 1 }, + { "define", sizeof("define") - 1 }, + { "include", sizeof("include") - 1 }, + { "if", sizeof("if") - 1 }, + { "ifdef", sizeof("ifdef") - 1 }, + { "ifndef", sizeof("ifndef") - 1 }, + { "elif", sizeof("elif") - 1 }, + { "else", sizeof("else") - 1 }, + { "endif", sizeof("endif") - 1 }, + { "pragma", sizeof("pragma") - 1 }, + { "__NA__", sizeof("__NA__") - 1 }, + { "struct", sizeof("struct") - 1 }, + { "struct", sizeof("struct") - 1 }, + { "__NA__", sizeof("__NA__") - 1 }, + { "template", sizeof("template") - 1 }, + { "typedef", sizeof("typedef") - 1 }, + { "__NA__", sizeof("__NA__") - 1 }, + { "union", sizeof("union") - 1 }, + { "union", sizeof("union") - 1 }, + { "__NA__", sizeof("__NA__") - 1 }, + { "using", sizeof("using") - 1 }, + { "using namespace", sizeof("using namespace") - 1 }, + { "__NA__", sizeof("__NA__") - 1 }, + }; + return lookup[type]; +} + +forceinline Str to_str(CodeType type) +{ + return codetype_to_str(type); +} + +forceinline Str to_keyword_str(CodeType type) +{ + return codetype_to_keyword_str(type); +} + +enum Operator : u32 +{ + Op_Invalid, + Op_Assign, + Op_Assign_Add, + Op_Assign_Subtract, + Op_Assign_Multiply, + Op_Assign_Divide, + Op_Assign_Modulo, + Op_Assign_BAnd, + Op_Assign_BOr, + Op_Assign_BXOr, + Op_Assign_LShift, + Op_Assign_RShift, + Op_Increment, + Op_Decrement, + Op_Unary_Plus, + Op_Unary_Minus, + Op_UnaryNot, + Op_Add, + Op_Subtract, + Op_Multiply, + Op_Divide, + Op_Modulo, + Op_BNot, + Op_BAnd, + Op_BOr, + Op_BXOr, + Op_LShift, + Op_RShift, + Op_LAnd, + Op_LOr, + Op_LEqual, + Op_LNot, + Op_Lesser, + Op_Greater, + Op_LesserEqual, + Op_GreaterEqual, + Op_Subscript, + Op_Indirection, + Op_AddressOf, + Op_MemberOfPointer, + Op_PtrToMemOfPtr, + Op_FunctionCall, + Op_Comma, + Op_New, + Op_NewArray, + Op_Delete, + Op_DeleteArray, + Op_NumOps, + Op_UnderlyingType = 0xffffffffu +}; + +inline Str operator_to_str(Operator op) +{ + local_persist Str lookup[] = { + { "INVALID", sizeof("INVALID") - 1 }, + { "=", sizeof("=") - 1 }, + { "+=", sizeof("+=") - 1 }, + { "-=", sizeof("-=") - 1 }, + { "*=", sizeof("*=") - 1 }, + { "/=", sizeof("/=") - 1 }, + { "%=", sizeof("%=") - 1 }, + { "&=", sizeof("&=") - 1 }, + { "|=", sizeof("|=") - 1 }, + { "^=", sizeof("^=") - 1 }, + { "<<=", sizeof("<<=") - 1 }, + { ">>=", sizeof(">>=") - 1 }, + { "++", sizeof("++") - 1 }, + { "--", sizeof("--") - 1 }, + { "+", sizeof("+") - 1 }, + { "-", sizeof("-") - 1 }, + { "!", sizeof("!") - 1 }, + { "+", sizeof("+") - 1 }, + { "-", sizeof("-") - 1 }, + { "*", sizeof("*") - 1 }, + { "/", sizeof("/") - 1 }, + { "%", sizeof("%") - 1 }, + { "~", sizeof("~") - 1 }, + { "&", sizeof("&") - 1 }, + { "|", sizeof("|") - 1 }, + { "^", sizeof("^") - 1 }, + { "<<", sizeof("<<") - 1 }, + { ">>", sizeof(">>") - 1 }, + { "&&", sizeof("&&") - 1 }, + { "||", sizeof("||") - 1 }, + { "==", sizeof("==") - 1 }, + { "!=", sizeof("!=") - 1 }, + { "<", sizeof("<") - 1 }, + { ">", sizeof(">") - 1 }, + { "<=", sizeof("<=") - 1 }, + { ">=", sizeof(">=") - 1 }, + { "[]", sizeof("[]") - 1 }, + { "*", sizeof("*") - 1 }, + { "&", sizeof("&") - 1 }, + { "->", sizeof("->") - 1 }, + { "->*", sizeof("->*") - 1 }, + { "()", sizeof("()") - 1 }, + { ",", sizeof(",") - 1 }, + { "new", sizeof("new") - 1 }, + { "new[]", sizeof("new[]") - 1 }, + { "delete", sizeof("delete") - 1 }, + { "delete[]", sizeof("delete[]") - 1 }, + }; + return lookup[op]; +} + +forceinline Str to_str(Operator op) +{ + return operator_to_str(op); +} + +enum Specifier : u32 +{ + Spec_Invalid, + Spec_Consteval, + Spec_Constexpr, + Spec_Constinit, + Spec_Explicit, + Spec_External_Linkage, + Spec_ForceInline, + Spec_Global, + Spec_Inline, + Spec_Internal_Linkage, + Spec_Local_Persist, + Spec_Mutable, + Spec_NeverInline, + Spec_Ptr, + Spec_Ref, + Spec_Register, + Spec_Restrict, + Spec_RValue, + Spec_Static, + Spec_Thread_Local, + Spec_Virtual, + Spec_Const, + Spec_Final, + Spec_NoExceptions, + Spec_Override, + Spec_Pure, + Spec_Delete, + Spec_Volatile, + Spec_NumSpecifiers, + Spec_UnderlyingType = 0xffffffffu +}; + +inline Str spec_to_str(Specifier type) +{ + local_persist Str lookup[] = { + { "INVALID", sizeof("INVALID") - 1 }, + { "consteval", sizeof("consteval") - 1 }, + { "constexpr", sizeof("constexpr") - 1 }, + { "constinit", sizeof("constinit") - 1 }, + { "explicit", sizeof("explicit") - 1 }, + { "extern", sizeof("extern") - 1 }, + { "forceinline", sizeof("forceinline") - 1 }, + { "global", sizeof("global") - 1 }, + { "inline", sizeof("inline") - 1 }, + { "internal", sizeof("internal") - 1 }, + { "local_persist", sizeof("local_persist") - 1 }, + { "mutable", sizeof("mutable") - 1 }, + { "neverinline", sizeof("neverinline") - 1 }, + { "*", sizeof("*") - 1 }, + { "&", sizeof("&") - 1 }, + { "register", sizeof("register") - 1 }, + { "restrict", sizeof("restrict") - 1 }, + { "&&", sizeof("&&") - 1 }, + { "static", sizeof("static") - 1 }, + { "thread_local", sizeof("thread_local") - 1 }, + { "virtual", sizeof("virtual") - 1 }, + { "const", sizeof("const") - 1 }, + { "final", sizeof("final") - 1 }, + { "noexcept", sizeof("noexcept") - 1 }, + { "override", sizeof("override") - 1 }, + { "= 0", sizeof("= 0") - 1 }, + { "= delete", sizeof("= delete") - 1 }, + { "volatile", sizeof("volatile") - 1 }, + }; + return lookup[type]; +} + +inline bool spec_is_trailing(Specifier specifier) +{ + switch (specifier) + { + case Spec_Const: + case Spec_Final: + case Spec_NoExceptions: + case Spec_Override: + case Spec_Pure: + case Spec_Delete: + case Spec_Volatile: + return true; + default: + return false; + } +} + +inline Specifier str_to_specifier(Str str) +{ + local_persist u32 keymap[Spec_NumSpecifiers]; + do_once_start for (u32 index = 0; index < Spec_NumSpecifiers; index++) + { + Str enum_str = spec_to_str((Specifier)index); + keymap[index] = crc32(enum_str.Ptr, enum_str.Len); + } + do_once_end u32 hash = crc32(str.Ptr, str.Len); + for (u32 index = 0; index < Spec_NumSpecifiers; index++) + { + if (keymap[index] == hash) + return (Specifier)index; + } + return Spec_Invalid; +} + +forceinline Str to_str(Specifier spec) +{ + return spec_to_str(spec); +} + +forceinline Specifier to_type(Str str) +{ + return str_to_specifier(str); +} + +forceinline bool is_trailing(Specifier specifier) +{ + return spec_is_trailing(specifier); +} + +#define GEN_DEFINE_ATTRIBUTE_TOKENS Entry(Tok_Attribute_GEN_API, "GEN_API") + +enum TokType : u32 +{ + Tok_Invalid, + Tok_Access_Private, + Tok_Access_Protected, + Tok_Access_Public, + Tok_Access_MemberSymbol, + Tok_Access_StaticSymbol, + Tok_Ampersand, + Tok_Ampersand_DBL, + Tok_Assign_Classifer, + Tok_Attribute_Open, + Tok_Attribute_Close, + Tok_BraceCurly_Open, + Tok_BraceCurly_Close, + Tok_BraceSquare_Open, + Tok_BraceSquare_Close, + Tok_Paren_Open, + Tok_Paren_Close, + Tok_Comment, + Tok_Comment_End, + Tok_Comment_Start, + Tok_Char, + Tok_Comma, + Tok_Decl_Class, + Tok_Decl_GNU_Attribute, + Tok_Decl_MSVC_Attribute, + Tok_Decl_Enum, + Tok_Decl_Extern_Linkage, + Tok_Decl_Friend, + Tok_Decl_Module, + Tok_Decl_Namespace, + Tok_Decl_Operator, + Tok_Decl_Struct, + Tok_Decl_Template, + Tok_Decl_Typedef, + Tok_Decl_Using, + Tok_Decl_Union, + Tok_Identifier, + Tok_Module_Import, + Tok_Module_Export, + Tok_NewLine, + Tok_Number, + Tok_Operator, + Tok_Preprocess_Hash, + Tok_Preprocess_Define, + Tok_Preprocess_Define_Param, + Tok_Preprocess_If, + Tok_Preprocess_IfDef, + Tok_Preprocess_IfNotDef, + Tok_Preprocess_ElIf, + Tok_Preprocess_Else, + Tok_Preprocess_EndIf, + Tok_Preprocess_Include, + Tok_Preprocess_Pragma, + Tok_Preprocess_Content, + Tok_Preprocess_Macro_Expr, + Tok_Preprocess_Macro_Stmt, + Tok_Preprocess_Macro_Typename, + Tok_Preprocess_Unsupported, + Tok_Spec_Alignas, + Tok_Spec_Const, + Tok_Spec_Consteval, + Tok_Spec_Constexpr, + Tok_Spec_Constinit, + Tok_Spec_Explicit, + Tok_Spec_Extern, + Tok_Spec_Final, + Tok_Spec_ForceInline, + Tok_Spec_Global, + Tok_Spec_Inline, + Tok_Spec_Internal_Linkage, + Tok_Spec_LocalPersist, + Tok_Spec_Mutable, + Tok_Spec_NeverInline, + Tok_Spec_Override, + Tok_Spec_Restrict, + Tok_Spec_Static, + Tok_Spec_ThreadLocal, + Tok_Spec_Volatile, + Tok_Spec_Virtual, + Tok_Star, + Tok_Statement_End, + Tok_StaticAssert, + Tok_String, + Tok_Type_Typename, + Tok_Type_Unsigned, + Tok_Type_Signed, + Tok_Type_Short, + Tok_Type_Long, + Tok_Type_bool, + Tok_Type_char, + Tok_Type_int, + Tok_Type_double, + Tok_Type_MS_int8, + Tok_Type_MS_int16, + Tok_Type_MS_int32, + Tok_Type_MS_int64, + Tok_Type_MS_W64, + Tok_Varadic_Argument, + Tok___Attributes_Start, + Tok_Attribute_GEN_API, + Tok_NumTokens +}; + +inline Str toktype_to_str(TokType type) +{ + local_persist Str lookup[] = { + { "__invalid__", sizeof("__invalid__") - 1 }, + { "private", sizeof("private") - 1 }, + { "protected", sizeof("protected") - 1 }, + { "public", sizeof("public") - 1 }, + { ".", sizeof(".") - 1 }, + { "::", sizeof("::") - 1 }, + { "&", sizeof("&") - 1 }, + { "&&", sizeof("&&") - 1 }, + { ":", sizeof(":") - 1 }, + { "[[", sizeof("[[") - 1 }, + { "]]", sizeof("]]") - 1 }, + { "{", sizeof("{") - 1 }, + { "}", sizeof("}") - 1 }, + { "[", sizeof("[") - 1 }, + { "]", sizeof("]") - 1 }, + { "(", sizeof("(") - 1 }, + { ")", sizeof(")") - 1 }, + { "__comment__", sizeof("__comment__") - 1 }, + { "__comment_end__", sizeof("__comment_end__") - 1 }, + { "__comment_start__", sizeof("__comment_start__") - 1 }, + { "__character__", sizeof("__character__") - 1 }, + { ",", sizeof(",") - 1 }, + { "class", sizeof("class") - 1 }, + { "__attribute__", sizeof("__attribute__") - 1 }, + { "__declspec", sizeof("__declspec") - 1 }, + { "enum", sizeof("enum") - 1 }, + { "extern", sizeof("extern") - 1 }, + { "friend", sizeof("friend") - 1 }, + { "module", sizeof("module") - 1 }, + { "namespace", sizeof("namespace") - 1 }, + { "operator", sizeof("operator") - 1 }, + { "struct", sizeof("struct") - 1 }, + { "template", sizeof("template") - 1 }, + { "typedef", sizeof("typedef") - 1 }, + { "using", sizeof("using") - 1 }, + { "union", sizeof("union") - 1 }, + { "__identifier__", sizeof("__identifier__") - 1 }, + { "import", sizeof("import") - 1 }, + { "export", sizeof("export") - 1 }, + { "__new_line__", sizeof("__new_line__") - 1 }, + { "__number__", sizeof("__number__") - 1 }, + { "__operator__", sizeof("__operator__") - 1 }, + { "#", sizeof("#") - 1 }, + { "define", sizeof("define") - 1 }, + { "__define_param__", sizeof("__define_param__") - 1 }, + { "if", sizeof("if") - 1 }, + { "ifdef", sizeof("ifdef") - 1 }, + { "ifndef", sizeof("ifndef") - 1 }, + { "elif", sizeof("elif") - 1 }, + { "else", sizeof("else") - 1 }, + { "endif", sizeof("endif") - 1 }, + { "include", sizeof("include") - 1 }, + { "pragma", sizeof("pragma") - 1 }, + { "__macro_content__", sizeof("__macro_content__") - 1 }, + { "__macro_expression__", sizeof("__macro_expression__") - 1 }, + { "__macro_statment__", sizeof("__macro_statment__") - 1 }, + { "__macro_typename__", sizeof("__macro_typename__") - 1 }, + { "__unsupported__", sizeof("__unsupported__") - 1 }, + { "alignas", sizeof("alignas") - 1 }, + { "const", sizeof("const") - 1 }, + { "consteval", sizeof("consteval") - 1 }, + { "constexpr", sizeof("constexpr") - 1 }, + { "constinit", sizeof("constinit") - 1 }, + { "explicit", sizeof("explicit") - 1 }, + { "extern", sizeof("extern") - 1 }, + { "final", sizeof("final") - 1 }, + { "forceinline", sizeof("forceinline") - 1 }, + { "global", sizeof("global") - 1 }, + { "inline", sizeof("inline") - 1 }, + { "internal", sizeof("internal") - 1 }, + { "local_persist", sizeof("local_persist") - 1 }, + { "mutable", sizeof("mutable") - 1 }, + { "neverinline", sizeof("neverinline") - 1 }, + { "override", sizeof("override") - 1 }, + { "restrict", sizeof("restrict") - 1 }, + { "static", sizeof("static") - 1 }, + { "thread_local", sizeof("thread_local") - 1 }, + { "volatile", sizeof("volatile") - 1 }, + { "virtual", sizeof("virtual") - 1 }, + { "*", sizeof("*") - 1 }, + { ";", sizeof(";") - 1 }, + { "static_assert", sizeof("static_assert") - 1 }, + { "__string__", sizeof("__string__") - 1 }, + { "typename", sizeof("typename") - 1 }, + { "unsigned", sizeof("unsigned") - 1 }, + { "signed", sizeof("signed") - 1 }, + { "short", sizeof("short") - 1 }, + { "long", sizeof("long") - 1 }, + { "bool", sizeof("bool") - 1 }, + { "char", sizeof("char") - 1 }, + { "int", sizeof("int") - 1 }, + { "double", sizeof("double") - 1 }, + { "__int8", sizeof("__int8") - 1 }, + { "__int16", sizeof("__int16") - 1 }, + { "__int32", sizeof("__int32") - 1 }, + { "__int64", sizeof("__int64") - 1 }, + { "_W64", sizeof("_W64") - 1 }, + { "...", sizeof("...") - 1 }, + { "__attrib_start__", sizeof("__attrib_start__") - 1 }, + { "GEN_API", sizeof("GEN_API") - 1 }, + }; + return lookup[type]; +} + +inline TokType str_to_toktype(Str str) +{ + local_persist u32 keymap[Tok_NumTokens]; + do_once_start for (u32 index = 0; index < Tok_NumTokens; index++) + { + Str enum_str = toktype_to_str((TokType)index); + keymap[index] = crc32(enum_str.Ptr, enum_str.Len); + } + do_once_end u32 hash = crc32(str.Ptr, str.Len); + for (u32 index = 0; index < Tok_NumTokens; index++) + { + if (keymap[index] == hash) + return (TokType)index; + } + return Tok_Invalid; +} + +enum TokFlags : u32 +{ + TF_Operator = bit(0), + TF_Assign = bit(1), + TF_Identifier = bit(2), + TF_Preprocess = bit(3), + TF_Preprocess_Cond = bit(4), + TF_Attribute = bit(5), + TF_AccessOperator = bit(6), + TF_AccessSpecifier = bit(7), + TF_Specifier = bit(8), + TF_EndDefinition = bit(9), // Either ; or } + TF_Formatting = bit(10), + TF_Literal = bit(11), + TF_Macro_Functional = bit(12), + TF_Macro_Expects_Body = bit(13), + + TF_Null = 0, + TF_UnderlyingType = GEN_U32_MAX, +}; + +struct Token +{ + Str Text; + TokType Type; + s32 Line; + s32 Column; + u32 Flags; +}; + +constexpr Token NullToken { {}, Tok_Invalid, 0, 0, TF_Null }; + +forceinline +AccessSpec tok_to_access_specifier(Token tok) { + return scast(AccessSpec, tok.Type); +} + +forceinline +bool tok_is_valid( Token tok ) { + return tok.Text.Ptr && tok.Text.Len && tok.Type != Tok_Invalid; +} + +forceinline +bool tok_is_access_operator(Token tok) { + return bitfield_is_set( u32, tok.Flags, TF_AccessOperator ); +} + +forceinline +bool tok_is_access_specifier(Token tok) { + return bitfield_is_set( u32, tok.Flags, TF_AccessSpecifier ); +} + +forceinline +bool tok_is_attribute(Token tok) { + return bitfield_is_set( u32, tok.Flags, TF_Attribute ); +} + +forceinline +bool tok_is_operator(Token tok) { + return bitfield_is_set( u32, tok.Flags, TF_Operator ); +} + +forceinline +bool tok_is_preprocessor(Token tok) { + return bitfield_is_set( u32, tok.Flags, TF_Preprocess ); +} + +forceinline +bool tok_is_preprocess_cond(Token tok) { + return bitfield_is_set( u32, tok.Flags, TF_Preprocess_Cond ); +} + +forceinline +bool tok_is_specifier(Token tok) { + return bitfield_is_set( u32, tok.Flags, TF_Specifier ); +} + +forceinline +bool tok_is_end_definition(Token tok) { + return bitfield_is_set( u32, tok.Flags, TF_EndDefinition ); +} + +StrBuilder tok_to_strbuilder(Token tok); + +struct TokArray +{ + Array(Token) Arr; + s32 Idx; +}; + +struct LexContext +{ + Str content; + s32 left; + char const* scanner; + s32 line; + s32 column; + // StringTable defines; + Token token; +}; + +struct StackNode +{ + StackNode* Prev; + + Token* Start; + Str Name; // The name of the AST node (if parsed) + Str ProcName; // The name of the procedure +}; + +struct ParseContext +{ + TokArray Tokens; + StackNode* Scope; +}; + +enum MacroType : u16 +{ + MT_Expression, // A macro is assumed to be a expression if not resolved. + MT_Statement, + MT_Typename, + MT_Block_Start, // Not Supported yet + MT_Block_End, // Not Supported yet + MT_Case_Statement, // Not Supported yet + + MT_UnderlyingType = GEN_U16_MAX, +}; + +forceinline +TokType macrotype_to_toktype( MacroType type ) { + switch ( type ) { + case MT_Statement : return Tok_Preprocess_Macro_Stmt; + case MT_Expression : return Tok_Preprocess_Macro_Expr; + case MT_Typename : return Tok_Preprocess_Macro_Typename; + } + // All others unsupported for now. + return Tok_Invalid; +} + +inline +Str macrotype_to_str( MacroType type ) +{ + local_persist + Str lookup[] = { + { "Statement", sizeof("Statement") - 1 }, + { "Expression", sizeof("Expression") - 1 }, + { "Typename", sizeof("Typename") - 1 }, + { "Block_Start", sizeof("Block_Start") - 1 }, + { "Block_End", sizeof("Block_End") - 1 }, + { "Case_Statement", sizeof("Case_Statement") - 1 }, + }; + local_persist + Str invalid = { "Invalid", sizeof("Invalid") }; + if ( type > MT_Case_Statement ) + return invalid; + + return lookup[ type ]; +} + +enum EMacroFlags : u16 +{ + // Macro has parameters (args expected to be passed) + MF_Functional = bit(0), + + // Expects to assign a braced scope to its body. + MF_Expects_Body = bit(1), + + // lex__eat wil treat this macro as an identifier if the parser attempts to consume it as one. + // This is a kludge because we don't support push/pop macro pragmas rn. + MF_Allow_As_Identifier = bit(2), + + // When parsing identifiers, it will allow the consumption of the macro parameters (as its expected to be a part of constructing the identifier) + // Example of a decarator macro from stb_sprintf.h: + // STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(sprintf)(char* buf, char const *fmt, ...) STBSP__ATTRIBUTE_FORMAT(2,3); + // ^^ STB_SPRINTF_DECORATE is decorating sprintf + MF_Identifier_Decorator = bit(3), + + // lex__eat wil treat this macro as an attribute if the parser attempts to consume it as one. + // This a kludge because unreal has a macro that behaves as both a 'statement' and an attribute (UE_DEPRECATED, PRAGMA_ENABLE_DEPRECATION_WARNINGS, etc) + // TODO(Ed): We can keep the MF_Allow_As_Attribute flag for macros, however, we need to add the ability of AST_Attributes to chain themselves. + // Its thats already a thing in the standard language anyway + // & it would allow UE_DEPRECATED, (UE_PROPERTY / UE_FUNCTION) to chain themselves as attributes of a resolved member function/variable definition + MF_Allow_As_Attribute = bit(4), + + // When a macro is encountered after attributes and specifiers while parsing a function, or variable: + // It will consume the macro and treat it as resolving the definition. + // (MUST BE OF MT_Statement TYPE) + MF_Allow_As_Definition = bit(5), + + // Created for Unreal's PURE_VIRTUAL + MF_Allow_As_Specifier = bit(6), + + MF_Null = 0, + MF_UnderlyingType = GEN_U16_MAX, +}; +typedef u16 MacroFlags; + +struct Macro +{ + StrCached Name; + MacroType Type; + MacroFlags Flags; +}; + +forceinline +b32 macro_is_functional( Macro macro ) { + return bitfield_is_set( b16, macro.Flags, MF_Functional ); +} + +forceinline +b32 macro_expects_body( Macro macro ) { + return bitfield_is_set( b16, macro.Flags, MF_Expects_Body ); +} + +#if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP +forceinline b32 is_functional( Macro macro ) { return bitfield_is_set( b16, macro.Flags, MF_Functional ); } +forceinline b32 expects_body ( Macro macro ) { return bitfield_is_set( b16, macro.Flags, MF_Expects_Body ); } +#endif + +typedef HashTable(Macro) MacroTable; + +#pragma endregion Types + +#pragma region AST + +/* + ______ ______ ________ __ __ ______ __ + / \ / \| \ | \ | \ / \ | \ +| ▓▓▓▓▓▓\ ▓▓▓▓▓▓\\▓▓▓▓▓▓▓▓ | ▓▓\ | ▓▓ | ▓▓▓▓▓▓\ ______ ____| ▓▓ ______ +| ▓▓__| ▓▓ ▓▓___\▓▓ | ▓▓ | ▓▓▓\| ▓▓ | ▓▓ \▓▓/ \ / ▓▓/ \ +| ▓▓ ▓▓\▓▓ \ | ▓▓ | ▓▓▓▓\ ▓▓ | ▓▓ | ▓▓▓▓▓▓\ ▓▓▓▓▓▓▓ ▓▓▓▓▓▓\ +| ▓▓▓▓▓▓▓▓_\▓▓▓▓▓▓\ | ▓▓ | ▓▓\▓▓ ▓▓ | ▓▓ __| ▓▓ | ▓▓ ▓▓ | ▓▓ ▓▓ ▓▓ +| ▓▓ | ▓▓ \__| ▓▓ | ▓▓ | ▓▓ \▓▓▓▓ | ▓▓__/ \ ▓▓__/ ▓▓ ▓▓__| ▓▓ ▓▓▓▓▓▓▓▓ +| ▓▓ | ▓▓\▓▓ ▓▓ | ▓▓ | ▓▓ \▓▓▓ \▓▓ ▓▓\▓▓ ▓▓\▓▓ ▓▓\▓▓ \ + \▓▓ \▓▓ \▓▓▓▓▓▓ \▓▓ \▓▓ \▓▓ \▓▓▓▓▓▓ \▓▓▓▓▓▓ \▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓ +*/ + +struct AST; +struct AST_Body; +struct AST_Attributes; +struct AST_Comment; +struct AST_Constructor; +// struct AST_BaseClass; +struct AST_Class; +struct AST_Define; +struct AST_DefineParams; +struct AST_Destructor; +struct AST_Enum; +struct AST_Exec; +struct AST_Extern; +struct AST_Include; +struct AST_Friend; +struct AST_Fn; +struct AST_Module; +struct AST_NS; +struct AST_Operator; +struct AST_OpCast; +struct AST_Params; +struct AST_Pragma; +struct AST_PreprocessCond; +struct AST_Specifiers; + +#ifdef GEN_EXECUTION_EXPRESSION_SUPPORT +struct AST_Expr; +struct AST_Expr_Assign; +struct AST_Expr_Alignof; +struct AST_Expr_Binary; +struct AST_Expr_CStyleCast; +struct AST_Expr_FunctionalCast; +struct AST_Expr_CppCast; +struct AST_Expr_ProcCall; +struct AST_Expr_Decltype; +struct AST_Expr_Comma; // TODO(Ed) : This is a binary op not sure if it needs its own AST... +struct AST_Expr_AMS; // Access Member Symbol +struct AST_Expr_Sizeof; +struct AST_Expr_Subscript; +struct AST_Expr_Ternary; +struct AST_Expr_UnaryPrefix; +struct AST_Expr_UnaryPostfix; +struct AST_Expr_Element; + +struct AST_Stmt; +struct AST_Stmt_Break; +struct AST_Stmt_Case; +struct AST_Stmt_Continue; +struct AST_Stmt_Decl; +struct AST_Stmt_Do; +struct AST_Stmt_Expr; // TODO(Ed) : Is this distinction needed? (Should it be a flag instead?) +struct AST_Stmt_Else; +struct AST_Stmt_If; +struct AST_Stmt_For; +struct AST_Stmt_Goto; +struct AST_Stmt_Label; +struct AST_Stmt_Switch; +struct AST_Stmt_While; +#endif + +struct AST_Struct; +struct AST_Template; +struct AST_Typename; +struct AST_Typedef; +struct AST_Union; +struct AST_Using; +struct AST_Var; + +#if GEN_COMPILER_C +typedef AST* Code; +#else +struct Code; +#endif + +#if GEN_COMPILER_C +typedef AST_Body* CodeBody; +typedef AST_Attributes* CodeAttributes; +typedef AST_Comment* CodeComment; +typedef AST_Class* CodeClass; +typedef AST_Constructor* CodeConstructor; +typedef AST_Define* CodeDefine; +typedef AST_DefineParams* CodeDefineParams; +typedef AST_Destructor* CodeDestructor; +typedef AST_Enum* CodeEnum; +typedef AST_Exec* CodeExec; +typedef AST_Extern* CodeExtern; +typedef AST_Include* CodeInclude; +typedef AST_Friend* CodeFriend; +typedef AST_Fn* CodeFn; +typedef AST_Module* CodeModule; +typedef AST_NS* CodeNS; +typedef AST_Operator* CodeOperator; +typedef AST_OpCast* CodeOpCast; +typedef AST_Params* CodeParams; +typedef AST_PreprocessCond* CodePreprocessCond; +typedef AST_Pragma* CodePragma; +typedef AST_Specifiers* CodeSpecifiers; +#else +struct CodeBody; +struct CodeAttributes; +struct CodeComment; +struct CodeClass; +struct CodeConstructor; +struct CodeDefine; +struct CodeDefineParams; +struct CodeDestructor; +struct CodeEnum; +struct CodeExec; +struct CodeExtern; +struct CodeInclude; +struct CodeFriend; +struct CodeFn; +struct CodeModule; +struct CodeNS; +struct CodeOperator; +struct CodeOpCast; +struct CodeParams; +struct CodePreprocessCond; +struct CodePragma; +struct CodeSpecifiers; +#endif + +#ifdef GEN_EXECUTION_EXPRESSION_SUPPORT + +#if GEN_COMPILER_C +typedef AST_Expr* CodeExpr; +typedef AST_Expr_Assign* CodeExpr_Assign; +typedef AST_Expr_Alignof* CodeExpr_Alignof; +typedef AST_Expr_Binary* CodeExpr_Binary; +typedef AST_Expr_CStyleCast* CodeExpr_CStyleCast; +typedef AST_Expr_FunctionalCast* CodeExpr_FunctionalCast; +typedef AST_Expr_CppCast* CodeExpr_CppCast; +typedef AST_Expr_Element* CodeExpr_Element; +typedef AST_Expr_ProcCall* CodeExpr_ProcCall; +typedef AST_Expr_Decltype* CodeExpr_Decltype; +typedef AST_Expr_Comma* CodeExpr_Comma; +typedef AST_Expr_AMS* CodeExpr_AMS; // Access Member Symbol +typedef AST_Expr_Sizeof* CodeExpr_Sizeof; +typedef AST_Expr_Subscript* CodeExpr_Subscript; +typedef AST_Expr_Ternary* CodeExpr_Ternary; +typedef AST_Expr_UnaryPrefix* CodeExpr_UnaryPrefix; +typedef AST_Expr_UnaryPostfix* CodeExpr_UnaryPostfix; +#else +struct CodeExpr; +struct CodeExpr_Assign; +struct CodeExpr_Alignof; +struct CodeExpr_Binary; +struct CodeExpr_CStyleCast; +struct CodeExpr_FunctionalCast; +struct CodeExpr_CppCast; +struct CodeExpr_Element; +struct CodeExpr_ProcCall; +struct CodeExpr_Decltype; +struct CodeExpr_Comma; +struct CodeExpr_AMS; // Access Member Symbol +struct CodeExpr_Sizeof; +struct CodeExpr_Subscript; +struct CodeExpr_Ternary; +struct CodeExpr_UnaryPrefix; +struct CodeExpr_UnaryPostfix; +#endif + +#if GEN_COMPILER_C +typedef AST_Stmt* CodeStmt; +typedef AST_Stmt_Break* CodeStmt_Break; +typedef AST_Stmt_Case* CodeStmt_Case; +typedef AST_Stmt_Continue* CodeStmt_Continue; +typedef AST_Stmt_Decl* CodeStmt_Decl; +typedef AST_Stmt_Do* CodeStmt_Do; +typedef AST_Stmt_Expr* CodeStmt_Expr; +typedef AST_Stmt_Else* CodeStmt_Else; +typedef AST_Stmt_If* CodeStmt_If; +typedef AST_Stmt_For* CodeStmt_For; +typedef AST_Stmt_Goto* CodeStmt_Goto; +typedef AST_Stmt_Label* CodeStmt_Label; +typedef AST_Stmt_Lambda* CodeStmt_Lambda; +typedef AST_Stmt_Switch* CodeStmt_Switch; +typedef AST_Stmt_While* CodeStmt_While; +#else +struct CodeStmt; +struct CodeStmt_Break; +struct CodeStmt_Case; +struct CodeStmt_Continue; +struct CodeStmt_Decl; +struct CodeStmt_Do; +struct CodeStmt_Expr; +struct CodeStmt_Else; +struct CodeStmt_If; +struct CodeStmt_For; +struct CodeStmt_Goto; +struct CodeStmt_Label; +struct CodeStmt_Lambda; +struct CodeStmt_Switch; +struct CodeStmt_While; +#endif + +// GEN_EXECUTION_EXPRESSION_SUPPORT +#endif + +#if GEN_COMPILER_C +typedef AST_Struct* CodeStruct; +typedef AST_Template* CodeTemplate; +typedef AST_Typename* CodeTypename; +typedef AST_Typedef* CodeTypedef; +typedef AST_Union* CodeUnion; +typedef AST_Using* CodeUsing; +typedef AST_Var* CodeVar; +#else +struct CodeStruct; +struct CodeTemplate; +struct CodeTypename; +struct CodeTypedef; +struct CodeUnion; +struct CodeUsing; +struct CodeVar; +#endif + +#if GEN_COMPILER_CPP +template< class Type> forceinline Type tmpl_cast( Code self ) { return * rcast( Type*, & self ); } +#endif + +#pragma region Code C-Interface + + void code_append (Code code, Code other ); +GEN_API Str code_debug_str (Code code); +GEN_API Code code_duplicate (Code code); + Code* code_entry (Code code, u32 idx ); + bool code_has_entries (Code code); + bool code_is_body (Code code); +GEN_API bool code_is_equal (Code code, Code other); + bool code_is_valid (Code code); + void code_set_global (Code code); +GEN_API StrBuilder code_to_strbuilder (Code self ); +GEN_API void code_to_strbuilder_ref(Code self, StrBuilder* result ); + Str code_type_str (Code self ); +GEN_API bool code_validate_body (Code self ); + +#pragma endregion Code C-Interface + +#if GEN_COMPILER_CPP +/* + AST* wrapper + - Not constantly have to append the '*' as this is written often.. + - Allows for implicit conversion to any of the ASTs (raw or filtered). +*/ +struct Code +{ + AST* ast; + +# define Using_Code( Typename ) \ + forceinline Str debug_str() { return code_debug_str(* this); } \ + forceinline Code duplicate() { return code_duplicate(* this); } \ + forceinline bool is_equal( Code other ) { return code_is_equal(* this, other); } \ + forceinline bool is_body() { return code_is_body(* this); } \ + forceinline bool is_valid() { return code_is_valid(* this); } \ + forceinline void set_global() { return code_set_global(* this); } + +# define Using_CodeOps( Typename ) \ + forceinline Typename& operator = ( Code other ); \ + forceinline bool operator ==( Code other ) { return (AST*)ast == other.ast; } \ + forceinline bool operator !=( Code other ) { return (AST*)ast != other.ast; } \ + forceinline bool operator ==(std::nullptr_t) const { return ast == nullptr; } \ + forceinline bool operator !=(std::nullptr_t) const { return ast != nullptr; } \ + operator bool(); + +#if ! GEN_C_LIKE_CPP + Using_Code( Code ); + forceinline void append(Code other) { return code_append(* this, other); } + forceinline Code* entry(u32 idx) { return code_entry(* this, idx); } + forceinline bool has_entries() { return code_has_entries(* this); } + forceinline StrBuilder to_strbuilder() { return code_to_strbuilder(* this); } + forceinline void to_strbuilder(StrBuilder& result) { return code_to_strbuilder_ref(* this, & result); } + forceinline Str type_str() { return code_type_str(* this); } + forceinline bool validate_body() { return code_validate_body(*this); } +#endif + + Using_CodeOps( Code ); + forceinline Code operator *() { return * this; } // Required to support for-range iteration. + forceinline AST* operator ->() { return ast; } + + Code& operator ++(); + +#ifdef GEN_ENFORCE_STRONG_CODE_TYPES +# define operator explicit operator +#endif + operator CodeBody() const; + operator CodeAttributes() const; + // operator CodeBaseClass() const; + operator CodeComment() const; + operator CodeClass() const; + operator CodeConstructor() const; + operator CodeDefine() const; + operator CodeDefineParams() const; + operator CodeDestructor() const; + operator CodeExec() const; + operator CodeEnum() const; + operator CodeExtern() const; + operator CodeInclude() const; + operator CodeFriend() const; + operator CodeFn() const; + operator CodeModule() const; + operator CodeNS() const; + operator CodeOperator() const; + operator CodeOpCast() const; + operator CodeParams() const; + operator CodePragma() const; + operator CodePreprocessCond() const; + operator CodeSpecifiers() const; + operator CodeStruct() const; + operator CodeTemplate() const; + operator CodeTypename() const; + operator CodeTypedef() const; + operator CodeUnion() const; + operator CodeUsing() const; + operator CodeVar() const; + #undef operator +}; +#endif + +#pragma region Statics +// Used to identify ASTs that should always be duplicated. (Global constant ASTs) +GEN_API extern Code Code_Global; + +// Used to identify invalid generated code. +GEN_API extern Code Code_Invalid; +#pragma endregion Statics + +struct Code_POD +{ + AST* ast; +}; +static_assert( sizeof(Code) == sizeof(Code_POD), "ERROR: Code is not POD" ); + +// Desired width of the AST data structure. +constexpr int const AST_POD_Size = 128; + +constexpr static +int AST_ArrSpecs_Cap = +( + AST_POD_Size + - sizeof(Code) + - sizeof(StrCached) + - sizeof(Code) * 2 + - sizeof(Token*) + - sizeof(Code) + - sizeof(CodeType) + - sizeof(ModuleFlag) + - sizeof(u32) +) +/ sizeof(Specifier) - 1; + +/* + Simple AST POD with functionality to seralize into C++ syntax. + TODO(Ed): Eventually haven't a transparent AST like this will longer be viable once statements & expressions are in (most likely....) +*/ +struct AST +{ + union { + struct + { + Code InlineCmt; // Class, Constructor, Destructor, Enum, Friend, Functon, Operator, OpCast, Struct, Typedef, Using, Variable + Code Attributes; // Class, Enum, Function, Struct, Typedef, Union, Using, Variable // TODO(Ed): Parameters can have attributes + Code Specs; // Class, Destructor, Function, Operator, Struct, Typename, Variable + union { + Code InitializerList; // Constructor + Code ParentType; // Class, Struct, ParentType->Next has a possible list of interfaces. + Code ReturnType; // Function, Operator, Typename + Code UnderlyingType; // Enum, Typedef + Code ValueType; // Parameter, Variable + }; + union { + Code Macro; // Parameter + Code BitfieldSize; // Variable (Class/Struct Data Member) + Code Params; // Constructor, Define, Function, Operator, Template, Typename + Code UnderlyingTypeMacro; // Enum + }; + union { + Code ArrExpr; // Typename + Code Body; // Class, Constructor, Define, Destructor, Enum, Friend, Function, Namespace, Struct, Union + Code Declaration; // Friend, Template + Code Value; // Parameter, Variable + }; + union { + Code NextVar; // Variable + Code SuffixSpecs; // Typename, Function (Thanks Unreal) + Code PostNameMacro; // Only used with parameters for specifically UE_REQUIRES (Thanks Unreal) + }; + }; + StrCached Content; // Attributes, Comment, Execution, Include + struct { + Specifier ArrSpecs[AST_ArrSpecs_Cap]; // Specifiers + Code NextSpecs; // Specifiers; If ArrSpecs is full, then NextSpecs is used. + }; + }; + StrCached Name; + union { + Code Prev; + Code Front; + Code Last; + }; + union { + Code Next; + Code Back; + }; + Token* Token; // Reference to starting token, only available if it was derived from parsing. + Code Parent; + CodeType Type; +// CodeFlag CodeFlags; + ModuleFlag ModuleFlags; + union { + b32 IsFunction; // Used by typedef to not serialize the name field. + struct { + b16 IsParamPack; // Used by typename to know if type should be considered a parameter pack. + ETypenameTag TypeTag; // Used by typename to keep track of explicitly declared tags for the identifier (enum, struct, union) + }; + Operator Op; + AccessSpec ParentAccess; + s32 NumEntries; + s32 VarParenthesizedInit; // Used by variables to know that initialization is using a constructor expression instead of an assignment expression. + }; +}; +static_assert( sizeof(AST) == AST_POD_Size, "ERROR: AST is not size of AST_POD_Size" ); + +#if GEN_COMPILER_CPP +// Uses an implicitly overloaded cast from the AST to the desired code type. +// Necessary if the user wants GEN_ENFORCE_STRONG_CODE_TYPES +struct InvalidCode_ImplictCaster; +#define InvalidCode (InvalidCode_ImplictCaster{}) +#else +#define InvalidCode (void*){ (void*)Code_Invalid } +#endif + +#if GEN_COMPILER_CPP +struct NullCode_ImplicitCaster; +// Used when the its desired when omission is allowed in a definition. +#define NullCode (NullCode_ImplicitCaster{}) +#else +#define NullCode nullptr +#endif + +/* + ______ __ ______ __ ______ + / \ | \ | \ | \ / \ +| ▓▓▓▓▓▓\ ______ ____| ▓▓ ______ \▓▓▓▓▓▓_______ _| ▓▓_ ______ ______ | ▓▓▓▓▓▓\ ______ _______ ______ +| ▓▓ \▓▓/ \ / ▓▓/ \ | ▓▓ | \| ▓▓ \ / \ / \| ▓▓_ \▓▓| \ / \/ \ +| ▓▓ | ▓▓▓▓▓▓\ ▓▓▓▓▓▓▓ ▓▓▓▓▓▓\ | ▓▓ | ▓▓▓▓▓▓▓\\▓▓▓▓▓▓ | ▓▓▓▓▓▓\ ▓▓▓▓▓▓\ ▓▓ \ \▓▓▓▓▓▓\ ▓▓▓▓▓▓▓ ▓▓▓▓▓▓\ +| ▓▓ __| ▓▓ | ▓▓ ▓▓ | ▓▓ ▓▓ ▓▓ | ▓▓ | ▓▓ | ▓▓ | ▓▓ __| ▓▓ ▓▓ ▓▓ \▓▓ ▓▓▓▓ / ▓▓ ▓▓ | ▓▓ ▓▓ +| ▓▓__/ \ ▓▓__/ ▓▓ ▓▓__| ▓▓ ▓▓▓▓▓▓▓▓ _| ▓▓_| ▓▓ | ▓▓ | ▓▓| \ ▓▓▓▓▓▓▓▓ ▓▓ | ▓▓ | ▓▓▓▓▓▓▓ ▓▓_____| ▓▓▓▓▓▓▓▓ + \▓▓ ▓▓\▓▓ ▓▓\▓▓ ▓▓\▓▓ \ | ▓▓ \ ▓▓ | ▓▓ \▓▓ ▓▓\▓▓ \ ▓▓ | ▓▓ \▓▓ ▓▓\▓▓ \\▓▓ \ + \▓▓▓▓▓▓ \▓▓▓▓▓▓ \▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓ \▓▓▓▓▓▓\▓▓ \▓▓ \▓▓▓▓ \▓▓▓▓▓▓▓\▓▓ \▓▓ \▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓ +*/ + +#pragma region Code Type C-Interface + +GEN_API void body_append ( CodeBody body, Code other ); +GEN_API void body_append_body ( CodeBody body, CodeBody other ); +GEN_API StrBuilder body_to_strbuilder ( CodeBody body ); + void body_to_strbuilder_ref ( CodeBody body, StrBuilder* result ); +GEN_API void body_to_strbuilder_export( CodeBody body, StrBuilder* result ); + +Code begin_CodeBody( CodeBody body); +Code end_CodeBody ( CodeBody body ); +Code next_CodeBody ( CodeBody body, Code entry_iter ); + + void class_add_interface ( CodeClass self, CodeTypename interface ); +GEN_API StrBuilder class_to_strbuilder ( CodeClass self ); +GEN_API void class_to_strbuilder_def( CodeClass self, StrBuilder* result ); +GEN_API void class_to_strbuilder_fwd( CodeClass self, StrBuilder* result ); + + void define_params_append (CodeDefineParams appendee, CodeDefineParams other ); + CodeDefineParams define_params_get (CodeDefineParams params, s32 idx); + bool define_params_has_entries (CodeDefineParams params ); + StrBuilder define_params_to_strbuilder (CodeDefineParams params ); +GEN_API void define_params_to_strbuilder_ref(CodeDefineParams params, StrBuilder* result ); + +CodeDefineParams begin_CodeDefineParams(CodeDefineParams params); +CodeDefineParams end_CodeDefineParams (CodeDefineParams params); +CodeDefineParams next_CodeDefineParams (CodeDefineParams params, CodeDefineParams entry_iter); + + void params_append (CodeParams appendee, CodeParams other ); + CodeParams params_get (CodeParams params, s32 idx); + bool params_has_entries (CodeParams params ); + StrBuilder params_to_strbuilder (CodeParams params ); +GEN_API void params_to_strbuilder_ref(CodeParams params, StrBuilder* result ); + +CodeParams begin_CodeParams(CodeParams params); +CodeParams end_CodeParams (CodeParams params); +CodeParams next_CodeParams (CodeParams params, CodeParams entry_iter); + + bool specifiers_append (CodeSpecifiers specifiers, Specifier spec); + bool specifiers_has (CodeSpecifiers specifiers, Specifier spec); + s32 specifiers_index_of (CodeSpecifiers specifiers, Specifier spec); + s32 specifiers_remove (CodeSpecifiers specifiers, Specifier to_remove ); + StrBuilder specifiers_to_strbuilder (CodeSpecifiers specifiers); +GEN_API void specifiers_to_strbuilder_ref(CodeSpecifiers specifiers, StrBuilder* result); + +Specifier* begin_CodeSpecifiers(CodeSpecifiers specifiers); +Specifier* end_CodeSpecifiers (CodeSpecifiers specifiers); +Specifier* next_CodeSpecifiers (CodeSpecifiers specifiers, Specifier* spec_iter); + + void struct_add_interface (CodeStruct self, CodeTypename interface); +GEN_API StrBuilder struct_to_strbuilder (CodeStruct self); +GEN_API void struct_to_strbuilder_fwd(CodeStruct self, StrBuilder* result); +GEN_API void struct_to_strbuilder_def(CodeStruct self, StrBuilder* result); + + StrBuilder attributes_to_strbuilder (CodeAttributes attributes); + void attributes_to_strbuilder_ref(CodeAttributes attributes, StrBuilder* result); + + StrBuilder comment_to_strbuilder (CodeComment comment ); + void comment_to_strbuilder_ref(CodeComment comment, StrBuilder* result ); + +GEN_API StrBuilder constructor_to_strbuilder (CodeConstructor constructor); +GEN_API void constructor_to_strbuilder_def(CodeConstructor constructor, StrBuilder* result ); +GEN_API void constructor_to_strbuilder_fwd(CodeConstructor constructor, StrBuilder* result ); + +GEN_API StrBuilder define_to_strbuilder (CodeDefine self); +GEN_API void define_to_strbuilder_ref(CodeDefine self, StrBuilder* result); + +GEN_API StrBuilder destructor_to_strbuilder (CodeDestructor destructor); +GEN_API void destructor_to_strbuilder_fwd(CodeDestructor destructor, StrBuilder* result ); +GEN_API void destructor_to_strbuilder_def(CodeDestructor destructor, StrBuilder* result ); + +GEN_API StrBuilder enum_to_strbuilder (CodeEnum self); +GEN_API void enum_to_strbuilder_def (CodeEnum self, StrBuilder* result ); +GEN_API void enum_to_strbuilder_fwd (CodeEnum self, StrBuilder* result ); +GEN_API void enum_to_strbuilder_class_def(CodeEnum self, StrBuilder* result ); +GEN_API void enum_to_strbuilder_class_fwd(CodeEnum self, StrBuilder* result ); + + StrBuilder exec_to_strbuilder (CodeExec exec); + void exec_to_strbuilder_ref(CodeExec exec, StrBuilder* result); + + void extern_to_strbuilder(CodeExtern self, StrBuilder* result); + + StrBuilder include_to_strbuilder (CodeInclude self); + void include_to_strbuilder_ref(CodeInclude self, StrBuilder* result); + + StrBuilder friend_to_strbuilder (CodeFriend self); + void friend_to_strbuilder_ref(CodeFriend self, StrBuilder* result); + +GEN_API StrBuilder fn_to_strbuilder (CodeFn self); +GEN_API void fn_to_strbuilder_def(CodeFn self, StrBuilder* result); +GEN_API void fn_to_strbuilder_fwd(CodeFn self, StrBuilder* result); + + StrBuilder module_to_strbuilder (CodeModule self); +GEN_API void module_to_strbuilder_ref(CodeModule self, StrBuilder* result); + + StrBuilder namespace_to_strbuilder (CodeNS self); + void namespace_to_strbuilder_ref(CodeNS self, StrBuilder* result); + +GEN_API StrBuilder code_op_to_strbuilder (CodeOperator self); +GEN_API void code_op_to_strbuilder_fwd(CodeOperator self, StrBuilder* result ); +GEN_API void code_op_to_strbuilder_def(CodeOperator self, StrBuilder* result ); + +GEN_API StrBuilder opcast_to_strbuilder (CodeOpCast op_cast ); +GEN_API void opcast_to_strbuilder_def(CodeOpCast op_cast, StrBuilder* result ); +GEN_API void opcast_to_strbuilder_fwd(CodeOpCast op_cast, StrBuilder* result ); + + StrBuilder pragma_to_strbuilder (CodePragma self); + void pragma_to_strbuilder_ref(CodePragma self, StrBuilder* result); + +GEN_API StrBuilder preprocess_to_strbuilder (CodePreprocessCond cond); + void preprocess_to_strbuilder_if (CodePreprocessCond cond, StrBuilder* result ); + void preprocess_to_strbuilder_ifdef (CodePreprocessCond cond, StrBuilder* result ); + void preprocess_to_strbuilder_ifndef(CodePreprocessCond cond, StrBuilder* result ); + void preprocess_to_strbuilder_elif (CodePreprocessCond cond, StrBuilder* result ); + void preprocess_to_strbuilder_else (CodePreprocessCond cond, StrBuilder* result ); + void preprocess_to_strbuilder_endif (CodePreprocessCond cond, StrBuilder* result ); + + StrBuilder template_to_strbuilder (CodeTemplate self); +GEN_API void template_to_strbuilder_ref(CodeTemplate self, StrBuilder* result); + + StrBuilder typedef_to_strbuilder (CodeTypedef self); +GEN_API void typedef_to_strbuilder_ref(CodeTypedef self, StrBuilder* result ); + + StrBuilder typename_to_strbuilder (CodeTypename self); +GEN_API void typename_to_strbuilder_ref(CodeTypename self, StrBuilder* result); + +GEN_API StrBuilder union_to_strbuilder (CodeUnion self); +GEN_API void union_to_strbuilder_def(CodeUnion self, StrBuilder* result); +GEN_API void union_to_strbuilder_fwd(CodeUnion self, StrBuilder* result); + + StrBuilder using_to_strbuilder (CodeUsing op_cast ); +GEN_API void using_to_strbuilder_ref(CodeUsing op_cast, StrBuilder* result ); + void using_to_strbuilder_ns (CodeUsing op_cast, StrBuilder* result ); + + StrBuilder var_to_strbuilder (CodeVar self); +GEN_API void var_to_strbuilder_ref(CodeVar self, StrBuilder* result); + +// TODO(Ed): Move C-Interface inlines here... + +#pragma endregion Code Type C-Interface + +#if GEN_COMPILER_CPP +#pragma region Code Types C++ + +// These structs are not used at all by the C vairant. +static_assert( GEN_COMPILER_CPP, "This should not be compiled with the C-library" ); + +#define Verify_POD(Type) static_assert(size_of(Code##Type) == size_of(AST_##Type), "ERROR: Code##Type is not a POD") + +struct CodeBody +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeBody ); + forceinline void append( Code other ) { return body_append( *this, other ); } + forceinline void append( CodeBody body ) { return body_append(*this, body); } + forceinline bool has_entries() { return code_has_entries(* this); } + forceinline StrBuilder to_strbuilder() { return body_to_strbuilder(* this); } + forceinline void to_strbuilder( StrBuilder& result ) { return body_to_strbuilder_ref(* this, & result ); } + forceinline void to_strbuilder_export( StrBuilder& result ) { return body_to_strbuilder_export(* this, & result); } + +#endif + forceinline Code begin() { return begin_CodeBody(* this); } + forceinline Code end() { return end_CodeBody(* this); } + Using_CodeOps( CodeBody ); + forceinline operator Code() { return * rcast( Code*, this ); } + forceinline AST_Body* operator->() { return ast; } + AST_Body* ast; +}; + +struct CodeClass +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeClass ); + forceinline void add_interface( CodeType interface ); + forceinline StrBuilder to_strbuilder(); + forceinline void to_strbuilder_def( StrBuilder& result ); + forceinline void to_strbuilder_fwd( StrBuilder& result ); +#endif + Using_CodeOps( CodeClass ); + forceinline operator Code() { return * rcast( Code*, this ); } + forceinline AST_Class* operator->() { + GEN_ASSERT(ast); + return ast; + } + AST_Class* ast; +}; + +struct CodeParams +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeParams ); + forceinline void append( CodeParams other ) { return params_append(* this, other); } + forceinline CodeParams get( s32 idx ) { return params_get( * this, idx); } + forceinline bool has_entries() { return params_has_entries(* this); } + forceinline StrBuilder to_strbuilder() { return params_to_strbuilder(* this); } + forceinline void to_strbuilder( StrBuilder& result ) { return params_to_strbuilder_ref(*this, & result); } +#endif + Using_CodeOps( CodeParams ); + forceinline CodeParams begin() { return begin_CodeParams(* this); } + forceinline CodeParams end() { return end_CodeParams(* this); } + forceinline operator Code() { return { (AST*)ast }; } + forceinline CodeParams operator *() { return * this; } // Required to support for-range iteration. + forceinline AST_Params* operator->() { + GEN_ASSERT(ast); + return ast; + } + CodeParams& operator++(); + AST_Params* ast; +}; + +struct CodeDefineParams +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeDefineParams ); + forceinline void append( CodeDefineParams other ) { return params_append( cast(CodeParams, * this), cast(CodeParams, other)); } + forceinline CodeDefineParams get( s32 idx ) { return (CodeDefineParams) (Code) params_get( cast(CodeParams, * this), idx); } + forceinline bool has_entries() { return params_has_entries( cast(CodeParams, * this)); } + forceinline StrBuilder to_strbuilder() { return define_params_to_strbuilder(* this); } + forceinline void to_strbuilder( StrBuilder& result ) { return define_params_to_strbuilder_ref(* this, & result); } +#endif + Using_CodeOps( CodeDefineParams ); + forceinline CodeDefineParams begin() { return (CodeDefineParams) (Code) begin_CodeParams( cast(CodeParams, * this)); } + forceinline CodeDefineParams end() { return (CodeDefineParams) (Code) end_CodeParams( cast(CodeParams, * this)); } + forceinline operator Code() { return { (AST*)ast }; } + forceinline CodeDefineParams operator *() { return * this; } // Required to support for-range iteration. + forceinline AST_DefineParams* operator->() { + GEN_ASSERT(ast); + return ast; + } + forceinline CodeDefineParams& operator++(); + AST_DefineParams* ast; +}; + +struct CodeSpecifiers +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeSpecifiers ); + bool append( Specifier spec ) { return specifiers_append(* this, spec); } + s32 has( Specifier spec ) { return specifiers_has(* this, spec); } + s32 remove( Specifier to_remove ) { return specifiers_remove(* this, to_remove); } + StrBuilder to_strbuilder() { return specifiers_to_strbuilder(* this ); } + void to_strbuilder( StrBuilder& result ) { return specifiers_to_strbuilder_ref(* this, & result); } +#endif + Using_CodeOps(CodeSpecifiers); + forceinline operator Code() { return { (AST*) ast }; } + forceinline Code operator *() { return * this; } // Required to support for-range iteration. + forceinline AST_Specifiers* operator->() { + GEN_ASSERT(ast); + return ast; + } + AST_Specifiers* ast; +}; + +struct CodeAttributes +{ +#if ! GEN_C_LIKE_CPP + Using_Code(CodeAttributes); + forceinline StrBuilder to_strbuilder() { return attributes_to_strbuilder(* this); } + forceinline void to_strbuilder(StrBuilder& result) { return attributes_to_strbuilder_ref(* this, & result); } +#endif + Using_CodeOps(CodeAttributes); + operator Code(); + AST_Attributes *operator->(); + AST_Attributes *ast; +}; + +// Define_CodeType( BaseClass ); + +struct CodeComment +{ +#if ! GEN_C_LIKE_CPP + Using_Code(CodeComment); + forceinline StrBuilder to_strbuilder() { return comment_to_strbuilder (* this); } + forceinline void to_strbuilder(StrBuilder& result) { return comment_to_strbuilder_ref(* this, & result); } +#endif + Using_CodeOps(CodeComment); + operator Code(); + AST_Comment *operator->(); + AST_Comment *ast; +}; + +struct CodeConstructor +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeConstructor ); + forceinline StrBuilder to_strbuilder() { return constructor_to_strbuilder(* this); } + forceinline void to_strbuilder_def( StrBuilder& result ) { return constructor_to_strbuilder_def(* this, & result); } + forceinline void to_strbuilder_fwd( StrBuilder& result ) { return constructor_to_strbuilder_fwd(* this, & result); } +#endif + Using_CodeOps(CodeConstructor); + operator Code(); + AST_Constructor* operator->(); + AST_Constructor* ast; +}; + +struct CodeDefine +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeDefine ); + forceinline StrBuilder to_strbuilder() { return define_to_strbuilder(* this); } + forceinline void to_strbuilder( StrBuilder& result ) { return define_to_strbuilder_ref(* this, & result); } +#endif + Using_CodeOps(CodeDefine); + operator Code(); + AST_Define* operator->(); + AST_Define* ast; +}; + +struct CodeDestructor +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeDestructor ); + forceinline StrBuilder to_strbuilder() { return destructor_to_strbuilder(* this); } + forceinline void to_strbuilder_def( StrBuilder& result ) { return destructor_to_strbuilder_def(* this, & result); } + forceinline void to_strbuilder_fwd( StrBuilder& result ) { return destructor_to_strbuilder_fwd(* this, & result); } +#endif + Using_CodeOps(CodeDestructor); + operator Code(); + AST_Destructor* operator->(); + AST_Destructor* ast; +}; + +struct CodeEnum +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeEnum ); + forceinline StrBuilder to_strbuilder() { return enum_to_strbuilder(* this); } + forceinline void to_strbuilder_def( StrBuilder& result ) { return enum_to_strbuilder_def(* this, & result); } + forceinline void to_strbuilder_fwd( StrBuilder& result ) { return enum_to_strbuilder_fwd(* this, & result); } + forceinline void to_strbuilder_class_def( StrBuilder& result ) { return enum_to_strbuilder_class_def(* this, & result); } + forceinline void to_strbuilder_class_fwd( StrBuilder& result ) { return enum_to_strbuilder_class_fwd(* this, & result); } +#endif + Using_CodeOps(CodeEnum); + operator Code(); + AST_Enum* operator->(); + AST_Enum* ast; +}; + +struct CodeExec +{ +#if ! GEN_C_LIKE_CPP + Using_Code(CodeExec); + forceinline StrBuilder to_strbuilder() { return exec_to_strbuilder(* this); } + forceinline void to_strbuilder(StrBuilder& result) { return exec_to_strbuilder_ref(* this, & result); } +#endif + Using_CodeOps(CodeExec); + operator Code(); + AST_Exec *operator->(); + AST_Exec *ast; +}; + +#ifdef GEN_EXECUTION_EXPRESSION_SUPPORT +struct CodeExpr +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr ); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Expr* operator->(); + AST_Expr* ast; +}; + +struct CodeExpr_Assign +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr_Assign ); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Expr_Assign* operator->(); + AST_Expr_Assign* ast; +}; + +struct CodeExpr_Alignof +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr_Alignof ); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Expr_Alignof* operator->(); + AST_Expr_Alignof* ast; +}; + +struct CodeExpr_Binary +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr_Binary ); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Expr_Binary* operator->(); + AST_Expr_Binary* ast; +}; + +struct CodeExpr_CStyleCast +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr_CStyleCast ); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Expr_CStyleCast* operator->(); + AST_Expr_CStyleCast* ast; +}; + +struct CodeExpr_FunctionalCast +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr_FunctionalCast ); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Expr_FunctionalCast* operator->(); + AST_Expr_FunctionalCast* ast; +}; + +struct CodeExpr_CppCast +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr_CppCast ); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Expr_CppCast* operator->(); + AST_Expr_CppCast* ast; +}; + +struct CodeExpr_Element +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr_Element ); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Expr_Element* operator->(); + AST_Expr_Element* ast; +}; + +struct CodeExpr_ProcCall +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr_ProcCall ); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Expr_ProcCall* operator->(); + AST_Expr_ProcCall* ast; +}; + +struct CodeExpr_Decltype +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr_Decltype ); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Expr_Decltype* operator->(); + AST_Expr_Decltype* ast; +}; + +struct CodeExpr_Comma +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr_Comma ); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Expr_Comma* operator->(); + AST_Expr_Comma* ast; +}; + +struct CodeExpr_AMS +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr_AMS ); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Expr_AMS* operator->(); + AST_Expr_AMS* ast; +}; + +struct CodeExpr_Sizeof +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr_Sizeof ); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Expr_Sizeof* operator->(); + AST_Expr_Sizeof* ast; +}; + +struct CodeExpr_Subscript +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr_Subscript ); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Expr_Subscript* operator->(); + AST_Expr_Subscript* ast; +}; + +struct CodeExpr_Ternary +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr_Ternary ); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Expr_Ternary* operator->(); + AST_Expr_Ternary* ast; +}; + +struct CodeExpr_UnaryPrefix +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr_UnaryPrefix ); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Expr_UnaryPrefix* operator->(); + AST_Expr_UnaryPrefix* ast; +}; + +struct CodeExpr_UnaryPostfix +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr_UnaryPostfix ); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + AST* raw(); + operator Code(); + AST_Expr_UnaryPostfix* operator->(); + AST_Expr_UnaryPostfix* ast; +}; +#endif + +struct CodeExtern +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExtern ); + forceinline void to_strbuilder( StrBuilder& result ) { return extern_to_strbuilder(* this, & result); } +#endif + Using_CodeOps(CodeExtern); + operator Code(); + AST_Extern* operator->(); + AST_Extern* ast; +}; + +struct CodeInclude +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeInclude ); + forceinline StrBuilder to_strbuilder() { return include_to_strbuilder(* this); } + forceinline void to_strbuilder( StrBuilder& result ) { return include_to_strbuilder_ref(* this, & result); } +#endif + Using_CodeOps(CodeInclude); + operator Code(); + AST_Include* operator->(); + AST_Include* ast; +}; + +struct CodeFriend +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeFriend ); + forceinline StrBuilder to_strbuilder() { return friend_to_strbuilder(* this); } + forceinline void to_strbuilder( StrBuilder& result ) { return friend_to_strbuilder_ref(* this, & result); } +#endif + Using_CodeOps(CodeFriend); + operator Code(); + AST_Friend* operator->(); + AST_Friend* ast; +}; + +struct CodeFn +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeFn ); + forceinline StrBuilder to_strbuilder() { return fn_to_strbuilder(* this); } + forceinline void to_strbuilder_def( StrBuilder& result ) { return fn_to_strbuilder_def(* this, & result); } + forceinline void to_strbuilder_fwd( StrBuilder& result ) { return fn_to_strbuilder_fwd(* this, & result); } +#endif + Using_CodeOps(CodeFn); + operator Code(); + AST_Fn* operator->(); + AST_Fn* ast; +}; + +struct CodeModule +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeModule ); + forceinline StrBuilder to_strbuilder() { return module_to_strbuilder(* this); } + forceinline void to_strbuilder( StrBuilder& result ) { return module_to_strbuilder_ref(* this, & result); } +#endif + Using_CodeOps(CodeModule); + operator Code(); + AST_Module* operator->(); + AST_Module* ast; +}; + +struct CodeNS +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeNS ); + forceinline StrBuilder to_strbuilder() { return namespace_to_strbuilder(* this); } + forceinline void to_strbuilder( StrBuilder& result ) { return namespace_to_strbuilder_ref(* this, & result); } +#endif + Using_CodeOps(CodeNS); + operator Code(); + AST_NS* operator->(); + AST_NS* ast; +}; + +struct CodeOperator +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeOperator ); + forceinline StrBuilder to_strbuilder() { return code_op_to_strbuilder(* this); } + forceinline void to_strbuilder_def( StrBuilder& result ) { return code_op_to_strbuilder_def(* this, & result); } + forceinline void to_strbuilder_fwd( StrBuilder& result ) { return code_op_to_strbuilder_fwd(* this, & result); } +#endif + Using_CodeOps(CodeOperator); + operator Code(); + AST_Operator* operator->(); + AST_Operator* ast; +}; + +struct CodeOpCast +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeOpCast ); + forceinline StrBuilder to_strbuilder() { return opcast_to_strbuilder(* this); } + forceinline void to_strbuilder_def( StrBuilder& result ) { return opcast_to_strbuilder_def(* this, & result); } + forceinline void to_strbuilder_fwd( StrBuilder& result ) { return opcast_to_strbuilder_fwd(* this, & result); } +#endif + Using_CodeOps(CodeOpCast); + operator Code(); + AST_OpCast* operator->(); + AST_OpCast* ast; +}; + +struct CodePragma +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodePragma ); + forceinline StrBuilder to_strbuilder() { return pragma_to_strbuilder(* this); } + forceinline void to_strbuilder( StrBuilder& result ) { return pragma_to_strbuilder_ref(* this, & result); } +#endif + Using_CodeOps( CodePragma ); + operator Code(); + AST_Pragma* operator->(); + AST_Pragma* ast; +}; + +struct CodePreprocessCond +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodePreprocessCond ); + forceinline StrBuilder to_strbuilder() { return preprocess_to_strbuilder(* this); } + forceinline void to_strbuilder_if( StrBuilder& result ) { return preprocess_to_strbuilder_if(* this, & result); } + forceinline void to_strbuilder_ifdef( StrBuilder& result ) { return preprocess_to_strbuilder_ifdef(* this, & result); } + forceinline void to_strbuilder_ifndef( StrBuilder& result ) { return preprocess_to_strbuilder_ifndef(* this, & result); } + forceinline void to_strbuilder_elif( StrBuilder& result ) { return preprocess_to_strbuilder_elif(* this, & result); } + forceinline void to_strbuilder_else( StrBuilder& result ) { return preprocess_to_strbuilder_else(* this, & result); } + forceinline void to_strbuilder_endif( StrBuilder& result ) { return preprocess_to_strbuilder_endif(* this, & result); } +#endif + Using_CodeOps( CodePreprocessCond ); + operator Code(); + AST_PreprocessCond* operator->(); + AST_PreprocessCond* ast; +}; + +#ifdef GEN_EXECUTION_EXPRESSION_SUPPORT +struct CodeStmt +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeStmt ); + forceinline StrBuilder to_strbuilder(); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Stmt* operator->(); + AST_Stmt* ast; +}; + +struct CodeStmt_Break +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeStmt_Break ); + forceinline StrBuilder to_strbuilder(); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Stmt_Break* operator->(); + AST_Stmt_Break* ast; +}; + +struct CodeStmt_Case +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeStmt_Case ); + forceinline StrBuilder to_strbuilder(); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Stmt_Case* operator->(); + AST_Stmt_Case* ast; +}; + +struct CodeStmt_Continue +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeStmt_Continue ); + forceinline StrBuilder to_strbuilder(); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Stmt_Continue* operator->(); + AST_Stmt_Continue* ast; +}; + +struct CodeStmt_Decl +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeStmt_Decl ); + forceinline StrBuilder to_strbuilder(); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Stmt_Decl* operator->(); + AST_Stmt_Decl* ast; +}; + +struct CodeStmt_Do +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeStmt_Do ); + forceinline StrBuilder to_strbuilder(); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Stmt_Do* operator->(); + AST_Stmt_Do* ast; +}; + +struct CodeStmt_Expr +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeStmt_Expr ); + forceinline StrBuilder to_strbuilder(); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Stmt_Expr* operator->(); + AST_Stmt_Expr* ast; +}; + +struct CodeStmt_Else +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeStmt_Else ); + forceinline StrBuilder to_strbuilder(); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Stmt_Else* operator->(); + AST_Stmt_Else* ast; +}; + +struct CodeStmt_If +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeStmt_If ); + forceinline StrBuilder to_strbuilder(); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Stmt_If* operator->(); + AST_Stmt_If* ast; +}; + +struct CodeStmt_For +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeStmt_For ); + forceinline StrBuilder to_strbuilder(); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Stmt_For* operator->(); + AST_Stmt_For* ast; +}; + +struct CodeStmt_Goto +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeStmt_Goto ); + forceinline StrBuilder to_strbuilder(); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Stmt_Goto* operator->(); + AST_Stmt_Goto* ast; +}; + +struct CodeStmt_Label +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeStmt_Label ); + forceinline StrBuilder to_strbuilder(); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Stmt_Label* operator->(); + AST_Stmt_Label* ast; +}; + +struct CodeStmt_Switch +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeStmt_Switch ); + forceinline StrBuilder to_strbuilder(); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Stmt_Switch* operator->(); + AST_Stmt_Switch* ast; +}; + +struct CodeStmt_While +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeStmt_While ); + forceinline StrBuilder to_strbuilder(); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Stmt_While* operator->(); + AST_Stmt_While* ast; +}; +#endif + +struct CodeTemplate +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeTemplate ); + forceinline StrBuilder to_strbuilder() { return template_to_strbuilder(* this); } + forceinline void to_strbuilder( StrBuilder& result ) { return template_to_strbuilder_ref(* this, & result); } +#endif + Using_CodeOps( CodeTemplate ); + operator Code(); + AST_Template* operator->(); + AST_Template* ast; +}; + +struct CodeTypename +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeTypename ); + forceinline StrBuilder to_strbuilder() { return typename_to_strbuilder(* this); } + forceinline void to_strbuilder( StrBuilder& result ) { return typename_to_strbuilder_ref(* this, & result); } +#endif + Using_CodeOps( CodeTypename ); + operator Code(); + AST_Typename* operator->(); + AST_Typename* ast; +}; + +struct CodeTypedef +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeTypedef ); + forceinline StrBuilder to_strbuilder() { return typedef_to_strbuilder(* this); } + forceinline void to_strbuilder( StrBuilder& result ) { return typedef_to_strbuilder_ref(* this, & result); } +#endif + Using_CodeOps( CodeTypedef ); + operator Code(); + AST_Typedef* operator->(); + AST_Typedef* ast; +}; + +struct CodeUnion +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeUnion ); + forceinline StrBuilder to_strbuilder() { return union_to_strbuilder(* this); } + forceinline void to_strbuilder_def( StrBuilder& result ) { return union_to_strbuilder_def(* this, & result); } + forceinline void to_strbuilder_fwd( StrBuilder& result ) { return union_to_strbuilder_fwd(* this, & result); } +#endif + Using_CodeOps(CodeUnion); + operator Code(); + AST_Union* operator->(); + AST_Union* ast; +}; + +struct CodeUsing +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeUsing ); + forceinline StrBuilder to_strbuilder() { return using_to_strbuilder(* this); } + forceinline void to_strbuilder( StrBuilder& result ) { return using_to_strbuilder_ref(* this, & result); } + forceinline void to_strbuilder_ns( StrBuilder& result ) { return using_to_strbuilder_ns(* this, & result); } +#endif + Using_CodeOps(CodeUsing); + operator Code(); + AST_Using* operator->(); + AST_Using* ast; +}; + +struct CodeVar +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeVar ); + forceinline StrBuilder to_strbuilder() { return var_to_strbuilder(* this); } + forceinline void to_strbuilder( StrBuilder& result ) { return var_to_strbuilder_ref(* this, & result); } +#endif + Using_CodeOps(CodeVar); + operator Code(); + AST_Var* operator->(); + AST_Var* ast; +}; + +struct CodeStruct +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeStruct ); + forceinline void add_interface( CodeTypename interface ) { return struct_add_interface(* this, interface); } + forceinline StrBuilder to_strbuilder() { return struct_to_strbuilder(* this); } + forceinline void to_strbuilder_fwd( StrBuilder& result ) { return struct_to_strbuilder_fwd(* this, & result); } + forceinline void to_strbuilder_def( StrBuilder& result ) { return struct_to_strbuilder_def(* this, & result); } +#endif + Using_CodeOps( CodeStruct ); + forceinline operator Code() { return * rcast( Code*, this ); } + forceinline AST_Struct* operator->() { + GEN_ASSERT(ast); + return ast; + } + AST_Struct* ast; +}; + +#undef Define_CodeType +#undef Using_Code +#undef Using_CodeOps + +#undef Verify_POD + +struct InvalidCode_ImplictCaster +{ + // operator CodeBaseClass() const; + operator Code () const { return Code_Invalid; } + operator CodeBody () const { return cast(CodeBody, Code_Invalid); } + operator CodeAttributes () const { return cast(CodeAttributes, Code_Invalid); } + operator CodeComment () const { return cast(CodeComment, Code_Invalid); } + operator CodeClass () const { return cast(CodeClass, Code_Invalid); } + operator CodeConstructor () const { return cast(CodeConstructor, Code_Invalid); } + operator CodeDefine () const { return cast(CodeDefine, Code_Invalid); } + operator CodeDefineParams () const { return cast(CodeDefineParams, Code_Invalid); } + operator CodeDestructor () const { return cast(CodeDestructor, Code_Invalid); } + operator CodeExec () const { return cast(CodeExec, Code_Invalid); } + operator CodeEnum () const { return cast(CodeEnum, Code_Invalid); } + operator CodeExtern () const { return cast(CodeExtern, Code_Invalid); } + operator CodeInclude () const { return cast(CodeInclude, Code_Invalid); } + operator CodeFriend () const { return cast(CodeFriend, Code_Invalid); } + operator CodeFn () const { return cast(CodeFn, Code_Invalid); } + operator CodeModule () const { return cast(CodeModule, Code_Invalid); } + operator CodeNS () const { return cast(CodeNS, Code_Invalid); } + operator CodeOperator () const { return cast(CodeOperator, Code_Invalid); } + operator CodeOpCast () const { return cast(CodeOpCast, Code_Invalid); } + operator CodeParams () const { return cast(CodeParams, Code_Invalid); } + operator CodePragma () const { return cast(CodePragma, Code_Invalid); } + operator CodePreprocessCond() const { return cast(CodePreprocessCond, Code_Invalid); } + operator CodeSpecifiers () const { return cast(CodeSpecifiers, Code_Invalid); } + operator CodeStruct () const { return cast(CodeStruct, Code_Invalid); } + operator CodeTemplate () const { return cast(CodeTemplate, Code_Invalid); } + operator CodeTypename () const { return cast(CodeTypename, Code_Invalid); } + operator CodeTypedef () const { return cast(CodeTypedef, Code_Invalid); } + operator CodeUnion () const { return cast(CodeUnion, Code_Invalid); } + operator CodeUsing () const { return cast(CodeUsing, Code_Invalid); } + operator CodeVar () const { return cast(CodeVar, Code_Invalid); } +}; + +struct NullCode_ImplicitCaster +{ + operator Code () const { return {nullptr}; } + operator CodeBody () const { return {(AST_Body*) nullptr}; } + operator CodeAttributes () const { return {(AST_Attributes*)nullptr}; } + operator CodeComment () const { return {nullptr}; } + operator CodeClass () const { return {nullptr}; } + operator CodeConstructor () const { return {nullptr}; } + operator CodeDefine () const { return {nullptr}; } + operator CodeDefineParams () const { return {nullptr}; } + operator CodeDestructor () const { return {nullptr}; } + operator CodeExec () const { return {nullptr}; } + operator CodeEnum () const { return {nullptr}; } + operator CodeExtern () const { return {nullptr}; } + operator CodeInclude () const { return {nullptr}; } + operator CodeFriend () const { return {nullptr}; } + operator CodeFn () const { return {nullptr}; } + operator CodeModule () const { return {nullptr}; } + operator CodeNS () const { return {nullptr}; } + operator CodeOperator () const { return {nullptr}; } + operator CodeOpCast () const { return {nullptr}; } + operator CodeParams () const { return {nullptr}; } + operator CodePragma () const { return {nullptr}; } + operator CodePreprocessCond() const { return {nullptr}; } + operator CodeSpecifiers () const { return {nullptr}; } + operator CodeStruct () const { return {nullptr}; } + operator CodeTemplate () const { return {nullptr}; } + operator CodeTypename () const { return CodeTypename{(AST_Typename*)nullptr}; } + operator CodeTypedef () const { return {nullptr}; } + operator CodeUnion () const { return {nullptr}; } + operator CodeUsing () const { return {nullptr}; } + operator CodeVar () const { return {nullptr}; } +}; + +forceinline Code begin( CodeBody body) { return begin_CodeBody(body); } +forceinline Code end ( CodeBody body ) { return end_CodeBody(body); } +forceinline Code next ( CodeBody body, Code entry_iter ) { return next_CodeBody(body, entry_iter); } + +forceinline CodeParams begin(CodeParams params) { return begin_CodeParams(params); } +forceinline CodeParams end (CodeParams params) { return end_CodeParams(params); } +forceinline CodeParams next (CodeParams params, CodeParams entry_iter) { return next_CodeParams(params, entry_iter); } + +forceinline Specifier* begin(CodeSpecifiers specifiers) { return begin_CodeSpecifiers(specifiers); } +forceinline Specifier* end (CodeSpecifiers specifiers) { return end_CodeSpecifiers(specifiers); } +forceinline Specifier* next (CodeSpecifiers specifiers, Specifier& spec_iter) { return next_CodeSpecifiers(specifiers, & spec_iter); } + +#if ! GEN_C_LIKE_CPP +GEN_OPTIMIZE_MAPPINGS_BEGIN + +forceinline void append ( CodeBody body, Code other ) { return body_append(body, other); } +forceinline void append ( CodeBody body, CodeBody other ) { return body_append_body(body, other); } +forceinline StrBuilder to_strbuilder ( CodeBody body ) { return body_to_strbuilder(body); } +forceinline void to_strbuilder ( CodeBody body, StrBuilder& result ) { return body_to_strbuilder_ref(body, & result); } +forceinline void to_strbuilder_export( CodeBody body, StrBuilder& result ) { return body_to_strbuilder_export(body, & result); } + +forceinline void add_interface ( CodeClass self, CodeTypename interface ) { return class_add_interface(self, interface); } +forceinline StrBuilder to_strbuilder ( CodeClass self ) { return class_to_strbuilder(self); } +forceinline void to_strbuilder_def( CodeClass self, StrBuilder& result ) { return class_to_strbuilder_def(self, & result); } +forceinline void to_strbuilder_fwd( CodeClass self, StrBuilder& result ) { return class_to_strbuilder_fwd(self, & result); } + +forceinline void append (CodeDefineParams appendee, CodeDefineParams other ) { params_append(cast(CodeParams, appendee), cast(CodeParams, other)); } +forceinline CodeDefineParams get (CodeDefineParams params, s32 idx) { return (CodeDefineParams) (Code) params_get(cast(CodeParams, params), idx); } +forceinline bool has_entries (CodeDefineParams params ) { return params_has_entries(cast(CodeParams, params)); } +forceinline StrBuilder to_strbuilder(CodeDefineParams params ) { return define_params_to_strbuilder(params); } +forceinline void to_strbuilder(CodeDefineParams params, StrBuilder& result ) { return define_params_to_strbuilder_ref(params, & result); } + +forceinline void append (CodeParams appendee, CodeParams other ) { return params_append(appendee, other); } +forceinline CodeParams get (CodeParams params, s32 idx) { return params_get(params, idx); } +forceinline bool has_entries (CodeParams params ) { return params_has_entries(params); } +forceinline StrBuilder to_strbuilder(CodeParams params ) { return params_to_strbuilder(params); } +forceinline void to_strbuilder(CodeParams params, StrBuilder& result ) { return params_to_strbuilder_ref(params, & result); } + +forceinline bool append (CodeSpecifiers specifiers, Specifier spec) { return specifiers_append(specifiers, spec); } +forceinline s32 has (CodeSpecifiers specifiers, Specifier spec) { return specifiers_has(specifiers, spec); } +forceinline s32 remove (CodeSpecifiers specifiers, Specifier to_remove ) { return specifiers_remove(specifiers, to_remove); } +forceinline StrBuilder to_strbuilder(CodeSpecifiers specifiers) { return specifiers_to_strbuilder(specifiers); } +forceinline void to_strbuilder(CodeSpecifiers specifiers, StrBuilder& result) { return specifiers_to_strbuilder_ref(specifiers, & result); } + +forceinline void add_interface (CodeStruct self, CodeTypename interface) { return struct_add_interface(self, interface); } +forceinline StrBuilder to_strbuilder (CodeStruct self) { return struct_to_strbuilder(self); } +forceinline void to_strbuilder_fwd(CodeStruct self, StrBuilder& result) { return struct_to_strbuilder_fwd(self, & result); } +forceinline void to_strbuilder_def(CodeStruct self, StrBuilder& result) { return struct_to_strbuilder_def(self, & result); } + +forceinline StrBuilder to_strbuilder(CodeAttributes attributes) { return attributes_to_strbuilder(attributes); } +forceinline void to_strbuilder(CodeAttributes attributes, StrBuilder& result) { return attributes_to_strbuilder_ref(attributes, & result); } + +forceinline StrBuilder to_strbuilder(CodeComment comment ) { return comment_to_strbuilder(comment); } +forceinline void to_strbuilder(CodeComment comment, StrBuilder& result ) { return comment_to_strbuilder_ref(comment, & result); } + +forceinline StrBuilder to_strbuilder (CodeConstructor constructor) { return constructor_to_strbuilder(constructor); } +forceinline void to_strbuilder_def(CodeConstructor constructor, StrBuilder& result ) { return constructor_to_strbuilder_def(constructor, & result); } +forceinline void to_strbuilder_fwd(CodeConstructor constructor, StrBuilder& result ) { return constructor_to_strbuilder_fwd(constructor, & result); } + +forceinline StrBuilder to_strbuilder(CodeDefine self) { return define_to_strbuilder(self); } +forceinline void to_strbuilder(CodeDefine self, StrBuilder& result) { return define_to_strbuilder_ref(self, & result); } + +forceinline StrBuilder to_strbuilder (CodeDestructor destructor) { return destructor_to_strbuilder(destructor); } +forceinline void to_strbuilder_def(CodeDestructor destructor, StrBuilder& result ) { return destructor_to_strbuilder_def(destructor, & result); } +forceinline void to_strbuilder_fwd(CodeDestructor destructor, StrBuilder& result ) { return destructor_to_strbuilder_fwd(destructor, & result); } + +forceinline StrBuilder to_strbuilder (CodeEnum self) { return enum_to_strbuilder(self); } +forceinline void to_strbuilder_def (CodeEnum self, StrBuilder& result ) { return enum_to_strbuilder_def(self, & result); } +forceinline void to_strbuilder_fwd (CodeEnum self, StrBuilder& result ) { return enum_to_strbuilder_fwd(self, & result); } +forceinline void to_strbuilder_class_def(CodeEnum self, StrBuilder& result ) { return enum_to_strbuilder_class_def(self, & result); } +forceinline void to_strbuilder_class_fwd(CodeEnum self, StrBuilder& result ) { return enum_to_strbuilder_class_fwd(self, & result); } + +forceinline StrBuilder to_strbuilder(CodeExec exec) { return exec_to_strbuilder(exec); } +forceinline void to_strbuilder(CodeExec exec, StrBuilder& result) { return exec_to_strbuilder_ref(exec, & result); } + +forceinline void to_strbuilder(CodeExtern self, StrBuilder& result) { return extern_to_strbuilder(self, & result); } + +forceinline StrBuilder to_strbuilder(CodeInclude self) { return include_to_strbuilder(self); } +forceinline void to_strbuilder(CodeInclude self, StrBuilder& result) { return include_to_strbuilder_ref(self, & result); } + +forceinline StrBuilder to_strbuilder(CodeFriend self) { return friend_to_strbuilder(self); } +forceinline void to_strbuilder(CodeFriend self, StrBuilder& result) { return friend_to_strbuilder_ref(self, & result); } + +forceinline StrBuilder to_strbuilder (CodeFn self) { return fn_to_strbuilder(self); } +forceinline void to_strbuilder_def(CodeFn self, StrBuilder& result) { return fn_to_strbuilder_def(self, & result); } +forceinline void to_strbuilder_fwd(CodeFn self, StrBuilder& result) { return fn_to_strbuilder_fwd(self, & result); } + +forceinline StrBuilder to_strbuilder(CodeModule self) { return module_to_strbuilder(self); } +forceinline void to_strbuilder(CodeModule self, StrBuilder& result) { return module_to_strbuilder_ref(self, & result); } + +forceinline StrBuilder to_strbuilder(CodeNS self) { return namespace_to_strbuilder(self); } +forceinline void to_strbuilder(CodeNS self, StrBuilder& result) { return namespace_to_strbuilder_ref(self, & result); } + +forceinline StrBuilder to_strbuilder (CodeOperator self) { return code_op_to_strbuilder(self); } +forceinline void to_strbuilder_fwd(CodeOperator self, StrBuilder& result ) { return code_op_to_strbuilder_fwd(self, & result); } +forceinline void to_strbuilder_def(CodeOperator self, StrBuilder& result ) { return code_op_to_strbuilder_def(self, & result); } + +forceinline StrBuilder to_strbuilder (CodeOpCast op_cast ) { return opcast_to_strbuilder(op_cast); } +forceinline void to_strbuilder_def(CodeOpCast op_cast, StrBuilder& result ) { return opcast_to_strbuilder_def(op_cast, & result); } +forceinline void to_strbuilder_fwd(CodeOpCast op_cast, StrBuilder& result ) { return opcast_to_strbuilder_fwd(op_cast, & result); } + +forceinline StrBuilder to_strbuilder(CodePragma self) { return pragma_to_strbuilder(self); } +forceinline void to_strbuilder(CodePragma self, StrBuilder& result) { return pragma_to_strbuilder_ref(self, & result); } + +forceinline StrBuilder to_strbuilder (CodePreprocessCond cond) { return preprocess_to_strbuilder(cond); } +forceinline void to_strbuilder_if (CodePreprocessCond cond, StrBuilder& result ) { return preprocess_to_strbuilder_if(cond, & result); } +forceinline void to_strbuilder_ifdef (CodePreprocessCond cond, StrBuilder& result ) { return preprocess_to_strbuilder_ifdef(cond, & result); } +forceinline void to_strbuilder_ifndef(CodePreprocessCond cond, StrBuilder& result ) { return preprocess_to_strbuilder_ifndef(cond, & result); } +forceinline void to_strbuilder_elif (CodePreprocessCond cond, StrBuilder& result ) { return preprocess_to_strbuilder_elif(cond, & result); } +forceinline void to_strbuilder_else (CodePreprocessCond cond, StrBuilder& result ) { return preprocess_to_strbuilder_else(cond, & result); } +forceinline void to_strbuilder_endif (CodePreprocessCond cond, StrBuilder& result ) { return preprocess_to_strbuilder_endif(cond, & result); } + +forceinline StrBuilder to_strbuilder(CodeTemplate self) { return template_to_strbuilder(self); } +forceinline void to_strbuilder(CodeTemplate self, StrBuilder& result) { return template_to_strbuilder_ref(self, & result); } + +forceinline StrBuilder to_strbuilder(CodeTypename self) { return typename_to_strbuilder(self); } +forceinline void to_strbuilder(CodeTypename self, StrBuilder& result) { return typename_to_strbuilder_ref(self, & result); } + +forceinline StrBuilder to_strbuilder(CodeTypedef self) { return typedef_to_strbuilder(self); } +forceinline void to_strbuilder(CodeTypedef self, StrBuilder& result ) { return typedef_to_strbuilder_ref(self, & result); } + +forceinline StrBuilder to_strbuilder (CodeUnion self) { return union_to_strbuilder(self); } +forceinline void to_strbuilder_def(CodeUnion self, StrBuilder& result) { return union_to_strbuilder_def(self, & result); } +forceinline void to_strbuilder_fwd(CodeUnion self, StrBuilder& result) { return union_to_strbuilder_fwd(self, & result); } + +forceinline StrBuilder to_strbuilder (CodeUsing op_cast ) { return using_to_strbuilder(op_cast); } +forceinline void to_strbuilder (CodeUsing op_cast, StrBuilder& result ) { return using_to_strbuilder_ref(op_cast, & result); } +forceinline void to_strbuilder_ns(CodeUsing op_cast, StrBuilder& result ) { return using_to_strbuilder_ns(op_cast, & result); } + +forceinline StrBuilder to_strbuilder(CodeVar self) { return var_to_strbuilder(self); } +forceinline void to_strbuilder(CodeVar self, StrBuilder& result) { return var_to_strbuilder_ref(self, & result); } + +GEN_OPITMIZE_MAPPINGS_END +#endif //if GEN_C_LIKE_CPP + +#pragma endregion Code Types C++ +#endif //if GEN_COMPILER_CPP + +#pragma region AST Types + +/* + ______ ______ ________ ________ + / \ / \| \ | \ +| ▓▓▓▓▓▓\ ▓▓▓▓▓▓\\▓▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓▓__ __ ______ ______ _______ +| ▓▓__| ▓▓ ▓▓___\▓▓ | ▓▓ | ▓▓ | \ | \/ \ / \ / \ +| ▓▓ ▓▓\▓▓ \ | ▓▓ | ▓▓ | ▓▓ | ▓▓ ▓▓▓▓▓▓\ ▓▓▓▓▓▓\ ▓▓▓▓▓▓▓ +| ▓▓▓▓▓▓▓▓_\▓▓▓▓▓▓\ | ▓▓ | ▓▓ | ▓▓ | ▓▓ ▓▓ | ▓▓ ▓▓ ▓▓\▓▓ \ +| ▓▓ | ▓▓ \__| ▓▓ | ▓▓ | ▓▓ | ▓▓__/ ▓▓ ▓▓__/ ▓▓ ▓▓▓▓▓▓▓▓_\▓▓▓▓▓▓\ +| ▓▓ | ▓▓\▓▓ ▓▓ | ▓▓ | ▓▓ \▓▓ ▓▓ ▓▓ ▓▓\▓▓ \ ▓▓ + \▓▓ \▓▓ \▓▓▓▓▓▓ \▓▓ \▓▓ _\▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓\▓▓▓▓▓▓▓ + | \__| ▓▓ ▓▓ + \▓▓ ▓▓ ▓▓ + \▓▓▓▓▓▓ \▓▓ +*/ + +/* + Show only relevant members of the AST for its type. + AST* fields are replaced with Code types. + - Guards assignemnts to AST* fields to ensure the AST is duplicated if assigned to another parent. +*/ + +struct AST_Body +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + Code Front; + Code Back; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) ]; + s32 NumEntries; +}; +static_assert( sizeof(AST_Body) == sizeof(AST), "ERROR: AST_Body is not the same size as AST"); + +// TODO(Ed): Support chaining attributes (Use parameter linkage pattern) +struct AST_Attributes +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + StrCached Content; + }; + StrCached Name; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Attributes) == sizeof(AST), "ERROR: AST_Attributes is not the same size as AST"); + +#if 0 +struct AST_BaseClass +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_BaseClass) == sizeof(AST), "ERROR: AST_BaseClass is not the same size as AST"); +#endif + +struct AST_Comment +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + StrCached Content; + }; + StrCached Name; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Comment) == sizeof(AST), "ERROR: AST_Comment is not the same size as AST"); + +struct AST_Class +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + struct + { + CodeComment InlineCmt; // Only supported by forward declarations + CodeAttributes Attributes; + CodeSpecifiers Specs; // Support for final + CodeTypename ParentType; + char _PAD_PARAMS_[ sizeof(AST*) ]; + CodeBody Body; + char _PAD_PROPERTIES_2_[ sizeof(AST*) ]; + }; + }; + StrCached Name; + CodeTypename Prev; + CodeTypename Next; + Token* Tok; + Code Parent; + CodeType Type; + ModuleFlag ModuleFlags; + AccessSpec ParentAccess; +}; +static_assert( sizeof(AST_Class) == sizeof(AST), "ERROR: AST_Class is not the same size as AST"); + +struct AST_Constructor +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + struct + { + CodeComment InlineCmt; // Only supported by forward declarations + char _PAD_PROPERTIES_ [ sizeof(AST*) * 1 ]; + CodeSpecifiers Specs; + Code InitializerList; + CodeParams Params; + Code Body; + char _PAD_PROPERTIES_2_ [ sizeof(AST*) * 2 ]; + }; + }; + StrCached Name; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Constructor) == sizeof(AST), "ERROR: AST_Constructor is not the same size as AST"); + +struct AST_Define +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + struct + { + char _PAD_PROPERTIES_ [ sizeof(AST*) * 4 ]; + CodeDefineParams Params; + Code Body; // Should be completely serialized for now to a: StrCached Content. + char _PAD_PROPERTIES_2_ [ sizeof(AST*) * 1 ]; + }; + }; + StrCached Name; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Define) == sizeof(AST), "ERROR: AST_Define is not the same size as AST"); + +struct AST_DefineParams +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeDefineParams Last; + CodeDefineParams Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) ]; + s32 NumEntries; +}; +static_assert( sizeof(AST_DefineParams) == sizeof(AST), "ERROR: AST_DefineParams is not the same size as AST"); + +struct AST_Destructor +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + struct + { + CodeComment InlineCmt; + char _PAD_PROPERTIES_ [ sizeof(AST*) * 1 ]; + CodeSpecifiers Specs; + char _PAD_PROPERTIES_2_ [ sizeof(AST*) * 2 ]; + Code Body; + char _PAD_PROPERTIES_3_ [ sizeof(AST*) ]; + }; + }; + StrCached Name; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Destructor) == sizeof(AST), "ERROR: AST_Destructor is not the same size as AST"); + +struct AST_Enum +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + struct + { + CodeComment InlineCmt; + CodeAttributes Attributes; + char _PAD_SPEC_ [ sizeof(AST*) ]; + CodeTypename UnderlyingType; + Code UnderlyingTypeMacro; + CodeBody Body; + char _PAD_PROPERTIES_2_[ sizeof(AST*) ]; + }; + }; + StrCached Name; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + ModuleFlag ModuleFlags; + char _PAD_UNUSED_[ sizeof(u32) ]; +}; +static_assert( sizeof(AST_Enum) == sizeof(AST), "ERROR: AST_Enum is not the same size as AST"); + +struct AST_Exec +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + StrCached Content; + }; + StrCached Name; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Exec) == sizeof(AST), "ERROR: AST_Exec is not the same size as AST"); + +#ifdef GEN_EXECUTION_EXPRESSION_SUPPORT +struct AST_Expr +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Expr) == sizeof(AST), "ERROR: AST_Expr is not the same size as AST"); + +struct AST_Expr_Assign +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Expr_Assign) == sizeof(AST), "ERROR: AST_Expr_Assign is not the same size as AST"); + +struct AST_Expr_Alignof +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Expr_Alignof) == sizeof(AST), "ERROR: AST_Expr_Alignof is not the same size as AST"); + +struct AST_Expr_Binary +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Expr_Binary) == sizeof(AST), "ERROR: AST_Expr_Binary is not the same size as AST"); + +struct AST_Expr_CStyleCast +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Expr_CStyleCast) == sizeof(AST), "ERROR: AST_Expr_CStyleCast is not the same size as AST"); + +struct AST_Expr_FunctionalCast +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Expr_FunctionalCast) == sizeof(AST), "ERROR: AST_Expr_FunctionalCast is not the same size as AST"); + +struct AST_Expr_CppCast +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Expr_CppCast) == sizeof(AST), "ERROR: AST_Expr_CppCast is not the same size as AST"); + +struct AST_Expr_ProcCall +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Expr_ProcCall) == sizeof(AST), "ERROR: AST_Expr_Identifier is not the same size as AST"); + +struct AST_Expr_Decltype +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Expr_Decltype) == sizeof(AST), "ERROR: AST_Expr_Decltype is not the same size as AST"); + +struct AST_Expr_Comma +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Expr_Comma) == sizeof(AST), "ERROR: AST_Expr_Comma is not the same size as AST"); + +struct AST_Expr_AMS +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Expr_AMS) == sizeof(AST), "ERROR: AST_Expr_AMS is not the same size as AST"); + +struct AST_Expr_Sizeof +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Expr_Sizeof) == sizeof(AST), "ERROR: AST_Expr_Sizeof is not the same size as AST"); + +struct AST_Expr_Subscript +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Expr_Subscript) == sizeof(AST), "ERROR: AST_Expr_Subscript is not the same size as AST"); + +struct AST_Expr_Ternary +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Expr_Ternary) == sizeof(AST), "ERROR: AST_Expr_Ternary is not the same size as AST"); + +struct AST_Expr_UnaryPrefix +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Expr_UnaryPrefix) == sizeof(AST), "ERROR: AST_Expr_UnaryPrefix is not the same size as AST"); + +struct AST_Expr_UnaryPostfix +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Expr_UnaryPostfix) == sizeof(AST), "ERROR: AST_Expr_UnaryPostfix is not the same size as AST"); + +struct AST_Expr_Element +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Expr_Element) == sizeof(AST), "ERROR: AST_Expr_Element is not the same size as AST"); +#endif + +struct AST_Extern +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + struct + { + char _PAD_PROPERTIES_[ sizeof(AST*) * 5 ]; + CodeBody Body; + char _PAD_PROPERTIES_2_[ sizeof(AST*) ]; + }; + }; + StrCached Name; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Extern) == sizeof(AST), "ERROR: AST_Extern is not the same size as AST"); + +struct AST_Include +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + StrCached Content; + }; + StrCached Name; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Include) == sizeof(AST), "ERROR: AST_Include is not the same size as AST"); + +struct AST_Friend +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + struct + { + CodeComment InlineCmt; + char _PAD_PROPERTIES_[ sizeof(AST*) * 4 ]; + Code Declaration; + char _PAD_PROPERTIES_2_[ sizeof(AST*) ]; + }; + }; + StrCached Name; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Friend) == sizeof(AST), "ERROR: AST_Friend is not the same size as AST"); + +struct AST_Fn +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + struct + { + CodeComment InlineCmt; + CodeAttributes Attributes; + CodeSpecifiers Specs; + CodeTypename ReturnType; + CodeParams Params; + CodeBody Body; + Code SuffixSpecs; // Thanks Unreal + }; + }; + StrCached Name; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + ModuleFlag ModuleFlags; + char _PAD_UNUSED_[ sizeof(u32) ]; +}; +static_assert( sizeof(AST_Fn) == sizeof(AST), "ERROR: AST_Fn is not the same size as AST"); + +struct AST_Module +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + ModuleFlag ModuleFlags; + char _PAD_UNUSED_[ sizeof(u32) ]; +}; +static_assert( sizeof(AST_Module) == sizeof(AST), "ERROR: AST_Module is not the same size as AST"); + +struct AST_NS +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + struct { + char _PAD_PROPERTIES_[ sizeof(AST*) * 5 ]; + CodeBody Body; + char _PAD_PROPERTIES_2_[ sizeof(AST*) ]; + }; + }; + StrCached Name; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + ModuleFlag ModuleFlags; + char _PAD_UNUSED_[ sizeof(u32) ]; +}; +static_assert( sizeof(AST_NS) == sizeof(AST), "ERROR: AST_NS is not the same size as AST"); + +struct AST_Operator +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + struct + { + CodeComment InlineCmt; + CodeAttributes Attributes; + CodeSpecifiers Specs; + CodeTypename ReturnType; + CodeParams Params; + CodeBody Body; + char _PAD_PROPERTIES_ [ sizeof(AST*) ]; + }; + }; + StrCached Name; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + ModuleFlag ModuleFlags; + Operator Op; +}; +static_assert( sizeof(AST_Operator) == sizeof(AST), "ERROR: AST_Operator is not the same size as AST"); + +struct AST_OpCast +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + struct + { + CodeComment InlineCmt; + char _PAD_PROPERTIES_[ sizeof(AST*) ]; + CodeSpecifiers Specs; + CodeTypename ValueType; + char _PAD_PROPERTIES_2_[ sizeof(AST*) ]; + CodeBody Body; + char _PAD_PROPERTIES_3_[ sizeof(AST*) ]; + }; + }; + StrCached Name; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_OpCast) == sizeof(AST), "ERROR: AST_OpCast is not the same size as AST"); + +struct AST_Params +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + struct + { + // TODO(Ed): Support attributes for parameters (Some prefix macros can be converted to that...) + char _PAD_PROPERTIES_2_[ sizeof(AST*) * 3 ]; + CodeTypename ValueType; + Code Macro; + Code Value; + Code PostNameMacro; // Thanks Unreal + // char _PAD_PROPERTIES_3_[sizeof( AST* )]; + }; + }; + StrCached Name; + CodeParams Last; + CodeParams Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) ]; + s32 NumEntries; +}; +static_assert( sizeof(AST_Params) == sizeof(AST), "ERROR: AST_Params is not the same size as AST"); + +struct AST_Pragma +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + StrCached Content; + }; + StrCached Name; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Pragma) == sizeof(AST), "ERROR: AST_Pragma is not the same size as AST"); + +struct AST_PreprocessCond +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + StrCached Content; + }; + StrCached Name; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_PreprocessCond) == sizeof(AST), "ERROR: AST_PreprocessCond is not the same size as AST"); + +struct AST_Specifiers +{ + Specifier ArrSpecs[ AST_ArrSpecs_Cap ]; + CodeSpecifiers NextSpecs; + StrCached Name; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) ]; + s32 NumEntries; +}; +static_assert( sizeof(AST_Specifiers) == sizeof(AST), "ERROR: AST_Specifier is not the same size as AST"); + +#ifdef GEN_EXECUTION_EXPRESSION_SUPPORT +struct AST_Stmt +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Stmt) == sizeof(AST), "ERROR: AST_Stmt is not the same size as AST"); + +struct AST_Stmt_Break +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Stmt_Break) == sizeof(AST), "ERROR: AST_Stmt_Break is not the same size as AST"); + +struct AST_Stmt_Case +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Stmt_Case) == sizeof(AST), "ERROR: AST_Stmt_Case is not the same size as AST"); + +struct AST_Stmt_Continue +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Stmt_Continue) == sizeof(AST), "ERROR: AST_Stmt_Continue is not the same size as AST"); + +struct AST_Stmt_Decl +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Stmt_Decl) == sizeof(AST), "ERROR: AST_Stmt_Decl is not the same size as AST"); + +struct AST_Stmt_Do +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Stmt_Do) == sizeof(AST), "ERROR: AST_Stmt_Do is not the same size as AST"); + +struct AST_Stmt_Expr +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Stmt_Expr) == sizeof(AST), "ERROR: AST_Stmt_Expr is not the same size as AST"); + +struct AST_Stmt_Else +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Stmt_Else) == sizeof(AST), "ERROR: AST_Stmt_Else is not the same size as AST"); + +struct AST_Stmt_If +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Stmt_If) == sizeof(AST), "ERROR: AST_Stmt_If is not the same size as AST"); + +struct AST_Stmt_For +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Stmt_For) == sizeof(AST), "ERROR: AST_Stmt_For is not the same size as AST"); + +struct AST_Stmt_Goto +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Stmt_Goto) == sizeof(AST), "ERROR: AST_Stmt_Goto is not the same size as AST"); + +struct AST_Stmt_Label +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Stmt_Label) == sizeof(AST), "ERROR: AST_Stmt_Label is not the same size as AST"); + +struct AST_Stmt_Switch +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Stmt_Switch) == sizeof(AST), "ERROR: AST_Stmt_Switch is not the same size as AST"); + +struct AST_Stmt_While +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Stmt_While) == sizeof(AST), "ERROR: AST_Stmt_While is not the same size as AST"); +#endif + +struct AST_Struct +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + struct + { + CodeComment InlineCmt; + CodeAttributes Attributes; + CodeSpecifiers Specs; // Support for final + CodeTypename ParentType; + char _PAD_PARAMS_[ sizeof(AST*) ]; + CodeBody Body; + char _PAD_PROPERTIES_2_[ sizeof(AST*) ]; + }; + }; + StrCached Name; + CodeTypename Prev; + CodeTypename Next; + Token* Tok; + Code Parent; + CodeType Type; + ModuleFlag ModuleFlags; + AccessSpec ParentAccess; +}; +static_assert( sizeof(AST_Struct) == sizeof(AST), "ERROR: AST_Struct is not the same size as AST"); + +struct AST_Template +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + struct + { + char _PAD_PROPERTIES_[ sizeof(AST*) * 4 ]; + CodeParams Params; + Code Declaration; + char _PAD_PROPERTIES_2_[ sizeof(AST*) ]; + }; + }; + StrCached Name; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + ModuleFlag ModuleFlags; + char _PAD_UNUSED_[ sizeof(u32) ]; +}; +static_assert( sizeof(AST_Template) == sizeof(AST), "ERROR: AST_Template is not the same size as AST"); + +#if 0 +// WIP... The type ast is going to become more advanced and lead to a major change to AST design. +struct AST_Type +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + struct + { + char _PAD_INLINE_CMT_[ sizeof(AST*) ]; + CodeAttributes Attributes; + CodeSpecifiers Specs; + Code QualifierID; + // CodeTypename ReturnType; // Only used for function signatures + // CodeParams Params; // Only used for function signatures + Code ArrExpr; + // CodeSpecifiers SpecsFuncSuffix; // Only used for function signatures + }; + }; + StrCached Name; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) ]; + b32 IsParamPack; +}; +static_assert( sizeof(AST_Type) == sizeof(AST), "ERROR: AST_Type is not the same size as AST"); +#endif + +struct AST_Typename +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + struct + { + char _PAD_INLINE_CMT_[ sizeof(AST*) ]; + CodeAttributes Attributes; + CodeSpecifiers Specs; + CodeTypename ReturnType; // Only used for function signatures + CodeParams Params; // Only used for function signatures + Code ArrExpr; + CodeSpecifiers SpecsFuncSuffix; // Only used for function signatures + }; + }; + StrCached Name; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) ]; + struct { + b16 IsParamPack; // Used by typename to know if type should be considered a parameter pack. + ETypenameTag TypeTag; // Used by typename to keep track of explicitly declared tags for the identifier (enum, struct, union) + }; +}; +static_assert( sizeof(AST_Typename) == sizeof(AST), "ERROR: AST_Type is not the same size as AST"); + +struct AST_Typedef +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + struct + { + CodeComment InlineCmt; + char _PAD_PROPERTIES_[ sizeof(AST*) * 2 ]; + Code UnderlyingType; + char _PAD_PROPERTIES_2_[ sizeof(AST*) * 3 ]; + }; + }; + StrCached Name; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + ModuleFlag ModuleFlags; + b32 IsFunction; +}; +static_assert( sizeof(AST_Typedef) == sizeof(AST), "ERROR: AST_Typedef is not the same size as AST"); + +struct AST_Union +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + struct + { + char _PAD_INLINE_CMT_[ sizeof(AST*) ]; + CodeAttributes Attributes; + char _PAD_PROPERTIES_[ sizeof(AST*) * 3 ]; + CodeBody Body; + char _PAD_PROPERTIES_2_[ sizeof(AST*) ]; + }; + }; + StrCached Name; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + ModuleFlag ModuleFlags; + char _PAD_UNUSED_[ sizeof(u32) ]; +}; +static_assert( sizeof(AST_Union) == sizeof(AST), "ERROR: AST_Union is not the same size as AST"); + +struct AST_Using +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + struct + { + CodeComment InlineCmt; + CodeAttributes Attributes; + char _PAD_SPECS_ [ sizeof(AST*) ]; + CodeTypename UnderlyingType; + char _PAD_PROPERTIES_[ sizeof(AST*) * 3 ]; + }; + }; + StrCached Name; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + ModuleFlag ModuleFlags; + char _PAD_UNUSED_[ sizeof(u32) ]; +}; +static_assert( sizeof(AST_Using) == sizeof(AST), "ERROR: AST_Using is not the same size as AST"); + +struct AST_Var +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + struct + { + CodeComment InlineCmt; + CodeAttributes Attributes; + CodeSpecifiers Specs; + CodeTypename ValueType; + Code BitfieldSize; + Code Value; + CodeVar NextVar; + }; + }; + StrCached Name; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + ModuleFlag ModuleFlags; + s32 VarParenthesizedInit; +}; +static_assert( sizeof(AST_Var) == sizeof(AST), "ERROR: AST_Var is not the same size as AST"); + +#pragma endregion AST Types + +#pragma endregion AST + +#pragma region Gen Interface +/* + / \ | \ | \ / \ +| ▓▓▓▓▓▓\ ______ _______ \▓▓▓▓▓▓_______ _| ▓▓_ ______ ______ | ▓▓▓▓▓▓\ ______ _______ ______ +| ▓▓ __\▓▓/ \| \ | ▓▓ | \| ▓▓ \ / \ / \| ▓▓_ \▓▓| \ / \/ \ +| ▓▓| \ ▓▓▓▓▓▓\ ▓▓▓▓▓▓▓\ | ▓▓ | ▓▓▓▓▓▓▓\\▓▓▓▓▓▓ | ▓▓▓▓▓▓\ ▓▓▓▓▓▓\ ▓▓ \ \▓▓▓▓▓▓\ ▓▓▓▓▓▓▓ ▓▓▓▓▓▓\ +| ▓▓ \▓▓▓▓ ▓▓ ▓▓ ▓▓ | ▓▓ | ▓▓ | ▓▓ | ▓▓ | ▓▓ __| ▓▓ ▓▓ ▓▓ \▓▓ ▓▓▓▓ / ▓▓ ▓▓ | ▓▓ ▓▓ +| ▓▓__| ▓▓ ▓▓▓▓▓▓▓▓ ▓▓ | ▓▓ _| ▓▓_| ▓▓ | ▓▓ | ▓▓| \ ▓▓▓▓▓▓▓▓ ▓▓ | ▓▓ | ▓▓▓▓▓▓▓ ▓▓_____| ▓▓▓▓▓▓▓▓ + \▓▓ ▓▓\▓▓ \ ▓▓ | ▓▓ | ▓▓ \ ▓▓ | ▓▓ \▓▓ ▓▓\▓▓ \ ▓▓ | ▓▓ \▓▓ ▓▓\▓▓ \\▓▓ \ + \▓▓▓▓▓▓ \▓▓▓▓▓▓▓\▓▓ \▓▓ \▓▓▓▓▓▓\▓▓ \▓▓ \▓▓▓▓ \▓▓▓▓▓▓▓\▓▓ \▓▓ \▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓ +*/ + +#if 0 +enum LogLevel : u32 +{ + Info, + Warning, + Panic, +}; + +struct LogEntry +{ + Str msg; + u32 line_num; + void* data; +}; + +typedef void LoggerCallback(LogEntry entry); +#endif + +// Note(Ed): This is subject to heavily change +// with upcoming changes to the library's fallback (default) allocations strategy; +// and major changes to lexer/parser context usage. +struct Context +{ +// User Configuration + +// Persistent Data Allocation + AllocatorInfo Allocator_DyanmicContainers; // By default will use a genral slab allocator (TODO(Ed): Currently does not) + AllocatorInfo Allocator_Pool; // By default will use the growing vmem reserve (TODO(Ed): Currently does not) + AllocatorInfo Allocator_StrCache; // By default will use a dedicated slab allocator (TODO(Ed): Currently does not) + +// Temporary Allocation + AllocatorInfo Allocator_Temp; + + // LoggerCallaback* log_callback; // TODO(Ed): Impl user logger callback as an option. + +// Initalization config + u32 Max_CommentLineLength; // Used by def_comment + u32 Max_StrCacheLength; // Any cached string longer than this is always allocated again. + + u32 InitSize_BuilderBuffer; + u32 InitSize_CodePoolsArray; + u32 InitSize_StringArenasArray; + + u32 CodePool_NumBlocks; + + // TODO(Ed): Review these... (No longer needed if using the proper allocation strategy) + u32 InitSize_LexerTokens; + u32 SizePer_StringArena; + + u32 InitSize_StrCacheTable; + u32 InitSize_MacrosTable; + +// TODO(Ed): Symbol Table + // Keep track of all resolved symbols (naemspaced identifiers) + +// Parser + + // Used by the lexer to persistently treat all these identifiers as preprocessor defines. + // Populate with strings via gen::cache_str. + // Functional defines must have format: id( ;at minimum to indicate that the define is only valid with arguments. + MacroTable Macros; + +// Backend + + // The fallback allocator is utilized if any fo the three above allocators is not specified by the user. + u32 InitSize_Fallback_Allocator_Bucket_Size; + Array(Arena) Fallback_AllocatorBuckets; + + StringTable token_fmt_map; + + // Array(Token) LexerTokens; + + Array(Pool) CodePools; + Array(Arena) StringArenas; + + StringTable StrCache; + + // TODO(Ed): This needs to be just handled by a parser context + Array(Token) Lexer_Tokens; + + // TODO(Ed): Active parse context vs a parse result need to be separated conceptually + ParseContext parser; + + // TODO(Ed): Formatting - This will eventually be in a separate struct when in the process of serialization of the builder. + s32 temp_serialize_indent; +}; + +// TODO(Ed): Eventually this library should opt out of an implicit context for baseline implementation +// This would automatically make it viable for multi-threaded purposes among other things +// An implicit context interface will be provided instead as wrapper procedures as convience. +GEN_API extern Context* _ctx; + +// Initialize the library. There first ctx initialized must exist for lifetime of other contextes that come after as its the one that +GEN_API void init(Context* ctx); + +// Currently manually free's the arenas, code for checking for leaks. +// However on Windows at least, it doesn't need to occur as the OS will clean up after the process. +GEN_API void deinit(Context* ctx); + +// Retrieves the active context (not usually needed, but here in case...) +GEN_API Context* get_context(); + +// Clears the allocations, but doesn't free the memoery, then calls init() again. +// Ease of use. +GEN_API void reset(Context* ctx); + +GEN_API void set_context(Context* ctx); + +// Mostly intended for the parser +GEN_API Macro* lookup_macro( Str Name ); + +// Alternative way to add a preprocess define entry for the lexer & parser to utilize +// if the user doesn't want to use def_define +// Macros are tracked by name so if the name already exists the entry will be overwritten. +GEN_API void register_macro( Macro macro ); + +// Ease of use batch registration +GEN_API void register_macros( s32 num, ... ); +GEN_API void register_macros_arr( s32 num, Macro* macros ); + +#if GEN_COMPILER_CPP +forceinline void register_macros( s32 num, Macro* macros ) { return register_macros_arr(num, macros); } +#endif + +// Used internally to retrive or make string allocations. +// Strings are stored in a series of string arenas of fixed size (SizePer_StringArena) +GEN_API StrCached cache_str( Str str ); + +/* + This provides a fresh Code AST. + The gen interface use this as their method from getting a new AST object from the CodePool. + Use this if you want to make your own API for formatting the supported Code Types. +*/ +GEN_API Code make_code(); + +// Set these before calling gen's init() procedure. + +#pragma region Upfront + +GEN_API CodeAttributes def_attributes( Str content ); +GEN_API CodeComment def_comment ( Str content ); + +struct Opts_def_struct { + CodeBody body; + CodeTypename parent; + AccessSpec parent_access; + CodeAttributes attributes; + CodeTypename* interfaces; + s32 num_interfaces; + CodeSpecifiers specifiers; // Only used for final specifier for now. + ModuleFlag mflags; +}; +GEN_API CodeClass def_class( Str name, Opts_def_struct opts GEN_PARAM_DEFAULT ); + +struct Opts_def_constructor { + CodeParams params; + Code initializer_list; + Code body; +}; +GEN_API CodeConstructor def_constructor( Opts_def_constructor opts GEN_PARAM_DEFAULT ); + +struct Opts_def_define { + CodeDefineParams params; + Str content; + MacroFlags flags; + b32 dont_register_to_preprocess_macros; +}; +GEN_API CodeDefine def_define( Str name, MacroType type, Opts_def_define opts GEN_PARAM_DEFAULT ); + +struct Opts_def_destructor { + Code body; + CodeSpecifiers specifiers; +}; +GEN_API CodeDestructor def_destructor( Opts_def_destructor opts GEN_PARAM_DEFAULT ); + +struct Opts_def_enum { + CodeBody body; + CodeTypename type; + EnumT specifier; + CodeAttributes attributes; + ModuleFlag mflags; + Code type_macro; +}; +GEN_API CodeEnum def_enum( Str name, Opts_def_enum opts GEN_PARAM_DEFAULT ); + +GEN_API CodeExec def_execution ( Str content ); +GEN_API CodeExtern def_extern_link( Str name, CodeBody body ); +GEN_API CodeFriend def_friend ( Code code ); + +struct Opts_def_function { + CodeParams params; + CodeTypename ret_type; + CodeBody body; + CodeSpecifiers specs; + CodeAttributes attrs; + ModuleFlag mflags; +}; +GEN_API CodeFn def_function( Str name, Opts_def_function opts GEN_PARAM_DEFAULT ); + +struct Opts_def_include { b32 foreign; }; +struct Opts_def_module { ModuleFlag mflags; }; +struct Opts_def_namespace { ModuleFlag mflags; }; +GEN_API CodeInclude def_include ( Str content, Opts_def_include opts GEN_PARAM_DEFAULT ); +GEN_API CodeModule def_module ( Str name, Opts_def_module opts GEN_PARAM_DEFAULT ); +GEN_API CodeNS def_namespace( Str name, CodeBody body, Opts_def_namespace opts GEN_PARAM_DEFAULT ); + +struct Opts_def_operator { + CodeParams params; + CodeTypename ret_type; + CodeBody body; + CodeSpecifiers specifiers; + CodeAttributes attributes; + ModuleFlag mflags; +}; +GEN_API CodeOperator def_operator( Operator op, Str nspace, Opts_def_operator opts GEN_PARAM_DEFAULT ); + +struct Opts_def_operator_cast { + CodeBody body; + CodeSpecifiers specs; +}; +GEN_API CodeOpCast def_operator_cast( CodeTypename type, Opts_def_operator_cast opts GEN_PARAM_DEFAULT ); + +struct Opts_def_param { Code value; }; +GEN_API CodeParams def_param ( CodeTypename type, Str name, Opts_def_param opts GEN_PARAM_DEFAULT ); +GEN_API CodePragma def_pragma( Str directive ); + +GEN_API CodePreprocessCond def_preprocess_cond( EPreprocessCond type, Str content ); + +GEN_API CodeSpecifiers def_specifier( Specifier specifier ); + +GEN_API CodeStruct def_struct( Str name, Opts_def_struct opts GEN_PARAM_DEFAULT ); + +struct Opts_def_template { ModuleFlag mflags; }; +GEN_API CodeTemplate def_template( CodeParams params, Code definition, Opts_def_template opts GEN_PARAM_DEFAULT ); + +struct Opts_def_type { + ETypenameTag type_tag; + Code array_expr; + CodeSpecifiers specifiers; + CodeAttributes attributes; +}; +GEN_API CodeTypename def_type( Str name, Opts_def_type opts GEN_PARAM_DEFAULT ); + +struct Opts_def_typedef { + CodeAttributes attributes; + ModuleFlag mflags; +}; +GEN_API CodeTypedef def_typedef( Str name, Code type, Opts_def_typedef opts GEN_PARAM_DEFAULT ); + +struct Opts_def_union { + CodeAttributes attributes; + ModuleFlag mflags; +}; +GEN_API CodeUnion def_union( Str name, CodeBody body, Opts_def_union opts GEN_PARAM_DEFAULT ); + +struct Opts_def_using { + CodeAttributes attributes; + ModuleFlag mflags; +}; +GEN_API CodeUsing def_using( Str name, CodeTypename type, Opts_def_using opts GEN_PARAM_DEFAULT ); + +GEN_API CodeUsing def_using_namespace( Str name ); + +struct Opts_def_variable +{ + Code value; + CodeSpecifiers specifiers; + CodeAttributes attributes; + ModuleFlag mflags; +}; +GEN_API CodeVar def_variable( CodeTypename type, Str name, Opts_def_variable opts GEN_PARAM_DEFAULT ); + +// Constructs an empty body. Use AST::validate_body() to check if the body is was has valid entries. +CodeBody def_body( CodeType type ); + +// There are two options for defining a struct body, either varadically provided with the args macro to auto-deduce the arg num, +/// or provide as an array of Code objects. + +GEN_API CodeBody def_class_body ( s32 num, ... ); +GEN_API CodeBody def_class_body_arr ( s32 num, Code* codes ); +GEN_API CodeDefineParams def_define_params ( s32 num, ... ); +GEN_API CodeDefineParams def_define_params_arr ( s32 num, CodeDefineParams* codes ); +GEN_API CodeBody def_enum_body ( s32 num, ... ); +GEN_API CodeBody def_enum_body_arr ( s32 num, Code* codes ); +GEN_API CodeBody def_export_body ( s32 num, ... ); +GEN_API CodeBody def_export_body_arr ( s32 num, Code* codes); +GEN_API CodeBody def_extern_link_body ( s32 num, ... ); +GEN_API CodeBody def_extern_link_body_arr ( s32 num, Code* codes ); +GEN_API CodeBody def_function_body ( s32 num, ... ); +GEN_API CodeBody def_function_body_arr ( s32 num, Code* codes ); +GEN_API CodeBody def_global_body ( s32 num, ... ); +GEN_API CodeBody def_global_body_arr ( s32 num, Code* codes ); +GEN_API CodeBody def_namespace_body ( s32 num, ... ); +GEN_API CodeBody def_namespace_body_arr ( s32 num, Code* codes ); +GEN_API CodeParams def_params ( s32 num, ... ); +GEN_API CodeParams def_params_arr ( s32 num, CodeParams* params ); +GEN_API CodeSpecifiers def_specifiers ( s32 num, ... ); +GEN_API CodeSpecifiers def_specifiers_arr ( s32 num, Specifier* specs ); +GEN_API CodeBody def_struct_body ( s32 num, ... ); +GEN_API CodeBody def_struct_body_arr ( s32 num, Code* codes ); +GEN_API CodeBody def_union_body ( s32 num, ... ); +GEN_API CodeBody def_union_body_arr ( s32 num, Code* codes ); + +#if GEN_COMPILER_CPP +forceinline CodeBody def_class_body ( s32 num, Code* codes ) { return def_class_body_arr(num, codes); } +forceinline CodeDefineParams def_define_params ( s32 num, CodeDefineParams* codes ) { return def_define_params_arr(num, codes); } +forceinline CodeBody def_enum_body ( s32 num, Code* codes ) { return def_enum_body_arr(num, codes); } +forceinline CodeBody def_export_body ( s32 num, Code* codes) { return def_export_body_arr(num, codes); } +forceinline CodeBody def_extern_link_body( s32 num, Code* codes ) { return def_extern_link_body_arr(num, codes); } +forceinline CodeBody def_function_body ( s32 num, Code* codes ) { return def_function_body_arr(num, codes); } +forceinline CodeBody def_global_body ( s32 num, Code* codes ) { return def_global_body_arr(num, codes); } +forceinline CodeBody def_namespace_body ( s32 num, Code* codes ) { return def_namespace_body_arr(num, codes); } +forceinline CodeParams def_params ( s32 num, CodeParams* params ) { return def_params_arr(num, params); } +forceinline CodeSpecifiers def_specifiers ( s32 num, Specifier* specs ) { return def_specifiers_arr(num, specs); } +forceinline CodeBody def_struct_body ( s32 num, Code* codes ) { return def_struct_body_arr(num, codes); } +forceinline CodeBody def_union_body ( s32 num, Code* codes ) { return def_union_body_arr(num, codes); } +#endif + +#pragma endregion Upfront + +#pragma region Parsing + +#if 0 +struct StackNode +{ + StackNode* Prev; + + Token Start; + Token Name; // The name of the AST node (if parsed) + Str FailedProc; // The name of the procedure that failed +}; +// Stack nodes are allocated the error's allocator + +struct Error +{ + StrBuilder message; + StackNode* context_stack; +}; + +struct ParseInfo +{ + Arena FileMem; + Arena TokMem; + Arena CodeMem; + + FileContents FileContent; + Array Tokens; + Array Errors; + // Errors are allocated to a dedicated general arena. +}; + +CodeBody parse_file( Str path ); +#endif + +GEN_API CodeClass parse_class ( Str class_def ); +GEN_API CodeConstructor parse_constructor ( Str constructor_def ); +GEN_API CodeDefine parse_define ( Str define_def ); +GEN_API CodeDestructor parse_destructor ( Str destructor_def ); +GEN_API CodeEnum parse_enum ( Str enum_def ); +GEN_API CodeBody parse_export_body ( Str export_def ); +GEN_API CodeExtern parse_extern_link ( Str exten_link_def ); +GEN_API CodeFriend parse_friend ( Str friend_def ); +GEN_API CodeFn parse_function ( Str fn_def ); +GEN_API CodeBody parse_global_body ( Str body_def ); +GEN_API CodeNS parse_namespace ( Str namespace_def ); +GEN_API CodeOperator parse_operator ( Str operator_def ); +GEN_API CodeOpCast parse_operator_cast( Str operator_def ); +GEN_API CodeStruct parse_struct ( Str struct_def ); +GEN_API CodeTemplate parse_template ( Str template_def ); +GEN_API CodeTypename parse_type ( Str type_def ); +GEN_API CodeTypedef parse_typedef ( Str typedef_def ); +GEN_API CodeUnion parse_union ( Str union_def ); +GEN_API CodeUsing parse_using ( Str using_def ); +GEN_API CodeVar parse_variable ( Str var_def ); + +#pragma endregion Parsing + +#pragma region Untyped text + +GEN_API ssize token_fmt_va( char* buf, usize buf_size, s32 num_tokens, va_list va ); +//! Do not use directly. Use the token_fmt macro instead. +Str token_fmt_impl( ssize, ... ); + +GEN_API Code untyped_str( Str content); +GEN_API Code untyped_fmt ( char const* fmt, ... ); +GEN_API Code untyped_token_fmt( s32 num_tokens, char const* fmt, ... ); + +#pragma endregion Untyped text + +#pragma region Macros + +#ifndef gen_main +#define gen_main main +#endif + +#ifndef name +// Convienence for defining any name used with the gen api. +// Lets you provide the length and string literal to the functions without the need for the DSL. +# if GEN_COMPILER_C +# define name( Id_ ) (Str){ stringize(Id_), sizeof(stringize( Id_ )) - 1 } +# else +# define name( Id_ ) Str { stringize(Id_), sizeof(stringize( Id_ )) - 1 } +# endif +#endif + +#ifndef code +// Same as name just used to indicate intention of literal for code instead of names. +# if GEN_COMPILER_C +# define code( ... ) (Str){ stringize( __VA_ARGS__ ), sizeof(stringize(__VA_ARGS__)) - 1 } +# else +# define code( ... ) Str { stringize( __VA_ARGS__ ), sizeof(stringize(__VA_ARGS__)) - 1 } +# endif +#endif + +#ifndef args +// Provides the number of arguments while passing args inplace. +#define args( ... ) num_args( __VA_ARGS__ ), __VA_ARGS__ +#endif + +#ifndef code_str +// Just wrappers over common untyped code definition constructions. +#define code_str( ... ) GEN_NS untyped_str( code( __VA_ARGS__ ) ) +#endif + +#ifndef code_fmt +#define code_fmt( ... ) GEN_NS untyped_str( token_fmt( __VA_ARGS__ ) ) +#endif + +#ifndef parse_fmt +#define parse_fmt( type, ... ) GEN_NS parse_##type( token_fmt( __VA_ARGS__ ) ) +#endif + +#ifndef token_fmt +/* +Takes a format string (char const*) and a list of tokens (Str) and returns a Str of the formatted string. +Tokens are provided in '<'identifier'>' format where '<' '>' are just angle brackets (you can change it in token_fmt_va) +--------------------------------------------------------- + Example - A string with: + typedef ; + Will have a token_fmt arguments populated with: + "type", str_for_type, + "name", str_for_name, + and: + stringize( typedef ; ) +----------------------------------------------------------- +So the full call for this example would be: + token_fmt( + "type", str_for_type + , "name", str_for_name + , stringize( + typedef + )); +!---------------------------------------------------------- +! Note: token_fmt_va is whitespace sensitive for the tokens. +! This can be alleviated by skipping whitespace between brackets but it was choosen to not have that implementation by default. +*/ +#define token_fmt( ... ) GEN_NS token_fmt_impl( (num_args( __VA_ARGS__ ) + 1) / 2, __VA_ARGS__ ) +#endif + +#pragma endregion Macros + +#pragma endregion Gen Interface + +#pragma region Constants +// Predefined typename codes. Are set to readonly and are setup during gen::init() + +GEN_API extern Macro enum_underlying_macro; + +GEN_API extern Code access_public; +GEN_API extern Code access_protected; +GEN_API extern Code access_private; + +GEN_API extern CodeAttributes attrib_api_export; +GEN_API extern CodeAttributes attrib_api_import; + +GEN_API extern Code module_global_fragment; +GEN_API extern Code module_private_fragment; + +GEN_API extern Code fmt_newline; + +GEN_API extern CodePragma pragma_once; + +GEN_API extern CodeParams param_varadic; + +GEN_API extern CodePreprocessCond preprocess_else; +GEN_API extern CodePreprocessCond preprocess_endif; + +GEN_API extern CodeSpecifiers spec_const; +GEN_API extern CodeSpecifiers spec_consteval; +GEN_API extern CodeSpecifiers spec_constexpr; +GEN_API extern CodeSpecifiers spec_constinit; +GEN_API extern CodeSpecifiers spec_extern_linkage; +GEN_API extern CodeSpecifiers spec_final; +GEN_API extern CodeSpecifiers spec_forceinline; +GEN_API extern CodeSpecifiers spec_global; +GEN_API extern CodeSpecifiers spec_inline; +GEN_API extern CodeSpecifiers spec_internal_linkage; +GEN_API extern CodeSpecifiers spec_local_persist; +GEN_API extern CodeSpecifiers spec_mutable; +GEN_API extern CodeSpecifiers spec_neverinline; +GEN_API extern CodeSpecifiers spec_noexcept; +GEN_API extern CodeSpecifiers spec_override; +GEN_API extern CodeSpecifiers spec_ptr; +GEN_API extern CodeSpecifiers spec_pure; +GEN_API extern CodeSpecifiers spec_ref; +GEN_API extern CodeSpecifiers spec_register; +GEN_API extern CodeSpecifiers spec_rvalue; +GEN_API extern CodeSpecifiers spec_static_member; +GEN_API extern CodeSpecifiers spec_thread_local; +GEN_API extern CodeSpecifiers spec_virtual; +GEN_API extern CodeSpecifiers spec_volatile; + +GEN_API extern CodeTypename t_empty; // Used with varaidc parameters. (Exposing just in case its useful for another circumstance) +GEN_API extern CodeTypename t_auto; +GEN_API extern CodeTypename t_void; +GEN_API extern CodeTypename t_int; +GEN_API extern CodeTypename t_bool; +GEN_API extern CodeTypename t_char; +GEN_API extern CodeTypename t_wchar_t; +GEN_API extern CodeTypename t_class; +GEN_API extern CodeTypename t_typename; + +#ifdef GEN_DEFINE_LIBRARY_CODE_CONSTANTS + GEN_API extern CodeTypename t_b32; + + GEN_API extern CodeTypename t_s8; + GEN_API extern CodeTypename t_s16; + GEN_API extern CodeTypename t_s32; + GEN_API extern CodeTypename t_s64; + + GEN_API extern CodeTypename t_u8; + GEN_API extern CodeTypename t_u16; + GEN_API extern CodeTypename t_u32; + GEN_API extern CodeTypename t_u64; + + GEN_API extern CodeTypename t_ssize; + GEN_API extern CodeTypename t_usize; + + GEN_API extern CodeTypename t_f32; + GEN_API extern CodeTypename t_f64; +#endif + +#pragma endregion Constants + +#pragma region Inlines + +#pragma region Serialization +inline +StrBuilder attributes_to_strbuilder(CodeAttributes attributes) { + GEN_ASSERT(attributes); + char* raw = ccast(char*, str_duplicate( attributes->Content, get_context()->Allocator_Temp ).Ptr); + StrBuilder result = { raw }; + return result; +} + +inline +void attributes_to_strbuilder_ref(CodeAttributes attributes, StrBuilder* result) { + GEN_ASSERT(attributes); + GEN_ASSERT(result); + strbuilder_append_str(result, attributes->Content); +} + +inline +StrBuilder comment_to_strbuilder(CodeComment comment) { + GEN_ASSERT(comment); + char* raw = ccast(char*, str_duplicate( comment->Content, get_context()->Allocator_Temp ).Ptr); + StrBuilder result = { raw }; + return result; +} + +inline +void body_to_strbuilder_ref( CodeBody body, StrBuilder* result ) +{ + GEN_ASSERT(body != nullptr); + GEN_ASSERT(result != nullptr); + Code curr = body->Front; + s32 left = body->NumEntries; + while ( left -- ) + { + code_to_strbuilder_ref(curr, result); + // strbuilder_append_fmt( result, "%SB", code_to_strbuilder(curr) ); + curr = curr->Next; + } +} + +inline +void comment_to_strbuilder_ref(CodeComment comment, StrBuilder* result) { + GEN_ASSERT(comment); + GEN_ASSERT(result); + strbuilder_append_str(result, comment->Content); +} + +inline +StrBuilder define_to_strbuilder(CodeDefine define) +{ + GEN_ASSERT(define); + StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 512 ); + define_to_strbuilder_ref(define, & result); + return result; +} + +inline +StrBuilder define_params_to_strbuilder(CodeDefineParams params) +{ + GEN_ASSERT(params); + StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 128 ); + define_params_to_strbuilder_ref( params, & result ); + return result; +} + +inline +StrBuilder exec_to_strbuilder(CodeExec exec) +{ + GEN_ASSERT(exec); + char* raw = ccast(char*, str_duplicate( exec->Content, _ctx->Allocator_Temp ).Ptr); + StrBuilder result = { raw }; + return result; +} + +inline +void exec_to_strbuilder_ref(CodeExec exec, StrBuilder* result) { + GEN_ASSERT(exec); + GEN_ASSERT(result); + strbuilder_append_str(result, exec->Content); +} + +inline +void extern_to_strbuilder(CodeExtern self, StrBuilder* result ) +{ + GEN_ASSERT(self); + GEN_ASSERT(result); + if ( self->Body ) + strbuilder_append_fmt( result, "extern \"%S\"\n{\n%SB\n}\n", self->Name, body_to_strbuilder(self->Body) ); + else + strbuilder_append_fmt( result, "extern \"%S\"\n{}\n", self->Name ); +} + +inline +StrBuilder friend_to_strbuilder(CodeFriend self) +{ + GEN_ASSERT(self); + StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 256 ); + friend_to_strbuilder_ref( self, & result ); + return result; +} + +inline +void friend_to_strbuilder_ref(CodeFriend self, StrBuilder* result ) +{ + GEN_ASSERT(self); + GEN_ASSERT(result); + strbuilder_append_fmt( result, "friend %SB", code_to_strbuilder(self->Declaration) ); + + if ( self->Declaration->Type != CT_Function && self->Declaration->Type != CT_Operator && (* result)[ strbuilder_length(* result) - 1 ] != ';' ) + { + strbuilder_append_str( result, txt(";") ); + } + + if ( self->InlineCmt ) + strbuilder_append_fmt( result, " %S", self->InlineCmt->Content ); + else + strbuilder_append_str( result, txt("\n")); +} + +inline +StrBuilder include_to_strbuilder(CodeInclude include) +{ + GEN_ASSERT(include); + return strbuilder_fmt_buf( _ctx->Allocator_Temp, "#include %S\n", include->Content ); +} + +inline +void include_to_strbuilder_ref( CodeInclude include, StrBuilder* result ) +{ + GEN_ASSERT(include); + GEN_ASSERT(result); + strbuilder_append_fmt( result, "#include %S\n", include->Content ); +} + +inline +StrBuilder module_to_strbuilder(CodeModule self) +{ + GEN_ASSERT(self); + StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 64 ); + module_to_strbuilder_ref( self, & result ); + return result; +} + +inline +StrBuilder namespace_to_strbuilder(CodeNS self) +{ + GEN_ASSERT(self); + StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 512 ); + namespace_to_strbuilder_ref( self, & result ); + return result; +} + +inline +void namespace_to_strbuilder_ref(CodeNS self, StrBuilder* result ) +{ + GEN_ASSERT(self); + GEN_ASSERT(result); + if ( bitfield_is_set( u32, self->ModuleFlags, ModuleFlag_Export )) + strbuilder_append_str( result, txt("export ") ); + + strbuilder_append_fmt( result, "namespace %S\n{\n%SB\n}\n", self->Name, body_to_strbuilder(self->Body) ); +} + +inline +StrBuilder params_to_strbuilder(CodeParams self) +{ + GEN_ASSERT(self); + StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 128 ); + params_to_strbuilder_ref( self, & result ); + return result; +} + +inline +StrBuilder pragma_to_strbuilder(CodePragma self) +{ + GEN_ASSERT(self); + StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 256 ); + pragma_to_strbuilder_ref( self, & result ); + return result; +} + +inline +void pragma_to_strbuilder_ref(CodePragma self, StrBuilder* result ) +{ + GEN_ASSERT(self); + GEN_ASSERT(result); + strbuilder_append_fmt( result, "#pragma %S\n", self->Content ); +} + +inline +void preprocess_to_strbuilder_if(CodePreprocessCond cond, StrBuilder* result ) +{ + GEN_ASSERT(cond); + GEN_ASSERT(result); + strbuilder_append_fmt( result, "#if %S", cond->Content ); +} + +inline +void preprocess_to_strbuilder_ifdef(CodePreprocessCond cond, StrBuilder* result ) +{ + GEN_ASSERT(cond); + GEN_ASSERT(result); + strbuilder_append_fmt( result, "#ifdef %S\n", cond->Content ); +} + +inline +void preprocess_to_strbuilder_ifndef(CodePreprocessCond cond, StrBuilder* result ) +{ + GEN_ASSERT(cond); + GEN_ASSERT(result); + strbuilder_append_fmt( result, "#ifndef %S", cond->Content ); +} + +inline +void preprocess_to_strbuilder_elif(CodePreprocessCond cond, StrBuilder* result ) +{ + GEN_ASSERT(cond); + GEN_ASSERT(result); + strbuilder_append_fmt( result, "#elif %S\n", cond->Content ); +} + +inline +void preprocess_to_strbuilder_else(CodePreprocessCond cond, StrBuilder* result ) +{ + GEN_ASSERT(cond); + GEN_ASSERT(result); + strbuilder_append_str( result, txt("#else\n") ); +} + +inline +void preprocess_to_strbuilder_endif(CodePreprocessCond cond, StrBuilder* result ) +{ + GEN_ASSERT(cond); + GEN_ASSERT(result); + strbuilder_append_str( result, txt("#endif\n") ); +} + +inline +StrBuilder specifiers_to_strbuilder(CodeSpecifiers self) +{ + GEN_ASSERT(self); + StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 64 ); + specifiers_to_strbuilder_ref( self, & result ); + return result; +} + +inline +StrBuilder template_to_strbuilder(CodeTemplate self) +{ + GEN_ASSERT(self); + StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 1024 ); + template_to_strbuilder_ref( self, & result ); + return result; +} + +inline +StrBuilder typedef_to_strbuilder(CodeTypedef self) +{ + GEN_ASSERT(self); + StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 128 ); + typedef_to_strbuilder_ref( self, & result ); + return result; +} + +inline +StrBuilder typename_to_strbuilder(CodeTypename self) +{ + GEN_ASSERT(self); + StrBuilder result = strbuilder_make_str( _ctx->Allocator_Temp, txt("") ); + typename_to_strbuilder_ref( self, & result ); + return result; +} + +inline +StrBuilder using_to_strbuilder(CodeUsing self) +{ + GEN_ASSERT(self); + StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 128 ); + switch ( self->Type ) + { + case CT_Using: + using_to_strbuilder_ref( self, & result ); + break; + case CT_Using_Namespace: + using_to_strbuilder_ns( self, & result ); + break; + } + return result; +} + +inline +void using_to_strbuilder_ns(CodeUsing self, StrBuilder* result ) +{ + GEN_ASSERT(self); + GEN_ASSERT(result); + if ( self->InlineCmt ) + strbuilder_append_fmt( result, "using namespace $S; %S", self->Name, self->InlineCmt->Content ); + else + strbuilder_append_fmt( result, "using namespace %S;\n", self->Name ); +} + +inline +StrBuilder var_to_strbuilder(CodeVar self) +{ + GEN_ASSERT(self); + StrBuilder result = strbuilder_make_reserve( get_context()->Allocator_Temp, 256 ); + var_to_strbuilder_ref( self, & result ); + return result; +} +#pragma endregion Serialization + +#pragma region Code +inline +void code_append( Code self, Code other ) +{ + GEN_ASSERT(self); + GEN_ASSERT(other); + GEN_ASSERT_MSG(self != other, "Attempted to recursively append Code AST to itself."); + + if ( other->Parent != nullptr ) + other = code_duplicate(other); + + other->Parent = self; + + if ( self->Front == nullptr ) + { + self->Front = other; + self->Back = other; + + self->NumEntries++; + return; + } + + Code + Current = self->Back; + Current->Next = other; + other->Prev = Current; + self->Back = other; + self->NumEntries++; +} +inline +bool code_is_body(Code self) +{ + GEN_ASSERT(self); + switch (self->Type) + { + case CT_Enum_Body: + case CT_Class_Body: + case CT_Union_Body: + case CT_Export_Body: + case CT_Global_Body: + case CT_Struct_Body: + case CT_Function_Body: + case CT_Namespace_Body: + case CT_Extern_Linkage_Body: + return true; + } + return false; +} +inline +Code* code_entry( Code self, u32 idx ) +{ + GEN_ASSERT(self != nullptr); + Code* current = & self->Front; + while ( idx >= 0 && current != nullptr ) + { + if ( idx == 0 ) + return rcast( Code*, current); + + current = & ( * current )->Next; + idx--; + } + + return rcast( Code*, current); +} +forceinline +bool code_is_valid(Code self) +{ + GEN_ASSERT(self); + return self != nullptr && self->Type != CT_Invalid; +} +forceinline +bool code_has_entries(Code self) +{ + GEN_ASSERT(self); + return self->NumEntries > 0; +} +forceinline +void code_set_global(Code self) +{ + if ( self == nullptr ) + { + log_failure("Code::set_global: Cannot set code as global, AST is null!"); + return; + } + + self->Parent = Code_Global; +} +#if GEN_COMPILER_CPP +forceinline +Code& Code::operator ++() +{ + if ( ast ) + ast = ast->Next.ast; + + return * this; +} +#endif +forceinline +Str code_type_str(Code self) +{ + GEN_ASSERT(self != nullptr); + return codetype_to_str( self->Type ); +} +#pragma endregion Code + +#pragma region CodeBody +inline +void body_append( CodeBody self, Code other ) +{ + GEN_ASSERT(self); + GEN_ASSERT(other); + + if (code_is_body(other)) { + body_append_body( self, cast(CodeBody, other) ); + return; + } + + code_append( cast(Code, self), other ); +} +inline +void body_append_body( CodeBody self, CodeBody body ) +{ + GEN_ASSERT(self); + GEN_ASSERT(body); + GEN_ASSERT_MSG(self != body, "Attempted to append body to itself."); + + for ( Code entry = begin_CodeBody(body); entry != end_CodeBody(body); entry = next_CodeBody(body, entry) ) { + body_append( self, entry ); + } +} +inline +Code begin_CodeBody( CodeBody body) { + GEN_ASSERT(body); + if ( body != nullptr ) + return body->Front; + + return NullCode; +} +forceinline +Code end_CodeBody(CodeBody body ){ + GEN_ASSERT(body); + return body->Back->Next; +} +inline +Code next_CodeBody(CodeBody body, Code entry) { + GEN_ASSERT(body); + GEN_ASSERT(entry); + return entry->Next; +} +#pragma endregion CodeBody + +#pragma region CodeClass +inline +void class_add_interface( CodeClass self, CodeTypename type ) +{ + GEN_ASSERT(self); + GEN_ASSERT(type); + CodeTypename possible_slot = self->ParentType; + if ( possible_slot != nullptr ) + { + // Were adding an interface to parent type, so we need to make sure the parent type is public. + self->ParentAccess = AccessSpec_Public; + // If your planning on adding a proper parent, + // then you'll need to move this over to ParentType->next and update ParentAccess accordingly. + } + + while ( possible_slot->Next != nullptr ) + { + possible_slot = cast(CodeTypename, possible_slot->Next); + } + + possible_slot->Next = cast(Code, type); +} +#pragma endregion CodeClass + +#pragma region CodeParams +inline +void params_append( CodeParams appendee, CodeParams other ) +{ + GEN_ASSERT(appendee); + GEN_ASSERT(other); + GEN_ASSERT_MSG(appendee != other, "Attempted to append parameter to itself."); + Code self = cast(Code, appendee); + Code entry = cast(Code, other); + + if ( entry->Parent != nullptr ) + entry = code_duplicate( entry ); + + entry->Parent = self; + + if ( self->Last == nullptr ) + { + self->Last = entry; + self->Next = entry; + self->NumEntries++; + return; + } + + self->Last->Next = entry; + self->Last = entry; + self->NumEntries++; +} +inline +CodeParams params_get(CodeParams self, s32 idx ) +{ + GEN_ASSERT(self); + CodeParams param = self; + do + { + if ( ++ param != nullptr ) + return NullCode; + + param = cast(CodeParams, cast(Code, param)->Next); + } + while ( --idx ); + + return param; +} +forceinline +bool params_has_entries(CodeParams self) +{ + GEN_ASSERT(self); + return self->NumEntries > 0; +} +#if GEN_COMPILER_CPP +forceinline +CodeParams& CodeParams::operator ++() +{ + * this = ast->Next; + return * this; +} +#endif +forceinline +CodeParams begin_CodeParams(CodeParams params) +{ + if ( params != nullptr ) + return params; + + return NullCode; +} +forceinline +CodeParams end_CodeParams(CodeParams params) +{ + // return { (AST_Params*) rcast( AST*, ast)->Last }; + return NullCode; +} +forceinline +CodeParams next_CodeParams(CodeParams params, CodeParams param_iter) +{ + GEN_ASSERT(param_iter); + return param_iter->Next; +} +#pragma endregion CodeParams + +#pragma region CodeDefineParams +forceinline void define_params_append (CodeDefineParams appendee, CodeDefineParams other ) { params_append( cast(CodeParams, appendee), cast(CodeParams, other) ); } +forceinline CodeDefineParams define_params_get (CodeDefineParams self, s32 idx ) { return (CodeDefineParams) (Code) params_get( cast(CodeParams, self), idx); } +forceinline bool define_params_has_entries(CodeDefineParams self) { return params_has_entries( cast(CodeParams, self)); } + +forceinline CodeDefineParams begin_CodeDefineParams(CodeDefineParams params) { return (CodeDefineParams) (Code) begin_CodeParams( cast(CodeParams, (Code)params)); } +forceinline CodeDefineParams end_CodeDefineParams (CodeDefineParams params) { return (CodeDefineParams) (Code) end_CodeParams ( cast(CodeParams, (Code)params)); } +forceinline CodeDefineParams next_CodeDefineParams (CodeDefineParams params, CodeDefineParams entry_iter) { return (CodeDefineParams) (Code) next_CodeParams ( cast(CodeParams, (Code)params), cast(CodeParams, (Code)entry_iter)); } + +#if GEN_COMPILER_CPP +forceinline +CodeDefineParams& CodeDefineParams::operator ++() +{ + * this = ast->Next; + return * this; +} +#endif +#pragma endregion CodeDefineParams + +#pragma region CodeSpecifiers +inline +bool specifiers_append(CodeSpecifiers self, Specifier spec ) +{ + if ( self == nullptr ) + { + log_failure("CodeSpecifiers: Attempted to append to a null specifiers AST!"); + return false; + } + if ( self->NumEntries == AST_ArrSpecs_Cap ) + { + log_failure("CodeSpecifiers: Attempted to append over %d specifiers to a specifiers AST!", AST_ArrSpecs_Cap ); + return false; + } + + self->ArrSpecs[ self->NumEntries ] = spec; + self->NumEntries++; + return true; +} +inline +bool specifiers_has(CodeSpecifiers self, Specifier spec) +{ + GEN_ASSERT(self != nullptr); + for ( s32 idx = 0; idx < self->NumEntries; idx++ ) { + if ( self->ArrSpecs[ idx ] == spec ) + return true; + } + return false; +} +inline +s32 specifiers_index_of(CodeSpecifiers self, Specifier spec) +{ + GEN_ASSERT(self != nullptr); + for ( s32 idx = 0; idx < self->NumEntries; idx++ ) { + if ( self->ArrSpecs[ idx ] == spec ) + return idx; + } + return -1; +} +inline +s32 specifiers_remove( CodeSpecifiers self, Specifier to_remove ) +{ + if ( self == nullptr ) + { + log_failure("CodeSpecifiers: Attempted to append to a null specifiers AST!"); + return -1; + } + if ( self->NumEntries == AST_ArrSpecs_Cap ) + { + log_failure("CodeSpecifiers: Attempted to append over %d specifiers to a specifiers AST!", AST_ArrSpecs_Cap ); + return -1; + } + + s32 result = -1; + + s32 curr = 0; + s32 next = 0; + for(; next < self->NumEntries; ++ curr, ++ next) + { + Specifier spec = self->ArrSpecs[next]; + if (spec == to_remove) + { + result = next; + + next ++; + if (next >= self->NumEntries) + break; + + spec = self->ArrSpecs[next]; + } + + self->ArrSpecs[ curr ] = spec; + } + + if (result > -1) { + self->NumEntries --; + } + return result; +} +forceinline +Specifier* begin_CodeSpecifiers(CodeSpecifiers self) +{ + if ( self != nullptr ) + return & self->ArrSpecs[0]; + + return nullptr; +} +forceinline +Specifier* end_CodeSpecifiers(CodeSpecifiers self) +{ + return self->ArrSpecs + self->NumEntries; +} +forceinline +Specifier* next_CodeSpecifiers(CodeSpecifiers self, Specifier* spec_iter) +{ + return spec_iter + 1; +} +#pragma endregion CodeSpecifiers + +#pragma region CodeStruct +inline +void struct_add_interface(CodeStruct self, CodeTypename type ) +{ + CodeTypename possible_slot = self->ParentType; + if ( possible_slot != nullptr ) + { + // Were adding an interface to parent type, so we need to make sure the parent type is public. + self->ParentAccess = AccessSpec_Public; + // If your planning on adding a proper parent, + // then you'll need to move this over to ParentType->next and update ParentAccess accordingly. + } + + while ( possible_slot->Next != nullptr ) + { + possible_slot = cast(CodeTypename, possible_slot->Next); + } + + possible_slot->Next = cast(Code, type); +} +#pragma endregion Code + +#pragma region Interface +inline +CodeBody def_body( CodeType type ) +{ + switch ( type ) + { + case CT_Class_Body: + case CT_Enum_Body: + case CT_Export_Body: + case CT_Extern_Linkage: + case CT_Function_Body: + case CT_Global_Body: + case CT_Namespace_Body: + case CT_Struct_Body: + case CT_Union_Body: + break; + + default: + log_failure( "def_body: Invalid type %s", codetype_to_str(type).Ptr ); + return (CodeBody)Code_Invalid; + } + + Code + result = make_code(); + result->Type = type; + return (CodeBody)result; +} + +inline +Str token_fmt_impl( ssize num, ... ) +{ + local_persist thread_local + char buf[GEN_PRINTF_MAXLEN] = { 0 }; + mem_set( buf, 0, GEN_PRINTF_MAXLEN ); + + va_list va; + va_start(va, num ); + ssize result = token_fmt_va(buf, GEN_PRINTF_MAXLEN, num, va); + va_end(va); + + Str str = { buf, result }; + return str; +} +#pragma endregion Interface +#pragma region generated code inline implementation + +inline Code& Code::operator=(Code other) +{ + if (other.ast != nullptr && other->Parent != nullptr) + { + ast = rcast(decltype(ast), code_duplicate(other).ast); + ast->Parent = { nullptr }; + } + ast = rcast(decltype(ast), other.ast); + return *this; +} + +inline Code::operator bool() +{ + return ast != nullptr; +} + +inline CodeBody& CodeBody::operator=(Code other) +{ + if (other.ast != nullptr && other->Parent != nullptr) + { + ast = rcast(decltype(ast), code_duplicate(other).ast); + ast->Parent = { nullptr }; + } + ast = rcast(decltype(ast), other.ast); + return *this; +} + +inline CodeBody::operator bool() +{ + return ast != nullptr; +} + +inline CodeAttributes& CodeAttributes::operator=(Code other) +{ + if (other.ast != nullptr && other->Parent != nullptr) + { + ast = rcast(decltype(ast), code_duplicate(other).ast); + ast->Parent = { nullptr }; + } + ast = rcast(decltype(ast), other.ast); + return *this; +} + +inline CodeAttributes::operator bool() +{ + return ast != nullptr; +} + +inline CodeAttributes::operator Code() +{ + return *rcast(Code*, this); +} + +inline AST_Attributes* CodeAttributes::operator->() +{ + if (ast == nullptr) + { + log_failure("Attempt to dereference a nullptr!\n"); + return nullptr; + } + return ast; +} + +inline CodeComment& CodeComment::operator=(Code other) +{ + if (other.ast != nullptr && other->Parent != nullptr) + { + ast = rcast(decltype(ast), code_duplicate(other).ast); + ast->Parent = { nullptr }; + } + ast = rcast(decltype(ast), other.ast); + return *this; +} + +inline CodeComment::operator bool() +{ + return ast != nullptr; +} + +inline CodeComment::operator Code() +{ + return *rcast(Code*, this); +} + +inline AST_Comment* CodeComment::operator->() +{ + if (ast == nullptr) + { + log_failure("Attempt to dereference a nullptr!\n"); + return nullptr; + } + return ast; +} + +inline CodeConstructor& CodeConstructor::operator=(Code other) +{ + if (other.ast != nullptr && other->Parent != nullptr) + { + ast = rcast(decltype(ast), code_duplicate(other).ast); + ast->Parent = { nullptr }; + } + ast = rcast(decltype(ast), other.ast); + return *this; +} + +inline CodeConstructor::operator bool() +{ + return ast != nullptr; +} + +inline CodeConstructor::operator Code() +{ + return *rcast(Code*, this); +} + +inline AST_Constructor* CodeConstructor::operator->() +{ + if (ast == nullptr) + { + log_failure("Attempt to dereference a nullptr!\n"); + return nullptr; + } + return ast; +} + +inline CodeClass& CodeClass::operator=(Code other) +{ + if (other.ast != nullptr && other->Parent != nullptr) + { + ast = rcast(decltype(ast), code_duplicate(other).ast); + ast->Parent = { nullptr }; + } + ast = rcast(decltype(ast), other.ast); + return *this; +} + +inline CodeClass::operator bool() +{ + return ast != nullptr; +} + +inline CodeDefine& CodeDefine::operator=(Code other) +{ + if (other.ast != nullptr && other->Parent != nullptr) + { + ast = rcast(decltype(ast), code_duplicate(other).ast); + ast->Parent = { nullptr }; + } + ast = rcast(decltype(ast), other.ast); + return *this; +} + +inline CodeDefine::operator bool() +{ + return ast != nullptr; +} + +inline CodeDefine::operator Code() +{ + return *rcast(Code*, this); +} + +inline AST_Define* CodeDefine::operator->() +{ + if (ast == nullptr) + { + log_failure("Attempt to dereference a nullptr!\n"); + return nullptr; + } + return ast; +} + +inline CodeDefineParams& CodeDefineParams::operator=(Code other) +{ + if (other.ast != nullptr && other->Parent != nullptr) + { + ast = rcast(decltype(ast), code_duplicate(other).ast); + ast->Parent = { nullptr }; + } + ast = rcast(decltype(ast), other.ast); + return *this; +} + +inline CodeDefineParams::operator bool() +{ + return ast != nullptr; +} + +inline CodeDestructor& CodeDestructor::operator=(Code other) +{ + if (other.ast != nullptr && other->Parent != nullptr) + { + ast = rcast(decltype(ast), code_duplicate(other).ast); + ast->Parent = { nullptr }; + } + ast = rcast(decltype(ast), other.ast); + return *this; +} + +inline CodeDestructor::operator bool() +{ + return ast != nullptr; +} + +inline CodeDestructor::operator Code() +{ + return *rcast(Code*, this); +} + +inline AST_Destructor* CodeDestructor::operator->() +{ + if (ast == nullptr) + { + log_failure("Attempt to dereference a nullptr!\n"); + return nullptr; + } + return ast; +} + +inline CodeEnum& CodeEnum::operator=(Code other) +{ + if (other.ast != nullptr && other->Parent != nullptr) + { + ast = rcast(decltype(ast), code_duplicate(other).ast); + ast->Parent = { nullptr }; + } + ast = rcast(decltype(ast), other.ast); + return *this; +} + +inline CodeEnum::operator bool() +{ + return ast != nullptr; +} + +inline CodeEnum::operator Code() +{ + return *rcast(Code*, this); +} + +inline AST_Enum* CodeEnum::operator->() +{ + if (ast == nullptr) + { + log_failure("Attempt to dereference a nullptr!\n"); + return nullptr; + } + return ast; +} + +inline CodeExec& CodeExec::operator=(Code other) +{ + if (other.ast != nullptr && other->Parent != nullptr) + { + ast = rcast(decltype(ast), code_duplicate(other).ast); + ast->Parent = { nullptr }; + } + ast = rcast(decltype(ast), other.ast); + return *this; +} + +inline CodeExec::operator bool() +{ + return ast != nullptr; +} + +inline CodeExec::operator Code() +{ + return *rcast(Code*, this); +} + +inline AST_Exec* CodeExec::operator->() +{ + if (ast == nullptr) + { + log_failure("Attempt to dereference a nullptr!\n"); + return nullptr; + } + return ast; +} + +inline CodeExtern& CodeExtern::operator=(Code other) +{ + if (other.ast != nullptr && other->Parent != nullptr) + { + ast = rcast(decltype(ast), code_duplicate(other).ast); + ast->Parent = { nullptr }; + } + ast = rcast(decltype(ast), other.ast); + return *this; +} + +inline CodeExtern::operator bool() +{ + return ast != nullptr; +} + +inline CodeExtern::operator Code() +{ + return *rcast(Code*, this); +} + +inline AST_Extern* CodeExtern::operator->() +{ + if (ast == nullptr) + { + log_failure("Attempt to dereference a nullptr!\n"); + return nullptr; + } + return ast; +} + +inline CodeFriend& CodeFriend::operator=(Code other) +{ + if (other.ast != nullptr && other->Parent != nullptr) + { + ast = rcast(decltype(ast), code_duplicate(other).ast); + ast->Parent = { nullptr }; + } + ast = rcast(decltype(ast), other.ast); + return *this; +} + +inline CodeFriend::operator bool() +{ + return ast != nullptr; +} + +inline CodeFriend::operator Code() +{ + return *rcast(Code*, this); +} + +inline AST_Friend* CodeFriend::operator->() +{ + if (ast == nullptr) + { + log_failure("Attempt to dereference a nullptr!\n"); + return nullptr; + } + return ast; +} + +inline CodeFn& CodeFn::operator=(Code other) +{ + if (other.ast != nullptr && other->Parent != nullptr) + { + ast = rcast(decltype(ast), code_duplicate(other).ast); + ast->Parent = { nullptr }; + } + ast = rcast(decltype(ast), other.ast); + return *this; +} + +inline CodeFn::operator bool() +{ + return ast != nullptr; +} + +inline CodeFn::operator Code() +{ + return *rcast(Code*, this); +} + +inline AST_Fn* CodeFn::operator->() +{ + if (ast == nullptr) + { + log_failure("Attempt to dereference a nullptr!\n"); + return nullptr; + } + return ast; +} + +inline CodeInclude& CodeInclude::operator=(Code other) +{ + if (other.ast != nullptr && other->Parent != nullptr) + { + ast = rcast(decltype(ast), code_duplicate(other).ast); + ast->Parent = { nullptr }; + } + ast = rcast(decltype(ast), other.ast); + return *this; +} + +inline CodeInclude::operator bool() +{ + return ast != nullptr; +} + +inline CodeInclude::operator Code() +{ + return *rcast(Code*, this); +} + +inline AST_Include* CodeInclude::operator->() +{ + if (ast == nullptr) + { + log_failure("Attempt to dereference a nullptr!\n"); + return nullptr; + } + return ast; +} + +inline CodeModule& CodeModule::operator=(Code other) +{ + if (other.ast != nullptr && other->Parent != nullptr) + { + ast = rcast(decltype(ast), code_duplicate(other).ast); + ast->Parent = { nullptr }; + } + ast = rcast(decltype(ast), other.ast); + return *this; +} + +inline CodeModule::operator bool() +{ + return ast != nullptr; +} + +inline CodeModule::operator Code() +{ + return *rcast(Code*, this); +} + +inline AST_Module* CodeModule::operator->() +{ + if (ast == nullptr) + { + log_failure("Attempt to dereference a nullptr!\n"); + return nullptr; + } + return ast; +} + +inline CodeNS& CodeNS::operator=(Code other) +{ + if (other.ast != nullptr && other->Parent != nullptr) + { + ast = rcast(decltype(ast), code_duplicate(other).ast); + ast->Parent = { nullptr }; + } + ast = rcast(decltype(ast), other.ast); + return *this; +} + +inline CodeNS::operator bool() +{ + return ast != nullptr; +} + +inline CodeNS::operator Code() +{ + return *rcast(Code*, this); +} + +inline AST_NS* CodeNS::operator->() +{ + if (ast == nullptr) + { + log_failure("Attempt to dereference a nullptr!\n"); + return nullptr; + } + return ast; +} + +inline CodeOperator& CodeOperator::operator=(Code other) +{ + if (other.ast != nullptr && other->Parent != nullptr) + { + ast = rcast(decltype(ast), code_duplicate(other).ast); + ast->Parent = { nullptr }; + } + ast = rcast(decltype(ast), other.ast); + return *this; +} + +inline CodeOperator::operator bool() +{ + return ast != nullptr; +} + +inline CodeOperator::operator Code() +{ + return *rcast(Code*, this); +} + +inline AST_Operator* CodeOperator::operator->() +{ + if (ast == nullptr) + { + log_failure("Attempt to dereference a nullptr!\n"); + return nullptr; + } + return ast; +} + +inline CodeOpCast& CodeOpCast::operator=(Code other) +{ + if (other.ast != nullptr && other->Parent != nullptr) + { + ast = rcast(decltype(ast), code_duplicate(other).ast); + ast->Parent = { nullptr }; + } + ast = rcast(decltype(ast), other.ast); + return *this; +} + +inline CodeOpCast::operator bool() +{ + return ast != nullptr; +} + +inline CodeOpCast::operator Code() +{ + return *rcast(Code*, this); +} + +inline AST_OpCast* CodeOpCast::operator->() +{ + if (ast == nullptr) + { + log_failure("Attempt to dereference a nullptr!\n"); + return nullptr; + } + return ast; +} + +inline CodeParams& CodeParams::operator=(Code other) +{ + if (other.ast != nullptr && other->Parent != nullptr) + { + ast = rcast(decltype(ast), code_duplicate(other).ast); + ast->Parent = { nullptr }; + } + ast = rcast(decltype(ast), other.ast); + return *this; +} + +inline CodeParams::operator bool() +{ + return ast != nullptr; +} + +inline CodePragma& CodePragma::operator=(Code other) +{ + if (other.ast != nullptr && other->Parent != nullptr) + { + ast = rcast(decltype(ast), code_duplicate(other).ast); + ast->Parent = { nullptr }; + } + ast = rcast(decltype(ast), other.ast); + return *this; +} + +inline CodePragma::operator bool() +{ + return ast != nullptr; +} + +inline CodePragma::operator Code() +{ + return *rcast(Code*, this); +} + +inline AST_Pragma* CodePragma::operator->() +{ + if (ast == nullptr) + { + log_failure("Attempt to dereference a nullptr!\n"); + return nullptr; + } + return ast; +} + +inline CodePreprocessCond& CodePreprocessCond::operator=(Code other) +{ + if (other.ast != nullptr && other->Parent != nullptr) + { + ast = rcast(decltype(ast), code_duplicate(other).ast); + ast->Parent = { nullptr }; + } + ast = rcast(decltype(ast), other.ast); + return *this; +} + +inline CodePreprocessCond::operator bool() +{ + return ast != nullptr; +} + +inline CodePreprocessCond::operator Code() +{ + return *rcast(Code*, this); +} + +inline AST_PreprocessCond* CodePreprocessCond::operator->() +{ + if (ast == nullptr) + { + log_failure("Attempt to dereference a nullptr!\n"); + return nullptr; + } + return ast; +} + +inline CodeSpecifiers& CodeSpecifiers::operator=(Code other) +{ + if (other.ast != nullptr && other->Parent != nullptr) + { + ast = rcast(decltype(ast), code_duplicate(other).ast); + ast->Parent = { nullptr }; + } + ast = rcast(decltype(ast), other.ast); + return *this; +} + +inline CodeSpecifiers::operator bool() +{ + return ast != nullptr; +} + +inline CodeStruct& CodeStruct::operator=(Code other) +{ + if (other.ast != nullptr && other->Parent != nullptr) + { + ast = rcast(decltype(ast), code_duplicate(other).ast); + ast->Parent = { nullptr }; + } + ast = rcast(decltype(ast), other.ast); + return *this; +} + +inline CodeStruct::operator bool() +{ + return ast != nullptr; +} + +inline CodeTemplate& CodeTemplate::operator=(Code other) +{ + if (other.ast != nullptr && other->Parent != nullptr) + { + ast = rcast(decltype(ast), code_duplicate(other).ast); + ast->Parent = { nullptr }; + } + ast = rcast(decltype(ast), other.ast); + return *this; +} + +inline CodeTemplate::operator bool() +{ + return ast != nullptr; +} + +inline CodeTemplate::operator Code() +{ + return *rcast(Code*, this); +} + +inline AST_Template* CodeTemplate::operator->() +{ + if (ast == nullptr) + { + log_failure("Attempt to dereference a nullptr!\n"); + return nullptr; + } + return ast; +} + +inline CodeTypename& CodeTypename::operator=(Code other) +{ + if (other.ast != nullptr && other->Parent != nullptr) + { + ast = rcast(decltype(ast), code_duplicate(other).ast); + ast->Parent = { nullptr }; + } + ast = rcast(decltype(ast), other.ast); + return *this; +} + +inline CodeTypename::operator bool() +{ + return ast != nullptr; +} + +inline CodeTypename::operator Code() +{ + return *rcast(Code*, this); +} + +inline AST_Typename* CodeTypename::operator->() +{ + if (ast == nullptr) + { + log_failure("Attempt to dereference a nullptr!\n"); + return nullptr; + } + return ast; +} + +inline CodeTypedef& CodeTypedef::operator=(Code other) +{ + if (other.ast != nullptr && other->Parent != nullptr) + { + ast = rcast(decltype(ast), code_duplicate(other).ast); + ast->Parent = { nullptr }; + } + ast = rcast(decltype(ast), other.ast); + return *this; +} + +inline CodeTypedef::operator bool() +{ + return ast != nullptr; +} + +inline CodeTypedef::operator Code() +{ + return *rcast(Code*, this); +} + +inline AST_Typedef* CodeTypedef::operator->() +{ + if (ast == nullptr) + { + log_failure("Attempt to dereference a nullptr!\n"); + return nullptr; + } + return ast; +} + +inline CodeUnion& CodeUnion::operator=(Code other) +{ + if (other.ast != nullptr && other->Parent != nullptr) + { + ast = rcast(decltype(ast), code_duplicate(other).ast); + ast->Parent = { nullptr }; + } + ast = rcast(decltype(ast), other.ast); + return *this; +} + +inline CodeUnion::operator bool() +{ + return ast != nullptr; +} + +inline CodeUnion::operator Code() +{ + return *rcast(Code*, this); +} + +inline AST_Union* CodeUnion::operator->() +{ + if (ast == nullptr) + { + log_failure("Attempt to dereference a nullptr!\n"); + return nullptr; + } + return ast; +} + +inline CodeUsing& CodeUsing::operator=(Code other) +{ + if (other.ast != nullptr && other->Parent != nullptr) + { + ast = rcast(decltype(ast), code_duplicate(other).ast); + ast->Parent = { nullptr }; + } + ast = rcast(decltype(ast), other.ast); + return *this; +} + +inline CodeUsing::operator bool() +{ + return ast != nullptr; +} + +inline CodeUsing::operator Code() +{ + return *rcast(Code*, this); +} + +inline AST_Using* CodeUsing::operator->() +{ + if (ast == nullptr) + { + log_failure("Attempt to dereference a nullptr!\n"); + return nullptr; + } + return ast; +} + +inline CodeVar& CodeVar::operator=(Code other) +{ + if (other.ast != nullptr && other->Parent != nullptr) + { + ast = rcast(decltype(ast), code_duplicate(other).ast); + ast->Parent = { nullptr }; + } + ast = rcast(decltype(ast), other.ast); + return *this; +} + +inline CodeVar::operator bool() +{ + return ast != nullptr; +} + +inline CodeVar::operator Code() +{ + return *rcast(Code*, this); +} + +inline AST_Var* CodeVar::operator->() +{ + if (ast == nullptr) + { + log_failure("Attempt to dereference a nullptr!\n"); + return nullptr; + } + return ast; +} + +#pragma endregion generated code inline implementation + +#pragma region generated AST/Code cast implementation +GEN_OPTIMIZE_MAPPINGS_BEGIN + +forceinline Code::operator CodeBody() const +{ + return { (AST_Body*)ast }; +} + +forceinline Code::operator CodeAttributes() const +{ + return { (AST_Attributes*)ast }; +} + +forceinline Code::operator CodeComment() const +{ + return { (AST_Comment*)ast }; +} + +forceinline Code::operator CodeConstructor() const +{ + return { (AST_Constructor*)ast }; +} + +forceinline Code::operator CodeClass() const +{ + return { (AST_Class*)ast }; +} + +forceinline Code::operator CodeDefine() const +{ + return { (AST_Define*)ast }; +} + +forceinline Code::operator CodeDefineParams() const +{ + return { (AST_DefineParams*)ast }; +} + +forceinline Code::operator CodeDestructor() const +{ + return { (AST_Destructor*)ast }; +} + +forceinline Code::operator CodeEnum() const +{ + return { (AST_Enum*)ast }; +} + +forceinline Code::operator CodeExec() const +{ + return { (AST_Exec*)ast }; +} + +forceinline Code::operator CodeExtern() const +{ + return { (AST_Extern*)ast }; +} diff --git a/scripts/build.ps1 b/scripts/build.ps1 index 40c9055..393fc1e 100644 --- a/scripts/build.ps1 +++ b/scripts/build.ps1 @@ -208,9 +208,9 @@ push-location $path_root # $build_args += $flag_micro_architecture_native $build_args += $flag_use_separate_modules $build_args += $flag_thread_count + $CoreCount_Physical - $build_args += $flag_optimize_none + # $build_args += $flag_optimize_none # $build_args += $flag_optimize_minimal - # $build_args += $flag_optimize_speed + $build_args += $flag_optimize_speed # $build_args += $falg_optimize_aggressive $build_args += $flag_debug $build_args += $flag_pdb_name + $pdb diff --git a/thirdparty/stb/lib/stb_truetype.lib b/thirdparty/stb/lib/stb_truetype.lib index 715881fab2067308862d014c71962aa8ed745ff0..dd9c9363deb789e58a015a58cc0db0737848c73c 100644 GIT binary patch literal 945032 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 zOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#W zOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#W zOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#W zOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#W zOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#W zOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#W zOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#W zOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#W zOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#W zOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#W zOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#W zOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#W zOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#W zOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#W zOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#W zOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#W zOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#W zOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#W 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

&+06wx4rl(m^{2q|kbnrTQsG1|o%M>IX+ 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%0DdXI=57>x3KM{lzxj{Gz$ zaT@BL*zBX5h@kh)$`n(=YVfLU)peap9ipeb`Qs-*$B zmot@#sj*DE%r+TrtBw+$lyU26J*KlcsZn{@Dop|3FchS5cRL&L4!hnRXC)gh>kflJ9leP8gJ|74T~5>rh3yKNT| zH*?@dOQLOs`j&jvG=4sfFU(FZ9M*x{dLXY}delu9nYItnc4C_Hd)zSy&2?kxU>o1n zzUPm@9mI-q_@XSNYvsn4=Q^O%4D=k((`I){{9p~rboN+!|1F>eQ?+;h8pzW7VraX~ z7kwCSop_eq9i6@B^Tk+x)n__%8l>uZ1QI>c+wuC;TlTzHSKU!hwBWl3;7_*JJM;HO zGrKyY580y6a?y#--o37pI0rqZ?2!X1w(Gs>p1SJY(YueTRGl+_H+9b=cF@N^{)s~? zJQFidn2=L5O!|cI#@<(k;2Pmnbm=B&b9c0Y5erfIB^kwSW_WM{-jL4%y4|Fm3uK3! z6RjFChS%=0Kh4H~omV1b=$%pZ)gFA^pk8DNg5S!c53HKo&2~2ijoLW&+tsnhj(p(+%=1 z2C|cRb&zjMkS`PD(_u=!Fca2AD?HLG*5en zJ!zs!T0YLKpSjgf=*3&w@l0DiZrPdu5w6YrR-Hjggo>9M4rdk6Vgr2+Xp@2N1)6Oj zjxa2)>e}L!Zk)zk4#}8SOxRo1DKx*w zXaR77fihr#=Z<&IOkU{XPHD^NuEH9bqz`sCWH*MQhsT7R)deAppnDxu`El7P9y049S-o3)2-T^bh~lGI*KaB_!Vz<^k2Bx< zId`jZ3WvE8e$i#|*d-&#u9ja~o6RmIVF20Go~bXTA)rD4j3eAc8F?#BiF7Y_Nw8#yz_m8AoenW&O#0v)(vQi(s)W!<-Z! z-0Ejy#ZPiVZ&}KX?^L{l4MtNhhvUUhL{odHup6~&Vk(DIg?TBlCpLTEIyAP55{ERe zt%$QL`3tvrfYba8-k-&0cdRR}YYP+V3p>qN^>1J@!R#hj$CayAbp8n~S}$jh09kv} z!$28>^Ls%@3q`KVi%0_JPCw-dqSYt?k^7kdhXXn{c@$F6Kguw84X`+Dsft*~>sMep z6FaiM!EyDpBQb+Wpz-WSRgaaAh_%M3^DT_*=W^PgZkPuR<(K{Ax|m29+IZy|^$0E5 zN}zv77pB9iI|WZyAb!w3%QH{jtdVg%yAodZ>te2DaeOpUmFMjM9u@ImjDTJ{Ce^o% zZ^*7FtZQ2W`@!-4is%3{Elw|ZfRVY^>N|6`>+N)Y)%7bnPvWn&SN|lCkT_KE8~(Lq zqf|SZM2|7I1W!{iA&OgVux0Vy%nM>+Um$n`oXbADf$2P2l6{IvMU=T^TlE z4JD5?=Opi?Gwlr-Jt^eKtjq8wN}M-QHl1x*N<)8eINu`3N@;(rJ?LhBJ5)t5ev&dA zf2t!Qgg-s2je9`1xvf0Se&5>XR{z!_lI|cjWa$dbRl9OGiWBExr#FjbywJVTE#0UYT}-_~p6PTi6Ivl}w+HV}OZw*7E_I9hul!MO&zqP3q$ z9<^DWR!IV=wglD3_#=@}K?*m3)A~y@jiJN4kS)KYVVhRBjET*DI_|{ZYM6a!3(D=j zvE0WSGQZ>nj}-kmc3`AQp(BY}lx18AwwxRAh?=O0LR==QBR2RXcgn4O{o{}fd1G@k zM`G3QYJ_Xu;-AOps!J%_`v&P4E8iH3RX@#6XP1jVzfXvehq1^-h023ZF)hx0Pw=sA z5@8CBal-Dc2l^h;@SqwOQH3fpwQQ*j6gv6kw@hf86jPK#3>$WD{RPh8&gKp37T(!D zrnmJ-ihhrYxJa{b&UT9^6MaO94L(geq*X#qQHBE!;g^=@b?@8;T z3ROi|`yFHIna$ht#?K7xZOCpdjHV9WfZ@<-*}1)_Q;+~g+ZJmZt3dLF{>!Om!n#^j zGt;kzC5mW<{qj*;zTyPsIl%1WId)$jX4lilvkfb@9B91}X{`pbjM`^`?l5Ve2eORX z_kirieFex~&2IxiZCMGUY}qdW*|HK#*|LuU*|HlzOk1KA$d8b!w!|Mq zs0}5BVkFLs-`E~#15m7OWm9=W*8P@j z9ZRzAqx{`)nf<+ClJdhe|81_ogEk9^yVs9#yF1`522HM@$}dSqF+O$0dCB6~kr(3W zNn(ae;s~eEl;fbYqw@kr(rpklcgd18q%pV-b8GNV4# zjG6&3>e%2Ow1*mXXAxr^Z|pHQOy-Y!;~rc}Jdb15f0v9Sp)g7JOsS9SAJ?>4CK@i-) zEGeqb?5oc_ALai$WtjHpS!B&4O^65HM?AorjCR2H7(9P|6E}Z;8!z7L%A3&(i?X59 z#Ss;EHe{YB>mwp1?%f@K!5^b~4@fmGga(meP-l!f2^decOQ`Qz{!rf@{4h|TnF=Z` zv&&rE87t-~2$H!H@BTbs-V98jdfiG4UtySabVtEjUY;+Ss`(Ywx|YK@yVSL*20YHIM+fod;z67cHrb{STsMUvjfCq(DBUA zrJ^aP|GLaI@%={?>LdoO&HMm)=bV+8FbAW^y-wY~_UVxo2gvL=4<0K3=3!#WMe&SC zY7osd06gln0vMIOkv14oEFL_<5ml&KNksE@k)<6tSA~pf7wyt68fSOWL@BV$PU?{w zYj9WpD?_%=Y`c9X89f(UNI{ZqzDG{9mr#ZU8NQ*;CX3x8FKFY6dFW&$#mvLD3EFsA z^l9k2hiE>W9Za3ZR>Qveh-_$UB>Ak~yLx*YmcKkkGKM?Jw@n_m`cPNsV-&u((oDY3 zCLdn_vW6$% zVxf>u>mF)HL;xRMv6_FX?BH9i_1ua=bZiXM5DndbZ7l}B`nFNhkm1wT|B<28r>*~# zrSR*o^)k*mFR}PRY`SE#jDeG(Fqka!wCCC6Cs=>3JErP~buO9n)^11;v?97w1jX;S zr()=zM5*>+iQalCB9;-LuqMGwOMPgbLutp`3&}Y^R=adDkYyhvL9*JV2#{qT)&hOC zLYI^~fvk3JE0ER2{1wnQ%vW)pe{P@`fYyys37xBpP1>)4Y>7fvZ>dQe3uM#un$Ta- zcx8znGtUTAc=*(i8Nei>KGQqMQwaGmYdJdJxknx}J%M&z=F4}}Kta5CUv%*0M}bm5 z63OoWxZuc-w9opd8@T_Y`qOSdpJHM2d7OpObFtIES@|{o!YC%spZOv}Dp3_^g;q&w z=M;Z4&k<_xR@}wddl6CEIvGV22QWlAPdL8q#9$ZJ=W+>i^MV4lFdY zAKdN!mAdXlMp_D#E*j_Rx#=l2!Ge7FP8d;)q%TGij7x*$JX?!iv0f;zHfOaQT$C8q za`ZFFB@&WD%q)tqt0XS5x7<#HApNiG6cY9STlDZ_p~Q4c7l^W7JX;HR{B7J+GqgV=>*1;Qg#WvU)XUG% z-n|rP*LV{_18AN(mj?q#I(F-W>{=lE^-qB&k|R`LE-9wOn?YI`yUgaR51`Kj*%G?A zEHNcs0g4+)!3M81kTf3Ere-IAJ__`t;akrIvh?dhp#NpkJ^^Iumtq`unsMj_$YTa- z0@`h$l|YXhs5wacbO5ahpj!iIEl`&!kpSv8(8l2FCZHaZhNbR8MR1a1*mxxnesQI5 zEg@}giLhBZE%R}*`2a!?R@zNR`Pf0&*YG$Kg@MAjJU4Z%B#I)UR!L z4GV)zP}QIZ>ebw!jHyyi)$1y8^f!*#-^8>u<|i_4}|(p_BfHW5L@ z{0KMykdkZKNqQMzEncx#zRrJdlhDh52l?+1d6lh9*~->FhAOpEw5*&0_TQ^3r(6()L*i8-0;=CUan(lU zcW(O3LwBm4Yy z!X}GJ;e|u-=XlJa;I&APX;g85DMh0Og)I79$E=3usy9CJ0G@8qQSX5B#vw$!R;9s4 zV1t5WdB-um^Xs6va4l%a%xr+(!|Pi}%Zxd{e`W$~4b*M==Z)M{Mb+1a{QeC^Q!uC2 zAn6N=du`*fIn&K*sqbd!EAfP`i7;DGpFjutfa_?l%Vw5L8ec$WGyoFO7hJ45k?_!Jw6cG|-S&7C1Spo;11FoYou6dS%Sr&Dqv z4KgiF#E|IlYcs2yBSUuRR4}yCnhx*XP^@t-=v4QF z$bZ0Kc>$&&|=%+44p?+PWg=npf3x zGwg+7EMW>solCe58f$`%(zB+=)MYkTr_23V~3GmASLKH+^m9 zv-LDR`=!mRrNpR4*K)LI(|q0fP&2pm6}kKRbV<)nSu|8IqyG7Qix%S;YnOi37wTIIgx6n*^9Tuh;OM@DtS=4)$#In5Z#{5x7G-}fs^PaaoaRJ^t7>MLF4}ok2 zD5cnYhtRO*o}bZgtlg|BpSl!0EyB*t+7eK0x29e%#7WZi*-qywpa;yv-U6h{QQj2S zXo@SGs<-7Pj~>VKdQ6RWoi54i@qW$r+0h5EH6#py_1c9!A)9_3D^IsHO%=8e<~O&8 zTuQE23+c=EbA1VB4@uNfO(1<)l-HLl{J!9hC73hfQ_iYtRvTr+eP|5G!E7Wcnq z<|3Z6Ot}TklWtYbgLt0cR*2sRpBij2KHHhSr1pIyRBl!i4n`#GZ<xl2faY{;wBl_LniH9AbWAU3FyImy!DNCjjg76U5l138m`YAs>J)O zBE5%VaXEFuF7CO8%yKL(U)=KXn7mOx1&L;RPrS5Hf`0S-3R0fu>%Jp#vplS{bksD= z{>i2%2wR(&t>SEjm-1x#@`qoa>B1krn|pkdM76?%>9K(45`VuXA0YRMT;ij9>F%A%{@6{Q!siowb0Yj}exA1JD%p~x*Ov0%CzldF%f>Yx0{y&!LL z^N=c@hWm8&AFL;?qw*$rQ8;qZGj4jOp{aNws98joc_nsMbcsYagHXuZOEZCfX!cSq zkljn>pqH;I7SHpqUSYP3oI2%Ekr^;vC!!)4sORN6Z-iXdIe=c@tRFJn=bQX_(~Und z&W*Lb@==kqs1Vn8!p5<+H`LSjX>N(s|1bFZ zEg;+4_kw)VE7;a{2Kjn`EFbYUP#*U%Y~9SUEowJ(=|-HrAxl>=;v8Sk9K&b$b9_|3 zur$Y4dUHH~_#Ar%fZ~NtFvp_kcGMCn+Bu#DWJi5Dke%a2Kz5GB<=K3zfb1N9I>?s* zva=(anVTI57=mA-5!olGcfYZn&qK9AYoVKRfj28LN1K&-0a6`so?WsmLx|JtCKN!paBxvEw|mbPoo(0g#nT9; zj-AiryYtBf`O43QXWku)3**@Zg+>*)ewtPMeIzvy-83OJFn>!KhF*Pt1y7qAIN#YO zKNX15IadW%sLXjF>f&$iIu(PgBrgOHm?dt1&N9jWJ5rnz^ zFbQ@EiCv9ZP#KS1PUo@9<-Xq2SP#7R;Mg|!i2jSbX(6+@66W%IHWsl#%&cDA>gO-I zXm`{&{MrzTraCI<{zg0o42*TQZKiRxXYCQzpJAu(bfXqsk9ROUiftH`jaKv*^8k3x z#^i*#ZE^g===n`&e~+f&6J`>knSbT)v_fm2!bg*Da94v-d3v=UY&ll6ZnQT&dXs*B z^5ZT`C;uo~4h)$w^73?Z^0g+ECGK1#mbt~1pEdKekEld2^wa;jGR0Reuh_Ltgv$?1Hlp?+VTRKoJ5w$dG;=k709dgPF-)L_028Q zDD~7kac4%CSub$%{oNRSV0^f@b@$dowgz1pad*e^yyiGnc6{x

ZHtG<~HG?klI` zku01#@V-PqHPLZTM$_{vQwM&lV$&k+zX%nzN5}n2ZqRP4!W9~Jf}MTe;!^C-k~mhd zwHEtL<6z9WM@sBAeBgCxJrA1UNQWJfema7QE+IRln`No;Un(DRvuiQ^tVmtXHty0} zph#i#{q9t4P2$&La%m&tneXW*>w*r=f2O3LHB1VNalTo*JI5tU?3DG7^`xe!w^DdGorXorjnHdvoDR6@+Vonep6Q4?6e#fDzO6@O&O~5x()-r?*Gme+Db( zj!5g^)?eE}_5CrKL^eboT6xJag$1?xUmbXsK*J1qgjZKZOQ076SpuyC?-g^T-5lgw z3-n8qmJITxfZi}^PXYbPKzc7}b@s0Uy=~IkAp};}`yW7meTFUqF|;Q3UCbW^&}3*> zqxm`u$i9`i2gv68dI0?$kgX+fW+VSJT&~C8sdWG2)-8@ba9d#ej7X=PA=#DGp=*y&@v(L#F9fnHsYBPU zqz+x1Zz+&n$!mgqEkJ!{t$qz;ou34A8!=w~hxrgWseYun&FAl&5pv1p0iFm(!8V3H z<*Jx{!{;AfFujmBcHX*Wf&gSr+ZVwo4#jY0U(3r*%j=_@)+ zY9x=nmU#`N28xn_Gl-w228wgPx>5t7+^?Offzi2Ne}`pW?$iNEpQYQbisaJV;*O$w6L`1_0U*k{d>X@@-uWj_-L@IcFpE__T zHLzW6mwDZ{-+##W`~(gHC;fmDbvH9QZ@Xr~M{8L!6d$c+$xwW>csmpyE#Btv@owsS z*WhCs$Xbm20LZ%0c{E5n0905ZdZIHgWT4*yjWN)8R(_m;P6L`?pmTu22D%hzl7Vgp zvTexO(AllJoGS(R+BoRldnU~RvSqcexRc!~ z^L=i_R;rQbGfb`{^R7rEdGi=*nm&JojRtFwSJ#3Oa#@cn3ZAomoY{_jdYCAo3+S2) zq4To>?LP!BFL846#=?u&hLj5iWGO~3oTO9nkLO3y`56YakiRXLfTUBApqdamFfO4} zAZ@>Y2%V?$e1vRViKQvMm@N~&%+D_ENH~z`Ii83|Oc75c{jHdJ3Zrv_(ID`~X~tJ9 z5p)zjhgT8j8SANjthB~M?E5~(Pm9^uk}~|2NI8+_Km>gUq1Sg#XCf@R>qxa^^)euf z?sI`G`PGqX(OpNX&37Y^MfWv9J{_r3D}=^h0J8an_|r_f zI?LqS7^Drm`&;SR)t*9zz6a`W2F`F@GiA<83J6GoAai zGBaQFZUNa+ZVh$CYOW|rAQx3)#zPI_mYaqP2A}G$H@3M%BRTI{ZgvJKwHe)N|kAP0`!cq7u?kD%K~ zUDzYHq9S3VG|C8Bay#pjV5M;a`KTd;k_cD~j{xm5X^* zHFR6P`E8Uxr)3`~8pb}=3-p3PJrRGK?~_3PZqil+`Mwf- z{og>n=Ii~z*GZtLeeW+@7jAs4*)FTVv{C$~`%EBvthRFs1+5m+y8AGCN7RT$_4vHm z=thV5Kw+RRTw&fa=P3!zD*+>Dd>*BrB@XENtS2JxMlzXpydt@7Ne3kTYEGYO`gB^* zr{E%C)sIwP{6W>*hXvk#93oh5HY`luzHoM26;8eEWaqvI_i|3^_2SgA!u8|rr2_hc z`+>|=2r=w6f_s2TvjM3Ls4>}PIs>SxLUcxwb-SEb1KI0P#D7L1_H0O(K6`wZt_iy2 zd~q*T9M>(>8L)w{7X%m>au9!*+vtrtJU+x#^r}DjD*AZ@>Im$7?>6+*&fF@!5h&X6~-U(#q`LBTN1@tgb-UT#J?{K6Xf5V?S65$;( zrx%ZqE1p3s^<$qr$1~R;5ASNoEG&;z54cBuWlpt3C9Zym&UutK@jd9ru80@&JQb6I z>gNq1$IN~)bhx3o9g7zzx)-Z+?>r|Q>foQNJHj|4TMD$Yqr!wRVdutKd(>iA@8kGf zM7)K$I1dl)GeK=I#n~4Iinl9f#J&o^x^_0sJmX&+fqZB$p*r^>psy0Ih9Yic>2?oHH?ZzCDT)cN1pCjlXzLLM=Z_KT&TObu+Y|N zf$szY4rpzx_&$FH8q@BO9Zq}9(XIn-;GbhF5yB!}q zckt7QQ8CPlp7|Ir$1pwONevpV8&J1`Nulu=Cq=ei<<44MvURlEG7uTcHuOZPaEPo6 zEiIviZi5Vt=H`FfldGLuQ3%&PgO%dv7L=@Zeu}Z!*2Q?XV&QOlSK-plFI>+hNGIS% zd+Xs1P>Qa}x_+veCuqKzCwR?h=BN3_{j#fv4_pu?0#M18A$0O5!}}JWwKbe{Xg8kz z3{&(O*6uUq!fC|eD_3=Xj3z&0_`Vl_tf{!3GEC$bG#bc${U;!c_3c1^X|VZmAdAfk zRA@^q2D1590{ykgcLR{k=kbERzBJF`z%!c3^oi+|Ja6M@A~KZ>o%pw-$4z|vU3?ZE zmem0EHWOIVGdp>^rxktYI9E-toUpjN?Fp$ic|b1DVnpI8ezCvb;xIS}iS}U~C3+t3 zTOANS2#$PHr5mMnjyZfI=lJgVjN_W{X99B@iQdd-hXeql z7zh&-n2A{kyB5WODT<~{S_ijeFiii57Y0Si8A3#82_r9#OGM8hJhPlsTZC`v!Oq&^ zLir(UjT7NdEN2-UVv>!Ed^v^xZZYmg%I^HS)NdJ4a0h7wB}`4 zXO17eoa3u8iIpX$L;`La%LOV|JP%_5hhG`fXjf<^jX}ePnuO>a^BQfr=a&REH zEq5G3bQwFEc$fFYM+p*NC=RBhg!zkCcf?xS#}IM5n9EY!Sm4dHg33fbYkr4?YXTho2w7lx7c0{?mceT+THqiEPXjR8HrxM z>UsjKo<}z-45_~q$ddmk(3vJ}K9D^e8i3w4_;>@*NBKIwKumnX;PNv-Lw3G@gkIwb z98q#V4|>H#lMrrym}#rCul13~2J>bnN*GzNFmrJ`j*r~pxBPjN)a?W2t>J^`t)3us z$4#8h)HU+g3Hq+}Xw$((IFB*3<2@fXTfqib{?PKujEhL2wfL(GDW+oTWY zi0`Q~uhiY_rpjjTD_fo!@FESvSNIC4A$7FKD`=PwY%}MhHp49jLn?vVOxpAyZ2?fN z`MM0~HUkN}tY6qQK=$47XMt=j>8mTl5T0-y*%UpO`9 zNZ|oTI6ih`dlcJ|*}FDRe`kAsaZ?tRe#N1v^WZoY-OjIagb3aCugp9#ueA3brt(x7K-B6(t$eC5x>}Cu&F8(deOR^WQeH`wRvwBmucpTBDhVUJJNW}2 z@+O!4QjQ-=Z-!O3&cy9`_CTyAs)6D;j*?xA|v}CxN zU44StChb2p+mnOY#_=L2{)uOM7oJ9c*KC*glmDNX?VSEpH*|A6<8x8$J>F) zuPnlx9rGWCCbI-_f@%foq;*O)?Xj}AsVnXPfNx;c&bdVsJg_k9YqitpI*dgrdixn=} z*|wf4W0@}d=7-?FI#-)@MKwWtxu5b3< zS+__MlIB1Y^mhc2<*s=Eo+X~0Ulh;05Vw}4v3>pSk)Pmg#vp=OxGS@hi*bTf5}*Ct z=5eIBEKH9yZapy!^EwWcxYa*%`8Jks1@8C`ed>^Kprdah9=b{|jJCxvs?+b%mIGJ# zNrS47_Yq1TO*&fn$rtt)N56krJw|hCtEJauuIVp&@G|Pa)p9#a*};@#cxK98 z!~DgH_wy3M7v<|Z*dqD1dbh)M19%fzz<$o3`!^@@fP~I9Gw+>dY>AR2@(> zSZBv>XTIjC!vsM(E!$Y(%->~yYf`d}z52b{*@6?>ExVnE4^6%M0DVY}Hw)0|N3JVK ziCXV=&+Ks@23_^Ptx9Qk&)mf(0=%uGGq_UUW-iT4BZ8?@b8>_sQYowf_dsQKswzlL z;{2S`(pEZvpqb}J4cVoInY|qcOX4%-!LuhiGn6rY#9uzLw{sGiB*qG1k|rLXN-8}M zdz8gzZ>%s*A1JM&v6&&fd%cbi(oXT}!tXpGzzJVU9T(o9IjV4k`;9^TFw>%Mz=WUZ zh#LAv3$vwF>08U} z3#HX=`etn5ZY>KQ(R7f)3#FSUxAgKtsa*#CWxP#JTc;&4jB$Au-Cl&dx_^D3sBbgd-py_-jI?27EvKUuU{26$xQ1~FOk)UA zKiJKdqR=bOj!S3|vZMzjbLi0xY~k8@7~d>{v|r5+?s}2hYTukIQhRQa>pOBB#RH7Z ze%@)lfJ}?Bp+Y=CJ6}AVANU=1zE}nzpLUr}FF1hmwxqz2AUFW3tiYz=b)gPe&zu?u zzjDyuYaR5P!|ip>vRxomgQ5fEY!Wz%I>f$9oM(224GtjFkvQ(_u`e4-b$)b!U-h+k z?SJy{t}%&^&_2h$b(XA)#~M1&R>Y^|FHF-lG#$&9mb)E8nh)A{Gf_lTv7@E~Y)xZR zaHdLFe4#o%54PFZ1aHYg#yauM*-&k3!wjeI-!%G5k0iOfTwUq*J;hJ_O6peR29`~U zc=XclL}<>q?O|)^i=i4~kSEPup>=2M7%M*4MX@)?SvzT z@~j+msPPVDIt-V|3T|_Ku$p|;z9>6oz1#7MeblIznJ_ev2riAY<{sQU-m}xE)a7bH zPtt4T>7bGOTsd7MYqm7v7Vk!>x<_C2KxPk`)%YH;lrClBWE+h3YL$rA-qk;q4LmL} zid~;PwPE%zH}kyam;FV_b0H(7;gM2Xj4kMF`#zx-Y#nZ|E~F>1QGd$rc%ZoNDgMm* zo(Y@lwEmbMe8;D`fXurH`!btGL&c_yMu`R?EOuMA_7-d%qDVX0)sD|eZ=NJ;ubxN4 zgqjG)v6h3n20N|uRjY3lBxAV1C`fj&fl-h)@bN}L_jvo}25pmba{DjXzgiTzX!!35 z?(sjsCTI{lKk%ZZ3oENNz0SRj?Bk2@kc$xjk9nXRx75Zm>mtE}9%(T@&LrJYp@Vxa zkiFN$fHs-5D}n62My5eqP1+hDo9}Z#UodG2Ae-+Ktd+I(Sqx+YYkh~a!I}$Q#aXn? zlxPm1uK-z#iXQ^m7j>@z*;?KKvTy4?%3lAK5rw}AWP5N7sLj+j2xNP3;~2lS$g)p* ze#e{YogZ^V@J4YMk1^Nas$uSjpsbvC=M3oPjgTwWvbnrqsI^U<$(o1!md@PHHsdT_ z#GF8(%k>U!J98G#H1{f)Q>(6xZp$pRQ{Svi@jg+Ej3?f16iAAt+EvqD^{;fO99yu za!O}Q{6+9pM*OzKjv&p&2N}<=31wgu6?ea}m*$-?eAt>Wk4NL_H5GV0XalQt1fc{& z6Bc!TY~Pao*WxeMHEza3VV4g2C@eu_fWji#@mW|kf1Q3tGX`ZhM+tW2xpDBZHR5LP ztxTD*3`f~Up=_gvvP}kM8-=o*d~sjcpTnn9>)`18LZ@w_^#**q z+fFXRzQxC0ubz=m_=B2!WZ_5ngb-O zw3G6v3YK{_RvRA6Tv;OhCYb>9Oi0nR6fztts0Xs! zZ7Go5mdkdoYYG3~Z$R1|j0je{jHA zh~pItyrU+rg)BXim&7v`-)F+!67-D=28$KQ?VzIw?GP18G>3H-G|ebLah=qjB*YMw z8N|#Oov*eKjjYuS*2vwpfLBWK@&}ci&yH(PRAV-CklS-_uplRF&&?P~E_+^cLb+kCZEgR& zb>M#DyS4?lt}_zJw+((nRXm)R?B-pQChHE1^D-{pY7RN=u!;P#)-(2X80hXl*;#9( zH^UrvEEr);5JkvkOgDsvh~8xjn6Sa*s5)ft;YjTzij&eFt*zlgU)>$dfs`3w)6Ctz z0TA28qh82J4hhGHC^ufCvnRv{$k`Mtg*Z80%_~{riHAPs5>Cgss!qNY&z{9F*;AND zvcNJXjL2w%TcgJ@1^XoPbK56OF~zifn__vri|$-Qg6W$*khMtX#M8~(otoJ1Yb$Ut zQ(~IJg^llA#;>RL6N%-q>=vTdrnVN2OV*{Xm=I~(P?#)^v|ZvVNTTkL^A2wQ2onP( zR@-Je#2@JgcS^kckuN=?(;eh*_H$f=x+As8g5*E^&RLD_R7J7$s&GSkL%FFmmgQWb z_tQ-8ZO{s)RXpU|S&>Q9EWo45&Sd80I-{=2YE{8+k$si{Rgyb!FyB zL3~fxbLmFt89ep5H+H$RabtY%O-M*}FIvmJh&$0O!JTL&P7W&RyWJmRAnln@3uO1l zWk7a+WPt3h_%@IYeDV)Kw!}XJ*}x|f=Gzi41KAS40ctj9ht4sZ_6;C=!TD8?CiBo9 zvoEg(nqo@msn7zmFVjG_glL;_GZewJtfT-rO2R&p$Wsm~k1-t<;OU5>J1gjkSppWw zO)tRPQ30-N!l|ucULcNfTDR~W@d$DvKEv}PU^yAQ9JnA^+*PpB6SW|=dy@>#j&SPO zN|clcbO+n}5AhFjm%do_e$O`v7BMgvTh5ACcTs1kgcWooTO-z72OqY+-j7$t&LFrF zW_Hp21)nw3 z=jIY_9iDKDO~A6w;^mXvJPWQfiG4sutMIvTB8fOs4`@vPZ{CrwG|(LvyL)A?$HFeT6a}74`T9=zH7_Xkob+clS@_oGg`Mj^cBgy-OE7YbJ zaQoS*S-Hi`iUagX1Dy_Zm4VI!T5g~S&?*DvdP60)3pjl?j$rLHu{d0%(R7D3fa zPX0v1Z(QNg(0Tm&y?W3+FQVT0Es8JJrJBZ-Za39ufiNEgr8fl7b|Aa?b^+OZqAGqc zmt)7hRs8F7sM)`)nUynrCUjuFLx%5+kW2I9Y}4z6?s;|mtNHBKMrPWLXEYbk_ly?G z^Nd#KJ?U5xPe*vtQRhABh;#iRg(n@6+>?$vJ?W?$@}#3O?@32I&7l?HAwUG>aD;Q* z_cy0Nts|^bU?r{t^TT=|c)?IG;hH^3mID2|NfTRaPZH4|yC~xV2o;El*I@{e$j=-@ z_RPz$=9W9EbSgO8?jk?8iinnLEvEzMbBTvO3k>=UVYH3HURe zFFQ46TXT9rWae&jz98P_fPrS2Bb##u*>DX6p6+niFNm}?k+L=7&RSI>VY)r%KcJlo zznv4FV2Mq6r`JYKFH}zdZD-d;@9gp>m>FkxHLo%(hTT6}T)TgC&|2unK=$h|gS0x9 z%^q#H1KFcZmt1?adE}_&jxcNceBRCI?5YvA9mdU0c)adXjS}ItCuXj8K9{rTU+t{h zubZ8*x76(h9Vqt*9~1ohj=Zg=?_$ZQ#?p;R^tjg`YXy)+U^aEZD<(}w5-X+0JkE-CSPXMQz^VXSef>8|3{cD?hOv&)@*u4~fV9VLS)qX~dwuZrrXcOsAZ=X$-2r6FrhshOdxEc$8rw8Y zt9n{eAfDXz>Td$*!2t3W#E^;S6M7C}1`4Ubf_@V(EUgn|?j5y>u?nYAK)|e8L_e&3 zjm>)|iPspKgJP}5pR;Yxx=#JBPSQPffH^3{OL`1z1`GS=B}6ch`a*aib)vOn^(3Ud zwnR@tc-0ABUxPQUup162g1vHamGoYpD0pLfG4euQqoo(uDz)MuEz?=(3}}9m zdAz~nQ7is3H-5%y?$I24t2%Edv)zVmKvvQt%Bm3$qpb1Fzs2wz8cVNZB-YQLcgrb^ zrRN<)3WTTfFeY9EO9iUXp_thRR3k50^9aLS7KLB$us!4kdlyClI@%dTrrQZ~&T~43 zGQ0Yn+EWuH7}~ejhBYBb>NOdQxI`k1$05N~HM){NJ$eV!tIU}%BT%!P+5fD|FcU3m>f^AdGw1xb-umc*QE?KxX zYY}|j)S3(qPGoo^)TwnA5kPPC>BGJL>i#CgVc+e&pOi^exTQ+H@(JxFPZUs`>6i86Va1w!~OPq<~m5@ zA+l__i+EOr_3UIkq#*nC#Py!AC}>*^o9ZQUO)`EYV~AjQ)S8?KcNu1$5DT;G$c`h!vjZAbmv4~(H#zvxXb zqk+;PgsF;U?y70X+=wv7c$>Vg)8(6$d^7-A$;T&wtmNaHK$b8`k75av6i}8hi6mZb z4x&~dyD>5W^cIjUp$Jg+>kJ^vaxDR}UvuZw2)KWUP8fnOWUbG<#ln0QTQ(t1JabIT z1U`S2zhJ^!24}(OA8;NBb)U27Y>TM#0;Yg|`!oY0VI{-I$NI z-DZ}(vye_0w7uV;?Q@{*GX_O`wC(oLmQLl4!ED1?wy+9TvUIVfyrqUM0&I6s|2H6$> zO)}8N0L3KKvncj`Ad6zp1z(}o7$Bnd_a4(yY5tWz{|NApO+wSP4>ocnaq>g4t2$4k zjBP>umxcb2dUdvf`vo6dImdx9Y_E`7nB!gy;H+6A9yj*5ugO2VDN^gsnw?kVM8|z? z&?RvQAHE3FYncjs!v3ySt|qjqB>Ot+{exc5c{uG|akQ(9=NdbsX9sh;IDnQ1&=&&e z-T?ZS0D3fl3`y}kwHz-a`A!uWc_JA}W<^D6_6Mqjq5SN!MKx|3Nzy#F@$W5t(9I+# zbFezloXo+ahr#a4gYT`eCTuCiC}OV0@8J?UFLanE%aNyvuR6Zc#R!$Ar*ylZ@Mk3PzV zcZj&>>^yM~YQi)e7Y^L9x8T1#fe&;JO&?l!#xm>}kM6AT22q7>tGsK>S=|e&w5#0o z=U5n{4HXq!sye!j6j^N?A7WrZ3Eq(G6*wpQlcdQ_-{P_Lx4_olQqw(8I`M-3q97!J z_tK#m6y`oNjgMCHBpsh!U75pJ!I;rrePgF!SKqT%@K?XVUw!SWy7XP%^4Fzj=dC|JTml5h`Ea=oM=NRp7$7#C~lRfvpn^V9Ky-(WvIcGIT`Wf8iP zpTFkkX`7ZAyciN9Lmyw&KMIi%motW=Q@5NK%VH^O zb}uP5wN@ez7u4=WOgkktqZPSS*44aWKY(~PcDUj3!5(ZE|xT;BhiI5?8 zCNw-JUWsQ90aInJ-L#@@D3OtoUHaGhOao4XxLB>Ko3;6wgv0$kp0Pt=1gqk+Hs7Cr z#rnYq-|uZho^~_uexIv#tZWI3(qpWUv6oe|H~w{)q`!j2;B}oVNVC`Z6Wz5A^R>a; ztIlS|?M+Okeii}$2*}>6z7%|wI~fMwO+xC5bhM;93f82q;Mr$~oB+V$kD|^3cP1vb zAf}$W&EAI}Vd7bq5!^J((|xCY4^HosJX{TPy7R7Hkr~1ayn@jG2_=Dk-M;l(Gzn@{4$ve2W2vBPvJ~&u~nDOD^vtKf?-d8IF*)yis2jVr5 zv@TytGg9l9Ef3*p0PSt`5hkpF%|JX9kVsF!6l`+y>=*$=Hh+9kHnh-g4`!&Pp?Vhy zOK>09LTfzeURr`jhHNa9o_kawIyrB7=k_YErwEE-f|$KGxb=Iwm6X_Z$X_E9WI9bu z$L?rYE7cvX$X_s+mHY)mx@#5;)1RWuT$Ha1!&*kIoh*e}s@wv8L<<@#=Og6S9pZtG9zJbC1Tdp@}SpHpLRH*wWwl zI5bXc%a3Rc$qM7lK2-|%e|7jMAC`lC%db^_?UUsqP2pH2kV>-X;poMF$>&W9C0Cxt zo4rmNvS@3|RM|4&CBhALz_wfKm$vQV5B2I2v*WdgOv&ZKBh!P}3?RQlv)=C#nNPF?lmhBY>K-d+s-7d=oAlRH^$%QZ;UG8(y)yY_BIBKfW}oB z)|NWc=a@ZG>r{0+RWH#IZ;x~V&SfgSjpA*avNEUYIejs6seUhH2AlS?!<5PdHendX z_EXYh<~$)?r_1uWnyrP*ovJdqnJ{mSIM|fsPR-Qk=kSl+aZFN^ruVn}_r4rLGe2c_ z5I%a2ww^+PLwPfX>cuL+^-Q!R9j(ZSXqA~%;d~8`toW^CmgQzEWTGsCjT@~MFB4G< z$7<8ji!)JLEQ`%xqbSD|v#EHwzbmt+F0-d&;MBWc=4F0Cv|}L5tJ97skNH#V^Ol2a z@!PufylBhO!_K{b!GbsszkcdNIzXeKHuTRMAIRJ!`_JnPJ9t*?Ib?I%?2wAjOPuPR1dY`5P+j0j&b zTmKs$zR=8el~bqQfW8m$0V1(R96ll9GhkNiZvBFJXMtzWP*G={>Y?%p{CPY?7x4=> zr3c-QD|a4xt8P4c*!slXKaJ1}1&e28A=#}wrpn7_cL$_k5Qg*_sR>#nmlh9for*~2 z{}F6F#}`}%Wc_|fLT&kF`t7O^=vKuw%vkjJqE{VUz?=xWnPVSdSa{!Mryid*l`M0! zYyOf0LR>i)B;x<*o-~)O<{67lUwhD*zHxt@GdRCVwxeCK4P-C5!&T0D^KBpU92r`~CL z$3V))kN3=XfPOM9e_Q_?(?74*i_+9NO&tJFN1du8{Cy2#@_C$ARQ*;eW_}zc@n8Mz zr0P2BoNE}uHGBE57c$xOj{bR1pL$f=FZIuJ`uT+Zc}4&Hgfw-He{cFf`ghsin+4Sq z>q+3G@~A7Mn`TWumR{+dO0T~^$o~pctQLQ(^oIL~<~KcY$~Nb!ml(*;Bdzxn?D)-p zud+A&pP)|B8r6Bkwq=J-Hf1OI9m*vA+{v5#>S)}rF8_P|(C@Ug?C*zEz`cp7HKS4m z$7OK7(%xV60FfA>=@F@ag;m@H!z|0XL;Q1BFN-p7FaIoR=bx({;GY%W=ARq4^Up0Q zN`fWa8L#UU+FMKE*EL2%Z!TrVQzar~x)NIG>jCuR0D2>UO5xaSzVia;$^ha4rkJBc zG~k>V&q3R!uknwE-fM^6Qko^E%yMxv>%n|LqB&~9T=4bd>dH!UtcDYnbF>=!l!z52 z6Y+w;Pglml)1M2xwQ?n?X3d@icwE^#nEOeP`e*sOLTB=e0EDpbunc}s) zvcoAGuSO@6@TBs9d#3fPIH^s4=1nmzmo4IuHFo3b((mpDQa{@PrsrZHZ#HUGKSK<< z{;dg0<*QKft)g{}PruWsdb}JW$9{v3{8n4K2 zoDELfv{H7L7|B7VwCt)HvN92XD{2M4s0BMlo_TZB3x2%koZs!Q$unA$?qE%XAh69W z2CH**B}o6AAas%{2%C95@8YVktLKn!!dvpZn*9EdihrMdl&dBt1It6AwdE}pOZ?bv8DA`(;7u36>_8VCGt(y{89m4xpr_z@Cd2O16Z5xQw zAc~&lG7#7t(v?Fj9TSJ7t2;ePEpdzu1BruT=+b9z?UO)NHhxH(OPr12*el7R+j5(m zw%Y@G4{U$RQM2Rojz*}$K0n9~pTa_1*Umnxx$4UfaACa>#Cv+~g;jVEUg4hD69 z-D~~l?7E{YAE)j~S112AAL=&c&8F{SD<}q_8srFVp++ztQW9{739Rb4j#B%eY_+Kk z7%oc(s&7|Xgbh%un=g*j0NEE`#8WT3jCH>!d16fpS_oaua*UwOf&7&V9rJ3p2j zJxM8Vs3v3$A?!Ke|Lw9pVRKifoWpB8^-^DYE^js3{+kZ$Im^9H!?>{Dg<-Sc3m5i1 zC>O6S40}Ed8%~?Krx!sjvXtw>FjWlG7ryu^T{MH6aXS&RH8Uz>A$aHGyY(vy!JWD2 zYFT$iatlH0k9jbzzdE&99LTPVwZ2S#(LwCJpFX`Q+e6zf;ZJm;&Gy9++qTj z-ds)Ll%Q=r4D@L>OV^7N2W{wBg0OY4&oY>^SGyVo`vaO0RcE)!ay1I`b(v$8b35qO z31gKyXUH$p(Wm=^{v22qI;W4L^2%IwfKju*()(^#Blyd~-fpU^_XY$!J_dnJ>Z?$$ zH*be>{nZhMy%L5=EW5cuK0vpr>7nC$9Q0VVx`99_z>wo5eS({-5TXO|padI{S1q=ir8q$wIXr zU{b6W4J8eTWmy{-o|S<-=JaAUxUo^B(a84Rra|npj50X(`Bx~%KHI~v{xIwm7{sxU z@Ckfll^dbl8`i&nW?K6VX}M{w0OyMTFU)J3sBt_M&T9j+`8$}=G$s7EpV6KSW;7Lc zU`Bh}Gud~wL+zMSbE9LiUxs1NgkhJ$fG%D-WJO^*xv(e0u>O$x2%`FH#=MiD2AG%a zrSPa_=HMO7YEtJu@(U)d;JiU_+3}dCz1BN;$gu=Ok10=h!kFl>lLc8*mw(k>rmp4T z)RjnIC|6&$qQHE1)0e$+^z=okn7z7=nZ5Rh`bZ6EWrJrgOK)ICVRFvW%K}UogzKOK zY4dB66F#Aoc3~Vnc9J??lEHO6sgAyXnnz7sn|~L|wdyazu;;=sndz#n^<_Q^TEFE5 zAK+zkUdf(sV(Zuk2v6u{d{{UfVkol`IMWj8p(ITlO*E$I)-g{?C|2I9mrVy~u0ZM> z8BjNzA=do3)T*W2!kRf3i_&Y_Vfs4I7~HB@$Mfkp=g7v%m5d{s4m)!sAImWdWOu2I zuR{9j@x)($>9%$cP+)tOC}!mBu?h;qN#ACm#+Av9zE6eFHbcNAWChA&5nN*-#oF5gLS0w zRADmmoQx^b*_PfF~}KBg-(z|oH%#00h@ z;rWl%B5lu&U)3GV04BWzxX2A1uOw1CwOu_Vwo3P!5VPsIzG0n1a4VXg%WK18okPy! z0bgj{8@afpabgU;O;dk6-^>J@cS*3pDn_!>hQ1b=7?tXc;6piJ-)K(6x}1!a%AYW>z)0OS*;B7iEWPC zcDRwISFkrejiNZwG#lz)tahJ+a-vD)2vBOS;x5j^Z=pO_KS*K7k_=Lbiz!p$;!4_= zAxv%`2y-h9b35;Nxup(|+qLE`VodEhDZGpu^Yq}X{(idR2?TO)Uk zon0Bnoz_3tc=j~E;e=>`F#e z)5+F;3MRz2*2~;rR4E@HUjt(rjaD|dLx-hZQTdD@B z!vXhBq|Tvh@eU><4U+{pWO2-!QW&@<$}#ue7MuX|#+H^R2E9quz=v%;@8W&juHMc2 zD{Z{JyCizl-0v=l;#~EZfzG~*+O+6C?GEwUESqJ%2=y7GmWR}z723xcW}5?{jiHh` z#3WGT_-V-Sip$3P|5@Vu*nF=7y)ZL5AG)9c7?PNa<@XZ5z?lR9zwP$WIrML zv0sN>oBolYAwtGLYUt?zz7I$SMZm6MQ+5kvB@*>h2Ne|M{fMHMkysSsBm&s&I4N;; zR~=`oa+1p;=pWJK>`~RpWySr<_$1{LthFnE_Y1iOONkJfd%iiT!Q#z2aX6j6;E)y&L5^zzlm$7zt30pFx%tS!KescCSJby@Y zS!Gv^cC&KGVo^}Tm1^Q3r+F@?AWbD`#Z1;L@{>PUMZ84v*NRR`OH@y?BYjtpu9a(e zB4JBeydoz;GG$c@tkm3WB~xyh+;1arpngX+oTbD&OCp;2kFK6&VfFh#n#s-qT1W zc8J&LMQln3AG@~_lGU#uomlPJRv)SpE1 zx&rb^&H`=mrm{@Zc^JjA;O!1sTE{A^rWSyLFts#WcWCLV^IKlx4ymuRDPZ_B^bosU zsKZx-|BX<|8DWNLd`Sk zNvLmIynRsa-B+N#YheeV+`EO02saG|nCGcp6USHr9U>d>-3cT*2OVCNPE}gN4PoQI z9Pz$!GF8zuiT0(t9BIP^f@&$RNj+!mok%TXarVcmRP|YvxO90d@1~0J)RTVd4O`K^ zos|h1=y=pp)KA_bQC35peZ^n{oyo07<94Ll4_;r#LLpgG%(-K9d=_tAs7x&2{#EpsJ+jHeqB|v z7P5Ua7~ZsuFj>RKaM$zk;7z|c*dA8*7VTj;?hLYrW%Te9LY=ye-3%glk7re)H6#T+J+;h^+)PNZZI!#NB}UqRT&c!a>KZ zWlJeFcm4Ens4-C)JT8WE{iJ1!d#Yv2`Sw)%74GSK=)rrfw@-umm_5~rzO@!+N@dpS zFzfsiN<^?kwG$)mg0R8ni`OO{-P!5ouhZen&xqYahDbV-PEr6;!Hr^U z7y;(4B&&)NX|q1xk=x|oF|Vnxmg^N(yjlEuKTs|SXA~h8{*0DLiFc3KcEXU@x>)OifL_bWTx?uHS0{lLm+_|zgwYUdS5lg+n&*f8V)ARddsr%hwrg+5`T+!kj`$?p> zdOv8>UPAjb`K0LQ%_zo*UaBGJ4li?{-9V06T3z)(ykhIp^}3Mg>Z7WNNhYg`w^GEx zh1cRyg`a(F;g>AD8`HdYD;TUcidiFVC=)b=9n|7_&8i|==`mVqcvcfx>zz0k+ViMZ zy5V~lwDoNubwauHwnMq}1OV^e5SMbCiH;D&9qqqx;v8*HO-vuY_3pWy-Ymyr=Ebs5QaZWxS;VQ{58nXGJjsOjvvjR`m^vtspVxj z<$-S!Xn_vOCAB#F(wWI;sJx~6h=!NWOoCUMaI>9x24cyI5>MU`;a*8DowgLE}c1`ovmHk*_2Ws>;~wx<*HZw(U+=8JRuo+!MhAGdc*C=M&(r zqG6!s++U#Hx)#dy{>@Mh=BO3Q^}ddpxT{`<&8~+Zos8I+m$-Y-JPh@6@MZ}s#Q|+Im7`mtODnP=iqu+{~*V- zixe^6n`wn3jNF_*9d8c~WFxQs{XDHN?9irxJ1Q+qA$O{DYDh6zGA+B>{+GJin{Ow5 z!uer%=`Y}FPt5?s%;#)12lF|~9T|l)hx{O>kf&wCA)U$Rm*U}&0xL%O7|-8AMPJXO27()0 z9C3_#rQxtn{U5@o0bgSIo|1!&gFzgO+j0Sa$ASU4VqVD+_{emM35V8C#H}-O9vp{{ z4%TgcT#KvdRtj54=hROzSDPsjl@uCB)6ptfx2xlH6;-1uGo-=gE!|DnhpptqR>7yJ z;Dq7==FNFQDc#S9fjvy2DJKahqhE%)f@19_;#*-5Cy+?$H53YpjYKpG?% znNF;F5;Fh3dPNV@FgIL!O>J6qsq&#L^)zcHvN8-S6}2uM5DijRoM`A(Mq%OS^oS)m4C85p*;0+PINB)+vqaf zWr_^2;Y$>{{&Q5b{z{s=?gjq(c*f1l;b7FF>A!)5^Gd)gg*)ZJ!N3q2$^YooCae1PA)#kCpFdYyYN$JP)yUck%|a}~p9%-qGE zr8#zc=Wob3;cSo-&IUJKG2%5hVZU$y(Ih;MVX~3$3fy@bHZd3?Rm>54n0O=O+889= zLfcMGF7KMm$s7P!CKo0rk4{cLm)Ev?o&9ncc?G(c@535T?GTSRNA#Box6v8%>cs_} z@)(j-=b8_K#0Sln(8X?$1C@5d zA5d(Vrf!RKs;l2iph=}g1i~X!&T{tZ_7U|GasOnwy{W+5V1vhz6_2#5f|3+{wV0r~ zO$5!jn?%gb^O912PNijvCSz+rE0KNSE2b7yLtSswYACn={#__HsY(_2&|p=75r+jR z7Ik*dc$rQ9hT_o7YZ8Ks*vOXbo(E%a%>tjSxcJ1yj!!f*`s@7+xCg~oIFfZf&H&p) zjU@JWd7Yc?+HA_z9juQ8`SsQh~4=h1)%BY(2MnO`+mM~2`t3Xj#SZWqj=i|A;jUat8_`#JhFH)b_EKy7PC`(80T0%xFQ?{vr4J}&&2bG~gv^R) zMw`cT+NX#yK|bDU5$p@TNkO!=1KJ`6sul2)_fY)pd73{pkR5~V@mYa8-jX^)PF6pf@HsGn2e zx2eJqWGw%d*Pmyknw>(w>VzKQR$-+N;d|+2ytBki^1@^kHaw%Iqy9xVm8*fMw`O1_ zUOH6{mb4sm55`W6G_%Y|<9vHRLfvn)!J#SSp);gMFMx8B$y=^Zh6_}wnL$~5j$b|V zw#yXL$(gM|U4uG^Nv+5;{!Edjl(_D?C@eBA#jN6X>NoT41U^1j&c~G(@*zN#MT~;T zwP;>Tc0$}JovTvZ6`6Q0q`wYEHMdaVZ`5xfXxbfmI=vLK?lztxrt0_cW5D4afuO;^ zRD)ko9}RnXqh8lC@w*@PtZ##Ondbj##*eaBi73|Vndp7$Euzw?L_0+J$xG2BBN?&n zmJY8pQ0}60DP81C#X<0TlK-PplZ$@Cp&(SA{(4iGAd&+O`yFlavJsVoQ`$w1C53!Nu8j<&(UVDo!aqX1hxBR> zWtAtkbXd(G+o-^0rbymeq8BK=VGI0$c;B~T80YH7DM=jWrcB{o`-rnU^+0T$C>bTu zV$qD}<+>d_p?&NLlGnY%)I%9wwbxLpHT78PSoziBE}DvIGasBn@(f#xXCLM>z1n)w zMed;P$iR9oTP!`KjkP;cbHdiKmgQVt4F3V?=$~(fvrFWd? zI;Awv@SWr|`Na35Cm8x_6&O9eD%!}EF+ z^bT+8h$~-9OA0BF>SD9Qa|*krMAG83jPrp?6j>+iCg^jjjb_jd)MmF$Mn#_uE0L*n zP!q$p*hs-N*9phQYQu+8QJpBfMiktkqB7m6{H2O^F%hh~TG)`>5j~>RgNkMcuEHKQYV@N*j_lz*pwVbj%@gID{X#mG zP&YaWrT8D?14IWhDOy;IJalPY& zqOUO?TsKZ9F*UqtCj-5zn~$mM_?W?xKo}c*BKDPsulS+}8~cKn3hJ2%Vz5c5r-j5RIvlbX(0Go^U zvN~~#mHo^*l?cN_^oRi;viPUNCl;{AGt)nVyWQ(NaJeU(7i2i`1N<1M09S+V5JT3j z=Ov^aKYx$ifQFJtBk`x4ko4*SdP83wgm(e^UD~0AjKjO2j2=lvq*Q?9`51NG5~PZD z3BJIt%L&@fpLob5Z~fD}Q2z*7A>9kiw)6S1L{db@Z2`poicy-K~_bTLYOYR0e$6PclcwkVlz+oz$%|9C8OW*11VmAP&H!0e8DSyQ~B=Ghm>a_Hq@`DIvW&& z(l;F9-Nop!CPL^!%N8xqxB3))RL@lH*LZm^Pm3mLg`|*YyqS`s z^&0$>BsJD6z$^L+W1{}*0xcKygo$vyobH{OTqtp67vB5m_S zIFT|7WJ5$wWDL{`p*3RQpI0IQ-v&gadz;BQ5*IU|bw&)zHn}`k1I$7k+MprpUh9h4Wb4iRIO8P;!TG8KRQ+vWRUibT6lN`N4*GG?4HpWt z65?xRQpX}tx%|aPnR#5`<=-%i##|+4lK0#dCl*jf0Qp*gmw0=8L@US#Y&+nHs(>C;&qV9IxHU|U^Hi_sdx+&-zy}!vT z?V}5}xb}7cXV&gyoG4jBhoZk@?DOWp&QhrZ5H#c@lk?1O(wM`rkZsKUAf-9B>LuJWz#wzWzhaKvZ(N9X62~wjBGQEXu;+jYnoI+Ux znHdJPP}m*~)Pt7L62&z}10FVlJhetSszF?XT63s*GW8|0SXCQUgB!s$R@e%eHo4!M zsWl$gR|c)%Y_eG`QSVx!f-1U}kZZtJW9^?nh0_TLLk!|SXNIJlHW?an9ShJ!vP&Lq zl;pTn^KXMK0}PIXjC5`x?d){)I-q6D@mS=83&r_I0;q7O(01ag_hT% zsc)%TI{D)IOJ^j)o?G!kGd~CK=`TWk9D+GHHL*ZvG&oeosdT4H>J*VJV|3c9%x*Do z2Ra1d76Oliw(dgGcCc(RnI;Nk@0|=K@7?^I%b)^iwG}U{;>S_N-~waTs@kX`FUmAR z0%sm0#A#YAI;&wR3YkIy;8z`=DlVs>FVuS?5b%!hGsH9zJZaGPUVR*0b``~p)~@K< z_uOMVeQw8|V>^?y%FXf3^$@F2H!&iCI4~dM znk^@m`DX72gykX0+||qf@2fJUVW4o?)Zoqclj@aPV|SI(xH2WeYYz zjt_4R2O9dhE`0ctO-}pU=pjWleKgY_25l}r3i^Zt*Yv|Q#|!Lg!a;ATop%{CsOz3G zO3b#~DDjkQ`-NfK!=nH7@YXa*0p~V19cUkB{-(7V5R2;a;a=-%3WI}cyuX|0P0#YM zaVZZPudn5vrFFT%zl3+!Htt3$SQ__}qf6qy?0?h!^MBbK{F~1~!&cJLk*pp5xS}cP z{P+6@clc*=dawhp&X)Fqc*|b?4izlpAoA!E<@6poW-GVhDuNtde?P8`2fkM$@MG?d z;IcWnyY?#K;rzKHT5{bDo+K(B_gcTt6EYkUujuf;QId;OQMwQ$=}q1@-p3Dod-33n zwLCMdrDquNuWL-;Pj{&x7tRQdM{-wdf42fI_tp;KBoeKcZj#$%zsyF3EW75AdNN)J!~uItIPy0>AOmI)o>~yw$%Bp1i*5(mX!4G!==7Qi#T3KEZ03WuOus@LK;J(p#J7r)LfE)_SWZ!$~&}Sv9p^4h>De z>-~-rSn;OL)-0dyCx2S9K)I#w=okD^`-}LS--k;Vj0)&hfuFa3{+if2MYbvV0Vl>* z*nNcliVl0w@?vfi$30z2!Z2fMk7mx22H+zc_yxH3F4gnF(zU4tS-{Vd3yD z3k@SXe=GuJH*v(}Cz5Mm8*iB;1-o5)zA8Bz7>0sX(D*35AanxB*ZueSp-Wd`nhGAi; zdotyvk@#rfUH@ES0`}DYpD7R@0 zv(}6uvG!*o9Qw|Mm#fEZV_3w-tzX!!l$C6|OSW6*$$1WHJ|*P(fcCu+?i5(qef6fk zmHKtEeti62|9!nZ8pknO)d%bcYLmc0{FmSD-9GC(|NAGM{@)_zm?~5$@2<^$`=Pwr zafrTl&d;|q?iyPW^*X9IQG3%>hebcU3%d^9DAyUhc zldk`w@6Py7OtlI)79aZdezpPEPCSWWT9z1xv2^Xkq0prPoev!i=sf7+fF1%J3Futt z0!I(wOBsVbq0+?hr&9UVE*!Y@+xJqy_71IEPWZ2hC!aD7SO)bbhcWVUwBI#!q$my3 ze4`{Y@{G!d8e){3=yHuJgvv2WC#m}_6`5$9TbFZ()p2N~Ku$e#x;rj?yr-ADr~NkA z@y*J);^=_7qXTAIKqB?T46>Z&t!*u7<~=`M58K8$@V5h`u^GE-R?T>}HaX)3=vU*( z8QrzXs%^E&sXJFy%e5%hg9kB>_xR&udzYPp$5L=Iy|u0J0zY-C?R?6-z#?a25BK3z zf`{N0H4zKYUS+a?TOJfiu?d5uGxkIZcvir0M~@F_a9pBTf9rCS5lSSVIr>%A1R z`N$`mE^1y$U+YdK8DM(jmQK9Fj3$9=Y7QBzn&$ICk-qO?^{SiPsBs zA}-!M{=CNOcxn;{O_%iKE*;%`WATv2TFyfw1(D`u%>71^3MuNW6iQd8@7|!4vT_#R10|w|Te;r$19{@nN^odT#t? zk@BcmKDC}yEXMk^3QheJ6-!H&c&lH1!+FTTm2iwaJ{Fjl&B_<)?Wf-}r8HSApJr!I}a(R6biyI|tn zd8s%2@i+D?pCw+NmU^N`)@o>XwKYQLYJxHC*l&NQUNB{pBhc4q6n z>vrOK-liF`-8|exbt`fD7=HU0wtdowWu=jdA3AQK2HvC#Rpoc~I_KbKcT@)GrLajX}BXZn_XnPdX&N zZ67k1QE%<37e|^t*t(<90D8c9>EB3wZ+^a3t~{~S(Ah#e*oZ7vqq7+_5$qa^G=*7Xri8H_ss5ltjxr3`$tK;=;( z-Uy%qu(sm>To7A#2i&4?Jd(s-+-H`@rORbvq2!_humf;3sEicocS~C-N0&)`s@?9L zca+0>Y~2ETi#(1^&=NR)f=G%JC3we)6O5d=gfN#ex!Mq3nTu0!bxCo6;U3)bn~;;( z2^c0m2FKZeVKg3K7(_$JFn>qRFih5J)OcrV`ds6kYm9e*0^dtK#$k7S%maU#cP@r^ zfPp`ncg{SPcZ6R2p_XN%b8rSr)s*(VZ!iZn!a)cM$3Mt2yX!o|L~|V*bzD!WGF+4> zDR|q>61KwzRgXbcr#6~rZFJ&h@ml|Z=x@7e77aAb`&pE0NXP1NLH zdTPcw6DR9bRaE!Y>#M)AM-4Mi(Sf^^%-0ahw9eoLy_g2=+jdjfV!NSUaU(EwDR)!* z<0tkQm>A7~fVsxGK*P}W#UT9PggE}D9`9Q#tf8<@rw(RJ1zC_@m>ND*z{opC+WcsJ zoMO6sFhBNjC8Dk6`fzl0#IS(yQ=>lQm@F$fP=bmL<0oP=zp7{HwcaT-adYL}Oe^ z%fAwoIT#d^kRo-c2fLPB@zib$0bE~#{v*l%+)%$X9 zczjSOZ{U47zOHBaoYWDTWtb+nb3umU?Nnk|M5dY|-Po9wRNsefjpCY=htI?VE z@!9UD$dYCMzlhHgV%Z`-BbZ>FE40GXP{c?tLsO0}y&JbHmfEW!Tgt89`ewkM^jj?; z-Sl29O-S0FTdVwl2gy45DrZ5E9`;+Fe?3{8Y$)em*8bs3KgS_3HZK~=U*+d%OJ^u{ zvW}gPx=}5_ShTdWFWpeSM;|X3hA9d3V^s9hmmFnO^pix@fieg0>!&MW08GcvgO%VX zuLKHdVsSo2@`{G6x{@o_uEg`_q-s`bRAiC1x)uRuF5_IKHZLlJK~1n2YKaVZ&Abgy zP2;BRIUQPmx0-72t<7aM@tz4|oANqy8@#n3`}Mc8E_}(^K{SdS=7n_jDC^TJ4Bo90 zrGiDN0V7DWYQC68etZDT8t`hbRX1_hjN4-n_iv$eNx+5~;Qn_A4%Q+!?^uWU|*oy+}3=NkdvGE0OAC z$<_9@o|evEO9YL)YZi@8Mo1rW-6D2 z31p2)9hQjjMWul(G;|0t%2fp5q*|11%Ki!NeLUqOGX7%F>mRB7Svn z5sz&GN*ffBQ%R?wB6_XU5RSGy%M@Y0XG^q=wnVd9+ENg{%wDhc7W3YuRVAOsc-VUi z^cQG22Li8|=so=9=d^`k;*7Wrg>oqOG!cd^4#RGTYO;6&XmIglig96$P%aGFgM>L2 zHXhkvJwRg&rM-jW$f-!nzTC$1TJ{w-mbUE6Z#=E#wf8oTSVuk@tfd|63PMU|E*Ca5 zLwOKK-)%CQu&-M=brhxD8J2W|VI{>LycZ$a$c{a{E~|cQotnbRsP!K#HAxG=k-~h- zS_6Jk_q8l9^t;+<+Wy{Okcrut(9~^jV9e(EYgXxg>sh%L-t>EKt@aEA^a3Kx`()T@ zJ}hyQgShb#H*KvOn_d*`%Nc&Uq2vt2(S!*NP3IXjOlMxsF#!AnE!jBKirbk-N*ROJ z27B+%zoe0{+NOuBZ3(qe_Pxs5V0Q>m_d&U)-UKz;)W{uBuBmrHxu$+CjMpE=8%C-w zp5(5JCzO_OoBeGw%!GhzMmAp1vhOr;P2M1`p?JsekEV~e$UiMd@sD<+*#j};h{$k= zf%AZjai&o+5OnJl|3NteHW zjkYh@z4ZnC-kph2v2E$|esVlNnc}L7jhA(-V;c4g-B8f`PinGM6;m^>v8Fn^s?1ML zE$;o6!YjTO9Smu<+6p+J!*B5`t}Y!MC4Eek@i!F@Muqy;F;P-Cu?Y5*F$RRFpF6ee z088K8#*tZ||AzH1NMMvmRzHSts@2aYDd|r?B#Ac#%31C%h5Bm?y8_Bt?w$&t_CfvF zp6(By=F-CMUEQ|xzwD{5%y93Pgik*P^-uQn6XDYasIA$?oQy&t9;h7mVr}X%#{)FF z*ZSAw$u>*uo=S-L!N=K~&#N7?DV98Ugf@S<0)E8A0n}|QTUg-Bo{@A+sp(qAF|0eiG>LdUXE8e``6wS4dw~3veujPHa(0|U@T&AR zCAT5+wfzg2W^FLc(Aaj1wLcn;sRSE(#~o9*kxg~-o>%#b#T+Ej=j1Z9t_gE!v|Gdc!60 z+Ud(bhFKP6crSYgZJHax<#8f8o_E=2zkz-B8|aRB)R51guTK5PHWkC&u7XXlI{E8v z0>(isrLmGV`}t$9uV#XG?_NxMHEX(R)+`_fWLvUk3tzYMcQ=3A`0L>>Cw8E-z-xV) zNbyt?NS5)`vSJMRnf`VvkqoM(v2|w=noKebpMl4;sOz7}L1PdR13Vooj>I z<}gc|ptkv#g0Nvx+dQZor;+%ofnw}GrWgvy5-M63h{5aYFT!7OY!x;^PDCA8-V^|jvL4IW<_7WK2JzpA1OAH||7A?OiPWJi z7Ce({IL+{HoJ!1EZS?6%NUI)^`~ESJ`p3IfwT+CyXtL&RzDklcKj*77S+kC>bCWf{ z;;SrK)5h0@$(jv(l_zW1>i$Jd<@{s~60*Muo7OA6kC0HT`O^%lrw5jo@i9-kr|Wo% z^wSM{l7dkNlC6BCzt}dW;8_zmAQJ6`?QY*Vb%dd^8SNevr){7+zKT(@%DgcmA6*=7dtX1<< zRP(9OsO4_+ijR59MQJ;xuARr$HE~rB!e|&N{*U9-^)u=GFAPyQTO`ydYsH#bq#y5+ z)q!OkmF+)qWit!0%vy6}>abOIVzTgy0ZV8)tMk(}CYO9#33`pS6jlrAGc-7JC7O(S z6|qDqv!y^&LF_kLcl1qXY@wUg!s@N&>+U)`p1RefN<6j2x=_D+sBj#K;)fw3;%V;7 zZF+& zSAu41vB@l_5tGEO#tVSx>G9M29a|XKeSX|qzDd@tj5Lb%?}%~wYQ+Xk{UL7RoLRFw zK1E#{&CWU%%4u`cp{}eaVFF^?2U7w z+#AGxg4EsSCrXBOoS&HrOCl9Xh8V1?3FslfMhLXN{R#^jh@eG6AZHJNobIFR zvRmGtmEEZ)$}V|5YQ`@$2H(aD$)8yh$zu4^gl++H5!ypKOu-V!L+6JwxUdCQ<&c`KpjSlOmSxw6?} z$(BvFfJ#Vfn4uD4KX}Yfb0x?L}%DxmA}@B?IJUM!LBP6x&)_6DUC6zUV)?LL{wge*_&igzqf!}MySJDMju;?U;Ch7)Ua;;P zS6(z1E09%5>*D!> zDHHk_Kd6KuIo8Ew@=`1#1ZPqwXaitS-GKHYZ0CXmi=);%Lsi3l|I*FbsA}Dr7IuDV z^;Lz&k7V5D#;>^B`D@RHa;J^2hFV~Tf^ZD7H)I>+uX&LRRK&AU*t`gkdjdeAxKDYV zPtnH0>jD67>z#a4mOljmN5fotB)h1GDC%TaJS!s*OC;!ZJ|av55}X4}z#Pzq=757i z?hyO=qk?njucGT<8cGN?lD`?CP>04331nAA31nBXB~T7EFRbD`wpm&J(IF9_6x6qX z9tu!l&*cmvDg>sPxm`|EC4&k+tCpxV&r~@z%9MFx7{q#JbzI@Rh)ipI&p8wWg25_F z-jq8sL#9&dSTB$dswRYkB98|Kw#b8`nTjC{1WuV3T~c5#tFG+U;iZWxs>Y!}rATOE zOfICG=gsZ-JQ=z+(B7CEG&-5Agv1&xV=b!uWEZd)B_Hv`_P3mA$Kv#9f$)m%J8`G9w!h>UR|1>(-@%{*iff}Q=l zL2vSA?xlv{Q9R4Gz1R8ses5+E3E-YB&g#dn7M6>=!Ou>9o&_!U^BvIRjVs-lva#E( zLtUECw6R$RbY+e==kR>*=8XAepuK3M1vZsAKgGYN9`g$%P7v-307o5EjUdUtcwKVe zS~VhJC)^%ZLq3d=;jl9;(2eJuNw7eC%>gh);>$$WfYcI#(H!`BjwF;xKM5_#D%zwN zeti#rxa=dSb}{lLk>QI-9H9oVlSU52PS+ce>AYGm=_z?bsjj20KuI`_A3ZzlFkF;2|7!^0MVnJqWol-RLe*4 zW_?zBHzPHJEW0ctOO;U*rD!NHn=MgNxX+UEA`H9iG|D&)X(?JFf>%*@vJFTHuM?ut zO%6B3fKvFFaW@~cZZ{MXKCW)2A*=%>w?NXF)p0rRJGt}~C?~ZRLpiCHgmSV<2Z5Zd zY7fJn2*VDAVSh#Ix_C(_H?Fsa)KNPbw5yRs)j22H&^CG+D~+H{y~v@l z3u)^5=LjE9xTHuhE0|0!pc-x#q|6S2LxnYkuk;8~#4tF(bvnDSqy}b2+yFd!rL$u7=dmS5>Qw|O?~FT zGlUN5Rslk70*#cB>ve9q+>77@NZZ;o8ucMHYA-?Cq|$4ivXw$Tu>|Z~*XNyo-}Pul zZ4Ao$&>ZjUr4@5#^XIrppkHVbbip~4Dl!k~z55KTl^Btf|wSEI=IW%v8 z+nNsv+?OGJK~B4aMiqD)b1FYa3-BazWg)3@2Lm5k^K27A;SJ`Kv1;I&YSJwLU)Pf<~}a>FPv<;Fw^(K@8yP+G0ev^JC2FnGC)a$^gzd8{C9 zA=c+qR?}B!9-zIYN0vTBXXNmMBnI~1LxMYN*aGvw{-x3?cEa_C7#17&-YM>X zjU}crKQZgJG8Ed3|KXWBR9M5Dw2J}iw5EDPk?5~_uvHDgP>l?S>s5V(Z)r#gn31>O zga`D~sLi6z65jyp$WW(5f~mG{Hu!RiwOu;e4v3AE&jF~pXr1k9n>PArIJu(Nfw=_J zJAlDsXC9lumAEZFAV3$@0whRmJHnu|{Z17_H5Rs!{js*zYHf~I<68Luc+KOYsbUM- zmTsOmt3%#f!5~Uz%n>M`@=SPFOXWQb)xiMdUgUJ}#aYrDn*b?ptRfg70j31&O2;;a zd&3w}iNT)6RXk%%>8KwV^eS&?OkHF+5UnM*^E_NZ%!{WEAryXIatEQt^6Xm~qr+j^ z%A6KgC7&8lu+X-gmKO1p3Jhou%M_VKI?ZN7M9p8Rh^(`8Dut-iOy%P@NS7H*Bbd%> z=;VRoq_le98NAMUf&@pZI2$@EBA`Pwv$-8Ia(=5oQ=!(+j`{(Vn>=-%%Y~7FkkBGU z0#|oyf;tfkQG_($B!4#Yr;hXncqQHUVY_lG>WZj1ce;nV6!UInvJyl0^T=t#%V-!88kddZR+kIbzYRL z(%eg26Yt%OfzyH{>%hgXlRQG6^U5?tzku&GO)w=hq?c&brvuC31r?IDHkh>pw7GB# z%_`*ASJm9>5V&gVI{;oont^7x1$h$L=VoQiO7}@CqNKcWpE^WcGjA2j2?m4v?xX;( z@Q|5Xx{#Uwgy0D8)sg<#rxtq|ycTe(5OV@P%%EG2eRc6t<^uIqpejiBLO7QXD zeTK8^X?ozuxw{60_}8(>1x}TZspyfJr6C#3=|RpBL6hrMYnV5f+Ob=VbkYb(^j$`< z(^CHt%E_Ox%oNVLR|DnNh?j@dfsm3WrU@RIi0;MOlkP2Z`UdLY*`JrGh%PpT5WN$H z@FC1p(pLi}GxeM%Q3v)KTe+q6f&Rd$o}vy?}%;`?rG)B}f43 zs6^hJVA!xrb%SqRi`uQN~8x}{-Ad@lefD=1Y^hMJ8cTa45jIpuKJZ>_A?J7RV0)! z5}8d3^_l_aY@~?AE`q1s;ip>7{-H;%&r!u+@gh-}8I_H@Vc@SQy}h5&>~c z{LwurR>$LI{SI?AHN@19Ky~7O7u9Lf!3zQQ&I_BtxS|b9+QDl|%y9hIm_Y#DV8YF1g8#FmBD-OiRt2BW@$ z2(Qmoa_9@eoq-T$)Hh}71GIv}FpNSi%xG&Ik;3@FR3MO4EhRGh1sx%xTfQN>1se#N z{%m6&kPClh&cxKHZ)%VIsJ84}`a88{<=be?1Ix>3{2;v( zv>i?NjZD*ZE(JJBxD7Pjo7QwkqTcGnyKOpk?_Z|rrldy6y8fTibRVPXGU=V5?c&K% zoda#R~FKfbS z>vC7_iY1E$%~JzfAt`Onq_p{%l#YZc?Tn==^Q-fA2Fa}4)pQDpwzTEO0M2_Si4_ba zR>Ntrfz()ZzWt&Vo+!1#camD_^JGllu1PTek^%O zLH6%-ey!fhgFAzBLHMjdj{=G=N@RC5ky(PUV(()$sksHQU+D-+EOm2XEOmXPCUyO& zn$*nv8eHJopNaY-!5G{Nm}PX_-j*XruKQ>p0=>JkB%rbVnD&sHQ#-5kHpf=HB2JFA z96oaGP=EmYXzk+(;^5^hQJl9e7zMGG*X-T(diQue6}}sehEVFpD6R7C(7VSI+u^&J zF_?E~#X*(0rT@sa`8Wubq#m&0=iT+d!05|VwLchsdHYu!u$SJ{OP##5HF#<3u`j)u z8MAr&WA3$B3-3|NPL~}4D$lh(!yWJT{(S1y|u@#4ceAA;# z-OQHii?_VMcJ?^}D#iV6UMxA+WLaHJ(yK|r6G^xs2{$C+1~{cAIa78>;n~cIHGpWK zouu?|*-}0MbuK^MC6PCV2U6YB@T3@ab`DLTw*EiR{{Kjf!o z6erSv>E;2UF(o%hqpG-a)ww6h+k>}{PI4|K__48DDx`i4^#CXM=|?k;Skf;D z5Zr>5@a;tNQ@<*aLMxw=L`iwPYXkaWzi1YQz1X$ZX~j8DhA15?;w+1NPgurkt(?TN zqMyDMG?7}s$%2AJ#mn9;A0lod_4ATqd*|mRayPdXT+18aDcG_Ihmi*o6*on_wA^+x zn@0Eu%8hPX;2I{_oN}QC@ok$@i!A#Dcq2glst`dNZSzwFeyXy-ujsm&Ly9>4o#ax@TrhFtrHPd6P!(52tvM1j z$9|IF?ON}W=P3(bI@TO=rYYA)nI$_=#H`l&)&UbP&a`J+YhDp8o4L*N=jIK>0^xRY z81S5#jglX{QdH2lZ2=Ger}g`@A@y+@^7|I{4Jh~2PjU#j-S3JOkSV}Q;ZOB*2PmX~ zi{cPkRSdXj)DTIX2m50Tgs7jlDPGaN{F0WN%5uEcZGB5it(e;Z<|mEY1#RyXS#*!BM12G!BAj@4sM$2!@OJJxY(h|iJw1RmW0w)v#J z_@r<6M1Ju}x_lxq_+*yiv%o%KC1_IQlTvR4G=!gdVNiZi(a@rk z?B}qef}-I?BSsdUdZef88YP=*yI69>PYK;^uE?!Qh|Ay7MS_DrA- zPo(k^6_b&vVp4KqsF1yKXeI{@!Ps2fQp^S!(0Y)OLm6Bw%f>o5|Z{Km_kwjfe+7kLG*e4(46_7u$=8wnwno~_{PXco6 zgE8+nSLDX~JKLYZjw6})Luo+)huzaLR#glsXQrJwHjqi_rsrU2Nvkbe+-jArCG8M1^6Ao@GgNl#etGb8N6GTWTiIlMP)z{j`vRQ?m){_`a#`YLs;E^66{nyqT!39`_Zke zBr|hCfdFLgPmG^eaPy*!qHbD~8ouHy(Pi=ZYcl;6h#)5#EZK}`ppFBHS|_Cn;uTNa z{J|_abdLhS%{hf-ro?mK%^6m+d@j}WruxiZjc*}Vl1V^wBA^`kWWAT zNkVegkr49efyx72!y3;7!N+U;1|c=&_*g81(DJ9h+iqHVhNq3!@TBpJwZMbklXdsi zc679YrJwY}+pY#~z;e4(+<6t(omYkK&Z|xS%FRuu#JL#?EF=Ex&MQ(sMX3*0o-KCQ z)ef=@Aof7%VS{;-FLdo4cK=oT-cM`Yf<{5JfVTF3Lw({7FOX`v`mFcI00h1x;nlRo zsZXqBe{Kw0)7!O|S?T#)GeVwBj^a z97`D(H;pH2Svk1qQHn6<=%NSx7rXbbD07A(&(A2BwPNQqPmD2JA>#d;;1e#JGTsDB zs;zO6xaaD4Hg9sp3p=N;6)cS%mp8+uKb#dGH++iJ^Ml*{Gu!P>Ht}b?Wgma9aVHx^ z7~oHWbr;(X0<9x?_C9~iqkj9oPq+L&cTltXUF#9$Ts(E`Bf4hWgt6C;^6%--L*9Rr zQR)4--TV4g{21t}%lT#Yx@7(oU4)iHb>27sAgOc$`-0U!7T8RJyHNU(ctJQ6 z3S1EWJiq+Z94@ng^Oj>B-Fz=8>$%}KB`3Mf7Ab~N3Mt*;c0I>3r`2v)XiOzCt0q$1 z7PeK&M3l)r(DQFSd@xRj&3*@1;BnlTK$A*2|+L zFa1l&XX5(fe`+Q1ZfRCkf?vINsHanNFhTWs=~MLtJ+PEKaxiI8Ss8x?h3f3Wsjcxb z?qHZIdXb{1t|$gZH=g$}=G`GdMJ5$DcMO@>nO}<1GpTsus)o|sL~4GNeTX5Mj5Gb) zdzKYoxicQeZ05)mx%XO{xT<;SDg7K0`)*sTxox=563a^~Tq$$vp}e^_zxi;!_f1V$ ziHiG|y{D>q!YQ9_VmafQBX&2=2Y@*QEq1zIwM5Q4P9mof7Q6f8>=$05!PVn&ZZNCm z&#$;|Ssb(1s8hJ;k4aj$^msOJFD_`_7i)fP==JBgW@vE*7{cV*ZOjr|hx{b5peVPJ za;EbrxtG4508%bICBd3lTx01Vg9<;{&##+@a&V#VKiUuJ*a8Qp%uMIf%4G-ft8 zK`f0H0)AsP_Y;0qmnQbN#Z%pP3~TBYsLgBz*VU#r)p~brvC9)LGD~4b)W*5Ra9o6` z`W#=^Q!-U=)%BEZh{5oBN;jUBiMK|{aXn=lk0lZ}63X-p7$EpL*gJ1{zt)BrdxHv6 zA=Pj7WLrvP>_kq2Brxf)+!`3OfbnK^11sQbg+hj@Jm?rg=4IHlcNM$*)@^+Wyj;hnn{d;kLyyxRdf%CAX7uPSY@L(B;~z|AT@CfBQ9prl8#OW*I%-cyoemq`VQTwyDED+Z)c>+D@wyAs z+S6_Ae2mfO!djvJx5fL9ka`*FM;7MMx-On1&_7z(7sIfR(z~woe*@*>-2wFzi&x4J zJYc0i7wVuqb>V9WtsK>J6iOs6QH&fI4i{G^l=~DrdNv zE;y%2O^-UKNl1eIsx^F@L4O}Gq63G$2#p7ulUz-azCO2k!q_?0aH>~xkTWvt6Y0<7 z#w!lEagD{|{0XzY)_*b7O8fKDdd5L!Yh`HjhW!oYi z>8vh{W(uUP|STf=+^RM?vM2<+$o`D91|z*mZm}1Bm`BjrHgZY;YZA=C(v2^zrp%n{Jpz$ZPZLa=?@P z{>mP|r7L3B1(UmL4^`;v7t!d9mqbZV9EsMWVRO-OhfP@i6Am3?D6`gjDmEBgR*qe#OD1_xvZ-0{HiG+C&FE zwAq=TGe4w+_V1We0QCZG%+JYV=67M--3JmIF2pp9OGrzxL^(&sr*LU~9!EH@^HCg-4tkvjaj3&>sSfgae4FY7n-b&> zrT{PU0~eIJ4|!v|trXkCQaov;c=@POw7jrH8P3y*EP(;BLBS_yV)(>MI$JGK3*wz6 zcb50#?}OiQqd@0|2b?f9}jGvcz@O_QO!X^A+iYe#by6J_yKKmg)=57#$ zKkRJ!V=i7rbLAvC7gr^L{isc6Q>(fAYP_-Q^`M)8Hx|cY-q^#7EAWzRP-xMp5Mvnmvwm2(h?SUkZ~>!x8cz@99R5t;1B5tN`l58x5Y%Z+HIaZEUAB~ z)xXs0U#j}I;CFi_yyx@-X)(cB^%gKb02hgzVQ1Rp(@G2Cu=IpAVgw&tuk#6dOCCw; zsVBV7SLwqoa(yKqIa@tU)WQ<4^o?rVZSjMB1An90n|Vmfz*P9g;n74y*BJWU#RE0Q zbKcn9i_aGdieXjE-bhQ#7G~4jSM-5vyhS_cjeTYDFjx5@%Cw_lt_Ja?1b4L;d0uo0W<5=TH%_P1Q1`7tW93MO;;`?uj}Sg<=WIiiQ_VC0Iw$UUh%o5MCA|E8Ya*w>Ct8JG2K{1 zFNmkOq2z#H(eAbGqfO#1{rOE^YGf>RQZg@=Jf-(x7g*3#gu?2l*uX;NKc)9K1TVV~ z+ZKxecdbb{#d&MNvYS4{TRU36*?N^C{HM)mUl!`!>TM_FBK zgXl4#VZi1etZ2pPeO5DXlXj;YkvQ+j&y z>*ds5PHS%z?JXA!0lWa-P-_i}3Xaxzsa&e&d!Du4ch5T^5$*4M|KER<%$oPz&)R#h zeOr6&wf8-v;U3{_-l4){LGdP%dq4I_e-YZ)K}2X{r+hWO<%z;+ zTNY=_U@p)wI7fOYA9BUjhQTc_AmNt4moTQr9$XE`WnSrNA)#>Zj!N&*aPK3PC2#ug zei_N3!c&FVxP)8HSfN1F$@g#bSIGCz^H<9ExAPy6@4KbcoX!o-bu3nB(Y10;pY~(Z z@Mxcmp_hPK4HLT0T4t!*4D~!H?e8$W`lq+8nt-;5SuERPo3uswftJ>aw%F>wqLmHM zdDewND5(KMF6@#f*Fn!PZD-tNsqKvRXMM(@mzg@dYfTQmai|G;FXwoVtFR{ITo>i% zSw4MUunBAGCxg;cR*K9s`)+_xGfw8=EjDc(Uc8IjbHmG=iHBUoavalpI-MMcI_^5a z`Gtun>V7WXp%%W9E;n;fGPtXC6`nA2|)sP;8Lgzza|BBSYl39yfsPU;a%WB064(Q}Ueu&hL<6Yz_8_y%Q?= zo4=7OC85UKkM%}}U~#-LjwLqysQ*W3_KnBxNV=Lk1$}MOJwl=F!1B`&8ayAaFpF|R zv84eR^8A~=j2Odmd@?k`4WZd*`eEl_#Pg4ZC$;i2lV*f2c{~bz+pqNQ=z$}P5r%U@ zm0fWA$0A5p1)Z!udW09|gko1?28jPbsfH7X>Ko{V( z^*A&FotJY>wcK0BTg!Du4&%uLNbHwzuJ>7IgVGbB&jIyoc{T@>o(TPKptSOT1yr{* zgQK7n;X`q37sOytHUgBsWs&Q>N$bqp?}O?RF1t*)XF&Zd(D->Z7yUmA+R z2F;dlAsO~b-Ut?)xGNVtu`YK#7Ndy$ zj+-3KJD30!k&dTVI0!k7+^>4au{{&ZOR_`riO@GgM?VJk>9E&c z#47wK)cZKuY=BQC*+2sinL(;?M>Y3{UMYRH4p9Y2_Z?XOg=aq~-M>+7sCrO3fYDXk z3{e~hZXFB_Q-%hN5jMg0zi$GWQSZA$s3V{_fIG(-C&X1N;=(|NnGJPX)A{2-BFy>Z zSR_o>M)cCB3Y;IXt*dl$eGc@(`r&Ya3pQcH@lOA?L3j=a!-FX7Sq;Z0M;8LWZ4uns@vg1m zcwYUq(nwd)K`%{V3cv}N()f9Fl{h{P7sntfI*yw70*voEXehpW;fWZG|4qVqLr0&79$eb^ z%G;8)Z5YYm8T)Jm<8<%N(iQb{N^hzkQ(9j?r1VQz-HM%vmm^786z#+DjQGrkxi>|J z;`Ugmx3{I>(cn0aOW?co_-GKNE22Z3w~c%9D8e#{=g+N;tuHhlTkO9p%sL{A;Or&n zWZ%f|uy+qmltxqx{xFn7Z2Z}YlorX@DOd715Awia;~uW7JRCqc2I4E=j-=|Vs(xNk zv*$TpSQiV4H_c zq6|OEgp-R0@bNEHqPs@$_{$OXf>gcW16@t`f@y@vpl~_e6%lNlS=FK zOvAfQk0_*74KTS_G)}iQ%(kM(5-O_!h&VJ-L-mO>Ru-WHB?GgeQf_v6Zv_t$01Fdiwv6g9FV66=n8D+^yk zE3wN6ectBNu%yfB)-mQ5>#(fb^iEI5H>X_z`PQ9Y!OlTeq!62Y(AQO#d_={GW62$u zv+u+d^tM6H8cwXT+l+D>cd%0qUVUZ9aw_GY{gXBD$HP}CDSZQYod=#QUn<|H%7e5) zS?PnbGP1HVIeO@TdpRgw(=A06-G^rHwaP*57itfvyJcMDD(hWB6@yZ>>QX~}4U}>@ z4k{+$8c~bci+HV}7*-T}9w-g>El@gu{~XlcB(?`ZJtx#}K^+ikJE&)c`Xi|4g=z)$ zlu$cBJuOrhs27EL6x3gZ+6(Fhp`HTuq)-PyJtNd#LA@jthu6?`+8@#K(tuQ}3il94 zJ6I*kb!JF4;t|Olg4?PWb-|tTtn9MS!=%E+-PoI8i3{`&RmS#h-e2B){iDIy4tzc3 z|9Wer`T7I6el5~c+1hyAgI_&(hq~RvcP$lNy{+XuYP zLW3G66C|hsD|Jy58Wis5f|2KsvPx1O3ueVGNsonn&aE!TuwO6=Gh1b=J`wzp50P># zp#TRX0_p2sYFz6Z&6U>5BBZwH;WL>xbk8VBE4ZEWX_z$}rWLIfxP53^S*+6u(%6l2 zXe)~zrbwDAiX88xB*X{N-11l%jPh>$_rihgu|tNRN1BvqS<}&3C)0+jCE-+T4(J1qIEyWJh=sV zEgn2A#rbtm`-S3A^o&qPK~4X$dM@(pKpU|;3$Cha(?1W?lM*vV zddE1P)F$>g=~}_)Tq^0N{3<+wf)>FUamZjgP z&d@ZT@{FJBcEQsbAX5*Dr5-%?$?`^xDgz^n@(YBnla+X~FGC4a5N&XXrT|nHeZo>^0sl2ITmiI-fw#)27#cy@>nhiw1l(eH!Yu|Qv!DTCPa%cL2(njkiCNuK^1$)D zxy;@fUd$p(s*`zmQW@)pP5KeA!PcT*zKnSi-6p&)7aR%njx?i4%S|+9Z(?Zpf$9)-Rcj{P-s6uQOEP~l6M8bhPOBJ@7&cKs!+##sfzMIFt8z0W{D zRm-t)Jd;t zPP>ocYuU{-XpZr;mtoH{)=A;#r_^@8TSz- zaOAjnZoU{Ud4Ki%Etv0|?!>nKOxOqUTjJakiTzVEUh-mn0Lg+u%n7&wJDLB6l!L{p zKeM614fSw+Za8*xj}uE}?D}Kj#w%T8RWgP@GvfmY;Hn2=lb!f4uT5=U?6z}E}id0AMlgzm@K zJ82S<-jA^tYY1PWdG`|jIR`f0Xsx+Ldhq}lx)9Q>q!A}yP#f5}APeKDGe?4v4X`C2QtIEhDh` zardpOLXC5+dJN->;LhPIGAmd-$pAe@fh<13*evcuxXv@SD33Lg2HgefEUiof;X>R2 zyC5f?xV)}-fJ{f=at^m4TztPE5b}01Gw{B~n%B&TY%+ICg#J`&wVVn{t&B54snrtm zJllG>7}TG|qF4t?!`%Q%t&ul@QY+&DP-wTppcwVrFQaeBT!|a$ zF||fu|D5*vOq)4OI`42rqYSz&?lyl8>7&ooP|V=Cmj=$*#a8qv-GV>gFh?eL?fAyz zuJG9kXdoEdv0bqi4i4MUocC;cp+4tA_zl8d(Gi@}=8mN&QqmUo&+7{JwsWIh$^Lb) zjR1)JTy3Z8bfjynNmqRuGamPC+8<48xUILg{#B;4ufH4{B0P%@qYTiU@#u$i+&bI5 zwmS&xC)90v$ThD$fTYH}&ZW>R5SI7Ow$@L=>B54^!n8nLiWVHc zW2EY7Rno+`m!b+K08fTR-J#}LPlS3AGWH&PDiKZe`;-VQx#+raeh>GmuaJh{@h}pj zJ~ENmeyu|3w7Csx2_7x=t&y4$hjmmIt#Obn%~l!sJq}VkzArQ0*TZ>yYcrLyY;jV&hwgzXvBm9Ax zIA~^9!-?zbGf;Ud{F}dv7*XfTh%JRV%{KY?N;Of56lAt!HMfKhw`5%ue|_WeSt!z5 z2R+2EcxvPE8LK8Z=HKn7Z;oHWBawWu_Qtly5%XTL8NAncJbl$zClo3&R!kb(aALgk z9u*tLGMfauu5z6+hgVT;Uq}dn5%Sj%`gMYyIWkI)%uAxN)3Hf|E_8Y-g(#i&g=Cm_h z(y=}W2X~Iuv1g$Hv-y_K@kFPxfe#J!wxch=b~@DC4ToR|jkGMKejD5#0B2Y`BmRnK z<3;WlRPUV^=fN5lX}N?5`w_J1Kos^l_^_tW$&8NLgjP>KI6B<#soea+hS$S5={4;C zbA}pOQ}Gp_EvSly|zN+d}&sT^z8M?u|5$V*SVXMG>N<2`sjG$1bQaoE4%&>vU|m9dVQ`{Sej zK*1|L6}!A*9gY7CL?@zXA?e_p!O_vSsKwiQH)`C5*D71)r)+_&(^b|ZZ3FXl9ndNF z@&HeC{oQ19q55&7;d9?-u_N@xBTM5W^jTV{@yK~`h`o&_j!@gdyinV5Os3te?!$%; z_UVv0jMQd>9ffoXabF|i?(R?AS~O>~WTdMs&8ttFIvCy4ShT4$>>$gi&&Ep`(@;jO zkYe-&>C;(G_UU^kFP-jUKiS(xPC=0y|7VQo)@3imj*tqI!+CDnMxR5Qs)dLz#w`?RUX0_d?&V{4vzCnlDi z7BAgij4n*aq(Y29smLhQZLBM8%Fn|aIXJ_09IX>Lf_-jv_<_Y~%EMKO4h%=2uiOD-vCOL^FB`B zSoO*aa{UvgV$A7q#@ln1FnWCD9snY-TY4yfnY+S;osrqAk1cGOm4*pUTezh4jw)Q4 z){SNQZs#Bf~|6^%0092U{#v@Fz8ok#b>=GDho z7w1I0@7ZobPdk3Z!A{==41lDdYp><7eiM~jS$|(AKJisJy9u7$2mc3&R^J_Dr~o}4 z79N_0V|-uflGGd&|ZXy^!0QY23`k;ilo`xowBj8g@5i zwE}~&1#T1oa9t${^emdd=UVQx@_KvE?>#+W-I^bijZIt+DSP`b0)pXx-k-oB0gUZN zV{UIdf|lJqx8dO2SbM{+hPK05!G^8|qy&{?&6KR}rbvFU95K!lF3Oh)NMhCY#<2Xk z4ZC{~7(1-;%d#2>nQucd+FJO@^e1BHpus#-!_hi&t)aeUC{FqGZ7#&96s&FNv2m0e zK2&KFT5hDU{Rp3?>4>a9S(7_TnrHwpfe_SZ683 z@ngHz9Wk0W+!2m(LUu_{Sl&iT+C%bM^1R=<$nfzrZ6HMgmE3#EdSSNApAd;%W~m5G$wB3J3XMb_qO*d%P~0in z`Y=Y`XjZ6Y@dQV*;pUn^xaF2SeCPNB70{NmJ?u|%I7Sbras&$!@(zQF+JZWL`_&zHATrJRFF@J-iE2VgIYezj+Qb^qoN_A9EJ;6#c@vVYxe7P7PJo>q_GYJY zFb5wn2TNT!z!s#I8sy+MR}OlagAbU4le{N8eI>{N^3+cbt~5EIgHcirpc#tog${O! z)UzPwA(77;u_p>74=fPVphWVc0Xx=uR2&hRyDVhG2i~x%vpiT9;hjOMcUGq_2dtQ4 zfh8&#`s?aQEZoB>F&cEZuq`q>d(I zTZ;f58+oi&EDITa)VcQ|CLl5XL^GUpkZU<^H^V4|fgblsVHngDRy!5j7FrcM5UxO> zJ9u82C-mX?sPf{J`k}UQvA3hV*vr`nT-KmDz~b5RA0oa>FnqC7Lw3|?h#$yX*By&- zS2@N}%w|n-peStdvrb7~m?<-sN`?|yft^E#(zQC2UX7u&H#&@ImC;fs!BtnoqYKpq z9&EZ4th3|TPN_)ES0jB4jSW{1W zMu(~Zk5P>@hw>a*l&i)UX$j?AAHvDg)hdpM@P!K$O0j~|9`YWC*@3E{EpP~Dq%9oG zTmSzr7&W_^ZO&21ls>*;pV0mYr)V%>njss~fs%94Gz9;k%r^jrYEu89c3VGVOnIqY1+ zLAL^n4d%wk7w+8!)SBmJwsMdzd>%putB`-efpEzQ83HgLb&5kfP*_y8>KCDgVPfzA z^72F)^UQ7q3IR?Ol?+L@j>#1*i7vn7Ox)nm@8k+S_67*l@|t1m@U!Sx_nRyyEwzdoM3$}W@?zejYKYB=iu}WryJnKhS%u< zTC!VIHSzL<1z{c@>6mGEo_S%~4y5x;65xpe=XD>{&qY~b=v#kYsPHJg<$OaCcOKno zu!$Nrj~6z?&14i}D|W;NBZ93U*>k?c%RJ=x(@180LNd&TQ~@!4w6jQ_6ZY6W5-F5Y zD}q{rlV~t<*z-%eL+qDoB->5)Q8}GQlQ0^-ZU2S#+j3EFxUijFsH}m(t7rTcRO^9# zdSGnoP`}#7+tN``&(SATqY;@qX}^KzJA=#c7YW@5*S?(|(r_IQ zZeIa{ifoH70}fM--5)jw<~1*|KE#0-gV$XXYOeBKgrD!@XYRU7IdC>t;bgd~5se42 zPTiKnmxuW0Ot)!4SO_hM*FRTVqe8?m@vxnVA}CSU&pld zB#~gEAp3BWyp-pwlsbNi^j;=;WCyR*qo8cp<>ZP^0W`MR5yZT+=lj+rIsI>zf|62` zYV>IDd|&K#Ur9;ytj62Zt$KK)EUbg7A=4BsuXq4S4(#+IO2^3|kp;B=BAR4O1E6u^ z^OD*#L22t}$$eK!xCE4zCJhDZNxc%(QbBylP}2X|_5PDHbWeX7LY@|;mw2PT&AZ~$ zxcLhSZl0f>sDI+xU@E39uErbFJ)d3x((y^7x9c%FV>{>hpfu++L21q@1I;-{Yt8Qs zpww^t7Emg+W>6{@PJ}hwgN9uTFf8@v&Uz?Ai;PXJ6#oNl*hPN^4RKOO_()5 z4zEz>ee@MG#xWZ*jP&KoD*ZW0>}jCpN>wcfb-qySWRzkdULemn_U6&BRYt4U$qCP7 z6tX(RbH6KX1C`Fxn1?D%P>n_o6L|GsCWCi58X8^}@J}AsYPkyL-}HUFYObCTI(mS6 zVhWEnj|+qvU;hxk41wm_*&l`)dk3$BHc;aOZua~5nY*r+LU2yg1K1dWLT7G-c=m|q(TdiEkX;A=Mrd8Y(sW4@v>_U|Xeb>m)rKwL z3t|*4y9|eH(-pDh=lR`l;cS&W^ctF_WJB&|9xyJEL3P2=4cHM9oyAzEhhrPkojq-_ zCuAuEimEJajOk}-1H1Tlpd>;#m%C2X#mb(U`+2U{3jD$$OURzY53firWx|F7W!x25QaF`d3Kf;Pr>pqS{9u9i>L5C+UJ6gx!iv~StbuU zw_^~u1toDkN|VAw)k(*OS}NfOvqwkGWV5+{TLoN9Dtk~NuF&_T)1%%_Ppw&IrUk!( z?@Joio%42W{VcJ1)*?0-B10{J!^^BVFM8}(wX&+w1kqjUfyp1^v1ik+=-Y&c;T%C7 z>AX-ko7S$92_HUX1;fX}h)(hKInEu9g48Ak>mp4t(0t>aYuv&^N{o5cu z#DRsA3^?@I*=0^R$3NeTaQ=I`PyrEOGW?;EPn>AFJC&R$4O}jg3NFz%{o90lsAV%> z0XDqhIK^&3>>;SXtqAm%f7@n{0Kda8$SA0*Mzzst5e1evP2z-KHAG3OV>*NtEmav@viwlx>@%XH z?JZ8QU8Uh>UUpz0FAm_4pgi`5A?#o*XL`sPMw+~ce-U`zN1ix6GuS(dqrzK&aX)hi zlcaj!0RvL{D^kUpwtQOB2aH* zxx#1tCn%j1_kdDm=_62MWFSdFTT^A}VidN9dmmJnV2^_uC&P>f{l%T4iDZCkleyrT zpfudspfudMCL9lU)^Hm^trzTTpg1}6Ss#N^Ba0tniN;$1ijy;+HPcX=K~+i$+CeGy zuz8!3isKQ5^Au3}mM636+TdpMjQb6g^KMXzc-y@F7?gdo7Y9>y9mR0k#o@FV6+)|6 zpW!r*!)fznu+1F6iCNp_e5pRWyx%yB9icekxO=Tfv4g~AbBPZS3MVUYjBP*yIJy?$ zyCU|FNb}7PqU!s{Z>h|~Ne3uT$;`soxTB){a7TShWrKEn zb?Ep4k=P!)vqROe*xBLV7It_6c6j#-9{s`QT@V{PJm^w5)PwDpLwz{*NPIYqq)z8& zyR)FjTIn%e0lF-nOyuhS>a_n`$v)!d`|)op1DK8vtsQ0>_H;b2(Oxe?*Hb5{Srp4U z8figtu#q4Of0$Y90g`u>u}70%wR{^PuHR1Uo;rxp8YTCEtsU@-`-P z3QVXEW`N*4FC>JKBad-uWe_3vE=_l0su}>wBP_~f3zqnEZfs{wLPw57LIZe+ze3*x zOAIX=U+zWnv7dgjd_!drn;V8GapC=@zK^s_O$ly%l|dqfZx{pDl?_;x#MHm89LtC> zR)(;$_CY09mxe=V9JeB|bMP0{62q|!T?kYl=kjCN(ga{+l9+5CX#b|Wm^v`U!1RHC z(=ouAT~@{_@)|J9S|C+@giBo6r@-|s$N{2Zp_G{cO%8&xjqv-xl^kXnB1G zakSii2XWp?@P)=Zny`qDff>W!+W6%xJS+ifjaS`+g;&S1e5D-kd-NRN9&PS;cmdxGwEkida|n7XYE{<&8h7;I*458au%3K z7GM*REMTV}B-eXn99}RpZe^rT2K<}e6uI@$Ntl8HmS_AnCsj!TWknxQp#Du;fns6_jqTo2?$}DI zCs@a_@i={oIu*w#>R24JLa`PZA``k5hf?*~zZ%*VZ6K<(Oa!G`OBmFLqIrBClL8O*%Bri} z3raPLpMX+bj+V3gv!mu&I(i`umknyEAb5m@BBq+R z+?}~ubeapz+ok3$Z(C4JX0@TdW2he+>QO^IW2iyUxfGjisM|ql&cAD({m4)!4COOA z*9=3I8tNKD-Ds#E8tNB@ii0{XQhN{77exjhbPcNE%>ktnzXFt|^jbr00;QVUPfWPu zhAMzIq=+ym4HpBY{C;NM(t%&!zGdDHMLIN9IiNIEXM)mHv83$1OK3o_P}!D5b2e)g z4>}W@$~%r57P@qHa%IxH@_IoW*vcz*ovsMhMmZ`KPUw!mjck{&mlCkOvjH_S80&>i z4t>}ebW2aTr1O~9WVdt;UtWBNRbLxwxw2PH3k|n>GNR=TB}2-aZudmJ|`nz%)H@_zMwnQJZq=8qqnS1!F;;B_=4y!B7Ba6ZEVY%KY-oOE%=wn*8$C! zv%rtlHhLOy*PYt`_hN{mVdsFs$czog#BOI$<0*Qk681H3$u!#3`iwN<{w0Tv1dMwhA{ z{39BnTod$}nXxR2PaS`;EB=8)Q&B1AoB<`V&{iMI5dpTXu7mM-IFBDbMRYhmf%%1f z9k)g%bjZa4+Nr`Q8Ps4O&b|UgUY}8P^!F-4b$k<(nWe1_cf2``Th36W>MCMSz$%v| zJ|<0QmQ);9@)s;Uw0eshU-E4H`ojlasR0zBQL z;SS$4gohb?Nq#jBlV_qCS#-GJm5Qdg3FQZs_0RT|KfF9Zm|fiBYmFZkW;mGSVcN!c zXa)a&wlemT+SL;HZRJ@jL*Bi9eBToB;xv@Hy*dI5dt;jq2XS*V^QtEow)loW z#EDMW+Xilc3EP)k7INZ01wX3x!jGN`VQ&Xm;S2=0E7C8IHc>1T!%Y}c?v;xt>d;|r zSjD}~)%LVNigKV?fju2?PZzv^4qOeT?qDmLG#vC9y^8}!4nk{zCIZ!^H=c#m(c4{= zwonYSPBh|#4#M^?ItVVfh7xibM5L-mDJWGvsD!BM!Rdjj9+!bq)#F-F*)qse3DI!3 zf*K*uZa3k!fYJf!zYMhlln%BpnrE*YDu9$KVvM0KFckNk>Dvv4YBtm!Lp^P%N6g^; zgrR6`(ZNjIe2NfxtSn?N!m|V9Q7W*)jdd?)#xm{Yyq#W(xbgNAGa~HaU z$NuU1<3v!pjy~5=y4FuU++I{?%fM=SaC;evqt9bC9qZ`j%~=^-Mdy0@h0PIr9sLUU zEBP+QPhCfkzzl#VS@`Fyqx0n<{&BCP=eyR?BhA<|7~((JMngG?6?F8vnm6oKYF=0> zULWRculbtKjt7xOT_M-aCwhm_$;t2E4PY78>|JgEmm&Fha!NOVX|Cj(t{^m!CqQ_o zhb0u;87xIL;9a@1gT=T)B~idqt|(<^;X1i!wGg4E+l4p|lolc#<}k|V$+7~vy8^=l zO`pd_(H{r46gc*AG=XkqJ=8S(<}!^Z&QUugr(j(ts_h)SuM-3%+TTM~pZN=yW zd&J%Lx#T6|o-z){E=L0_Z$y(^5#H$=f-1%B;Ews1ZNh9Mw{#Hag3^xU zLi2VpsC(pXwRw9Zs9%eK*hcDv`WmQvCEWd>l=F{4-6zj}4oW$=nbZ#zQ73NV)OP2P%7#=^L8~T z6?F?J6*Y%W74=U*si@ihRn)%&rJ~*g$`-XO<(`k$RbpXTU*i`IV)Ig0`E)MNG+<4Fv%51Y= zRb#`a>ov4wYYM7Ps+Db1K8q{NOQf=4mS(@@sG|}n2307PjWMePDnJ#;vxT4*3zn02 zrLH$`qo5d@&-yZ`>nD(+Y?ac5@c(Dh8%T7N(*GA?pwgg1T4lt*EZY;WE|%`URE8|< zFChm$>og-vYBENu@XOE&!M$A6by2Shv|7?Vq8N=6N}Tm_Rrd9H!e520Y)~S*oG05C${;<1e;Reg3O8StMNgd zDVTuaG=R<&46?XfYgc_`(01dr&uGJzrj{VwINOX5XJPXCJ{&rEG8=c*W(S+-+lfQk zs_aABx>=Gxu=)$?B$k_`vd# zJ*!8BT0*!&X}A9#>e|fHk!Jt_o51p5$uq0Z#`_d`e*%w}x4n_p@J89ZrV-qr&CuB2 zma=DlQzX-K>8%tO|1!ylgo zy}}-^sgtjhX9*wq9z1(c3V;Wj{Z6Q9puR5Qc*NPS67x zQ2#|kwLGCle`|nHJTs4GAL?8c%{NTtLEJ|VR5VY4%b}KI;ob|I=>-4shqynm82%~Q zT7p+any*0#F3Z*uT!j7(Pf&u_IG%@mi4t6vt)7Q_r39yh8rxBVZ@}{qyEIXD6M#VR zU4!Dg26I6=9O53<*KuehOrRspZgrfDf+JyjcVgFd9Clb&(ZX0mE3XzUVAv+avvuD= zQ=^r51!pxYOXt?tvj@dD?ydBKZ8kT--wL*lpVA@!wnF$eK^*mEXtWDV#R$iiCMpJE zI}BM_>Z#g)#aN$Hw&^YZrW=t0!`{EC7C*VryEgnMGO(DLsS!beS!|jt4%f&*9-B!yAqa#+94yls}K|9o6?Sq+Ze%Z20(m|K{bW zM0WI{*gwH-68+fDs2|7t&lS<0B!h0{^n}BS!nnXKjL$j3z|8Z~?mog8!B)a!uWZkN z=Jh#oG`_?!@i$knt`1@5!?E`zt&jS*T?k1}^_F`4clnTH+!YCFyX)>Po9YIhI1od7D8Z%65qJrRF<@@TISmC8DC0#9Q#;4rIe1bFM*VBrG}AGr1^_E zaW6dyrOIX1H7y8KZ2F+ypQt*UpZkbsrq<^d&A|Ge7~{nqmYdZZcND{rR*U`nGg{-X zqc2K47zZ(HUvwrYojb5=*1qT*P&#**2Wmqe`>aKvG#uv+cgi!))im5xl#cdU_kq$r z>&Kw9&-x`O?X!51WQQmVw;SsFpcKJ9@EWcQl*aZnr~--YMNk^s$Dm#jtt1okEDbjd z)NAr=G$;)>AJh?f_DxWaq%$8~pft9>fzsGy-4!Q>;xaRCCpmeY;Y6taYL>jt@XrB4 zX*DiQNj8>zD50goABG&QN1b|XFWvC=15^pD^k656<3xvhO>s9~x3zwhZ7snY8z)S7 z_bwa)X0Pb>f8}W~r4Clct|S!XdMG*>7}CpQAB9^=2SrNW_HSxtpx9_90vxc7gQ42; z{iWXMq~P}R`PLcR>@{=tcy@B)XHQMV@L14ru&3d8T|Jf@`UPMUw1d467s;*czT*>8 zkDFh@jXQA<3+^>TF7Cb*)-s+hR>evVg97ryp|u*7IWKr64pSj@} zeh=ygd3@FeN>`sd&D%5&;*iRp2kKG@R{%<}JT^(+@ZEp?z?6IJD0+<#3pRA)1h!)hJcGWKTgeaM+u50j zbB(xD^nmQ^doK9UN4-ch7@Y?^4uKm9{+N+$yL%XkhT}b}K8I6#+Fm}r?ZoM^-N8xw zj_wOi+Kr>S$}@HEBlT2oc{6sF&_au*5$M1**A1&vD`LCjFQOfTFVEESAytF?zyJC? zI|3x^*t$O2f4Vu4(z$EyL`ZLRGJ+v6LpHuVm*M0L5(HMv?jyBmySS}-z89-=!1?dG5D$PtZ~=BR znn7|?tR0PwDJE^Hub6xu$IAIF+1OI}cJh zmX_6uqg0waIH6p!!uOcy-8#;Fa*BWXPS4wak(74^Q~uOZ9&3lxb_W3uV$KK2;hdBp zPDsIIFo^R~?1NH2J)q3Q+c+1YayRZ$6I{wXzPi%W<2XR-nDluBBjy60Y{( zeTT+SZpWEo;^d8Df?eTAZ7e5+~zwf{6 z2#7>tR+dg@V&2!p+~dD%H(rBtl?RmyeA^BV(-g5S<9RhwWT)|dJYllEiDYw@gL>Kc z%G|b>(}MW&J{fLo_2GwichI{h);8HXhIN~g&iduJOBpM{t7dFOdT_8($uk=k$J&-p zdaUhO#`2B3tiLXw^vLpHW~USl{zMkx8lpD*Yfq^tF7|Jpfl2-H3!6(ZEy5;BczkhE z51ko09NRE;wySVg7|$0PXkxEE-2o(7eY!Ch&euD%a4-Y5buE#rHWL?a^2W&W{BgMO z#C6}M50w%DXK zn;v0UXcNQPf(dM}k}L^0&Q22ofon~KvDF}{dSOfUU^tNMz=B^M=ITg3w$H-Q2p|^i z@wY4>7rE$3h)52uf zB6$FpD`rdhB@EB&J@FKGYRVgI!K0yZGE#E42xUH~8--eGs87m$^*FgN9!XDzP`r8p@i2%z>I{1!{B(nPbey6Djd!&^jRY)6;q<>1d!SYE6`QAyXPvL z#Gj3dnjMy!$trsZD(h8k_=m!hSC`mz9Pgy!0gcUzQhQPRaQ`f7A}Vb)PIYR06AcJ! zjwA9}Yw-|a@wYY$g$Xdi;;vdB-y=Mtu0|4S_TV3?el-K3X(4*&RrX*cA;_}NA@5?w ziW&({{2PJM9uEotFPFcOeBQCiRR;grZELddjkAn-1Whp<_vM>?pB#o^A8U;ChMMif zA>Kfia72oeGo}f!8?5B(YGg)Rz9h%Ul=mU=UL;4Rh!+pS;9a9q<|`S;bd{3Df?n%+ z;R52gvRFqmhJEQ1-C2c%&72Vr3NtYysNm{}rUDd?|BRPKjTPnMu?PX3$ zzple0U39X^3*p4ZK51t67HRf@6S9a(wL~hMR=XwnFqBDm3>l(yYL?`WUh(#N1= zd9iMtzu+0USQmHno=Jyz`YMZ@aV;)#F%@50+^FLPNS@?e>OuhCXAFd;DtuLUfdTx? z%KZgT^2*{MbAmr7aHH`qTrI4>cA>qY71!*QDpUKe|Lo2+cJ=9G_36~=gW$XALV&b@ zAGo3oo1&^kD~sv<5{v-aZ~@&ur@!kjKo-Fq7c`?j)*R3{P=U{CMFMNtqE9fTta!&j z)F4#$T;AJThhNzXeBeaaw2eC`u&c$VMyufO@Y`;noQTnrr3~XspbR5UZ5e$@P>g{P z{?vw0Fo9}xX0_Gqh|t&qAq17@H5ff=JNk^z_GpUYL$H&Il!H5XpwHo0jC(k-rZ1HS z;aPR~4(&L=0UeJJZz4GS?7$MW2M1b$#F^!&Hpq$8-*n*zB)bBHM6wYQW(kmdg?ozk zL%h`%Xk0c7iaDd~*cVEi^L%_&i3G7=8GD;QUx%;zt7 z4C1>8%xmV!Bg%UsGTFr&!%^;ae1(BJdoXUpW>6%d=5jpb&2qJ`Fi}j|HR9?WPJGb36@y)?-I)eg7DVQU+zXvi(xqJ#`X4LSd5bh2fyBLa z^7tC&MY>7tYD1@;y+ z9?3-ZCEEChqMUW`WpmeR46CZsr(&EDk%TCRGMrQm=C)eJ=8=k!=rU&It5yQdglY&i z21@5C!xF!CCOg{*%8 zndI9Ycq@Xr))vf@d<&7_Z?zqU93U!NDAZ~wlo!bW|Df{C%73n!iJ zkvq}#zHmcUvuU8*s=M$HG!smIh)eGfm-lwv(d*dieMg_yoi_iNz zTQBo>zJOcF?GCmEExiW)dNovr>gW7tcQ|?u(4yzax9B;E(H)F)z&Ka(Zr^jxOYJ*% zkuii&gB+4Gb5`9hrH8N(@zszL2jCD9#khBA&cOfFZ>Ht`K z5jhKvLWbfKn4eD7qD-Gc4Z`CEls$BzD%3(9bgE5#?3+x^08UOOhM7-FCd7KllkrR^ znY@#oI?=vc$0LEKgX1D*fd!qY^;bO~Ps4aBH7|QCQaPVVU8t$=n_hOfth%@d`Vhq_ z9i5IMHKBB=L0XgF^>=>20`JkT@M)CwyXaE=o%`{$`W;}=I;uZF2sU=i+b_})X zrK%srza2;hni08klw{>D16k8)*J&ac5CaX8i7M?_Qdi0WmMfV~A~1a zJB^$RskY=lb1izf6aLO#CifWj<5q14u@6KDgvlG?IsrYX49XC6Ab<67becK{U?AYo zC5llipt$fSkOFww1KP+jY2&Z$6tXHsZ=sm}&SFxf$X~$JV7d`$!964(#X0Q|26*L8w&cg*dX5R@zst7Q<{`%?Sy$b&6W_`zkTf zicZ!kY6sRSYS|sL^=j|MTHvT7q5`pQB{?2EA3i2SDL$8M6&%Nlq zd+~i-TP-w$>euiVUmueTzG;fV_+0Z5XjH)(XbUw@8wS+}@%V4bq#9bg4CAli`(ylj z#!+u3K)5w5WM(S+wk+yE(y%d__yd@FyyEYC1!+b9)qyV#Z{5-sYuf#tdwvSpA&u31 zgaAl38%-+)G(4^02*yOb;y-)Gnsk{yT(Sc)-XWvcm8L)T2hQ{dUi25d>hF9NaXjMh zd<0+Uy%-fPufT(+$r@2S#&7B+-TuzEdhK}P`28~ey$aT*K#@KcD5^@qJ}F^LlCo_J zvmBr14~$Xo?Elql+QZfk4qH29*zyNPqZZjC*HtKQdwfN1cC+{6(BjF{q{r@nFW$ZOB>&+-TSlx6`~qq6RU{GUS&IEY+untv7Q;8orD*A)i~aD4&e z71ExGf7h{!U2#%QYD`WbqR-Tw_30%rYeWRny6uJyhT2Q8i!&XB>C_VVMDGV735x(b zh+64063j4N*M5&L#cq|<0fq+X0b}#Bnu933Hr={Vg>vB{fzT5ENZeRm}bZtlD9H3`_9GdD7=;ZWoa+PQr}Ty}ckPo_E-Z zhm|2YcH(i{og21vSlr<5!_!tp^{^`#IM|DRTuf?{ML$kdbkUD?$Q5?-+FBE!skNGSK+iOpFh-`hR8N-wKpu(@(7Q5IX$lGYG@|-jln7LWF}JZ zZ<6p8puV74fNq7;>v7H;-4n4H1ku9DQWL6tspjP3Wm2B|xNky5t6SIt57DJqxjbSH zr9~GMnmsT5j-&#*t8W2CVl$!1MtB3>?djr)1^1ox*D?cnTU2lqBi22fi%B8C`4m)9 zv{d93JqH4;5&;%cqM0vDN zjHds^FgOcJy-qliQLjRIKm+P;t(kt)x~?1swL_{HE0$KV22fg3G!8c=EB;8T63&2t*3s4f5Yje@#645RbfkG}tefk;7XPPLg!kw0$jK{;<5+ zO1NuY3lkTd{Tz4A#aPqFlT*5D7A86SH6U&*7vcZD{+e|7>+ocxSQ(e5v7uS#@sItv z9nQyI$iuRfqS5LaEDU?C38^VoYQ0z|41#Yp9M_JOLd&!f z<4?q(DIw1_4pV&h$Mw%A(PuA$+^5jCSGr3fX`B;4tf-B?BXT3ovMZ|52@TXaR zY`^x;!uO2Kl|(FeVEE?ldzGkCL~amd?&MT!xaSNjYh`9#hLnV5(T{}^Tqg06O^ko+ z&jynUrO0cu@S1?57Sfl98Ob0dCP5&Gr3ms?1o^&*f6k{r-ZABE2XRuu(n-Xx6k|}n zA>-fAGT-b(_nI`6!Y;7O^GkX@^O_59|ys=8jfjDin&w-Lwy7P zoKJtezoWeEAP!&VG7*0w2IWhhe{`6dkja=IByxGD2BjC3^Lg6T3#FKkpPYnnS_Dzg z7=%(p{PHBkYzDPI&l-eMMEvd~1nqFn=YT;dMZ_OYLY(Ua$Mr&2^dmPn=D;?H*>?lf^JMZ}Yzh-fqjrHFX$ zB*Z3H9GeV6DI#7{#MX3c>#Qtm$daMfkX3`b2dzx2Bk*bdu|M4=Pf8K}s-UIkeP67; z2En%)4nb^+wO$eAOFua0(;x4+^0tFGDPavx#Gi;k`I2YJDfqslIZjKl(pIGuk^NRX z4t{MmGE$29II4(#YRd;M@3%Y;vv?b3Q>ij7+yi z)@NBGmt|TbQD!4oWp@*G5C7Pow@iyris&hdo}F&ZK7?KcrS6}F9>(rn;QePle>Z5Q zh@PhCFt-2ngZ8^p{gAVQsCNuX zDWc{oO4>uRUU8EP88fm~ipUBVatI^?>D;UR?k`=)yA4t)A{Q!hOolb4KHD0zEMSdU z;X) zu2cjR_!N;OdLtKN5Ijj$(^86v>jWV^=q#<;4uWqr99w`=Y;B5QC|XRMPk+3>puFuM z4qvvhMEr>ulrMR%cbJ-x$(S!{F8kD)b6luQlT)RbmuSBzca7nhPbwd!h`POB6#cZF zkKdq_B5I?e`l+G!IWT+&3{oi~?{Xp2QA1I`ZJl|(3z=<@N)bsjg*^*df<}XngWy{Y z$C6ZvC8-F8x)cALPk+3>ro4IX%V*+EzCU#sLKnltUj$ z$ypz8Qkl!>&rHDMJ$lMGox885% zLL16mGQ`To=#zWz$ZmrF%0Kq!zYGVZ$l-Mt2Ou%3=R%jugAy63t5@lG8o`fi_brCnmtKi@UERf_q^RFrF6Kg(4X z-!llMh{zU1ZjsL#?-`Vry;AE@9z44#m1Tlpd@cNAf9^MYlp>$e8uI`x;c*9w@6VYY zPAQ^KOQicw4eFi`&M*k2h?t}Z>LW8$ANh*{L-im2&| zLT5aD*+^^ntP!vR4TBX(BYRoDQFK2&%XeMK9~z`mM3%TxJJ@KWaTn@G z2Bj2HL05c(lSXWADR4gjZIDV4xj>P5J`1;C8<{#IAdx>dD5Z$1R1{0$*Q(`>W>EX{ zfI%ol#9~2cdjyG(gWy{Y$C{@U+oK{FD&199{qe3z@LuK@z7Ap_-ilzTJ5Is-YUPbo zxKl#SAd$C3>Xk2fe&rN=uQzQ-Y9%MuJ)1YLj1&(j8c@(EeV8e z3pmIm*`J>pgi=JTQ3QLNYc*Jz9hzSirqwD%#2qIgid~2W2B8!YjVB?_b0I!BBf$b*?|&zfs-@$&bUAwLcMmA_nD4p3xKm z$e;fBKBPH6-)Eg)pJ8lUUrvCmpPQU2#k~AQQDX)}gPjQNb%HepvKrbAo4+lqRW1(y zV>l>94v!>c^?sg&br2#+K~PqTpsW`s2OFmKC!8nRt`$_fElkpUqp6Y&mIW zIVAF?6jQHhCePMW@O@S#I(djSdB6EN zl2wYbdr>(JpkHirp?_)6N)i2vqH{8=9B8~b(0Fs8@#d_OcCZowtT$a89yA=3B8MZ& zp^x^khEV(SD}z#ssJ8``J1x^1yX*>U?2^l^v9oHdv7RN`0wrdgAA}+uhtLUaYrQKq zzczf8BHw>#YFv7ryI1^;K`2GUKQ$$1WgsP^k&;nJ$w+JLy9o&}F*!-8*y2jXZw*hS z$kPKuC~UHvOU%lq_TMwSJA1Fcb;!!BI&Cr6xZ3IO3aGLMb99D`I?>H6F9K@u$FtYNeK*06h}m#f1|%bn^!8njYGe@@Y(GB7(Ih1vN? zYt;T>J%R3_ty~)=heNLT|718QMGogF2kIuPQl$N>jfhyBh-DB;5pljCL~Dc%njZ(j zw;GPJS1JHX5e$WjZ$AC;o}b`dpCx=9#6Y|i!B7hfXD4pUK)e;f zQ2%}k-iwqsLb+3t9DhPG%9lLXo`UaXhOb+C1MyW^kY~QDw)ZFJD-2&Iz$w3h_-gr) z=b}^ay+-(Yq-V~wGFGYG{(4s~|6*#CQk4A-ni|@;*kJK-5PYlQSfi9;jZy?d{T2V5 zPk+2`PRgmnmpM(upNK*ElIOb)Qxh^7vs(D(-k)XNzhimI)@3VGPWRl9lF^giowgUN zSw-5Gctcq7XmS&DL+8_KWT6yudz(s7`p|5Qj(&`e7$xsbj1BIQpv`bliX1j*$_k-5 zd8(|;9;}+SrmpnWIcb825Bh}U(Pc6-XMfraPo>Cnv!=?`FHd)ZHWX7GsNrxf{pRrpO91v})9n^V%4-6Z{*gJSK_u&fiksvu|NIs|Az9nLpXdXmP8tqVqD6XJbC+s^XZT8cWl1kgmhb5u;pguiEu*BUc#)XI@XnwFrGBz$)oX(~l&{zOrIG^iOa)J}s^il|?nGOjLzQi`bG zoieUn2Bj2He^AtLk2QRrCTpU8$=}@up%f8qiV*uw^6KAe7jln5Dn;Z@MdqehxieIP zi(QCE4MHg*9#e#CM$gk+oX=whp%f8MDq;lI$yZ@~UOA*Lt144U>#zgE_u~es6p_y< z@)NYGqb?3l7!FF2!%NCxsK**=%knfAVy{6cMZ~Lu$UWU>WqT%DX+6Fw0=n^!wLj5n z&%iI|({1=DMLu!iGa)zK%6%%&8n$DCm5G_J5AzOw95h?1V%RGw#a>g<47CXVoKJu8 zyrc1?`>gasr^C}JUwAtxrdd(!9h736iejk6u2$S1|D(zuA>FBA@1UWXSEU%2@+D8+ zL*sn<bOcM@g&$!@Xk89=b4j1aM zK`BMlxf*YuUb#r4k-tX_N-3gBPl2}1i$*@ zyF8IwyYIfzg?QWKRw?H8rUc^q8q`S*fAtuIQberMw2ORbl^Fv0FqO&j(eRXyQk0J( z$)86bJD>jISUaG666sKiF)Ls4E7 zx5_g&)ynw3_(ay}EE4@K-r}W8j_x(tV}_SfJ2)@;Dte;Aew;~v-8ULJ5 zf4p0jw;jac%les!KM{lSCC~e91i$*@+bMi=vF5aaXzZ z7vKIQc{qG2k3^c3Vm_2FdA@N9z6XS_C(Uc6!T&~WDSGk}*vRLE$-Pp{{ogb-qIY;D z)P)*Y^d=3*bSQ(#@BW)X>Q>C|~mY&MEk&WK%nu06zSXH$MaMRSA;kPfx)&UHE#$ z`*?^oatS<;p%**e$7g9Y^7lhiQc5u=Lp4>DB%3il4uWqr93`m~%S#aqwGaQCPk+2e zB<0xQ%N!@-PsE^n$@5uPj{D;~M)-;?)8*;6*GUS#KSEY?omVO5B~MY(`ZR(Ou6WX* zDkwrJBF<1m4mB@W`>@j?XBO7PTlO}zZ#5jBD8)Lc2tH%K;e7hz zU6tUCbqhCQAl`}~-w6(5eD}xu^9kP2QQe4vc-si@TXzcHwaOcz+N)zL9YDt7e_;qoE*NCQz9KoQHIKwJl%a&e|-PL=9`9vML1j{?bc^X zJNa`jl=JB?j=NQ|S*cdmwX&Mh>S)1E-%hmONLDFI_Fhfhm~{Azz?b!X>>Q~dYUZ*I znle=kWvUc)Kt(eY*GHUBfAMThlCHy-(oLjADN0xQlIP}A@cpjlydMkpn@)1@9WXgp ziaGyb0=Xo4cfdp!GTR`PBJ!u27a5sRs`xkvzSVHdg;K1UieRW8;Ggs9kN1N~a&q`m zPKo#vF(_a1{EfrZgiOY4)7(~MSrw>-WzhXf&@=XJheKTTY?#TpQq0>QmCMCLt&0y0 zwZfSDm(RjpfE6j$kV^;m4BDI8>Rp*q$E0MtI1M+Plp?40&zznShKo|<(xqI=vaGWA zv#gRsnbx_;Ro0C3y=kpjQLNKe@E#Lne?}TEN|DRs%4JH1HN`W{8rzfGJ$moRR`E+O z3RDp|ox$wSD8oT1zIsYI^ivBR4^Dzd8>CW1KCj3=_RG&Rxc$j7D5Z$%R+MWk<;zZR zeCHa3QbfF_2$yx+nS&CDjSsetr4$iwej;M5K`2GUyC)$=k-7aDXAnveaZC_Dd~jQ< z*xl{wKFxvP`!s`6iYPcRa~xq_Y{V=VV!S~pMZ};4;#v)QkqdFUK`2GUkdqKx^Kd?J zNwnpq6cNJ}AtedB*rhu6Y;qv@o?uW)5tZvgr5lucB%NqbN)dIs3zgXGx5E|JB!g0l zsL3u=B8B(6Q27R>6j6mPR3e4ncA+L4lu|@}&V@>(aGMKthCwMs)Om_>)l#=La*9DH zMa21vnBujjtU!I3rxCbQS71;|5j9^?(Vc&lDPjQbb%P2wCN^Yjhr-@=e0#(}`csXR6_$6hmI2vAWukEj|Ik>Cdj?N)d6* zC#LgkgHVcy8$M$?ryCwhk;ly%D_fRpR(Y4CQvVbglu|^kJ}Gx@8{Ov&LMb9{Q$$g! zRkRg5G+g!R7q0S~VUS7@xj~UwmGnBtp6>7Q_=`5ePTDTe&2#+>i9@>gI!Fj4t%M&W$UH7KQs`i90VzJtSz z?_dMoP~%C&?)GRs&+t)-e7>WxXXA3*wV1=WWc>!-I-g>LREo$SDDsX`)*Z*Z)|$gU z>y`tl){QvulDV&~aO-J4)yYhBe;?_SU2B{R0zf_=RS z9XuyWl*D4}kzvS=v2B8!YZ7Kz>AHS?Y>+r=l ziPBxAFXZn9hKEuNxl?)Mq*#OBRsT{ZH<`yZE*^6Y52YCLG37BT1v59O3HY4M!#z%x z86HZJ$CIBTFLwxU{S!1ilp>GkgonqUYWe%r)bG2H^9)icB41Ku@nEYM{Yh?<#|mKW zb}-g%eRnFFC>x;Pd=ieSkwXWZqhCXDFHEnIWbp{Ub8V;}X;j>0z_uL4} z**(WA?VQg=hO<)S>{rgWj=C&x4h;g4BrvMK`C+=s~oCETUEz=)JnhwZx#5B5I+cPD{5=LwoG&JMxGNeVIWkMf4?#cFi>%Pfr3r zZxBimu~ZT0LWA2=tkMU(*5|hRtf|nACqp+L^fGbi&0QtG)NoOXT&`3uXAiZ`2A2YG znFuc9ny|ATdiqf4>CV{lf{RnN;iMEfU8kJ-nVox6m=gWe7^G4}enF7A!Qs}71B0xo zUFp`8?Srj}4`f)UZOycDnzF3nYhg88F%+$1ylEYEKu*QK#CZ9F7eDRKq6Yv!OT5 zg5ES8dQ&0vrs1>3p}!krrBk`Y=YE&8t~47T0%LMbBdQp7l~HO{3a zHMvk%8~|q|x{!4SsT7f4Q)FqXRSM)RARSNHZWrW>88I^)p3H zL_OUK%TALA8g{bQ(e2`Jz2Tq~Is8gFOh--FngZ?9YvrOp9D)82yQGT<{;I34EjJvL zB8T5AhZ}}lH*}>~*Fu*qhAvwKUA6$aY#wykasBAB<*xd5gW;+ax&BGH;&PLG^do-E zvHh51`}eDt%YG)z{;V))rHJnM)aWl5^#A4TE8wblzPDGUk(N~P0)ljzG>9k`pkkuZ z2$Ehd0w!W&cXxMpVt03=Vs|&b=j^$&chSq2|L+|>%bvS?o@dUSiQS!$3`Exkaj#2n0Z9@f&l9q*0oQk>8W%lNo$EYGgA2-o{7Ke=`wDZYXJ$~(OoaQ2 z4kACK3XCKn<5gl5wHD%)FVh4BNr<@ppNMn;K@uV!5W)moTj)O*m3MK^M23JQ36W0; z$zQQKxQbTcG@HU<2;yhUOaVy}B3~1-l_u8;O0EP-E}QGfuHff*9{QIhFpz`{A9)6I zH+W-sWmV2%W;L$HD3}=oR~}6$G3zR(mmraaG66{vBDD#LS7~Y0 z7>uSF{*#9s0YMTX40wciwi83(S<=I2dXms*gg~u!u(6oFfG!Nr;@r zBhBq$?WxF`@CLdCXAb>({5umD*qg}I=T-h%C7xvjkLU8*N)qzU;d%M>E{>SESV|$)Z z`=&64D-uc-N$97egc9`vq>2!u1q4ZmI4wqGp>l)>F-Aa;gouljVty2iy6PDM&ypUN zT#~Tl5(2fvvwM_rUng!3GFAQ}*#C_idBw9LlyTpcbAuTW7%%1~X_vR2Y(`EqdHq3@ zGTukzK{lc+rR%M;sJxFAyhswp^qf#Q>l8lLVH^p2SozY})1U<7S%v@PVVr;_3DIvU zEtm%~$^(YLv!sW4KoaHwAy8|bC_T!!KbP|p<3&Fy;#b5#yvTXD65gMbV*XkK>-08& z>y7+c(_e%fFQk?vOivYK{(hUEk*NzaGId}^Cd|%kUw%gBFA>WGfrTVwQ70Bdby$zW z9M+>S;|!sfn7w<^9yC~(D4!~83NCe z9;S#S^d2ElYYS{FDC2e_ZfK_UVbY=o-0g}{S*)H+!ScVprPE5w#yev>8TV<2ASyjcmapTH~jMMb>i3*>xI32(5#3nmJ=UJ)O#XQN|l9@M6lCFDl|CU*H9IPbIv)cwTx!F8{0`UOQ!~kV_Kc|4?1FN5Tr;WNf;OLBBxU&yu;7{wKd6 zw_7FrV+6Y~dCcDkQf4>#8##R|;hn_uR?$&|*<0G2jwigO8AIO)xP=kP!*rn}kc1^+ z23cgR#u>vam0G2maOZ=^75ySu21p;v07+Q-35on0M5RGl9P`ShnpuQNQrJNf<`(fH z=e|mKmr$x}X~Wxk=I~aD8QjB|!aa-$R}1byj7xwFf{BP_hTs8`Fr}+_7IRq3L%oU* zk0=HNo>BCWibrx_=u7_8NfK&qAWNWUdz8!s=Dope;1Z~h@)@{0c~<&2OF)x^=xyX5 zYz<-V9R`NLv!sWfAqn$?5U90LlsaYHdx#q}F)&{Ay&`@^48)6^M=RkyNGZmCo~ArC z=RiCD|7;LxAn!coyb-frBK}y#IgT5L>=L;2;S(9`hW0zeR&Kyd4aIXGsss07+N| z2!UGjU}HfU_ewTeGTYGtkIs{>U%CiuN2TEA$rI^mWpS=uM!X>Az~zt;54xTk~b&VV%fnK z2ph_{N7Z;OzW9K&h9|k|ab-{|6C? zs`9W-K#+upxrE>|pnNB88iT=py?`VMk&7!tP810vWR5;k*$KrPQoxOWpb z-gH9Ok47X6j*C#`S&1J@0-=z*MBBt(@Gif_LD{k+)>5qhhDCJE6m2rX)h=vIPY z+XMtjhu@l6*5?(i+w^?iYMBu+S5aL0I-9i~734PRr$19s= zaF)3V_Im^*Nr?0(;>50$)IpuT0&5*#rB7LUKvM z1oa`4YH4w`KEZ9n5xC`&!5jAQRV23F8)GmN81SZ%7$gD%YKiA4DT^z&T=E$&CSPF> zN$6m*3^_ZAZcCK$4&-?|b84`b*57N7d;lgE`f6e^!uUwS^pD`Ne6^9mntGzIj9p_e z*yjpJk`OtTko?$@KJ>fjLB9)(AxX=R9fgT(A1JVpge;SZMf6PLFNzl)FXa}Kgov36 zi{U0uJhNh&2#L8xX(b7f^Z!rCngWs}L@p&Hj&Lo8p7e4n+`}ymXs~cfC}SicdNq%x zCwrI@2Z15*Ea_p6lY~`@5U4dseki{*#3 z%f~>x$hp4~-o0{OP;2nN_yc)i(PAMev-yx4gxQLJ zmVzzt4x~`JNkZ?OBWv)|0;@r>RsR?Y^PF@s&q=Bwpiqmo5g;n%ze4<&`|#es7=f`9 zWBFJJfxOX3Di5TIULpz6w**g$dCTi4Vjy1ROp$ZqP8n~BoEI_^e1d`bqavHhi^$to zR2!6WKM`ye^HyXt@gnDtN_b!KyyE^Kan1}8a-Jki#|J|2YhU3^1Q>;bc^7OJg7}RU zE6}EviX=pT`%iQsCQcse!k*A1A-asv;nlft7+q}zx5Ocl8k{bS3+Q^nYV*ZvF$jhi z9EDI1Bw`^6SyZ6mgqsd*nJ3ez(r!VY*5V?BBacOd7LPEu(SX%2ayhLM`6?9hbs{H1 z4a3r{=vDnB;yWX>n0t>X3F{CcP|FdD7YoX`O%&V-eK|3r zB5pz;Zxj|Nc~Hh(i?~5U%!?q>E*}H&B4<%0yw(CQM$UXu5ij`yIVV)YYtQrkedn+T zBaw&ULJ21cQ{bvVLCI#fmq82y`w;?)Bt*gF5G+-&1p6td{bru#0*13(-h zkv~f0No8@s@E(*M>N?coEn)~vAtB1Agb=7zPziT$;>I#Esw!^@LsY~~2-IpQYHO6) zokiU86f$0{l%!og2I56daTlC2-o65_*n1W6k}r@mvJ!g-2)yF_tB9BK4>_|d;Vl$+ zA?ZTdtB9A%9&%o*gm)CrTg4DoFM&6`wBZdE_Lg{mQLc{@Y6VH?_3?z{=WrRr94?s0 z1$U%>&*3r?&Ec9Ou#ki-Q;9`Wh0~m@`i|8}CrqR~%oR{1A!;^x!&;5Ah9y!BVI40kkVW_;A%oE}2n>N|Ne@#?5~h|As8s|T3v?c>A_>vg%B7a^me(O| zjDdKO^E_-UDC51u^P1Pyg!!g+;;$CT?>ISrhCV2XuGZs4*f-tEmDF{r3=hL@0s~3N@P-)p771pS zMruQ;*W#=^%g-uh_kKJVIF0VaaS57g{D9{tV&P{4>2o@hVKzz@%?8p@M9)+=Hl=>hatRRi2gb*zOSu zwJbz=r;J~X_(4-_4VE*~E}sJ8MNaohc&iJ%KqdI2B3|+ba>8rfLQrO}A^6pwBAgC@T6z57D5cr#tP+$Bt%#eLdkIQZxM2xfFuc#bqUG0B|6ZSKzlNo zR{jtVJya8{Bngp@|5)iEiffY)7fFb4{|6ByLTnZgBq5^FKZs-zLPfBOBt-b~2z{U6 zc0FRvZQJkADv&@84lZ5H& zObl2q8klnWAK=>!@|lL8MMza42S`F>4@#4b8fPP`!5Mxsftl;ZJcc3BN2Fgvkf1@5 zBT>sx)P5?9Bfgy97%%!wVFyW=Gh`8R!lEZaP{x}=sUEJy4UaVB%wV+~Gnn;n26u~Q z9}G$mT2FMBswSkKBusrKG4MS?TJ&xT%#Sf{Pv{AvwnAM%lZ0qkwgTEteptK|-eQGo zlLhoC$=_n-3)4DL{2BrSNyyNj82%dO62JMaDWFI~)DS{d@`i{n8wUi0zQ95fvWyhP z4eu6us>Q%TE*byHgMok|2~p#C6b&0w1Pp;^Ne^Ih3Cj*4P)poKDdV1^;FhWLmM}y` z+=M`_<)S*KjC&SwgQnOLEQ5-)DXb@6ccXU(C3+Wh zirIT-2BP-RLSP{YS)TGN{M9?s8l&PE0?(2jz~mB^K0=_@lS;T>6E|QmFkUQkiue^V z5HE6OiLL^4zC7k5rCiC~Ts9vQ{i`XYmLyEicS1JNg0=Xna<)*)^l-g%C|!D!$z%OQ z3{VK<&lDsf!yif$J|RN+#J~`Emh{kHB%!|ufm%;tV?i0Wss;aKAXj0$7>go)MGVA? zoU=rwQ5ml`&szoWRbUNF{;RezDp*B@uehOHTSzTQm>vVN2;S&xuu_9_f|a4{U}Y$) zJb2Rp>Xzvz3(n|@HGG-Uic^V{Ac??e4>IvM3lc_2jEzA0EXrkNahsO&1|l$^Hx%}f zg#IR8t_4Y0AGEDkrplVXc7 zC8S+G6~v32dl{*qSsv3+;6+8|lkz$g1A2#if}9UfT^^L#>%;R_fg4i8D(={$5yRFV z3uQ3a*Aa4xBuqsRS=8T>>;J7f*ZY|c7k5LK>vlqqYrj*UYqipV^Pg$Rd5tpS8syc0 z)y<4Kn^I@4))g1d?1(GOd2!=Z8c<1NF$D@SH4`K}M=_yvOLW(#%%&FQyu^6XOA5P5 zLN5_7a(=CZw=H=|Gy*gV@GM9K?~tScCp!FtxX9FDZzUi|LPS?W{QW)83%bQ@ZHf?4 z+hZ*-kc14;lzOZ?rPQOw5O|jKFx@0!StkT)eXWE$k+=baf$^ee74a)#AYSC0Eoyn_ ze0fYNr5djRvw)xbpZJkmL*z4M{43=AWCODs%Q9(W8cD*mkln~B{wjwu-gV^33UYFw z$SNnnt0ZBJTL}Hv7{_-w!-BJbA_-Bu2vuE$s}7~6`es_$dIf{P-bFx>gs20GxJ0Ax z&LWhnfFcP|M+t@V*b*#gwFX#skKHl5h|q2Vnj}P@=Fv2d4X?vs8ULSNvLQWyaU@~c zAp~lfi+rby`yz46`4}(es3Lwv48)6^u9fg!rxc4O=Cf(17?rz_N|G>@cL`Ag-(&js zE63uJ?;)T`Li8g-|JBRljFHKMr+^{}QO^nWAFXFkQ9A1j3?w1L+y6`_+~&($Es_xN znGksY1?vN9!>VR#m*|PD0M4?|P(YG|$e)CC(BK?kHChR*Mr$TojW(V^Vc$qVlZ0qo zj2?Qjc>n(Uj5}V0ZY-clLbUpSqPvLDO$0Pah}I!A+XI|$xmP+37MRDCM*86DtnkaQjgbX zC;)Jzi#47kyjl)liQ;o&I zY{0gIG%*d0DGrdt7M0f_ZA=gGBIo={c>M%kfC*o>s)(0-f}F=H;SJ__#eH(^Famk- z7jlUtOkqnx=%~Q`f)%HBfu3_QCs+s&P$VHLoa{Hz;7pE4;BKHEr=4I2&$PBYh@o*$ z81yf9K^>#d>q6lwzi^lQ9Kxjm#C*lSv;}wc)%nG$cF** zpS01(Bw@KCe<5dPCA__O-YWb(t@5vJitkDTg`6b`V@)RpQHvoiK|un7Bt&Er!dZuN zhBf+aMyYeAuo{zTq%mg-U)?Z;)%oNvr*VHkn}wzV6G_OFPhP?G3}9V23=Dz4NDuu% z64q`)pw=l-&MM;`Ox&P}f$^fp74a)#AYSBj5qVr0?{G?e6CJJztj}xNKnnxb@t2;3wg_YCq^9W}1bH+`xV%vw`R3->`vI zv&G-22xlF41e7LcVUsj-W0k+XvPXjh&rnj6(vG}NpciPh`LNDCH>)pMM!f2NfIJ& zR*38-LW1k%agv0{`-J3k1xFxYU18{Puz(&1i}v)yULf)iyjUh@APE^B69cvnO(`;Q zi&9%akc5brgrI!PLX0N?`TsE8NFE1Chkcrt%Ba2GJDn1G{@p9ewK{@FNkX4#5(8h>%D;D(D2iJmAW1@`9w9}waD)h9 zB_K#bgfSstNTU{v16H&y<4lpo)&dJj$WoJ7{_2ldC5qc#K#_zfD?*7%=S301K|qj% zhM8=O#5~Gu8&u zE^j^AjGO}q!2egq+nVRC0v#%D@Z??_zAt9*POn7gf_AZHmPU-aJIxhbsH&iG5xhzg z#@vor{%Yy1M7al_(2%!GBq6FZq4;@adN7Abm($-&^U78$qT}2JBuR+uK}al_;A{+d zH^G93fFKDG@jQZ`!`p!L7y{3d9_BkqnD2x@tr@Vfpo}|(xaBI07xP9Dzaj?WMb3AO zRM0Gs$)r?D>u}OBM4I??#VI)TfMsjpvBu9@6n5oY-9%TUEsWIg2la09A4Ll$Z z?KzWoHA)n3(@->H;Gu^FPr*YZp$~E>Hc?#?w-3-%%JYvTMD!HxeoH)lk7kEB#l zgbZtl;jinBxV-xbD3TDhNhzv(Gl!X8RK@uYN5uyf^3|PDe z)}?v}SDXu4#Tr>`{$fL{i1H99Fpz`{hZUB>%zE|?FdKb9V32?!2~j6`6kU7ZGz5mg zv!sVvLlU+@gg~vGu(6;*Pj1{8+o5GV%RI=zDlXZdR|DXq5{MP3n?WD({h`v z;qxDsV!d*P}`*&pr|I6H}|WHi+M# zg^y~=y-N~m+K_EHbErWk&%qFQmh{jnlCY!_0=2ARV?i0W198LEvcXJO&iPXUXIq-c zSzbxvOpo;93}nf$DoG0TNcZN~31Dn>fs)wJ^CY3?i4C>HWB$tGb)$Hrbh)S-j$F$V zPVmiPXU=w|3w&eI4Zc+C4t-Z1y!DJpBE(cac49)U^O#-ope)XY6enniEkqD$m-i;| zBB#FSPFxwUkDRwEycV8N&QIkT35)qdenQ@~O1Ogrn=xT5-z&12@*O#MR>IqY=jBH@ zz-$a?7YnV0Qb-b}qb*s&mqOBG2s}%ASPDtPbA&)?K5Q%~BQc4o0C7P@;*Wk=?RiaWYuDT4?WrjW`3=ECe z0m9&QfFx*&^&wPkO|CYKM(aF;x7IGGW~szf6W-@*FN!xzU?2$@aw$DH?r;Pa!GORJc$V}q zB_v@k69Towi$5yk9!T8$d@fy{mmwak0s$9|uHLmkcb*??klx>OMP=#5tR>{!A zmQWksvZ8OOvTsJ;K||yrLdZdqFqP93UWWO$7#IT2k{;$DNtlC#K&>^R(xHrdPC0Kd zUi5|{enkw#i=59Y;ax=DfEPKYd{g84JyYj0PiS&UJGHo2Sm3rRjJ$`!xOO0nzI(yw zd+h`pcw)DPCw2*E!q*E}N>vm?JHaa?VY*k4<*?qT<_-LE}+7odtfDC6BiUa6za)mfY&Ug`|u!$t}IPoIq{z`c7%6S0=>EIw89HfJTba0Rk?te-L z#&xWc_#TnhMKkL~H|1PM!P6w6r=OFBqM7v!foDk%(@YZ9XhNV?J=j=K#{HJK|C(7Z zMj{^}@g9OCtUrWA{td9Ppe&Bhau36dEKp+>p_@p%d@6_+IrlPBL9;yOr@)Jf$c>@A z4#j}pA)g@U15}d-W%k17$>FI6SM<>>gf*~A)QVLiNWBT{&>xDYp%!$4|KCZ-JCZP6 z>O7Yf&Y8IaGlgL$nKsNMQ-NM33=EB)B@B9&B&;!nMy<{A`(6;`=P{j%cyuTpJPm>I zme(O|^ab%Er}%Dz&X>m+kuNM^rt@TY$Dl;L81J$$j(>g81`o?aXTcXFp)btIMqKv? ze4zy+p(?QQ0S1Od-;zFhge3F`AyG^G)kS4-)G6l&#*1lE*g;ZtffqS1iu|jL*Ouq4 zQc#mC_*NCJ+toPP4HYi&geuo*ryAFKr8?JqrUvITN)uW`_!fAwHfPYl66O$_apIm< zsi^huDtL$_^pF$9;;PNLj#B5$U}Xt|WKEc(Wdd*Jsmk9*f*xr-mXxkp-X)}Lx{HLlcx>mUr7LSPK&Tf$*!BS``hF`$-sP8*#^Uy_7zH7@6G##>&8 zw9((hi<}2Vo>0c?N1hOk95e?!3*CiOlZ2K86CzfZi-o?mDCijrg`P1-=wma1-Z9-| zbx!jG%~@S9%Ih8i6G_O_l9+HrRi*)>s_+H&NHtioRF$js&Z5NZf=MyjA?`uzDX@@) zEaAi=8ZAK|vk)yHNJ2zMLe$oRdp>=xc6;-8rX|J~jEW7i^kek+7O17j@)&`EBxHyp z2AEzHd;~`qbf9k@R!)N+XtVZ;(S;|XJIGjpg(PH&B^G|xg7U8*4`s=KeVo8R5;FAS z8DJibcxnX~)HJwRNb?q5$TqFwtAksUjA?$WheY+QUoVp6Z zeWcm4oW8kv`Tg8IJnJ`T*r;(6FDJMtmk<8%^N%P5z;C?kfU7nKS8uK{Y}iV9!R8H{ z4{W}$`N1ZF{UgF@4qb%K#$t-489OMjk5wHuOd;HpagcESeJ(87ICO@ShOk}7Rt(!U zL)eU9!?q0WEI1R`@JW+z(O~~i#PS0;c8m2C%L`oM_cDbj?jSg9<(d$ugDd$u&bd%vtSH`rX0Irtx)k{z9u znVTq$&Pfo+uPnY!NFS+l%1U@l}Vb%rljRa6TKx|jBR#|1Tw-l8&ZdH zCnv^cMQ6)mW!aLHY(A2dj1*Z4n2?>AAjwaZIZNVW)6yj6b)!*9l9U3)&WfiI@xZyH zOxN_-UMcYsKR-#gh&IuoAwdz*9U_AwJ4Ck)YSA)SIV1;Sj80EX&y?mPknH=17>vn` zkB-mG$&is&c1piQl(I52(_H-H;B0C%9^(Wz{(Y7|!I6HFG%+z65-US*+S~WdOi7S9 zI=DM*}fFUd`jB}-!Y=v}#NC7G42$SH+M zwvq;9zJ0QbKTmHbanEbwUOuFyIgnOxYzCh>%oJH{d}=+2jQ5t6BnX`nE6bGfO3*Z< zWF#h7{om6ND}f>qp9=P)GyTE$ebZe@_LHO~#wPF{l{iW880VhHwan-XX-R-0kd`P( z&rC?LUs(4u8faKVW1VsF!Mkf@CN%1cJ39+(RC93R{LOH?3Unp<&8*|;EM!ULl z2`N$~XgI0>+B!U&0KB}$X1#zjMQ>EqfiCpIAh+B2*&?wpj9 zCMs*A;HZL6aap2^8ePD+6tD|hmgrch1$>?6I(7(Z5rRqMBvH26JvgoKh{%@VVI5#F zU(*E>>;nJsJpE>pa4@8O`|$SA(ymNqbg&0>wu^sOW;QgUnNSHGBrXyU2YKT7nw6v^ zkCPOh!cvf!t+bTU8HK9idXyW-N#o#pXC-s-hpUM+CnEzA#qlNTuXZh1ng}gdWHRg$ zyd^CXWo=@!Wg${&rj!FPWw^YSvg->pKG+Q6MMs(m4PG)y8=V~>VH0Cq?d?PKBE2YUw&|4aO# zuuH%){)aCbh!R;0o=(Y>0+XO69Ps6@fUUxt;;q6;SwhZY&x$|#Jh?%Cy z;|yq9l@u5}tWc8WXC-1~#A|I(v&iVkt`Q;8;Z0kG1V^I9N>2y1Zy(f^%aNuiVTYp% za$8r&Y@y~Pr6i^$$SXuzW@c(m7MGEj8x40in92VpMsZR>s5l1Mj+V>s5(LY6(&;u~718A?*mPANDNLtLF) zxWo_+ckW%_cGEr2HZ3iWgMSHJSZo;Qg8y1(P{HI}1W6{%N#v4Z)3OseY@2z2tF60Z z0wNQ6xbU<5NzOKjOU#as&4Syj_~clrvbLq%d4;*Q*|zZ<`jwMrX398OVxElaAH`+H z^~Q3A$>Uv2*2xq&_SD^3MYP%yf=ac+)WW(7GfFSC&K6=_hhwT*}C1DM9Q>h)~1 z>v7(2zz?qblGlZE|FnKm50_}yL7c6-XBTwufBJ_DfJc~Mctq>Y zWx?e)lj{xBaN;=`mkmcc!I$=$!?6tb9n8hT@nksb!i94Qu=Hw zePQp;KVoHoIB8%nDEbK^La@$*saOWECDm3*sTR9Nvr2Vcw|)97vDN;_x<`!>c{lD=j~XO9qik zPM76zsfp4Iu0=$62QIjIa|xFoo0kR8p6Ku-AVLSl^Txw1w%k#eoE&g#7XLpQ&dazw zaBl|uPKPf@^aW>P=A^)xL_kTvRp=~*VU=T`SEYlSC*%v<8t`Cy$hW=_aSG(V1a6ZZ zX*MLM1bMHe5E=@{imp75LL{C!>-hUI{A zc17OhflZWGd2*}KEo6t{43;xyP5GnDCbB^W-pB%X=kh+my1{T%W-=iQPzSR_xsJj! z44DtQ#ETQ;{`MrEjRQu;%dGov9!xc*M^RSs80J|T#F7C%PvG;5Y2j}%3Lep*zQ;kX z+Vk}uo{%B`S^j!J(Q}8KOadOvck&;WhiEv41vwVtf$Nn>uOFW_Y*(aU0T$pCNEcc{ zXRx#|tFz&JES!tx8JTx5*Ls0pDIHlL!Rw0rG0X={TNdBmBm*u}UL~@DCmoJss+slJ zZPoYxppyj_<^e7Z(ijDD4`85bg}MFrSx3;q_77`IBCw+uFz@o=C|1exXlyyCmLV5D zp~0>II@JoAnC`fU7D9OEqjlZJ_w1Q7erM0LfeyI>|23;u``53(1v}>g%%mOxzgE4! z)HW_6U}@Gs=%6crtr$D%Vmfxb8gPBfU6dh|1W@PKTlw#IxG(-}|1O{(H|Ez5tMB+b z5H<*P13?VDt=AIv1+W!^d=mB$dVhnxeo*OYlOX6XgAFu>xxzk+mxo=S0s9-U4GxAG z5wKw>34UiIYdJe%&{5r*?OH9nlH36f7C^f8!u|k=uwi(I`(nT!gkxyWU*Uf_Ce|&$ zv=9DkgP;5{elL%xK(t3$*fN)gZvA6l>ic2JK8=wl+tkdm+BoLZQ2ke}8r&aeoE#{l; zozr>G;ae6PwTGW~xV1B~%l<&8y_YwHU9m}b>axiwc>UMH(|ax+&@a(g654p^n+Wc1 zLh_WuM}|tXP2SEO&Gx;&=I6UVT2sZZux?wsxbWP}CVme}Bc6G%{j8}`x~+zcajUVj zVbALZkBe@vU)N+>%*vOUua5RUcq1{sj?R$bV_P=MJhSvrNNe{4Q{xwmnO!BUAh=WK zGpiT4v|L)YYT1JOo%JuA{ZVwhzDlD+4gLHn-4Zj~HYwcga%RahALmEL>3MbqZs}7d ztULdH@@VZD&!iW0o2RqA_2Qz3w~qW=U2Vtb?p=Pb+t2)5cGGk15Rb9@y)tJS2F5rC z7_@oWcjxXeqxxmf%AMFba*>NmnXH+Xbk$d#6KY+1M^7IdW@NU0!Qm!zA4_tU_}y0P zc-(7Ifd4$dw{POO-u6q-@jg8qE{FD$=uaHo-SOAj6EzPP`3G#V=(x6x_QowWin1J+MRvM= zx%DvLZChFoeHlJNQ^PW#ST-t3`})-;+p87M`MI@6s~pQ_5iS?I+l6KXcDwu2vuJV0 zfg3jsyuRLFIx_y{lB(HdLk3*=GvJ*2lDY4ijOp^{n0~1CJ-?}jp?*DlGc5+R99QsV z#Iih>k+rtGsCULPaj^Zdet*{K4y``4>axLOM{_^cJ(%O9_5G4_>fYn~dW4;i?(9F{ zP#>4*Cw}{!cdI>^_vWtKwdQU5JFf~E(;~d%xphsuho4Jb%>at99ql!d8;Y`wC}jMoTWVH17MvxJY(%YIw`dny~|SSJI}wZFX+sc#A*p zr%k-D=}VQOhF^XyFmD}o=TTSvqM4`G4wyc*V~NVbA63`*nA9nHT%h9AqTbq%1sAS_ z8X688c5vBluTGMcgD>m9-+4LZldtLebr-B0XXw=~yT2!V({BIt?_YIvUJP!SJLKHV z9=S_KkFFNm-|$hd1zj2q(lzl>_1v60F59wx|JZ=A%};(UG+KRS+w;_QDd&2a=3E)@ zEaKZ2^XBVId|I}DXnB9U{G=8dpj0vLSWT%hF4GExe8lpAb0xw#vMntxmiTtFLaoTWj*dxECMueEqld zIHK`|{Z2`-RJGSl(AL@&>a)J&_UCpVLS7$gdS^h#`|FL&^Q}Ey|5ROc?P&cvRYIHI z*|u}+xm`a?e!j0eZy%?*KRRsx+SNbfp6%U!rRAM%w_Zf6KWMA6WUktU+FM>+7<1Kp z^!gu5O`l%haLlt`)a_IIOSs@QzUS9z_3QuVQY}@Lb9F7Z9kAJT`rx>peo5Ex~3ZoT2kYGh4ZRJLT^1kF`Z zBa%y`Q4@2fs<<0ga|*m4vHflHBQt`-7G*kUcNt>l)@gf>o7N#~;#*r6%&5BaK-Hkw zNe2rPewY@P&Gw3nz4@m0T2GUPve))!xt8@L?GM!2IK(}7@QppC-h-|*{+;)#<(NZ* z&uqKvv~t+H$saQlTi;rA)$;D%XZdxzJnfTnY3lC>HdZ6Ysom((H|1A*TUoYSYUI9m zz9sdOCP|Ws?VP|>HZDtZy(K@e#_t8Woq96 z7r%!NvmEm&{^PLH?)#hdTQg#Et2EE^yXsx*#MvCZtx=T!`}~y?$DVC^zIN8~=$PB< z42+649lrMM%JAJYj#Ur)UBC9?0Snux?zC?0QYADl!6CrVzMoporx{E3?u)zRJ0M@$ z=(YKnS}I4MmFYV_P=B+^xjwvrcwk8Ns%?CVx=#Nxce}T7OZ|`cC%xRW#n>*~vTkG3 zTPp&OEFB*h*J=M;zrtsG51Y@uc4zYP^TiP_jR*A%yYzOQtnRUQM;*f)xT!@YJ)X!? zM!9}bnUML=Y(VXkD|2gYSo5L7ozSw2*S6($TNCZtd(O3+J&eZebuDRNZ*bX2qlT_V zgzd6P>wo5%_S<|WDCf&6tFD<#opZxdnnW%4X_~s$HFnqFM|TbkX|#X0jrv=&2b&t3 zxvov$emLok{^KhrZnn6)CiFzre5aG!Y+PP!o-f@z!!p3=)NsAqUnDt_WzUY~PS}3> z)vNa#2g%~!=m+Pe^{I1Q>d<)6)#cv<_OyR@r;Yca?S>I<3C&-WzG^nx_Ili8?Zvj$ zE^T~!XP2Jjv(aOtsbRfrm+Q5EU&kr^tCrdKK9^r?joCbP){dvupKg+D2}|AlP+RYL zi-EIr8?ftFMf(G}w_-D_x2<~_F=ff=m;Jm)weI)e@QN8RqdT@RnsdzB+RiG!x8E<|SSmYZzLr8P#<1sXk4U`(JJMZRpvrb|3w3 z8b6=n^o{$m;KnAy8P8rk%KjGU_I2^%Cf)v5zOSvcTaVM9y@~M!q-Gs8vS~7h@%^r4 zJ7}jz@&wng)*DSVT7GHn;dpj*pM;oM!O}6cEa#*&QSlg}Tlt`$Fg z>vFx>Z$Fgv`=!xfU$f44YUMm?Y<9e9XE%c?`p5TJZM@%n+=;>451CpS9$BlVJ92X8 zxj(-5NoM(ZbK{!ck9+JN=eE%2P7ycoWpVzz8B--rZtT2W)nSvgOfNi~_OwaX&zTv2 z4vq+n25_&i>tIetR~=U{C0#4(pv9#&rE0ur_$%hp|0x zu=~`%_wzTdU%I=U-e4Bb^Cb&%O4E)v4&P;&@Z9d@GNYDl?RxgtxUte(yGfpTpH=Ml zj^#ZYNE+>}7HH-b9WdcxZr}Z%dxVD^*H~dTz$n}~Fy!RJi7)5+T&w!f`?hx{^3~vYgXk$&o|x+r=F-%aL#P_wBH*8hx$si`u_2AO$my4*ka9R)n)GUj%vlV|XSeUN9W%eo(S3N{Z*BE?J$D_wKF73LPM}4H zEUSUJJ_i;}7(Daw!qAGW zhG|U${tPiZuf6Qs@HHzN4Y-uE=zXK_KOzP_1X(!&~;d?t`U6 zTlVZ}U%(BVV-YWV>$$sHp63jSIy-+vtLOZB&1$uHI%klUuPo6I0%SAUAW?&8N9jRGd**8gJuq406hR`2ACjm{K=blO;~b$($) z>n)q--LSgyNAh*bviWX$#??Yvy*ya!+Pb)#8;=h$AKQDTb7rj*cMpx+J!Vksf*(WF zS6$vP?uTSS`$hGO4bwV5)^2mWkwxwJSkFo6J06@2^;EgIcT244R@Z|Gjav;JK66OF zU9ILO%{lrrxIx@eSJx`{qpuxqR&{Z^x}~MAU0XXA+qA#Dv4`CZ$LU5lmdwk0cW89o zWxd`=ul#std~el$*Xg?x&+l_QaPsBerTzN-jEM9x-S@|EfjP&@slno3$9#^u7P8+q zCz{t8`EFG$_PgL_)J(@F8uJGYFHP~NU-0Yi^Y0?k-_LT2QhgHH&fR8KQMjdXjp>Qo zRbvLLuAZwC)AjV1(xnr(4?J`8bi%w-#kO{~!M$9|jt#L`wlYm~ZQr4xyKARZ*5X&;)H?_WOGcl!HD7I}Bve|OHh*KFge7S_67 zr)|F>d2uW#c+`j%mzn;mfH%GKEf@I@Uz+qVcEqKDQ46a!JokLe5ti?)T+Z})cJlQo z<9${|DzonSnG{PixS6V6pLQnRbp!_g!_`^@MDBdkKd`)P;zhu2!M z_wV|&yreLBMbj~cu5k~oQ-2g}8T!j&M^C+WR|kd_jBRw+@AEwC#L;h6I;uD8H!0n; zW21&F-|n|7n$ddc^5YJF)^2{#@xHUBWcS*iueKka(YY|Leb)C8UIs6F-Cb*ShwcAv zpV@D{rrm3QH2t!s>a3L2?I(@4(w(++;B?Q3n!+(Sr%S= zN^^|uQosJ&d|R!0KQ8^Jqf5=h$Fg+v#_In`PhB{+O~KCn;d$$SSFPKs>=n~Lw2qZZatWM(Xh=7wx2uxyk+ah7fXV^tM~fVF#6h-i%#P%J_}Hl1Q;22vYp+Bm7|)r z0evF8G$!_M=st}5?SHyy^1-LQSD1`?T&uz6y+M-~?saLrq@$6B-i_j2gR7bsCGUvn zQF2Agu*iSJf-m3hS*)-gUi>bsYL~1IV{C>m_MEA{d(NcS%UjuvIesxIPs{cCQQzry ztr9kkw@Zy*6I0h_WLQ9tOBpu;UGEG|8RQ=)|(6 zTGy9m&YE3M)9{#+nI!kY7^fD|dvbrqILg+{I~ixx=U|A(n8De{H9Iye+-THX>Ro44 zz3aPFcb95C4qWx;z0b#j_Xe%C_Z_|RyKLs&^t$IVms)JFm{=_%R_D;|ZyQ37T6K&+ zdUJkYz~$4fvQE3U4}JJzQD)E6OHUnG+yDNEs6}2wH%O{YJd+_!Pv7&qMXl`3HD>;L zFuTtWUCoKjq_Q1M|EG7aje6hLHP7`OSEA#yd&iFFdTR50o4Gc!clX$o7;N&pYt)>6 zUEfwatamoOO5lN(HB@Eyyx%@37`7_6v-zKy%j}LgO(?tl^7`IZwN?z8-l)ay6UP@E zJ?&Vg{p)JLngc^#?r)@iJ?=`KOm_V7^>)(9&9s$FgWp{J|Xo?1SC z{+zPBO=I7*?%VQpnV!Sa#E#!Xrnd1)U88n-`Q-(6k6c%62>a3Y{H?h+zi;gyS#!t% z{|2SW9`7AeKbbXJoAKpzzwrrsw{D8+Q?|*}psHrJ*M`wqRh<^c>8=YhwC>W*driCX zuRgZi|MYHB#%F1uQDKIQS^D6m=g%L0>6d!j_hR)wla6I|(>{6DF8!NKJAZ2lyDzVE z`SqLK2j^)!Yb|Kv@y54JoxAfA-hJ*hB;?~HNk{)3V>S%l8(zG_c*8}V_hZL=Kcd$^ zro(CLx5ZqixHi&djf_S-)pa~kch0Y=tUX}u%a=NfH<@-^rlY;QXW)Ck8Xs8wVtU=( zehfU;rOE;yRhxO+YK3afYS3raqcM|)jTztPy|o(Yr%c#;UCE z)wiA=yB^Qo7H_N*IN`IGjZI_yA-mk}&Qv>jFlccn$@p%hY^s}Mg61vT1IerJy;dLXV}3O0!HUjTyKgh$ z3i~E~o}Dsc&bm-9(?5Ol3nI=r-L5zB`03@g>056vQcL!?yXF3)s9En-_x9#n@5!3e zN~K1IVS>aY;N-SGvD^I)MLcvZowdB{?{yse9F&;DCC{XEcFa_6G! znkbdlsk>@F@$Tc$-`v=K!KitshdCO3{`}6m`|q)qJ;M8YckSRg<;}v(k$0c(ZqcZl zUT%Yxc58o_-mlU7N>Q^15jU1SG46k&z)pY8geR_H8|QV|d%V^B?k&o0M_l{xX~MnB z!za8xRyN4FWnT8Xg4l!_hKJ5f+}8fBVQyH@Rz=mEs>Oc4nXqW8+JU-731RUzSv}KB zzFs^3WY)v@?4k2LEsORYY5m$J_v+%*iALk6JaoN~`S^C=+a`x*zB(H;srrnYMmD;I zZQgt-*rj!>-_jSOJ>4$(b@a;LTV%aq=Z5g=Z@YG1c6_AT$_qJf#(A8*++<>WQgGY^ z@68@H^g6tDwQgf&wsPBSy8-Qbw`+T1L1Ak0L$+UiG5>J<%S~_YP1xFD-RGN~Sa}+` zeOhPPiF)BlE4$|Qs(L@eTx;B&8SRq2`z9tPnx%KSYU+XWg^z}<+Hr9Ip#$&w zb?Z8O%+%7t=VQ+-Y7?GbcgF$ylQXVFR5P-d9$r5n=IlQI+?$7&YY%JXHzsG^xwDNI zG5*zEnsw{md2Y*+E zII^*p`+(-{BvIEw+I&A9F){Z@(Mq2)+K+sU>ra&WUT|My8QaUaZ2RQnk=Yjl&suKt z>a(~`pQ{hsq-0+4n%?(j)t^(&y^KD4z;MmW{=RiHy~i8b`&JuU^l_=dgIm*02ky=C z3!C@$MbAA+b@o_V%@~mCW$M~`&bP~7G^ef}vaMy@ca@drZY@~U@u|Uzu0ALF4tTiz zwzS>hvwc+d8aBFJy~W-#c1+xz73b$<43LcX7Soq4juktUxV=4x(k9RJZf>(%@_ z8}@z7vi;d<=D1-EeZEC52q~=D{@cjjj_f*b+r#(l+EQuWjz(D{Ji_lxoZidi+s#GS zbo%!F@ye!QPuY>-son3aSbl_EzxAKp{`knGlf^0*V{8(^+@}|>00c%8`tCTp2hWg&0*J-W1iP$|A>C-nOwK+?9m!^LPvb^dA=p% znD?~8u4e`{JeoQFY5ye|(+-?Fzqx+R>c)!#>#S>V>daS%;~I~3KPCP)pJuXYm}=UP z@cSdSOw*cGOHco`)5W3dUL7pcy1u`j%fsMmH8xqF;%q;+a2eI>o&Cr8pNFJ0+!r4` zumStcS*M>XI->JB{``e2T188G`8C~hqxn_;gND z-tSxg&L}@>L>kQubSn1e1})^?XKHR8);q~sk*Y}ohX|> zR!ckh{~D4yPOWtL(glaUcxILzS?M> zEq&3KrB{7}M_H2|-F{c}d-TWY4f>mFdOW$>dETVpkGWnZv8s8tDJ@Hf?Aq@5dg}O( zPg4UYSl0Wg(%QO8{*wAgvc!~pZ3UaAgTr}uiA7Ji_U`=;)@M$XS^ zu63&Hvg5oiRcm(c9aGSiduh9IivC9@Pd)#s7UuOj9NlS`*YVJiI`#TFv~=6Iq{OJL z_os`$S}e1!*7o-8lWX@hTD4#6^5hGi79JfmL$e=lcz&$=j8=h5_kTKkN5`Y6Y>>rN zmi_^67EQ7|d1}5_NcXyJE?>Df;>(Ej(%Az$v+~ezW~ahdmWc@&Zr zPaONR{=A)%?EXWHW-MP;HqP^4SUa!lx%W1oYE<{gj`kg#8DIF&_}2v&O#E4SX`i=f zcHOAQ2CTeXDYK7mqS9p1J@@C^-e!%Md1%?L5Ba`pitgDroxZ49LgxMLHEKRQ{WRud zQ$o=LjgH&8f$yV!b&Z&9AKhVr*_H2ZDz|nOFn_mc;cGu7 z+F=9B?~dnUFYRgk@<8aDm?P2|!~8sc+${QeD=d-OzxL(3wOIwJTCBdZ`uB2VE0@ll znq;>2ka}Gx3~S2xPo2CLa%Jn;Hz#wFza|ZCb~~Wi-ZrHP(!0z*>t9qcxV$gu@ryau zA(jqzmRS7o+sV1CUvGH-mrj{^%b53LnzUR0WJR?{63za#n$?H%*yxs###C;Fb5!+w8=diD6x#R2F4{yq6v zw>@b+rf!r@x@x`mcv%Yjz4POUIJ?ddkB%)^Z)%q7yNs1b)o~3+ZMeJo@#s5#Q?s6r zTWR1_dNc3p*q2vYpT9mJ@<6k#o!U0-u}6P?nn&{PUmxdeUOHXP@45eTkL|1Pr>**a zu2Js^VT;@k?`;z#m05AL?qXb^UzriS)Bw zCx<{T?^^qYGjCq~DjSuxyCW+Pi*813aOtpTQk3rjb>9!sMs7ZdqXNx_En@ktmgFe19`Q6wTZ!kq8l5hBy_v;qCbejE}V^U%fW9shRjHHB8eZ zJFolUQS7`*&X19YuT(EKO8uBOAS(6I(*vt>JSTkZvMujXm(mtrvzY#i5|ss)etmm9 zuKSQ)zds)5!ivYuc-i;n4IjP9y$!ebxVew7q#;PS5-Jf8X7qg_5W&EwpMcl~&p*?MjriO3`jhdr6|S zX%pILMfSCjNGMXYD@CFri6~3`W~S!-;-0=f{`t*AlQr}658`yDeBrMyvhs4 zG230=*E)!rkEY6dDkzy|i1&!@&ifvb-^2Q2MF3CiOHRKzeEGaQip$>;4XG*i9&)5b{saz5(k`sCm{iwADf6f`mzsv}!( zh|9lG@yOp)C@Xv;-X~9A_w;=)vACV1jiHR?53ln?lsFzVy5AdN_kyY1a%okFjq zYMU!x&->O8jK|lkn0_<FW(IcMJmmPO;!Jt> zBaetZ3x6cX8XOq?ZsWB#Eo%3DXWd{9^CkQWT!YbPL`vKXSuHl^>|n8QALmz$sWjt$ z>LwQbl;Xws3(s@BkJl-@pD8`>*BS+d9ou@(A2oXF!GPB}zju~zs;hWjQD0<9mk2Hs zXFRD~&-`s;;SafywR76e9MvxOFPJfUFb}T__q`V8n1=TD3%%Dg+U=2D8mV5S%_|*f zzixey(2iEe(Q!_51ylZAv*%XLlyX`mR_>8=hReZoWB*J}+Wyq5Uv@b*`zLV9RZnLf zKjN&(I4@*F&#V~rCw@IR?tkT3re(i#SMGv_oqhaf$&6bE;S=x8-6xZ9M@^9|9JOu&H5WM z3Dc4bl2#iDJj)RD;bdIDK8xYN`S4r)IL;~E%n({TPmnYHEfMF0MA_yvcpV-4^y!fN28A=s@|QQC`}M5)^wH?QY6JCzS{D&oKMb`N=W`;VkY~^6`j^#n3mYLk-@mdFab$9q4_&^V1Af zt$M9%$4kdn8pr5+zTK*pcWK-uv9L8q8te0M^S7@V5&AO)3C;J{;r01e zmeh?q+qe2GO5PKhrTt_n?$6gTte)VvS$4!x&+2ORs)yiswfCG=Xwl6~nTB6{g_{#} z7~j;?HeYe6NyPn&dAxoGKX4g+wX2N3&wl2exjf7k*MgQ=8V)f_;c?y-_ei2* zivshGFRH(Z_bYF9v+o&RY(am1%#yv_2Go78@Vvylv$tW4-pBV>;zOL=Ibl59h}|1HsN)P82Z*NP+$oxuagr~DAccKZ~E+-JTy@F_?fSW-Op!* zO;(k996cQ=?-+M!L@E0CUA$~GckOb?KCba~B_gVIPr@9!u5W*c*JZp8MEA-bIp2LT z5MLkQ@qp(G9?$0+3@e7Rv>3I!KE~hh)DwCseEysf)!BNVg@%r>zTY;D2DW+KV)i9? zUgLPM^Z3E-abmjl_4zR(ZEI+qhq+#DUMM%FGb^su-#{p>4*Q7`5BYw@rSgLJ@Aks`5gT_eyx``bYx&atTWs;E@E>Di{>%D5EX3u# z5}bEGzFJ~_A<<*S#qrAncz#Pt$h%i{E$ZPIzj?E6Af&@tXq%b%SEX}!o!_PTv-=Xq zgFJlwv}0*y6J)>@PZvH7hLg*Yg}>Nt@D@fdh;^+eX|=kv!-e4ug3mnLB9PZ zulPcPvLcT zxyDJIzHT-z*`5!pWA__K;Oo`CT|qrDIZRp9NW&nj&h&isH8am!b2Y7c64GKdnzY%Y zEY2k%opICg6UNT(`=4D%^0^;>r26`S>%qtLRBMlYQODx}->+)+u(_1YJZ>QMr^J$XFlbqGwf#Xu&AGNt_yR4J&zU$iM zD$?HdpYi>VI+jI4x(7}(C-)Ipb8rR|X8qbHN)QG1;zjBgN zd-<9bJRhdKEtQzT5zX1j;0sy|)zsi)oA>*##k+8Pt>7VP%%<=c?-b)oAntU4Jyuiwn^P^pxCO>ekJ zT9B@p*R!2_J=e`|kT+nxT(a=(@@0~CdmJl26*Xpd&K*0--DJ`h{=Vy;_2#qTWh=dY zJ=)WzCUHk^AW<a#n8M)=`Bq>H|}!NR>++U#59{ zmAsY}_5He==<1|E=FkAk{_Ysjxaz&5M{~|l=7p;7vZQGls^(mBDQpUpDdc$e^K}+= zuWH+foUX$Q!Ot2hCws1)=u7I(>w7sfDUNb9K>1@ymcgQ42BpO^G18d{Z6|Fxf)zc) zs!nc|WJo(=f2}txHOD5U@xjk&Z*uvM^KCzP(k;Yn)tBlngUHT0ow% zww`*=A-}-;nS1)@cFPB+OI{s!(0O$HgTtGQjK@cWa&~V|2oil~&NOf3>ks$*vUV?s ze!2de%BqS~Uki^L(RZe8m8EbdKR7lX7TVgz6fpjQn(aL^^#pr3FSll2!rajdj;a=1 zmj?0tWSy1N#Zp+dJ4m^(_;rNc>RmPM=RVq5-rm9vi$ z434$kbMN-X`}qHbzY2{j_t@l3;3C@!*?6J05eqnx%7jKB{7U3uR z%|0^RDEj|fKK2*bf8zc*_*N+LlHkfg`hCnhFm$AqJV{@Q_woHtJf3GZ9@uEBswZT8 zs=!LktNsjSw==uG-scOFu!B0I*ad%U=EK{ys!SgPr9U6n}+=^zAuRP z>rY63FZh;6a}O%Ja)>eNIgYEQ4fKhG`m1!~=PDlpnvTs?Ogm*aV%V#o{3J@SZijr6 zc-skw2mTFv9z75eHn=hR^X~QF4LxGl-|qE1mTK;0-f;VArtaFl*#Vkccx%(rFPU_4 zofDkz9r}K;^|Y-fEYXWgm+Z?jd~z+0CqD(RgE;QMe!6^YecPwf!bW_bb)jll#3!w5 z9e5rXaXvq_WK^b8lF`(|f5ypIDF@sl4-Zs};(6e#oKpR5NQqO__RA5AHTg$fBv(e} zY?B>)thyuphQ$7ysP&c6EbHGs!S^#46nVI@ie27~?`OVw(X=5uY~ix^t5%n9<8wHw z(y$~iz9X^!QP8!O&*B45wTgOGbPq_#FT8UwTdqRL6yMJbp3%Lmo?YJ*-_O*2!=86r z@AZISwduj0&$d5sKjZ6D+#fl&W!?>+{+5Ef8a5$ zsq!ejFuu9C;N@<7{rSkUut7|6(Ws2^n`T|pJKgwxO})yzlVh7_W-$LuWs*{;c&S_E zP;GrTaTH%~)~CxeJAV|t)P6#3(R|5`o8PMFZn2Cz@Ar85Jf@$DXD<6zmCxr-Jj{l# zqjG3tWsPg=ba(sM94MBVXE06ZK#~;iZJWCB!>eB0$ca>E+t9zR@<9b2pO)2iUh>x* z*Wr19pL5agZ{QNPEHQE1d|;Ey#-VrHta_P>uk4#9Uv)yM;&%+})LzwTy*~fV|T=zKJ8dVijNfXw+t(y6fA#bse=^VEi@MvSB_o!vvt>QYR2Vz^jajpFzu`~g>f)-XWn$+SGYRfj z;SGJN{`Kdbqk*M`>!yEldF1&n}gm)&6y4+oS!ZBq1nQE=Y2* zIrekdUbubuxn}NtJ)TnxB`nLir0#84eB?Ra$Itbao)x>Fe$uHHKc`>)X`_Gq*qY_F zRJPE#zzvU^!U|`%e&u`hO|>(BmrYI4m5dnh_H1s0w!quhL6$41>e>DaB%?$fowd$o zkI0qJH#FP4=$6ryCNai>ndMr0m`ZZ|A9@U{RG3S!Hg?rFe=FQ>R9O(_x%ug9my6Mc z{mZ^dn^t@}C}J9U;rQ~wWj2Ss6YXt&-E~vMahKTv=7tZho$^$jm^NEe4WCtCM((9@ z8M5QJ`22X=#`vboTdBOa+JD`uXG#wE9C`KFD+|V<9xnx53pZ>J?4PiG^(9v+?$0xw z6Jl3t6!Em|+{)5~k$RSQUs>hP>)$^e$wu|smL{0d#~AK)pf}J-r_E%8QMtCj8)utO z4+Cl24o95K{@5ZueTTv7idz4fLlTzQKT7?~pOsQsD=Yp*Q?_uCzFw*EW>p>CV%|ab z4VL#3xa@e;4R8SE=MIx@anlu=Jo9_;eV2<{;)d)ElRwv&MVZ?labgh} zH4SHMi_XL2OQ*k1o`21S_w13zb)y?x+|6ZTiw zUI8!ToH_4pbH@I#DpJFRbH$OFmi{kh3a1>HkDn`G{zO7cZsZ%kAiR&qE8aI=C9YAC zyW|k-_Hs6NxAqk+Q6Fr+oceYOuZ#T)i)mXe_s1VNYoPPuYUqHU``B9(8K++ZJ;IjN zKe7bzy2KFV880IpYDBB5v}!Y+ZG*3;f1IQ}QJH5i$79a7{`^|$3twb6gf19x9Iyd*g8%HRO8a{uY-0hNCLy0+YTwSLUDWcg{9EpFI1cQfq73_4;b_f$YYY!4=z0 z2UhXtKb_9oYM}its?Rq5%5+9|ZjJF4uDH$z;i<+7mb+dW&A*D*0grX7T=rRh2*J;n z@pG2-3jFWSu^i#V^)EQ^!n{RY?B(L;>t<<*Y|db}{vvCBXie?wRW6Iv@;P@se`q43 zCDgIK{8REJx9RdP@wmay%hJYgxhkxfz#@{aW*7ww?%neZ^y| zH{aP)6vd1CWMaED7pdGecK?o_)0h+#FWtr5eb&jxyL85BwQ&5LhN-5esXlhooh5=% zCMUf<#A82}c5GAPRgQfNzp>=qzVhftz881EoP@|%N(_8FDmf=>e4|$kZl4zQC53^q z@Wlql!#&s!MR(rLE>P(+yX^E~&(Qf#ehF=LvB~8ZD&L(uFi;u5INLfQfVp(pm)4cd zS3)XhYt$XwduL08h|xvthw=R&yuY-lD{0*?znnFTf_3f)u^L4&e3W|7P#Ci*vd_NQ?60f9<#--Ocv+Zr zUTx&T&pq-@u5MX;VfGpP{><&B=qiC1vKtMzUU@a-7cdRKFM{J9JWsJ-bxq!Rxp?En zZ>!|YbOWn)#Od5PR4>7+-D9x2(sGLslQ{OXkNw=YaxQS&iscIrStU@Tw*T+_lZx*f zmG@I_OD+>Cdn=`NtPbB#!Rs1+Kd5S?E$qnm(I+^*mJAU4?)^ZaZrYmK75*;A&CkSL zTFJ2FyrU>bmrS0;`Fl9-#BmkAAA{p{dimIXiKBsX846jp^yj~Lo*U3&?!v5_aI0Lm ztn7zE*z#tMWv^b}jAH!eB!9BVWI%?c>QP3frj*)w5xvdV@qWd_xM=n3zTf#<%5Bw} z_OCoT|0tDXqi+h9=RUl?FRYMbAKu6M;`xr_%FbTVna{H32Vnnp*<)b;fzpe5WqT=> zXIV?mM7c@ktlSo8{djRv;+B`K{^GY!Z<0^(_IX(0_1(0xtmuiNAa#)Ho5@a%Sk;yF z;u4l0{FM42$ye)+%#VvNrm?#;;OnCfKVGLpvHnBj;h%??b7<5B)3^;Cb)uS9e+w8H z=RY8H|6W^Vy~gL8vUh#IfA!p?@vg0kbCnRk#bfoA8RtC28u4>8Jih4blgQgzu*K%c zD8AoT6xp9?Z?|{#t<>`ct7gh9_V{r-O#8O(X%pdf$4;cZ;ePVUtTDXJ`a6C;LEk^S zMrVg7HN>2=?7CmJ(&lVa$J5mTEhpTx-!p_JT=u*wE_5PJEB(yj<7qD?t}S!42vkk= z@xOh}_%ml$%=gh32b(>gjNh^8rOmNmI*{pqfhnf6@s%LwG`Uv%yataC9M|IckZ5_c z(PH+4UwD4u_mS}U!u^l;J>YmKQw}|k65~Xtjjy6E$X62G%J0rr zTE011d7DUBMWO^(w#OpJ1s3|J#&8^u-`~LP!}o9T`u0@Saiwwll6yE#!uQLte%PPk zeeCbtwPUV65XR+woqT;Iol^`&nwwhu1vYW`Mg9B;J^x8Gflf64u`1+~du%SVa=jAr0C4PPhY z>#&^Z3m#o`5!Sylen-w`y#v?7@J}zB6&p9~5RcR=|8dXrl2Xgh6;0oal@DB*=Mq?S z5!?T^Q;gH1*UM}1KEwWP+j(y3D8m@5h zKG%nEjafl0H)AhSz8tE^D@@GhD%Q0eO?D7T-G4~bFaP5-10MIfH{YeUJ8vDFFFVbI zQz_M8Ug31rOFrM;uvs)1D1SQN=NX|hz7AhUcGRorUFDBjfybNP*YdGr4h4?kx-|hM z^W&A&RLW`+f0W-Dir&WR(>H(96HD4Efq4fLRCE^R1lqB?w12U_C&Y6oNR9C<%c^*; z9pXHtha8HZ00&>qmwDC1>Ut_;TAl9Er0LV2DW-fba>4ev!Ssx6XQt*w|2tL#(_)6? zlwE~p<}zB^m`d8Rxw9{`_^7qqlLO`tBlmNAdcQB-O;u-0OcTxf{&nxS z?j-wpaXKE2E_bD(H(c&A@t>uvyO#~W&)FQ`&~DeFx-W{|E_kQ=?S3b5HU-z@_>4f# z-m`0oz{n+-)iw~IQ;T!kmunW@~5?qw9eW0aeOkvB?Zpw~Mh$ zd}rJ7U*8szUZXIR_e4Rlx31pZoG?h~}%n#Jqh$T@Y}yLY|%a!)9A@|7o~-J0XUwjwFs9Y0TZsZdauJ5qCZ zrTLO}Rd+VAPRAVsB3h-9Z{)T=A1qt#iTx3NZ-?tEZ)=u(=Ag{=q0}eSX>I1q6O?64 z4J*Iwxm0I@!OAgyeEZw-SN@Co z2KU>=WFGO?-o#|n-Q4)?&Vlp{TR)?BdB!r-rm@EyezPUaukW&1cS1&WPeWt5tJnW}QzM{!x=^3zuwlV0#pHM!SHL?^UXWJ}YHC#PdeX$A)( zWk0QDc^JNbV@KXCYiWTlp6Nc1rD|BtM@9`ZZV>3&-?nYpNz>(`YfIaOIQw7x7(V+| zXr}v^h+>$JTyUfW_s6Yk9DZ7!ePHU?a9qpY@Q%?n$-zr(t-lWSJ6hXYyb$7Pd1HTV z*irxDeSH7dO;7T)W!7lY-S50l1`TZ&`xoDH_}MvdZ9$%b@1WNjows*ZH~(rHDU48y zU|KWO+ur%^dqJ zs#5awmcvh&`kwtfcTnO1tI!M;PkV)`_fn%R*A6dK1iz?~bXo1{NM(ZQ1)NX(-6J*HRGMVJrsYM=XcG4~q(&QKc>R-Sn6opXb%w0f#Pid87{ za_GlRQ#gFAw(llWN4vZ@OwKcA zmviQxRA6CO7G7p_u+)!@J6>_kidDMltM44M9g{b+Zz@|6S;P@i_HMJETOsp@Ib*{T z2Ys*czF~ZQJiWqcyx;w8$f4*8u5tgk>+}|Y0#wr+3Ge14xaXS1$)$;I=2BD~|;M`HK-FnvI%F1lBGq*U2C2{eOZ+Umd zCo}9p%MVPQ5upQtR}A4f9uWc5dEoJd%w-Zk~p^;;_X zTlt@~acFm~_1rO6dAX{#{XvIA`Tgdn>l~QbA8?7?Oi>o97-NZFEta{RC1lNt;Vv6z ze?^J;6)J0Ebo->7XU)q>b3S`zjid0UhQYfs9$p&F4Rs%nmZx!W2&IYfEHR8qs+JF19oLkcA$a~&i?+T{AKy*Zv(J*NZEUrMYs@>uXX%*T8b5Z- zrhEsrdqmDmp{0~IGPYnDXUC-xKI6>B_IQtDw<-Rv9c3~z+WZ@&(&x>$9OBNKomNx5 zkR$EWqWd%EgfFqzmQy!1C@w!US3*|0z`W~pY~Nn}dl8Bz;)UPt3e>Fhdlj7M`fT;v zrkqvU)s5YHFNE!L0`L2~Jkf5hM`0eF#U!M&e-xpN`NkwFyF@N#V(e#SDQ;fUPxlzdv zrkWaa86P+pH|l=>nOmYUBQeokdUfXa{)6$Wcpo0$>BT5fJ9Ocr>4#a{o&>5qYpxTm zy}0uAhSTcB2g1gGL~a)}6Ml0s&w6>WiqDm>MaMtCWN|vrE@0bio;}ZYt0$MfWZ#2#9kk^7-E~t=4PRaBlP~Hy{^*R8fNsl(0q@ce(|T^5X%s4T+^e;8us^jh z`6y>lTPEilZF#|-w9%Rp29d@ryG3To(KrUE$!HeETxj3jrTmSjIEWbt2Ny#(88D2 zpnp0^KhxnU+mmPSqGvv;e0ne5sCz?);Pko}*31(=Az_C*6jhzVGy+3gq{^+ z$!3{3u14P9#$Ic7ihFF_CN0agb8O4%1XQ&en9TQ41l8-c;{Uwv4KFi>x zTxM)m5r_Kh>AmTzKVENqs;C zQ$8Y`HY4S84YIa7%zx%o`9)M=fwu%ttVP`Hfa-H%S2IUvxoqTF@3_ayH&sZKk4Ng{ zjm0zbwRO+-sx-$&eX_lEVzbcs zFCSg6n2q;|=_RnPU-wXz_khc#FnpC7s8yq ziEvhkOtD~yrP^iD>8bVUHEzcv3Zw_Vd=seJ^IV9Ut~x*EtY3e%X>PED2{r07Q=hi< zUA-><6|+hLB(R)}|Yf{i6lAB;W`>tsR&z)=UdG1Hc=2|djXTA03zG4uu$hmvh z_OSjg@e?(3Gqa5x?`@t`nOdN*NY1GHy^GEQjNV!ix1x_4?Is9%COo%~S z@C!%+e;k3|C-V8@2>d#e4^VI7Ea@E{+u?VPV1n{!pajcB2PZSD$^Q{Uk%oWdT*wpt zR&bO?jQ}~c@1wD^;B!*2 zR+z>n{sUja5}>mN{4N%a$_YSdO_SL5wf~)kzmqzIkcBp_3j|0ekQpToWS-G8y1V`6L66PJ9ozeA@3!8DxMm z|D9C}j_?3>;>hp)&IXTC7ehfHCEno%LmI$;j1Bl@FdB6>1VHN0>+mKSSW2UIAp(3? zv(s~sWH=B5R7EwE9Qf^9IO@jc1%4r!1&D#32FiIhmH^C2U)REaV4!7aR4ivl*5xVsf)_CtfOx1+ zgiD+&Sr;E-!axr7+43tspJezE6F$idayXnJ83Dv#eO_OX@FSVUh;g2j)5~G2Pclmo z6AyHTeVS|MV?;87h=KDM{G)`f?uj57A;hejl;eMMX&%V{lK~r=f*iKJiDS=7k`X}+ z{GJ_Ta-PAzE)Hw`eGZEL10#l*3m}Jy`FhH9QqEFPLZgZU@vyEFeTUzZj5uQIKn}G~ zd%Alu$w>SI16xF+9tSy09j&(xkaFM(NuySS9O|=hziS7{NF&A!3+7Ca2nQ;9qWl2HI9G%5#RAT}#)lP}3AB8DF*1FiXVip@bN?GN3+XIbuP| z0e{#Y)FllVxTdaB)yX0mWyFkv9Hs!XPgC@T3Mipb*CB#J=~KAUL&{M_4Co}(u2i#m zA4mq69?1DSqmGy(Kxg22q zOiRFI0|<_iqxBX*Fufd2#K1@g+PO_(dM?RmAqIp~6XSVNf<4J-BWC?1!x6+ihh%gR z;|f%OF-ef~@-ULoMGPME^-jToB%_BIZ=f(U*osIokbZOz$U#74G?1ta#*ry!DcX^=ov%A_<#Q5z_HOYMu_PGIZPFNsWV9iYC@xa0}cVkj`O?HE|ZK2Vzz@EU=$8Tb1=E- z>w+GhMuqK$DU;>?R+51pj7HrIPK9!wZV?_M8Q7aNstCwol5}@FOfq140|t^XO)q+S zk!03_5*igowop@s9>!jh0WK0S_)EX(g-70!j1^)Opb(JC(*)m;4D<#dJ_HP$gFm(m zT_qW7#DE5)ByMjRL^5zj(5Q;Qh+w!<+Dl&Yk<13f6oVY9R9<3qlw@oWGYE2+@@!)t zkc=%T0rmkxU|*O;De;obM#RL-nuv?HisgEcj2&X;f*dBp0sSfZbQ36{QQ^FR_R;QH zwu6)d+yr0*Kn|1g;;mgI;{Zx%R2WIZ^mNp(jbt1_35^O@7MP-E@PefkTI%<;$qDS! zsL0x2t9pr*ILSC823ZMgnO$N9=A@V7f|xLH7|tCdV-Go!*^HPdn1dht^`D1H#uYK? zKn|Gbl$A%{B$Lb*#K5@&=a^IT?AIPEK=s&tZfMnbeGZzdn=r=Zp+E3B% zTM>iD&n)MS+N7Lqh=JevhT}(Y>r>EBdVRof0d|IMhb12)9bb@)Ct|+99Qr4j8cq0ZlZZvoD<4fB~#s@J)Fb6-g?!P%lGQNn>2RZcf`}0$dkc=N< z;1wjabBwvjUXt047})!8E)UOM1FEFA510nPKKpI_qNHunco z&Mr_wqYi-_j*a#FZNS;k*R>ll-rz9o_jcWnAlRX2{1F2j6ViF8ZJ{&C>_JR5XcX-C zH5ViAl1u<%vH&v&Yz^*{o}#Wm#JmGJ)PikTi;I*4H391d$e|6NRX&?lB5#u*0C-?fw&!n8_2|1uM48T_Cl`(gc zIe?fHkVBmfuYN5gnS+P{%MNO>y7$O4l8He~3FrtOu$7$hU4mp{5d-Z5EtitU0BCv} z9{L{xHYkBQGmJ?l4l(uMRCu+um?&^h#VB_QSp*K@pL$#}*B}|tg@EA)IZRcG6&)l4mYLs}Xx&&> zl7T%%qk_qaQX|)iVvbv@9%#x7wgeuk02|WRRe%_PpmgPv5s*V~ zAK*%W&I&LGKaQskpC*|i!~_EIv%!{&gw_;u5Dal3#|`9A3tf}`@1#Db5CbM2N=H%_ zfU!ZZGpHWOv7TgZx(3}KnKOui_Jc{gSZXfGlzS zuv7zm;=$nI09)0oFHfU7h&j4~)ERU$kh5Tt*(5%Ak7P;_BMgiKeR%5j zPG?e|GQ@O)9NN$?`T`h|u-4z_`%T2C10kAV%OST5=mY8BnOlhY0&-a5q1_4=SbF9* zVr(WEN|ysrpPng4%pzbPCa}dg%@E-9%pJslAOofH)y3OMohuLnIufP1LJE2$1BMH* z;VO{BJ{`%w4EmJ5?ZB*n`2}(~mzUJoWRpxKV&I5{a#H;k12;^s^L@m?K7}P+IcI>$ z>6t3TGy)Z%oJX0ObtD5+1o|ulr$Q!T)*-M(FXtg*6hRJ4esF&T!38}7h8>U-JUI?a zLayv0nQFxR06DBn!#7u$WNHut0ti$?Z_)g6l6j06-~=c1X{xXwnJ0(=QwJsLx|3k; z(Dy~{9}M%0;JqaC6ftrjhb`Whvx0@J3z!wO9nKDz=4kkUiA!&vdQd{6YQY@*Jn`%X z&W4_O_CE%exWu{%V|JNDL4$uHr4-Ug|ST-vY zIBa?bxMRSC0fiSsrqLKIdh|>)V(`3(NKOVWmY!)rj5f$&$_uPDBAHfDGO>0;ro})M zI8k~zZHU2g`d15qM$j`a5F-YKfMoQe7))z=rX7^fsAGr#UMH9f;PgxfV$3EP?tMN} z$a#qv(@Cc6Q`;1CuoE#@4hz$|^JHCJe=tq<=L1RR6=FVu9BTS-hmPt zbr~YS{SC8?V93(T=|zn4B-13jC6;9R5VL8LxuO^iMlHRZe#GFqB$_?;kj#6;Fo7JN zeZGCcMw0n}m`DhKw5Z5Fnq&q*$;7oV#Q3X&!Jwnp2lgh7S^#obvX0I6C&>&VCK=}7 zN2E>!41an#pAh2@a?lABuM6ulNd|hx z-yOCjnPJ4-0Xg(Pn=c*(&W~Q_uZV%O9+p&=FMdTb-w>k(0g$2?)&axQ%NYSB6W1V6 z=h&c|V9?PsqljSxhrs}(^aLo+C7JJtxdC$E;3;oc_EnP155z13jp71Z5^?jv0!v>P z=t7_m)C$V!X^sR0wDeu7jC5u$=wwL$9<#wWp=i{l zlg#Ni@03V}5iv_98RxFqV1U!hnf8aA#~k?00UEIic&Jkz&ijm z>hcMMvd2cRm}F)nMrM)`ai0O&1seH>&hTmY#CtMegYxiBNEWH{9K^u>f{d~BH*Qi6 zd@qYe6#(ThZOX2nPBQTAj*07KC?{-7l_$x}LyQI}2LdQflH69LK3s@_{t3#N`uQ^V zKQM4~{a??i=l=t<05NkW^>N>jc9v`xjM8aT=sDq-kCpj(j%?Q=#DGDJ#u%&RG&Yjq zMGW+=a2)bJKb}A`e25VP|GW>`ElM2l*3a<}vwBXPmV?zKj&|kuo+vYIE zTwaVAIB#I8UcD!Sl(PgevnCKqnnUAjk`YAAqDiLQBEN!Ug#KUx{o<$a8}JI3MuqK$ zNqij_FgZB%N4rE21KSRh^Bc$%$`6fHfeR|NjcE-Og!_2*qzO9r|65Nh>@F= zLoHfvP0E392TfeRLu?=w-c|vJ{?Hk|t4O1Q0fCZSSpisx=ov}GV4bh@1v-+96k_1o z1yh&h0}+yeZ>`X%n5pE}4j>sB#K5r((}>8GLXwe1%<&0?qI8JiCdtSlhI5k9sfq_n zFF5o^+u@bYe{EMwRQX0S%MhbHDQCWy886Aer|SQgofZG6Yic_yA?ELPUXB=S!>R48 z{0B3&omCL?cRQ;h2HTm3No9(-R}C?Lx3fB8@ECK6eR`O*p$209Zs!$jc{&!o9_;W z2{`nJ@7;hH=sjSGb@TfxWZP{J13DWew!DuPBx8#h*lRGZt74edLDsbqG2K8P7)woO zP){QnJH!lua%dyg8y}{K4>utOmokMxj?Ct{L8&IA~yJvLLsEnbKLP8r4O-kUA-Njct#xeXXN zzlK{(r-((-?;TNfKskUZicjJI4!3^qFJB}FuFJ4wv3_$U$@n2A6O_X~P3h2nL^9hE zgWEpmMGY`Hl=ypHI}q~<9EEG;$>(EWZK7v(B4z}XL;I)+t@0x0@-D={7y#;1nX?gu zw{YwCx^^Q*bCP+mg(ZSy{1LMgoC@{sX!c!C>azzi;~gM1_T+X?LXEm23z3JAMFZ8%x-WL`WKaiOH=fF2x6{)9FF`n`&a!NWL=SnSq>Oz-Jr41Dc0qEh!L4&p6v*~K+1_iOgYG5T^i{U zLZm+X5yJ?|VVZdU4i5dHb2MVW4MCK87<<4nM$a7h2RR23b00{7?Mjw;X++A2L5%uD zRTOjKC^3?WMGTlQDE$gM48|BZ^oP!e5cBtT#r*>lkC?@ib=}^OHAP(s{~#w3G2cNB z+s>q{4VE&n^M}q!h>4o4>&wsjDe5|mnEjKC@b|1K?o~ps``GoTsqucbKIbNI6Fk^KP;(tDMk!lF2}f<0SKFkF5pC97W9E`~4VV zp#K3I6eHp56{MWwh*>nrB=;PbBAHCYz<3qP*>0x3kYutDBMQo4>hrERPcqqvk(fXz zm&;r4kxUL^6epQ##`Os#llup=QTQOZECz@E7-J_8vjiN4CHFaVa!BSRVzz^FXh&rS zYoI=)e_wa<5CgB9U>dbraEJ6i`H0B|oetL&)tQt&QceM4+Q32ynR9Y)-ASepG4N^* z{G)u<`Q$+|MTmh{VUY1Dx-3L8#fWhP`hdwt>C0ucA(>N%fh!9$VA{7^fDjl;{Jrg` z5d-}*T;Ctwnyp4MXAlED1N6O#o{>|;kR^yQozzF?{8m#^&RN93D{HvMEmpX?j%3au z222>FGp(O*in`7t#ttx0p8>(fpQM}%h@pZUw%z^1p)8WQh?rDR4pWw(@)U9|A%+W- zgAH(BbP#NUM*d;L%ZLFNlc-(%o2UBSH|Q~F)JVY00zdT++NbFEtB5%X%3)uyjO-R5 zb-wmTU5D9xlt|_}VibT3nA%gi$4H%TAO=h-)UMFi9p^|nrHFy+GT5LzxHt;bf?L0j zpEAV!{o3IsVwOzGQ5{amCgt4v2RXM9BRDC?8d z+dUJ+{NT_Z`qUr>bO2(q!|INb%wxnX1`IrV&usNfl6is{H4xCk`DK}5C_pl`h*<}6 z*mmX2-6u%qDPmw;3^x8B&xz^~1FsICZ}I4}21_fXf1elii1`U}4p0)6_!7j%^vpBF zXo4L2v5nO24kYs&F?j7Re)wUExTOIxuuU+nWcHh4J#9qH-`mxM80hPuhf{s!Jw;zM zBW3}t2&Au<)x}AjTM&ciPMD2+JIS;n2J1X^T-Sz}zsKq?5aR@Nf#dL;(bfZGUG0d$ zvHGy$JJ3XM=#T#DK#Vpx3RB7X%dI5y5;1>|)jJXM_jYw5=I=Iqg_wv5btnxo!&Ag9 zum7R0Zp18}lrweA{{}H|1&96K*Zq2sY17%^{b2YUeewu71P_P1Y4P^u3W};MMg1b$#&xF>o|O`#f`Bv6_@KfEchC zqcrvP#Ye;x0s`tx6~8!z4|*C)gjfglR%(;jgXgzezaALDrlG3@|= zbdMNBRr;5@ZW zJm*L<-~NFaLCoh#Inz!XfLr6>&>w9dMa=t2=I0`jGi;7R6(#Ap&JXB;s?fB_p6 z0i)%&NCplG@SZ0qhbeW#CNR|?{rlQPMT{&WD3l{B=B1Mi{5_1rLL?)muk`l*5V`S-?R1 zEFIwlVHdrenTWw{pL*?{g_uYn1Nz?xe!g;24jW>?f{mCX5;t^6h8;0a0RvN}2h%r_ znT?paKus9icv_sFLoyr_3@C@K;j6ixOEPo*f#F2Vj7d3DKXZY<1w7T?nEJgh=KTZ1 zg%~&oq0UB%3qW{6-xu77f$wy|cWcU#S{VFT?QAuc@VqOR!hGSCaOmX2vQqE$;{JmXE5CiQ4+s^y7 zO_G!&h!`A4X=cB4AQ>UVJOnw^S%BeiG|31f23(LMAMU5bG{rp!5yU`!pd2=X+fk$( z_!~grZ#7KHdDS{rN-|=I0RsZ1m22OwBAKO#fpZG5cYdFzGKl$m3@M8k z8889mz}a)QgjJDprXrpPJ|wdOF$%CA@bfg=>K@6gM9d{n4mKz?mK}#kMiVj6k3oiqH*1P` zObam_pd2Pu&#CT9Xd^~_0-^ZjsCbff=^(~%lG&>j4^*SKp)O+J>I40T?^Cl6B%_BI z7)`--C&QP?m1Oi0!#P>k@M(T91nBEpg_vT%z>?#6{wyT38Zn)da)QAhEhQQF*8?VE zS}145*G%B@>FY8?j08Lkl3v5BW|CQh7%@-|vF_{YVEEI^F+vRP3oCnO5CYRP#)!dv z@nU}QCXz8hOd>cHo-G!072MLMmjmxk)2R8A`UolW>?0X7#MA=@#$@LmK5CPUIbw__ z<-{c936YG&AIwgs(LRz{ix?lMCP+V>4YrevC1T(xf<7v-M}G&&SRn>X7^L&t0J{#7 zS%;Xvx62waP%G%8?VI$bnD6TmgMEu>UX?6a*9OGc0~s*w7fFHbH(5h68xezJ0AB&!DdwOZV&K{h{aEIHjxbWrrir>HnKvV!7LklSV)!N* zyKkdYtQQW5=>+w_xdjWSkHa404zZmF1@x^UjEYcS~Se zqhke@Ot|y=n(Oipb!|pW1<2u;zqCPo4k^bKF`=Lwwu?>f;S_Uc3t~2aanq-rsw?8A3&^5uX7k;;P?R>l;CQS z3X%y&3?8d#OIb5WCIT@qW`T(>S*MO<_96y2CX^cY>;_#+uTLamz#vBHc%w47%%W%D z759I?-(;Q9K1IA5g%~>^1&%|X3(p^sa`q!eZK5iQ`p6!z?tnvo^l3C=@O|2>n`|pc z<^W>g9cH-ZS`{b7lXV?Lj6Nub`s8#EPjSr{gBa6EX3gpKQ?xx6F<>D|Iq`@A0~DnN^}oK8OafvgCz&K0VG~g6~Nt2{FQxjPF1PFcZDbhYF@M+jIAU-des5_RKUr5MV&L3?q?eP67(B+}Q@2gA#+^V+B{&sw zUbKcO#^FiCz%dVN@V$F#3g4TD7@0}tY_HuE^F1Fi8vz6R-tejCOH$_o#Qa_7Ld1+r z${G0R1Vqxey$CUQUPN4Q93q)w#9*Dvg-nl<%qhfx#vq+bZR~H8%;|rq>kML~fgGsm zk@t2BNI4~l`TICLix~KH2Hul#_b{8n*PTNQp6`K+$M2DKokt9O!;lTgsax^x3&~tS z3_Bw#6Ua4G`8&JJCeDK7+@5X%Hn_Tz&cPqlfkPxyj+iBra+*toDoN%JVmv10TyZljAsKizM5DrS z3RBkC_%5dFP_TR8>2b%C%u~dq0S2axp1IB>Q-_#upd9w;VDxz%lBq{bHz91u>u_k*3N*l2i0)D`LO^ zMd{sj@Xv zfPw3`K>T7Lj$Y17#6bTHHYiG>Ir~Yb6EV=Yz}U}E{MJU2=|T(`e8`5wj@20?^9nIB zKm{mg@o~PZB=Z_EupgkNQ^$whhyjBS>0GOSnTwS31~D{H(PF^WidRXIOb=o_Ku72S zCa^o>0?E8ZOaf2__Qi%Ii$s!nhZtet5Woc!MJT>Ph-7*ZGYgc%6n9S@R0&)7`bWBe4BKLhohGe={%sKQb?o@h$|guO{2F%)g&k$ao7BnWVp_AL7rvMkYRw z=lwrB`39LG<}kf&O6d;od0f0j##^8mSD)%rM*F+oA!8pGwaaAO?9Z6f6ufUSbwBMM zcf_ADzv|-u^*cCYrU<}dH-=CK@q z@SmssnS{t>_P%bmdiA<^m&X6jPa(7|qbn1R@ zb9l>C-Y)-pF47`X&cmjw@}*PWt5!@9ecf!MSLc1;&!k7juIE1zrhd=kGy^hr zJ%@c(Jg0v@=H4na#Ljci11aCLRx=@EuB+Hi#{1U4pUlYEHMTCKn77OSjw=f?_H|0- z-AQKoGg*=G76i7A>$1J)c(NhWgqf~yAHL__FFP_%y^Qydz}fKc^ZC1SAY)#?o5xq% zW_$MeGdYp*CJtMMUF|>dXL6}b#l*wBTl@cxJvTC0xu4wY`WEzO@*rc@q1o<_8sWW! z`tN@7B2(A^nGx?D57BRM;LSiNGXFfzGIWwhWRC~`gJU=p-nc4Q&`__B` zm5Ipmpq#%e44F^8{g^d>w?h7m{!Bq+ye9yRYk9*d-tEAD$6iP>UM#TTj}IFAGlh}q z=&7bF=Jvzq{h1=j*mXGhR!Z*{=D%GW3G-&TCdA&@BiFI4P@d5BY`BNi@)dj z-TXZn_q(&+|JjUM$e7pE=3IPnxZeo>@zh4fd&3ml`@a`i2bmsT!ds+)Cz;c3^6#fE zG8?_Gn|Z$aOIPo0`2Vh-ddQf267!V~M+RQ< zen!JP{{1vS#``a9bI)z?mcW0Hry(-GF*B(_>7K!(H^BUiP;krOji^n>h=^XjBNOv) z^RoxR&1B3LJNQ4|zbr{jl0L+ed?e{WhW6>vrsLqQ{XHcRE}62-?Dt4;3=K%)3h77^ zPslKmoKdVbnIw;p`6Ri7n0NfmmRpE4+d(_CTAHc^OqJeVzEh&{sQB#Ar{{AUl6ostIfN4Qdh_{lKMjCk<=5ilBAZ910=OW>?nRAsUzeLNev+{Nva8nW8PBqw(22v zKbc4>3o+lpHCvSso2gCGTu5t@Z-n$CsU>6*NmU^WNWSyVPVii8AlWTsFUcMu$4Rye zxj?c*$e$!Tg}fu#DkMpa0JdL*q$jx`Bsa|^vdgogV9eJ^z7_J2Uy> zcqy55Bp=AiG@sWu+Z)N0BZ(!MMkH?~(~TsCWQLMN7cz?^rjV5+r({2SNlps+h2)Ho zyCi3Y;G59iF&_|;(mY*z+aV!&NRA09MRHn5O_HC4bR^j?WF*OtLS~bk6SAD-ppac8 zKL|NPa>65_IM(YVM}<5hIW8osxlQr5BSKP;92QcLGBHj?xgvY#YE$SIQHLN1Z?74jF!Xd!P%`UpwH+s2+ka+8b_Qkm$w(o`NCpVGKr%+i9g@Kwi4ri|JCa^P zlJO>nh6t%Z^0AP{BqM}$C;3Ro2$Hozrjo1^vVdg0kZmMugnUo3LCA5EjY57S z$?UDw;7IS2WEJw3B%6@raRb=03&}>3MM!CqOhW3Aw3PNXBrSyWA!#LK6v-{w&oq+T zLKc$T5wd~ghLFP~H-+3FDJ0}RNl_thND2#y6AwcV6cLh+WT_l;E|O(Jij$NRQkkT@ zkcK2_goKl%71Ebvp|pQYvPj4@lCDC&AbBKYImu%o+ew}Y*-!GXkTWDtgk}X1hA(+4z}8SmLXw3-Qj;tel9gnUko+V|gp?#HE2K6_ z86j;*;>$7jB}pJ;49O57vq**tSx+)p$bOPxLQatk7jl)PwH(hqlD0x#le7_%Fi`+o zD%nqZk`zMnk|YySf+UTQ|B)mY(w-!}kU=ErgiIyLC}aUi1|e%nQVZEdl2XVClC(nZ zlH?ciFG&F*(Gv&9UQkGKk}x5eNnQvEBY7^QJV{cS)p{g#g|sFa2g^K~diL&s`na;6 z9?aAeYdFbQLMD<_6!Iy_WZBO`lJP<|lKd@?oo`6yN#+1aJP=Pp9>kaPtxU442F zGSR??GKvz+d?KV0$pW$3ckJ53SQS9bzv?ivRY+TsFNH*qWD2!oA4QT;$YhetLOv%c zE@U}LF(DgCN(lLuq=t|qB-MqSC8;UoGD&hFf03jU@`5C`kmyOx40!V`Br!<}AsI*# z3du|Ip^y?JS%g$2DI%mHNq!;WBsqojA}J|k7)ezj6G^27ypX?1QVDrU5+)>O z^57g+7Ltr4wUDeN1%(tMsUoBzNg5#yNeT(+NRn2_K$5~jCXmDxvVi1bh`lCkB$+7W z0Lc|0=SeOJxj}MS$TO1Pg~Uh^z;;1M8j`C*vXlHKB#dN|ka8qbh14OLAfzS96d@5L zp9mREGFiwRk{d!+lS~(~hvbfs(P0NDY#CLd@SRHrp2=_EFG>WUi2LB!3E- zOA+VPp+a7gyq5jMN*%!VMo3DMw?cA~JQHGm2aDOBhuCq| zBzY;MEy;Z$ACvqmWERN_AuC8;3E4yPK*$x6M?xNuJQfl)O#oX98GAgEmO@gJlopbg zq>_+|BvphoA}KDU9Z6Fmy-8{a8BS7G$Rv{5LgtWE5VD-4gph3{&4m0wQd7tol5#?> zk<=1me&d1J$_oie8zdEl#3QLLBsEE0AvsCP2q{WZRY*0GQbHP&loZmDq`r{;B+Z44 zBKevBv!iM{Hzj^nPdfsx$ExHF#@;v z=Oj~tnRn7vnPh>GMkHSe=}eMDo=*pmjGf4s=`$=*LIZIMa zj^`Rl9U%`$8VY$wQcp;{^uZZxEF>*SBOwJznh2>*GFnJOlCeVCklc}1k=;oC5;B0~ zwvcfoe+rpR@{#O$Ims9y+etnaa+qXM}B4M`WLQa#c6LO7YwU8$y>xIO~8r;tsA?Zoh3MoLc zN=S8*tRZ&nEl6?*=|z%3$P|){LY9zZ67mg6W+6Y3WD#oB-w=|%ND?vQ%E6_ z4~0}A2@}$cB$tpuB)Nr5CCMXX8A)Ct-;v}Ka+)N+kUJy=goI=dU@IsjJxOsP1xZQ? zsYX&rNEedALPnAl5i*ygsE{or#e^IsDIw$!l9EE+l9U#bE=K@c19_x;ND@cZPYIGQ zgj6Q^S@u(pWR_&wlgtz{gyd5pQ%F7&vV`PwA=^o23pqxTNXTy_35EPkl32(qk|aXn z(eIdV){4V4M z$weVgNv;a{AXjjtSA?V@xg;bf$z>tsNn*)aZb0&ZkS-*#g$yByBjihxE%LmxiDZM2 z10)-T{7SN3i1}T(RO zhlOk+IV5B+$&W(LkQ^6sgXEZyMNnq17kyj$rkPv>Tbj)Y2aC_G7kuK2pm^y7|a(ADQMO zU-`&ZA35$Lw|(TTkHpREMjsqS1|KQvBUOE*nUD1Mkx4%CrH`!lkz+pcmyg8G_uo-u z^O5pC(#A)I`N%9ES?42P`^Zrrx#lA;eI)LO{~bjZA1Ur5HGQOwkM#4AnLe_^M~?W& zMIZUcM*{i(JBp+}lEX(T`A7>N>Fy)Ld}OhY?DCOceB=SiaqrO`io=gmAUKK>LXwaK zuM*~~S$(9ikCgL~x<1l|WS(>lA~`Qtn<*sAC9{lVrI6hut3cWe>e;kNVh>#j2hlMmFIVPkF$&W$? zk*pRngJhqO#U%TMd`t35p3M)Dd>3M_>SjAjvRlYilD$Iik^CU!HAx2{9~2B=>m(!@ z$xq(#1iLbmEEZCVWRZ|YBuj+!Ac^os5nP!gN%{(zO43uv5|SQ5_LB4ya*Sk5l9Qy5kg_BLg)|`PCZre103pLk_Q-5ZCiz~-LXy2gwvqhc zkx(4$NskY}Tat31;4vzGikd!3nWIs7c&I&0(vPSk?gJiB`T9JGqqz}nX zu_lmg7qWolYav@nb_h94@|}?LB)f&&BiZVa;QT}{5*+C^A?ZlI6;hbw8zD7Fb_r=m zvdkmFH9weSsgP+TKMPqx@{5q|B<84s``Pa!Cw%0JkKFT-cRrG^XmISVE1i$z^pRpd zQrSo9`A91t>E$ECd}NA`Ebx(yKC<6O&XF|0JhvGX-mhQB;HQ|}Gumxt63V%FO_Ekf z{9?fwD=j29NmU^wNva8{PEuV+E0P*QB1q~8nL<)m$VQSWFtuhA*V?y3VBVEUPy{k!BJ!oQi>#>koqJA zg!Ce*BxEc}Wg$yQst7qk@}ZDxB>9Delnx$GJs}B6QVU5>QdmdE4PYLd1>z9nfVe8VhMk(o9G%l5Rpq zk+c-@1<6by>qzWR#HXBtwN%AekhjHOW{ZACY__ zJ+eVHKh+RzstlUyf^j!s(~eVjUC(Db+{#bEgFdwwzu=Ky_1gp z6tpC|C1HG%#{2CJ%5&RJ5xPT4_AEC~Eyi9NtTZ#x@u%-t=KvG*5ZwFn`04u@MJ zM>yINc@*@qq^LzbEh%XCGs+Ta?`BDHyXFU5A|vf(NnyL^@s2hBExR9i^ZT|X1q*T*cPz1|B5=c! zf(5-pG{61#rXw7x5IbRkLN+6-x2PqODQt;k%R( z#u9sJ38b||tcB8^-(y$3i|Qhegqr7qLixSJyn@{d^pm6teH3 z$)06}Kk|+MW0yzMV@qWHJhMdR`ClJ-YKffFCzceoT1O%F5!cQV8wqr_jR z7auX_4C9i=;3m6T>_a)Q*^)x`@xH~90`>^6+5O-QdQO1?}m%=N(gUq;~4d+EEm=h}#-46!w+}lS2 zkKmDl-Ha!}o-t#yA`_H<6`7!FO=N;+>K%%hE98Df%<-IzOv3Dpnd3pb+%*lc#6|)` zEh%WxFiVQsu@ARIt{bT=kt=@+OXP8p%#xyZ#?n|)z&;ryw?v*R(+ja@Ih`eP1~d9d z1|LZ+#4gs9mV_1OQ1e?-(2lf#B^CqT!$t%RpPbwb?6Jm!^*%JGJ3#9guf|kf^RIx;kCykF35@Ng3`bc3*Wc^&R zvmw`(OP0uNT(-pC8V9CWBF|`_SR(hLcPx?p-1d>1mdF{rZb_KEYJF-+K|9YgEfH&$ zB{GU9mPq?kOJwX1Es;@tVTtT{t|f9je_A4$cb3T63AL+EGOvA^H$L*#5_>reJoAy~ zmdLnX`pA7tWIzA<$O}tkKd*e`fhC3Pb>oqbJhnt$MV7W>mwU)cmdI?>ute_t%330s znwH43RXI!Km@8T$&meUzk=LG8Es_0{vP8~%NlWDV+`tk!!h14OJFS&%rl>ujmA=es zA$C2lvZRP5D=d-qlf*twh2*hB##PP|nX&jjlHErV_(%>*t|`ktjYAYKc5sJ+{Xq*jasTi99N!+v6!}&qWMN3fKqp8?o$yert(5mQP#DmIuyQQpmQS6;g=jw6P^_ z^;#l#r%f%9*TPZk<15TQ;6p7bWKU02OY95ZKr~BiB(TD+UOTM7QcL8qv)B@`mivf# zEr-XKWY$mK9xdVA1 z#Fjm@#Dc&-mSBF$d8^>QC30OAVlQlg-z8(G)x6flDCCvYRZHY}E?Ht1OW?94vNmGL z{MhHy*p|r5$FZba`b%zy?cXt!@_L{R7(xyB}#kX-Q$*e$*1V`W+Es+YehJ zcio39k+J{iBgZWf>zE~S%m;9&W zYu>yg;z&_1)6W~b5ImorP{drYQ+s1~8FPd~6){KnSP^py-$o|58V~f|#ghHt-sX2N z*T*|1%otule-@eG*}{AT+GH??IA3OLLd+ln<|8FSu*AwmCRkBbA`_gQT8fwzRaX&n zzRVevJ!6HpP{bTdxFY7DJ1b%ix~C$Tc}2`Y4^hM%^oYm=SL1Ptm}8zCnV7=~%#2Km z7&OgWKLhO?7BCat&^s3c?93N1FL-i9CYZz7o@p}fF}Pk4Gd~9-6Rb@0ey~_L%L^1S zV>jx?483NuOT=J`)!Z!h1kqq zA@&Mj#s*8CFUqb%N) zWVc7~xWMb&vECdS5668T=qFP1P72&A<{=CHI7PGP`&5+->$@Bf+3AhFYG zW(7pP`&P~p8wq5$L|)67@xihK4WzNePGKO0C9oy%yVi>!tBcuGnabLSuL>-^Z%6RhJAd z;o*vymEA)TV-@nQht4v`Gbb{^Yftm6CmB3f9*InfnzPc@yBbRdcY~irCU{#tLCi=Q zd_rJcWP*3~b8%KNhsDh??~P@xe1kiL_Ye1ww>9!c5*p&^*lPAm(kOk1cTm{!ndRnf z$OQ8BaaLnkUWIqoyuS<6Jmz#~Ri}kaAaYj|SV?FtyO{hNXSJt=jOsGq$qNm!T_eh* z&ETvNw2)C<&0r;9*ThY2ia2XNEo4+zbJaCJ;gx>Q+DQu;)zt!)ox{_`55`X?b9j~( zGODYk>iT2Ir@5TsM)m3Ws*ksNsOA8s*WgcUpA?8Z%J@^BuhHl&uJ4!TD>upVGA)~t5 zsjew=>&J6e4_e5muJ*9(I&41cd>?0xpoNU;>Y%zZuc|%8S)b8DMs;^Ms=BMw7YH$ zTa|9EvkK8dMs@XsW#@3_#%^CFkTqY87BZ@gw(5iZ5M*Xd$Dz z%&QJJE_3a5)+AcUsII=guI17-j}|hjD?)WOt~Pp}v)0l=Ms=Cj`R+Nz%;5xChu_gc zMs@X9UAgP7{MA_}X(6M!2Kc%rO4n6d$f&M?s_SL*B^90Zf)+BWYY;4ZJ)D&%_k)Bo zhY5opu@4}lx(2JR;-j}+a#nU)$f&L%zOF>lRf-les%xm~y0>f8RA)7&g^cPN2FtE_ z^ZfO-boHi%jOrS$y4F=WoX%OZXd$DzKJs;Km#%HJkWpRclR9qAn=WUar-h8_8sY2O zAzd$MA)~rRs;&%^`<{1JvTDI=6f&x76fAQ+G+XxK2QxL3t}t52sIJkfYw+MVb)40J z7BZ@9jC6Vb2oz3UDw?zU(LzRbja6N1^S`R*tl6}XQC;I;*=z4-v)26Utev!wQC;Iz zSF7Kq0G_lg!Ws%xU^s49?Plae3hVujOzMCb)85XwYald&_YIaO@?LH#_I635Aw-1Y8WkKRM!;M)$GWh z)15Vk7BZ@9s_L3hvHg?0(zS&aGOBBu>Y6!f{{?5Ap@odErk-)xpSJVXl_)%CgRD)#l6 zW6ruw3mMfl2bNujOY%kHL2a8Bw^oRysxGOBB?>bm-3ZHa}_ zRfQHZs%xI=x)r@miLc9)2TB` zJ1b=^v!_4+8P&BImc6$zul4GL+G}qqTF9ubC93Pm_DU0+Ri73zs%xq0>e74K=(^I? zkrpzlYnkfG@U&+?XAPl+jOtnr%RauM>>0ADzI08Yg^cQ2p}NX_|KT`iEuw{t>RJga z^4h2;U0Z1(qqL#|O-X(6M!)~POYKkuwEw2)C<>tWf~m5tL+EAOnvw2)C<8&uck z6w7{bRv%i(sIHB$>~;RfNUg?Tu zzDeS3$f&LzVwtWhW8b}UR$5xfsIHx`B449^m97tIA)~s!R$a5dZQI#d6=@-(y1r3e z(?3XY{%7fGObZ#+^{wiPcQDaPXLX~6jOzLhmR<9c+pO;BtdD3Rqq=sfu9dg{XzZ+6 zw2)Ce?scGAk~$T9!&*%lUdm3mMh5Uv-)Ld1oaz-=Oz4WK`D=VwtZu>f803 zUD6ds3mMgQKrHVcfhJ88+;>)WTF9ubgRtzHKic}i+;63;4J~9;*CEw4^WEi-oHdXZ zGOFuGSoZlVZj?8d_sMIbDYTGLU58ayrPD*2I%_E{WK`D?Smt|qW=nDJ$FU#C^Vc`D zkWpPnRoB^?rO!F*3@v0-*D+Z39-waR{UL8;4*#TujOseBy5f)OlGItD^@7KZjOsce zmPwek5ktn6nievu>!euTKLX=xC++X7g0zrPU8i8#wP9Yvo|19ZpoNU;`bl-g{`Tlv zXLX~6jOscK%f5CnuVGJ0*CblVsID`rYtPdk_d078Eo4;JSv9WwFOwucBVC7RA)~s^ zsjm6C=f!Z=HCo81uAf!cF+-L(D^>mA+CWBiorh)D;jF4l zyC0CQVziJ^UB9ZX2JN@hcUCi6$f&Lhs;kP{U2l#_*AQCBsIK2s*Q-K#W;tsnEo4;J zMOX=f!w#7H`P0(1iWV}e>vz@FAnk^y&e}^08P#Eo4;JWz`i{ zrQI24{YwiO)pZ4yeO?|CGtppYrTAZPxX7rktE%h3yMfu9RgxAms_UBS`nl=8QqF2k z3mMgQU3EPwy=bAcM$tk>b^Rfh8H2eOJtuRxj21Gg>xNj~KLRz%jVb1=U9^xk%zvRM%}-=6sp&Ax4ezQ{x|`D?tMfc^fjS>yGM* zJ)_KFXXT@XjOw~8U1qQ5dU!&*YSKbRb^WQjqBY9X+ga^tA)~tff@SB>d_U!=bPc72 zjOzMZb(#0foi&RVGOFvI>RP($!js-|53rgRGOFtz)fM}|FY%rABQ0c9*L|_f9GZ35 zUAk`2LPm8x5X<{Vpw5R!$~!A+L$jwq02$Tw5SD%Z>XQ1e6#b z&MHF-8P)X|mc1UD=j90LYDxuX*;#XFA)~tfg=NRJx!rHYMoZT^TF9ub=c?;n-&qr#b%+)+s_TVVW?Z{- zZ7$qLx~|YdMs>Xu%lk*by#8|5Yg)*tu2-<^<7?}q{Ox;6SBgfaKM+7hb-h+yVZ}Zk z=&a(jkWpQ4U?uVPXpXSmizNr0)r=N0s_U)lib#?uuCs>GLPmAHQ(c{YYP#N83uqyu zx&l$XW0TL@9Lu(-v9tElLPm9kz%pyYjO(knmA5(T8ZBg0R}|GX{)hGRofX>H+mW{+ zqq;&>*X1)gPdO_qEo4+zRMj==%)!des!9tP)fEkvT^r_lI7-$=S6axZuIQ@kr)YEj zan=Z0$f&Lus>^);tDAIvMhh9$6;pM+%R02Kv)0l=MsWZbh z?(JWY(^*$(A)~rt`?>~7*IQc1sIEAw>u|Lkjh&UeNpNi-qq^eyy2eV^hqRDUUGY?x z`Amhgs?$P7b;Va*=H6zgbhV>}jOt3Dx{@D1zusAcX(6M!68gG^N!L_b$f&MFs_W2& zGew-Wh88laE3vO@q;wskg^cP-;_GtO@3fFnT}fft=aj938gv;TT@Ps?qq>r*u6OaL z<#ASwropv=jOt46>l!0nX=ov%x>BgFe5oeybXGxH$f&NAurc)s^zZxu(uqN(&j)l~r|3U;JXevkuTgMs;OVUDe)wTFO~BX(6M!vcs}#BV>4{ zCeDi9JUF$;sIDBUE8nyvq0Y)q3mMgw6IKSEuWjpVEf^x_s~Rn2R97z5^}o2KMmnnl zEo4+zZdm4gna#Y``&hb0&_YIaqD{3xXkOXkEH89Eo4+zezDBsYtk39S2!!S`GGZWLq>HKfR)Aj znt5#=rTVj}Yo#k2Eo4+znCeP4aeaDcm7;}=>M97!-m{tK<#p0kpB6Hz%Y1_0-S?V% z0B3cjg^cPd3@Zc2^+Ah5bJk1ONLt9Kt|F?d^4@sCSaxmvyKeTLHPW@4 z7BZ@ME|fF2}o^WrK9xpoNU;Dxtc%?90^IS}Wb-qd;dJER)Cp&0q=k&?Dh(_0+Q=&Jr4*rsjOr?*y3F@RomHC_GODXA zEOXs3Yrg5JS~s#uS9@B>sIGFVtIn{DrL)pclUiHFYm zjutYit0Js4=CpWQlXWB4WRb4Zw2)Cj5ofR99tK_S*aT_&38cNmsm9 z!6QIMbyZPaW)7W|ofa~xt12w}_{v|sP_&k^4$IO)Ms-zFU0X^-o8hdcw2)C<)nVCn zShCW?BQ2z>4=rR=R}IxQ;e+0XoHdCSGODX4EPKB(vBIPg&RR?h8P!!wb)DI{^QE)C zqlJv>s;#>IcjRq5XZ=hI8P!!sb^V#5>rrRjr-h8_s;jydH%{5sSs%0xt_@^VS3TAB z?C*J_oRygtGODXSEPHPg{ZW~I&MHj{8P)Ya)m5Bld4Y9v))+1WTsIF$P?3!N@_4+Pn#cC5=8_1}x=Blga;ELCr zm4y~Es;dPoyEY0|YMIelWoRLzx>~BP=G~v)a8^@V$f&MXu(EgqFwZFw>EgG$CD+3U zTF9ub)~ajhsM)n)E&oVAS>GO8;aRtAo% zUC+;!+>x&1w2)CknGUsIK;~?6ue2AKs9z7qpO3T^&@H`57N)rEcpT zxVIsrx;nx#&z0tUojh%rwQUP2fQ;(u49lD^^GK=k zGR1snjcMy4Z$n0Pbx~ct&Ln>7tW|9x1&~o)U18ZZ-=uA|Sk5{@3mMhbO?547v3#+! z9??QZb#+(cI<>NKTW2K?4;~>hs;h_Un%nl;X=jz9g^cRzDVEvqjqsm)7LxN7P74{; z)k`ch^ZoW0z3D9bleWmHuHIsqF7x`UsC12I7c#1=k65NF(D2TW&iaxTGODYuSVl7A zDlA=_X(6M!BE+)ea@Jv5$f&MdM`*!FSHeN(&j)H3*hj^JX)jkzOWU#b_a;x(2JRexF~- zvZ>&Wu5guTF9ubaj-IY0|@p0^XOuw#m?$V3mMfl zUUfCwusMdaM$+A)~sc z!m{ho+}k{owNZc;GOBBu>iX^U+0UF+g%&cZYr3!Nv2-=3g^cQ&p}Nd_4$g|8g^cQ& z>FatXU6W`bqq=6Pu5Jrc<#5(lw2)CwYYwc)YvYM@#p@VcQOKySFI3m0;~#}P zD-$hbRM%Ws_S*Y*s(4#FN>^c8$f&M)s;hndG#i~&n-(&Gd;@#;=-;jf4thQ;@4v96 z{A%gWpw-69^z0C%$fzUy5|*6}^J(XHa)ce&g^W7F1+e0HI}P>z(`EM2Ma~*Q3mMh* zm00Fz%pFk&>6%Lm8P&B=EYtN-gA?PNwT%`ss%w#0wkuq^PSQd~buAXlb~)=WTF9ub zC9v$fbLOW_J4;uLPNqK)Kt^>fRbBV)bgkj6EVPhOUCVr3U8JiVEo4;Ja$lFT+R#Eq zb*)fcof;1--buPXqJ@m=TB*89jp;MMS@UQiqq;$f&M0u*|DbbC#=@ozdJ`muMlQy4I?$afg5X-C2)lA)~t1!LrY=$u>QG>8u!? z&C2lp)`-cduJx*GMBI2Cot1_bGOB9>EIWthS#Pte{Zl+QjXAz*)c1LPmA%fMu^6tv8ImeoY=e?maGF^2_cl^;=%V{B_x^}Cs*TY7AiQm*eaGxh`Ai?Qm9FSry?Sp$Ms@8| zUEx`O8sn@Cw2)C<`_;If#i-G!m2?%Sg^cR@L3Nq$E;*|qEo4;J0bf^Z>FPxb8P#=A zcX^+7cGe_X$f&MEzOFXXwUibzs_RG9wLV9cQ_k8$3mMgQ7?!!yGi&4Nlu4)NO4qNn zkWpPnRG0a5y0iYKg^cPt3d>wK%$mO)^XqNSdPfTx)pbmDrC$B$kh79>^LFHI$f&O4 zuUy&!a}#Hkp@odA9vO_w2)C<=fv`c6*!Rd+hh0SwN-FDSqo>y>TZtO`woH0sIFgO**P4aad~5BrKg3A>bju1 z>cwgKhqDUNLPmA{CYCvtnaxh8DJ%Cj)oCH4x-N=k=Ft2mLua+8g^cR@9hQB!XUg!g zQJgiL7BZ^qlIr@sajLt{nnMd2)pZ$`JzuM;?il8*EwqqPT~}0Bni+?;IqL*1WK`Ex zSoVD7-&MPwv+mGBMs;0NUCVl=$nC7q;LF?qGOFvk>WcsAflr;4jutYi>krkne_hlK z&MHm|8P#XBd4QU~xx^Aj2^BX6e)r%G~s_T|?;W~e=O)Y0lpoNU; zx~;lWSKeIASxaakqq^?Evga$}vumfFwVM_)s_U-m3X8j=r?Y;gg^cR@Q!F!w=BI<> z%XR)SEo4;JUt*crNHZ{PbZ5owY4#KdAfvkeh7~jT<$!sABY|{fqlJv>x~IB278>8$ zS>-Ge$I;9E4VLYRM#_DX3d+;{DfL6>B>qA8P)Z#>N5Ae&MHX@8P)Y1 zmR*PDlTIn5s~#<6RM!jDRX6FzCeG?a3mMh*5|+Krmup@9A7>4tg^cQYrMl`xyn5rT zS+tN*U9VNwPjR+%bk=HG$f&M2s;lO<{Ux0BJuPHZ*IU&Uc)4YUv(D2(Ms>YYUDXnI zAMC7uXd$Dz%uQ2hh`k=JY(0C7v!eA5t{7xgmw761pPtQ8F3C1$rJ;q4>M{$#b?y3M zT_tA~q=k&?GQUv4buIjDe-UTZpoNU;imJMnzIz^NZG_W8Ms-C~T`}{VIP1Cw(?Ujd zMTceAeD2n%k0p~eKb;mbsw;--O0+fpVrMO*g^cQoDdRHd=Ir)22h&K`*R+sPT_30} z^OKU!`jr+ksw);O`+n55wU_cb>t9;PsIJ(mYklXse>p2fpWuo@Ms>xJahYd5^V?&b zRh$+wsw=MQ$`xfsq^{<)kWpRn)VSi*KKs~p4WosO>WZ(rk__u#!C7C@LPm8Zka3xj z*WCJGR&qICyJ;b#x)Q1`b06ibUuYqtx)Q<4;Psd}?2vcb*UtKf7BZ?UvFggO^~e!t z#q8_t$lH)nT}fnIrpw$%IV%$_WK>sD)wN_vy9drHMGG0#l}x(Kv6xR{q?b8tObZ#+ zm0We@%Rl0rvm$6AqqBkx^9d7Yt)+#G>PiL6K7Wm9U3a^) z4%0$Lb){BaF_$0y$yv8)A)~s?-)nK#-XEt&jpD565oTV4f73<3Kc7~0t=pNfiL#RGpkWpRPVA=cm=xO6O%`aVne!;0lMs;OZT?@*5lh|3wXd$Dz%wNR_ zu0yk5^H?q*UAbu?qq=gcu8;(?1~{t%Eo4+zF0o9P`95qx>1s*~8P%0rEOTWm|FZh0 z&gx4G8P$~smc0ispQ;Lzu1U0zQC)dem-*>MXDy(GjOxm#y3F^#lA4<>Y@28yqq;s+ zUFJPlXZ=VE8P%2F*EL1Pb%_=-s>}Q>D0k0hx}0^N7BZ?U%-3~Z#uexv93L{OtDx>G zcJ5neC8ULn`V>JSSl%r&w&UNe%l9R^B7cei8Fhq()e$~?l&ESlbL)vMBfF4MM_5E1 z;e8eEw8P!!xceR=j;;eSGkWpR5RhM~{om9F8(LzRbl~7$- zFSq*ISyN~sqq<7^y7EfbB3j6(u2QP2{7<_dIBPpCWK>savCJv@_)x7>sif-&Eo4+z z8L`Y2p!ZjoM>^{YEo4+zS+PvlfX-u^gh|&ETF9uba$=b-^D4kuu?Cnu1p>&ZuJU4; zubV4dW$8*!3mMf_K`hgCqWa%&omH3?GODYhSfmB zg^cQ|ESBjqb68Ni2GK%BbyX3|bnRLE;b3P?qlJv>sw$T0GILl(x|Y#GMs-ya%XDS9 zGB<&Z%UQK0BBzb{gqAO$!;-RYP@|?|?h&Pg=;Ru9{+*ajj1IZfPOuiZakJ z?{$dDsIFRK**SDpYFfysuG+9NV4vQ*lBHVrN-JFjX(6M!>ZmUByY8J;ixx7ft1c{i zSJ|cX?FNOVs{<`$R98LK)qVN!GS2#l7BZ@r})wQY4kzLNZLJJwy)kuxYJbzu5uE(^H zQC*Ey*NlT-cXw9YLBW%cjOuEly38C-k*;jCkWpPtRhOAVXH}wwjOuCzEAkwEB3S`&Ld3^maS_hcu0wOa zZcEoeTF9ub)~f5_SN&@_>k2JoR972VW)98PAWFinH>K-2Eo4+zTh$fo?WUB@N;o*U zFJx3#xaw;Dv_Zk^(v_1IGODYc>RLHET|#G7p@odK8gsrrm9BQQkWpP7#Ionh zStDs7qq;iExXfd@$GFk^XG+%sTF9ubPO7U&=_hyHe^&+H`Qf+Cx)|9(LzRb zb%$lw;pFwjK6@%%`Dh`dx_YRt)x{Gea#l53$f&NKu<{275Qvp-NrH#c6;2Bo)zwRN zEjV)K7iSHng^cRz4J+~-ej#16Xd$Dz`lv25ht66<3mMhb7nYsFJmd4;nk!xVXd$Dz zB2<_8xf^F)riF~^>IW+a=kRix!nyyHu9visQCw1*>$XT^$A)~qm!7_7b)_kf*g|~%9@esC7w2)C-DN3&bmzt8PzpGb(!<^ zuXM#39-LZaRM$k+WzLtga?nCXbxne0&sW@W^-H~wu8OpfQC**?F7q7(XSJb)jOv=K z#%0deE9n|a3mMflMRnb|yZ*Yf=Fvh%bxrkkJ&>+%Xd$Dzrl~ITcT}Bqofa~xYdS3Z zTsd%P>AxRISFDeM=L;FtHA8jXh?o$|S(#}eqq=6Qt|FI?k9;g$C21j}x@M`aYBd^c za#j;s$f&MQVcE5jZe-WzrR6#wK?@nx^_l9rm1l2dXHBDpjOv;Vs}QdnbL+LbR7tv4 z(?UjdeXhF3<*b?4SwGT3Ms>}Bm4RLPMvXsGL%MFzLPm9cp}MvW=pMycFK8j7y5_>N z_ZyFE=UZD=y5fEuJOpG^*F4qL>epTWb5RJiQu0!)3pOVs5jutYiYnAFUzw5(UO=uybx>mzV6C6Nb(T91fH;}HLw2)Cl0eYsIIlJGO#QC-u;#D$+dR{Eo4;JI@R?yJn+U@`)DDfy4J(8*A4UCz{)bN zi?onYT^m%_(PRlyI_nuNWK`EiSmxSm?&mMPxqNt~j4Q#&;Bb*qU7J+b`92G~IV(3U zWK`E?Saxlg$MS0Fs!R(R)wM-+MVwha!&#kaA)~ss`npz0*F;*#sIG0Q>+<*Gsyk~n zEo4;Jc38y%!L38YgWD^l>j*7mRM!sGwfxzc($2a=3mMh5(>Japp&r5(eN^y&kx^Y= ztFB46CPi^p8d}Jxu5ZLL`~7WR;y!t#s{k!zRM)p+nQN5!K9RGk(n3aceFw{~`6!eB zOjb_1TGB#Bb?s7J`RcUqCdP@r# z)%Al|W^JS>HnDRK=}I=*Fz@|blTlp<#4>Bc{H-x(eMk!#)pZb-y%(J^aYnRiay_g{ z3mMgQNOhU><*Zh;kWpPfs;;M3Z=J6rT@kd9QC){s*Tuc9Dm!ZuEo4;J5mo_fBRM&CU72da4C1?FX z3mMgQ!q?SUx?a#iMs=O^bvY}+nBXKKqq&dls<(##R7BZ^qXJ6MC8P_pd$f&Mgd|l4^gBCKX>pU!bzS4y^O7XFDy`+VV>iSi6 zneTr&E9uzatRSPhE~u_z?aFT$AzdHRLPmA{rn=1c0-RNs7BZ^qA}o82O1U<}m!qVs z7cFE|*YB#!{4FGBO{Rs6>be9gi#O~L?>{LrZ!0%ax>nLcMs;0QUE@1nOYW=_w2)C< zSHv>2yt;Y4e=f;7d_)Tw)pb>@P|q41{o0?-iaXBiDG)$LbzOsH*SvWj`?_>xr-h8_ zx~{rT6n)U#S>5qSozQNoi{Vza`eg=&N@yD8P#=1b)6q^ca5|DriF~^ zx~sb8tnJyvS#idja~udDqq_c7T@@E>?BlFFw2)C^+H{Rf`rfs_Spn zm3Z#pNaN~33mMgQPj$V@HZqCpnnDX1)%B0+`aMg{HqKf{3mMgQU%Jd}nb&&HWo;a% zg^cQYpt{W8hTx*n;noF{QJ#4h|^!{hkm5UZKs_TjBI@j&e9A}lKg^cQY3d`QxjHtP0-+k$7Knoew^-Oim z{%7JMXZ4_kjOzMVb(!Dx^HRFT(n3acJy%`5j~1!wti`mDQC%;5T`#0-H!WmT*Gttk zKINOO&N@#E8P)X)mc1UDzh4$-eU?nt2`}aRM$IL_S$QnQ=&>&OIpaNu0V8eJsFvCLKUqanp_IqM89 zWK>r)u}s&J%sHw?k*>S6kWpRH#WG!ikJBu3R>&lS0s&-HR}8Vt*Uh*>r7Hz3WK>s7 zvFx~Zd3;r+g^cQorMh}=%k_t|+R;Krb;b5|J&>;9w2)C< zaa5Q2JH^hLLkk(z6<2kc$JZ0-+Dr=>)fG>5nZIe`tmCwhQC;y>SMNs!zIiBJw`d`w zx)P|atesTSoR+Kr-O~l zzml$cw2)CPq=k&?N(#%~v-LidVy?3$(LzRbB~x7+k0zewtd+EoQC-Pl z+54z?V;bLb)w4)%wVd?_Eo4+zN;R(KmDc>>tdPmUvy6=DN~OBeO!~Bn zv(nQ-Ms=lDT{XTO`P^BhX(6M!(x|R!1&Z`{Rts9lsIIiCYh=2x(ast|3mMgwPIZ0$ zTaC2NnnMd2)s-IB`_I>QTF9ub45};6&9RkS*I8P~sIH7+nR8>Vy{~1>Kct0>>dGXR zx%QgBL+7ldQ-Wt18P$~;R?Og+1Lpfg(d9Z{j21GgD~sy7w`dL0N4n5A+$XQ>|LPm9Ehh-nji}Eb}*;%`2A)~r-sIJ9LkIZn^by~=% zuAHhX&hS1nofUIxaB7iJUAa_Ot{fdEIx8P7WK>sfSau!eO4;{sXEmgSjOxmxx}v^| z+1Ob_X(6M!@``1~@YTqWOmAczE~15u>dGgUS%>*MRVnVQ-L#NVT_3`-uN_8hNtWlW zbX}l@jOxm-x>ml9vfWwFXd$Dz3P_hZ!d*>=zjIciX=bc}05Ym8Om(##)HcFd`Dr1e zx(dRw=c{J2Msb`~hZZubtB~qyoN>|sXZ4_kjOr>ZU1kK=`{iGJS{`4Y&_YIa6;WLg z<7+o@)?!-7sIH>0>}%Lt{dSKzBV9XbA)~sAsjkhjw#IYTNm|ILuHvxl+8AGZ+NiVA zb%Pc%s;h+R`tC_+a%V-EZe}PDKt^?ygk@eYWA)BYImcP)X(6M!N~x~qJL1i7RvB8z zsIJnm?AmCOuHgn}wW5WL>MEnU9{l_In6rk{LPm9!g=Npz^_uxIHkLV@PYW54gw2)C<6;xO8Rps_L>m@B@R98h<_B!9JRCrNm zrJP~<0|8`IS0&x`-OS6*DnSbw)m0gmT^pPCHc#)Y7POF2T~$<9&Q8--I%_yBWK>sG zHLkx(T|MEf1+iQ~I>y6GjP74{;RUejJhp8U) zI^(QIw2)C<|5IIUN^g7ZtW>jt=L;Ft)j-B&*2d&}6)!uh0xe`zS3}j+qEP$o&gw=B z8P(MYmR*Ni&;L=`S+i&%qq-Wau7~MUb#>Oaw2)C?&mr0oSH==}kZ--$EqlJv>YOcDTUOd{^SygEvqqIIAx$WK>rxSauzzxp@AKv&PdxMs>ATT~9l7F7B)aw2)Crs|&PwoEaE&0Nx;m(?1x?$>byjv-$f&N4YFx<|b)N35GPICUU7b`{u157= zJF5{bWK>sY=`v#&ezn_Y=*2m+F$iS-;alMs@X+ad}mN z=G*S%k0x{Ym=-dstC#9ZQE+J*XC;_z_7n&pqq=&_xXkymhwohV?F#u`b{<;DsIES$ z%Y2^AS(RuZqq_RSN`fN^1d5l9XuVXrTF^p9bw#MIL?;qQbJhS_$f&M<(q+!q@(WoO zJ8K#(WK>sw)%C%n_EDU*nievuYXB^J-FTb5(k^EmpoNU;8mPK{I8Z;Mv#!uWMs*E> zW#6|kKeNAB=I|vgWK`E+)n&f#;H)H{2Tuqxs%wbqGM{N*E?s$PA)~s6sxI?43Y}G- z7BZ@9nCdd$Ct5FE{b?bix`wN+4t-w#?X2mvkWpP9`MTCf*J@hGsIHGyml>C{j?h9z zb&Y^!)`od}wNCru?ON%&Lkk(zHBxn%-?8AVD07163mMfl%Gb3@x>D0ZMs}R$SCU*Uspz-g^aQ$`>aep3mIiiffY4)fPu0xE|$;ivyf5NRG*c_XCb4k zX|Q6mYeM#+8?yNEAra-&}Si| ztXb*^TclmGAk1eWqpVM1*|pIu)};Bld=@gw`pnmr+h-x8tl2&*kIzCzS)aqQYvcKz zg2VFqEM$~5$7kj9S;(j>z!$LWv!40Mh5WG0V!6!6GBWB4Fc(%FFJtC0!{TwbQa%eAWi5mic^ww=S;#1Bk*}+;&q797i+xrRpM{LFmcWX< z4vYFMWR$hkXBG2V$f$L=3|8cISOS(=DXG6O{~ZV*qt@YaSdrJEvr5rIMjhb_SdrIZ z(2Beckx|x4SdrIZN#D4TQPwJ0k=J2qpM{K?jn%O1Y?$vM&XW6$mK+x{YBtuuva?}6 zZ{w^%w2)Ckt{$wb|G8r*vhYg^cRjqPh-UI8($~ zC21j}y0*eH_q}E_?|nUxu12(wQC-_qSB-9iS~#m0Eo4;Jc3Adx<&m^0hdh+7@wAXp zT|0DFnT20EYYi=ARM$>ek=Oh`(shCsGOFuq)n$IyqO)$&LPk9*zkwC`I)4{kk*@&A zs3ZIqRt9g@%{6gp*58xemm_@5E@adZey5Jm{Dnze3mMh5-`90Xx(?AoMs@w5x*l#D`JuBe(LzRb9T3Z$&yne({c~Bm z9@9cbbsZGT+y|JSh<8@v`DRbvcaKa)bsZARe0_PZo5Nzsb7dGUWK`FWVwtWKDVvON zRxMh{sIJ4X?5oj16Pi46R!3UMsIDWbD_Z(-XPh;X7BZ^qD6ACT(U~Ls_EO)%&YDjP z8P#=6bv>VVxW2P?&_YIa9arPJ{B7z;vvHahGOFu@>dG+flfPWo-?WfXT_<7Lcd?T6 zS$M};F~0PM>TSrVu2ZV(=QYzJS(#`dqq=@lU3Z_J>F&Bp(?UjdomO307nkhgtfsV( zQC(+L*OSMAL(b|)3mMgQR&{0mWcC(kO{0a3>N*F@tPQi7Pu<6sHNTn`GOFum)n$HC z(pmfe4`Js4CPneI@dHGH0Ywam0Tm;P5>x~ckR&QWK)|@}-R;4_-R*h1M-u<2m=$vl zsHm6~a|9I=2F!|z0YwxQ1x3u^tE#T<>UVa}Z=XlJseXU`cK7u3^z_WmDkU25dOuL? z#ZQZE7`#4GN;KfLBv9OYFM9HpH;ig}J?BJkLtqVfeIS%S!`_j;Ys~}UDV@EQ5)F8L z2wp4a57^nL!;}&Yczq<4Kd11jpP+R*D7F5)F8*0k7k}{%5ICbxMf_ zj+7sT^4I2VTequsRD7g}21@voP=4&?tDBd@k#dfDi3Uoz7D~v!?_ktCr9=Z>KMNJl zdlv<-_mvV2c&!7kuSVSbxlyZ?5)F9$5-9EmeExbdcs0Ax^$pR0*RO%%^A|rAY}9s2 zi3YrW3l!(eUM~f&Zc2#;ynYW9d-2oGMh#O+G~o3|pa>GL*Me82QlbH`KLf>HKi@F# zOQU8gB^vPhD^LW9*Q>$nI;BJdUVjIQy*6I`)$>L@ppz_aoRI>lCZ!Ufzc)g^Q zXu#{=K(QD9=7Le5C?y*3DrrVDkVbyQe&y;RvyJ*mDbaveBcc4t(mOZ2*v+UGH<3Mk zL<3%ph4LdC|HiIS?UfP@cr^j9m8YMui&6V4B^nq3))UHK(ZBU&lLH+Uj{u^95;hGb z8UN8fzRs0Wo24S2N#uRGtH6t%`;r9=ZQzkyKH8Rb*9_t(vx zSKRWVff8;QycpxRG`|++hhM9gXrP1}1&Zsn|7Jty8`Wrz6re;j;I*+(e(Zg4z@8^9 z4qjU;B^vN*1zy+AsC&k!Zc2#;yfzWa&ksM%d^+=*;59@k(SX;c;5BjS3D+1^t(0iM ztF=&mrYGMt30~(bB^vPB47`T*9dyz9fx1H}(STPQp?n+is$;W2y`Yq6z-x2xy8MX~ z#u@d6QlbH`EegDv2d{sW5)F85S>R>VHaEMzAsX=7N+>@E=zU*@2}^?40ZNGmyxM}- zg7cQPGitO_q5-e1gBSPSr{C=~$f!D{L<3&!!0W4vUjEvsiPnuPG%O@Y+r&KhC$DHv4$<`c^5?fYt)m~N{I%%b^xyd>$PudRDY#J1715qy+)+ZpJP<1QlbH`oxp49U)ybK)G11d z2D~~1ifew`s-}0`8v5aEr9=Z>I|r%>QEhkXTxrw-r9=Z>y9nj4q?+d23^D2xr9=Z> zyMkAy?A|Yp`bR0zfY)w9`T0hty*?dk)b_W!y(}8=+8w+$UA6nQM)grjG~l&|P`)3Y zbI$L_8I@K_G~m?{yuSb6VW%2(no^(6y9FBsd z5T!%|UR{LpWAFK`27cW#c#T&|G~m@0y!cI_MxCjYXuzvmf!7AX>t>}y177=r7ykl< zQO_zR8t~drC_e|-d+gEwZWz2iRZ2AAwLf@G@6~UVQGY8X8u02al;2;^t-EQjje=LZ z+uU9j4R{>@Ui{V$qk1SM8u02N6xXW}{WoLQi!J5`udzyr2E2NL*SxKFILWA-QlbH` z1BLSA#>$qDE-`ABQlbH`Uf}id6LTIj>JFtu16~J#*Imozl^XSeQlbH`-r%*gZ{=vC zK37UK;MGScKSu2{d|e}>{#Hsf;MEtrO84JjfKhF4cY9eh;B_!~9lK`ILZkLoN;Kfr z54^6pe0f)+j!;T8;MG4+TpFIwzZLpMwNj!1uK|JL^Vg5BTz8&PXDKBb@ERB>_Tn{% zw}aP>N{I%%1_g?}atrrgVboJfi3Yq55z60p7{2t=on8rEOOz4~cnt=xk7v(c->4sz z5)F7ADpYf>6n*$fj2DAf%R5|DG~jg@c<~&-s2!CO4R{?6UVQEFa_~ApDbaw}5cE23 zuf;|kt(0iMYp77%hCFV((*L5di-OlQr9=Z>!@%q1UFM!;)Wu4P2E2wBc)c3DZc|D$ z;B^FeZPUEb9HSN}B^vM=A(X!+THAcsUM~f&ca;(ic#QuB&=Z{NZ97_PYJD?Tz|SDbaw}@!-{|?Bbh@ z`cWy-fL98P@G1qb zCw}SmrBO#HB^vN51Fy-aA9<`%6OMV?nmG~hK3yf$g``vjwwDJ2^48XqXG*PDL~e*VPZ^`}yz z0k6tH@d&_gxH4*!yE#O^|HT^cnjn-PH!eNBHljKxB^vOW2wu;2Z@QUz^-xMQ;8i7* zKfYF7cG$K?4OdDu;8hJ?z$-75Z^PwRu9vC_UYp(HN+25Wst2zpKm9dt)SgO-2D~N-<rj%&FYr0Ur4d-64_kBivr<7>G>tyg6 zzv#l>joR>Dx0gi&UjGaA;@&&`h_#c9+Dj?XfY%K0`nF`{@kR|*N;Kegicsyzhv%Ye z*B$%#q|k<0r9=Z>r-Ik9*S)yRsPmK(4S1a<6t^LNCS88bnG=H7T%|+s+CH zpMP+lK68zlrj%&F>pbvkGQZPiMqR0tXu#`yq5K-`t5vTKHtHdzL<3&4!0U(~UTbaC zTS|!rye<&Rk5Q|~Ouf^nACwXecwGoymz~ybJ)<_5=lX_d!0RIL>hmx34Hqc>`XQlbH`%fO500M7-l zYn2iWcwG)&KfgM5C!^*oB^vO$La0q#6U&>EpATN2DkU25x)QvuZB$ckRHOS{W}*SF ztH5i)gNJPVLh#y2Dbaw})!_BfTkl+ERBxq3176n%<@Xo2;k&`>Xr)90Ue|)x@{!{P z8&#*2Xu#{b0m6QkZ% zN;Gh{{YIhI*S>M#p<~x`RD8ExG*H5ugz_se>&8>ppoDXvg#3iRQR_Y6 ziXa;Bx>+bcil(NonP${>N{I%%ZUL_Y>bH2ts2)m*2E1++ijNeYIlQ@L&+$f$R!TJB zH5a_j$PT;Ss5+%Y175cY<|oR#N{I%%?g;hbR(@*c zO&uQ%Ue75d8t}Rky!f|ujQT<;(SX-oLiwweb_s;Ps1Aq5-dmz$?Fe$y}p0dq{S2iDrtWntdieoM?Zo_pYaqoye(8t{5NP+YIhPkq_=mf&@zQlbH` zCj!Ow;t|`Zhm{fycs(gp8zPuGZ--il|8DZ4kN{I%%o)*fFz0d6MQPdhkl@bkjJp*2MZ++J?^Qu-# zG~o3tcztoiQBiB0uas!OYaw`jnBC=2^SVnZ(SX-;Lit(BiQnux_vX+yUQtRk;PpIs zeZTPf-HlqQlxV=~1)=-wgb9c$F3N{I%% zUKNUuFTSFG=c1dMy&u|eo>HO#uh+oqq0|j&qh3`?G~l&ZsP^Q;pZzbbym;H-wL&S; zfYuvCwe9y_(88uZY(SX-GLiyvXZ0CNb9}>JSQc5)7^)7fFIJ36i zsJTjs2E5(_uOoI`^TXia^`ugw0k8Mbi;gd&mMA3}@LD32Z^MJ;?)urG!RsfbL<3$Q zfY){HFWA+nR*$*9AsX=dP$+*+dFqDiS{c<*Dbaw}N8ok+&OdHz)L^AV171so^2c)R zD<94_YMfG{0k4n2>-o#3ml}13QlbH`Pl6ZMoWC7BG_>K(N{I%%J_WDb6`$>B)C)?9 z2E0BKYAe^oC9igw_Vt0m>no*1176F(YwWCxdKuODahI8B!0U6N{Qhd$zy2MgwpB_r z;PnM~eLrCQAftLHB^vNrE|lM24~={2bfd;7B^vPh61-XrefUnJ@=A#YyjBD+uKB%l zN4|GhXv2$@5)F8L1zvv~J*S^hk1Hh_@cLS)Zsfz~ubwk+zSpQ_N{I%%R)W`-wEZ%!^tDw-{SDl zhNmkf8t_^LUi=h+QFkgO8u0pFDBln7TfWr;M!lhwXu#_S@XCF1*Of;7qLgUBYqe1R zx^lzuPc}1Z+b5;rOGE=+Yrt!8n{~e!)n6&mfY*;g`96Qc{(p5cYNAr20k5CH>(rG! z&ok;0r9=Z>Yr%`}N*ndKQlbH`pTX;z&a)3PYMD}^0k3tzi`#3}@565z68c87r(7F~ z2E2X&udyFa`NOELN{I%%eiiC)%9Q*3C+#-sWYqCWi3YrW1FvPXOBWh-zEYwAuirzx z*z2LLd-pTy38h2>UVnhsZN2*}GHRt#q5-czh4RN2KULKuwBZ)>T^ou9y#4|&{;g-D z_EkzW;PrQb*B-%Zq*9^*uYbVnv`LS?V$@`%L<3&`3gypV3!biSw|VfoMk&#NR|z$Q z{r*?4ms-AL)T2s?2D};x<;RVGuP?vHsCSeS4R|#Mua{a}*~6$Gl@bkjH4(}m%Wv&< z-2aSfwZQE!(SX-_;Pvl>t`W7DQlbH`rooHz>w_1+{miIJr9=Z> z&4lv%i`NhL3SMU_B^vN*4qoYFUfb2E+msRwc(o{~*KWbX_5WI#cB^vPB z7`*yCv-cTB<&+W)c(nqrH-6sc?j3{IRZ58lyfy)^h1XT>Y1AW1i3Yqj70UOGVM7)+ z>KeS>QA#x6)f&9`o5)7}q?BmDYcrwfANlZIm~O#qlV@C1G~m?+y!eSAqq-<18t~d& zD6SWe^W}?AdDN(pN{I%%wg9iE`X0E>s7XqR2E4Weucc28e95S*l@bkjZ3SLacE9&V zqn=VqG~m@%C_hH=(?>>qrj%&FYisc8ed(8P8P)jN68VS*yxIxn`#kr0i{F(UVDHSek(SX<9LiuwF&o}l9UPF`;4S4MXUVXk@`jt`R zloAbibry>Lkq_^$t%KJoN{I%%x_}q&FQcwjN;KfrRVeO<{5f~(R-?BIUiT{{8u01{ zULT#&bEHvkD{ge_7cy$M_l~>+B(5Q@3q5-c13cL;uUS}#L8u01?Ub&UeooUoOr9=Z>J%!rF zRlDSrirTjQg4c&ii3Yq51h2E_tet1nhA+6xL<3&Ego^vd_QC5Qr9=Z>2Z2}rGcLZt zs8Xdw175ugyxIq^Gn5hyc=Z7k9_!^RHxweu~MP|uY+a(ZG3s=sL<3%fgyMeKg#P=YPrJX2x>G69fY%}5b@K)v%`oasr9=Z>gM|v` z%7HC@H0l?nL<3%jg4dWwMm%BEHZQrB7Y%qF23|8;UVgn%2P-8S@H!m4I+g8pu~Fld z5)F6_5sLni5BJ0Vp>JHElxVj%F;sjVgJWia;OHfY(^?ny|%V!;IQZDbaw}Q9}8-&7cdPdv0Lp z8^e_n4R{?5Uc3%q)C{FW1761nMgPc$`~2R)>mH><176317x#Ii=u4CG5e;}9Csccv zOix{1H*25ZwMr?`fY7Ic$I?J_UHU~fl-erB^vN56RN$dcF7;VKl#@1 z(1xEWB^vN52d{~@PCv+~UzHLKcx8m5f8@jS-gd!j<5yi&G~iVMUOWdds)JIZ0k3gF z?M9h4qW^vv@#QW12CoB@5)F8b2d_~F4t>O^kxGdMyeftA=gNfx9(~8CDy2jNUK7Bp z@6uVFjXFyy(SX-Pp*m2VxF2?G_VLw5(bsV0BO36k049Rei&h`r+^8#+5)F8rEEFGK{Nd*}jt^e$yk-gI`{BL+ zoVZ?H*k3uNL<3$IfY-5$I_+xIc}j@}yeVwx2N{I%%t_T#5y|?|<_+g_aDkU25x>6|mM?O4m zbPQgnD*MZl~k3V&vQ3I3`4R~D-_2PawC3qdDlxV!k0E$}1%r z@VX(?i}&(x=QO>|sB@JP4S3xMUY9P|VTDn1loAbi-2`5vK74<4_k!2AyBx8%QQIjc8t}SLDBlnH z_vnr4p_FLAYaV!gIAhPRjT)_#Xu#`!q55kZc6jHPzQ=|(tW!!f;Pn7_9sb*yS)(pi zN;Kg0piuOWe0Yqi4PN&tB^vO02)y{5V$_RDi3YqL1}{FRR0Xe(l@bkjJpx{QUN-7) zr9=Z>kAfH1D;vDFeb?1iG~o3ZcuktW`WvHqDkU25dK|pCUNymMtWu%@uP4B3&diS< zH)@hnq5-cbh4OQ@`(7`7zdCqbs+4HJ>nZT!wwnW|NGkyMt!T4Xu#_O z@LIC)sCh;;|G>48Xu#`3q5L@i#qdRCr-nA%MJdsM*GJ&hXF=B;jOwG5XuxZ!P=1cR zf0OQ+X~F9#r9=Z>AA?u_x2BFYYPwRQ0k2Pj7w@m#@4L9CQL~j24S0PDUVm=+UR1(` zN{I%%J`>9CuiJZe`rN#}Qc5)7wG6z5bv&=isFokP{UsXk`dp~3Tyn{KEf%jiC$wQF zr9=Z>Uw{|?dV*0SloAbiEeEfrw|zM6^x##mlxV=~OYq|7H;lSYDbaw}3ZZ=8Sar_V zf98YNLZw6lUSEM1-*+(TYo$a3USA8l>kb-?*p8w}Xuuqm*dC>s#>Zw)3pJj5=8<(SX-?!HefMclQ2l+?k;bZ&pe) z;I#_8_^rQ2y{wdI!0UUV{5j>b>mPo=s2`LP4S4+kUN0Xr?RcX$U+P+3G~l&bsC_7z z_t#}xH+jsc1CKY`b)Q;xdY zs0Wl14S1~;%J+>Qu3fsBQ6DKK8u0oVys~>tc*>~8AGwusDJ2^4`VGAPm+i2DQFD|M4S4-76#XL~UUQfg z`ur0I!anpPX*g_ezNdy#5r*w_%ruCY@|lt4~}BL<3%bfmiRtTJL96SEWP) zUVjVa`^HO4SG{1=7^Or5UjKks_5FL^WYkGYi3Ys>4HVa5!vptddqHT!8N2H7176L9@^gUS*E{3+GlJJWN{I%%nuAxXfAjYn^`cUu0k0N9`99yc=`T+i z^{G;#0k4+ewdR*=rW*B|QlbH`4Zv&noyN8_s`Y2wt|cX+0j~|gYr^X--Z5%Vr9=Z> z8wut6#x~n5e#WSQN{I%%HU_Wln{B+cQ70%R8t`fbUduP%sku?ploAbiZ31484)0iI z)MZME2D~;EY9H5FB^yntm~m0)8}}+D8t`fjUL(sMIKrsKN{I%%HWSMCjVs>U@<5}$ zQ%W@8)dswpoc&dEqc&LP3N9M(+FU5Vzn(s4#Y&?(DkU25+5)^D`Q!G3j5wci+(Qc5)7)gHWBuRgzzQPY(Y z4S4M!lyAeDN7`&+)YVFf2E29zuaX_hPB-cir9=Z>J3+nrUA@PHM!lnyXuzujc-1UF zdVx`EloAbi?JN}cL;f6g+RW!#hyAtD7cMFq@Y)5uzF%2+s8L;&5)F9mD%5V2DWCP; zxox{UjT)6LXB3p_FLAYj>gi{%X|tptVNLRZ2AAwFh{$o_WCqMlDuK zG~m?{>UF>^kKbX`&q|2~y!HgIrI((PF{<5i*YctPuf2q#iJN@*T_2l-{dKTXq5-c? z;MKOp3oVU0Mk&#N*WN<;F>2W_kFGE(r<7>GYaj4>=CqDy88u5O(STQHp?KVALjOIz zf6pzAx=kt3fL9mr8uQZg+Z*+)QlbH`u0r{~vFG^d2N|_gDbaveH}K+jeHgV)Dbaw} zzTmZP`6Uk;)#^*P7exbJ`+*m~>%*wsl@bkj?JpG14;#^cmwr>xdTQt!{ge_7cy$La ze#5X)$15co@H#-K_TUDv+ghVuQ%W@8)k`Sfh6|56`sqtT8?IDJG~jg*c+FYT<$p#sSwRg% zAJKqUZ=rmjZ?VOo$wqCflxV=K4|sjm?S;te0Hs6&UVVk~Z8)@7<|XqwQYq1Z*TLY` zsHRI(qfS&xG~m@wr~_TKOOE>W{e900Z8%FQ(STQf@Txuk`p=BIUn$Xm*8rjXe52=g z>o1)cyxvtxG~hK5yq-J%pQDWWRVmSc*C3%fP`$X%H{RsSRz|h`%2ii1;B^Rib?z~L zd!u?OB^vM=ER^40dsp1C%&4?dq5-c%!E65sE3Y-`45dT^UWWQ8ntk;Pru0q5-d=;C1DfV|O!Ztx}=^uVF&@ zzH!-3yL2BFyf*sU6+txMH5|NFUw3PTQGJvW4R{?Ply5_R_MlDhs#8id;57og_&IZ< z<|-u`@ER$UUk5mJ`2h!?61+ZCN;Kd#3cOY?8gi3SKPe>|@H$c`--cVid*PB9!K>v; z*M_12uhHN&V%J5>joLve(SX+&s26`PV9VgOzfz(Bud(2Dz-bSCVpK{g(Uf#5Pv_Ix z^Ntc~9-S!pTsgM&px&B5|2tDD(Uf$mGwf)gdZ_f{1sz|eaX`1OR*E%^fjUO0?Nzt$ z_uXjMdFpMYScBBDLT#bc$^CC#Xw(MZxG-ywI!>roO1(2{^=?KTpcHG6I$kLHM?P2I z@huH-zJ%kHVhvI$q1IFCud(;-W7Jtnu?DFVfa+ekY=}{}D8(A2(n4*mUavlS(j`Vc ztrTmJDivydr9K_D;jKpfs}yUHDig}r|J;?U|1fHYZ(U}rL8@FRJ~Qy=pnET)ZsPOU zPbtx7{`|%o-r-mxU8lp;bIhS`yNrh00?&rRn{FEvs8t8}Pgc_v4uh)Dp`MS-? zO0fn@I9{l(O1;r?=R>W8_bSC2q$-8lMX8wwUq0EW@04NB!du?DFV!RxZo_Yv>= z;ay6x2B|us{9bNBNSgH%o^-x@D0SUAV1?Z0;gXAM$$p=j62CpYo8dZUh2 ziZw{p3q}9P=bSSxZ*SCPO0fp1NkaLv-W99=e$=Rklwu81lZEmlK+P7jo-^tvrC8(I zwb>6PB~%!9EKBM3;0T2ZkK8Geb8Au2d*kofGU`7=h~f`xuslu1 zgy$5_opZc~%R^&&VR@!W&i>p~v8>rlpG!%}9hx(1uskOT<MB3 z%@E2Tr)`>L>3){?x=|_CAa#mRt+a&uk2`O%Q6DPB8l+AY%I7||^~SUl{8qCyE;H63 zbsA8+y*4px)HX`72C11s`TqQ3>AMFQ)m16hAa%M>n`^yRuPCWB>QJRvgVY&9ZLHLg zR?F#mCtt70O0mYp=5nNSv7ULRtiTGL)FUx-GD0ZOq3sdI(eM5!$|9R84b<&|O$ zQs)Wf`}3lU$1XBzu2QT)>U^Pme;#`Wz37M(?(?ZqtU+p)P`A9WYh2D}QH0O5cHWsok&8mktbSf1jf$L!t`INZ zM)`Ivs4Mxc73#$r7yF$eXG6{#t|Kp+N1JBJq5PHInj>~N)4Z-yiZw`GFVqI=HTIwPXpZXZ^@LKaL29;8e(W7G z{lv&?sZy*#>IR{Fz5Y0D_ovKj(_dW?ScBA!LirNDxBc6v8r5AX)*yA0P&CDn&w{t^ zz0{~urC5X19HH7MHS>XkqrP#nQmjGhW}*CEzUY@5qciM0rC5X1EkeV{ zexVd=kh)bU9v%3z>CAJY61M-%MOlN?T%o$V30`q4N`Xr<Vg#NZl)xFX5WW^>kQ! z=ZBSI4N~_3)$ZX1Wap`um0}H2^MvxcIUP>F+^CO~VhvLF3+3nP*Oflr!>H9tu?DFJ zg!0GN*#C{a(WtGc|MQ16NIfW2JC|It;>jcF0?wCrtWvB&>LH=FQYu^i&xJ;vqZDh9 zdRVAEl-gp!nk|ibRw>pX^@vcuHU2zd?GmGYQ;Ic6Jt`C#$YtU>B=p>|Me-4`ETWzxAT?j8EtG1u_w*U&^^j7mL27|eet&JY z`e-_p`5yI!QmjGhY4B>j`J5w+YW=q>0&9?Z2E4ZDG$ZO8y_I4OQqKz2L+jP6$LOdH zvr4fBsf9vquGCjw_I}?=_@Gj(LFzf7{ER3&ZSSE*EmMj$NIfrz(-tA)4rAn~| zsYOE3NlQLkJ$O+x9=@U!YmjH1d9enmSA_B$o}v_MkXkO3pXtqg{oqQY9#x7pNPQ`k-^-Po z@rlm2{Etep2B{T5jeC1Dy7=(a#!XxsvIeQIfZDwL!j(qttQ2dI`WmPX&$rvur~{Q^ z4N@zG@-5$~$#>B>KT;{yAoYz<{;KVyBVW4PysDLA4N~6<`y9-|a%kor-mK6<1a-u={H%`2}I zYmoX$DBtIA8@&siqJ8guSSi*ZwN@x!uk2H!YmItaDb^tMGkEoVaOEdPeXA5}kXi>+ ze$kBaMzw6}TAnpX{UVg_hkriO_*SEKQHnK4{R-5<7rYmp_4+8q8l-*$YU}$?rpc^t z!()|V4N|`g<#p``K5&~+QUvRYe5Vv^kos3Bzn33dQ2VBN zt+&4G8>~U9gid%(8u<}m>MNOO?Q2`5Sc6m}q5KFi;=s4hFt5XuVhvJ_!K?q}?W2}I zNh#JK)dalm-~5f<=5@PLtU+o$q3H5SKG*$q$QMR^pcHG6YATeUIdr(?*>8>dRVmgW zwZ2gPI%U>7C(|j~@8w;axt3=QQq6?&Gl!bavyL=slv1ogs<}{py?5IW&%MN`nM$z+ zsTM-{{q@h__iK#0MJd)G)lw*5lghtqCmHpkQmjF01EKsV`p&DvcQ@)2rC5X1hCoeT za8`8I`&}v4AhnTDbRv<@R%cytym@Wb+_gMwklI)%U#|oA_;jpMBb8zeQmugMF!R&r zjGCYnYh1pkQshP|z)^fu!c$e7NIw75GJjn4O*AXGMDt+{x^F7fK1%I)b8biPR8q1| zDb^s>S}2mrr_E6x(1p9N_xKjBeOQCkW%NQOlKL4N}_zHDul%(K+{brC5X1c0jdnzsbAiwaJFAFI#b?QPoPZ z2C1EdYOnq9#@Bz|*{IW%VhvIqgeq66e&5m;jasD?YmnMmDBpXh^q3aSGly*CTAnpX z?IM&PH%8BT{1EfXD8(A2b`@$9E#chHe~(7vkCb8!Qo9M|*Xxd5*sRjLw%pj2kTpo{ zE>s)!I_K8*FBx^3QmjF0521VsH|}^yKcn7IiZw`e1gh(w^9LE#s+B7tYmnMgC||-3 z>7lzAHB2eiAhnlJduYAZ?zTg8mbp$T)*#hMsH2rSs>wN2C_m0`!b_R-VGUAy3*}pW z)nms-S4pw}N)&65+D9mVcG#$L(lYb<~QI{*l8l?6Gs^@~n4;uBJ zQmjF0KcW1Y=$c(i=Nh&7X0C*+L27@X)?Pa&x-OWh6l;*`F4WfAhV}2aS!G_|D8(A2 z4gjxT9{H%PQ3thgC1ed!J%sXoK2`qa5~J==iZw{}1nSU>zB|{bwMwxDsRM=bd-;`j zo{d%^dTs7X$Qq=20oDK4WxJZ!ElRNlse^>_N6LkbCPrL6|TUGM1l zg?Z(bVhvJ#g!0z~{ijUG8TElutU;=;P=1_WI(u7Mu=688>n&XgS>s~6YlMr2`5Y|y ztfyt}-|L{6o+&BWS1HyY)eorm+Mi07P~LrjQmjF$KTx?>|Cw*pkxH=!sR2SY*Aiac z{Lx#D$|%Jeqy~c5{)^~^qoIT+E5#b51_5>VtcQ0pYL-&0LFy2oj_cq1RHLp}iZw_L z25Q+EU;JUzJxZ|#sY8L9)@sA0M$K1>HAo!>)aX?`UNLI1QmjGhaG-kaRq=>XpD4u| zq=o?X>^I9FFzS1yScBA1q5NL{WAXg?$nq$=UO0fp1F+g4M9{=8uA2%LW ziZw`$1#02c>^P$qE5#b5juOg`Y!~(YI2r*~D8(A2js~y&ZtQlJd9725HAo!;UYBot z>zPJv)YkPw)*y8(P*Y#4xyPt&m0}H2#{sqU!_*L?_EL&9NF5Ke&Q`38g+(J ztU;;_s9TOqU1rqfO0fp1a-n>^hMfF3?O5M?Z&ivlNM*olP4h3KdFFhjSc6mrcs0)M z@}7AuR*E%9jRUVu59)DU4N~KQ+N{2AkWuTDVhvK2KwWXt^sG@$w|0G=HAqbm z%D3T*%kR41sLhpP4N?=q>w~)v`pu}llwu81Rp7O%Tbd@Set-2+iZw`8gIABsbN3l_ zq*AOwss^a`GarlAWHL&z2B|DiTOQW*TJx$`iZw{p0=4bEpB`h>8A`DRsS|-3z29*s z7wlr#scCJ6O2C2zFUD)&4UPkp&iZw`0 z0SadzD{?^Z_YWFudA#Xm&(=B|MC?nPU>?&p92IQ zpGnuI(p6R2vUEOMm#VGHmbpwPSJrgxLM~OAR4$X5SP-nsq{|C}lj|z;TF8hmtIFmy zTAiuR)=f=j8%HhQI2vUfhb`ywOhvlBD(`a6)@JI``O0jKYsZ*~l6q5nRA)jfr3k97 z&u3C6*4A13q{`~bs2!r#r@(&QG;s9r!&4&$q*6l$jOv@}cSzq6BTIZ}%prqE4H!AR zZ@&R0sZ?F2He07Vr)+$tY+^;avZ}r=Q$kH&Ij$yCo~o$JL|fIeN2Gbvxm<=&>K5fy znYuVsR+r9=mq2AMRhylhsY_)mQu)bQC*q7#71_GU={mQg#L7ofmDDY{bJS+3QxKXi zcPhV~t1nHar^={BU7z!+^2&+|kxk3gWmCDzX>LDLi&tkSg}-wdM^QL8IbACN{arTR z)rbD9i~cUl(%X-?XwnF-g=|~?s>=i`_h(YYecl+}N>ycQBqBXNmrv(&smhv4SFk9? zhjfZcMBOwgcjYO|*4GqJvQtIxJ7Ph(@JMrotIO1+T{ZdWD;BdOvNoHok`hOCl~|FZ zS3`6Jq{z11_ZxSZTa=HMDsjzGXUdn2*NR)iB;(v>DQY5sLIH|LtqRoYWfQHwmXJ!< z)upGp+EK%0>a_1@ocd3yEM1!}tIWHdqVaKc*~#Lm+v(ccOiejexr&bEA_-|ajx23b zwJVAUX+sV{?sxPzjhNLwURz%`&Q*9)WnI2LUFBP;Ha(68N8jh&D4k7J@sTL3kJMAK zq6i(WIjW1xQZy7PuN$t7^xmEq5X%LT8FhU8NhkB`ZE}(19(=kW(D= zg$s$0DIMwgx~%pMI(R5Is}~&+6UN>WOyuD-^JseC+xVV!qKnJ^SerC~jO3$t(uu6wI?0-d)YOFhSEvXoH{Gd|RB>iujM2;rs|w?sx12=N1)l#!0|(8@@_uF) zE1AiS6NaV|eoi1!I`nEXWqyt!#dUF-i|KSuwrTFZ__!HNHm)PMRvJf#m1AO_<*KKsfq*AeYa$Q%Rn#u;`rZE_3__oqk;bIZ$5% z>3*8WrgG6C&MfpP4zM(L_2nw;F2p9e6S-cNW$LswTq13zR8SG2`nOLijgs_lpOlWr zUBBTIb2Sm@H+*7Uc|PaHTHe{TPuzIuH&WHE*UEN%K2p*KB<80jHl_Bts!XQVC(!k3 zdA8anoVqY#sz!^m&b(d8-{Y3plvy!K>nD)qc-I)19Fss2t3p)eJYs|^{{ODpyG ztn9pB%1?XhyN5q3=`z)ac|H;T=BkA)DqHxwA|j}!Azqg*=L43nSnJ*VB93(4Put!^ zVMkfWPkYAKS5)Y_1mEL zMas!lrnY-6^*+i<&-}Dio*}2KyEdRrx+bWutclXYG>=ZW+zZpXrbC|qStKg94yH!;-Tc>}QWh$%m&pO(*<^FG~C%5Ui4$iLru4!>1LWPbac22DK@5N)5{Op@_p7N>AI6_RM)#sCmZFJ!Ln@?UE|j4kyhKZBW%Lh0YvxSsi*r2%Eg~#<}k18a3J?`)Es)zJYir zxeo$dVBaSLf*-5u#MX{5=pc}H>+~DxXR=mRhhP;D$|xu%cOR+iN)|yUy^7$ zQJ6Gc2hw64olX6YlBFoguF9X6T}A1HoTX)S6z0m(2~;9(*ExtHp%Vt(wBa4)rVbK?QOdD;TSqqhX-+nL zUyu!dYV;{q5IzG&TXqWcIqJE`lkujViYztCOOoSlJs~-gscOx|17Ce0?ZaJ3d2K4wW@wLgZ82a%_==((II2PZtuIIyW)QRcEub*b>$> z+&1-+5aBZq-3L=W4|cHC4Yp`bKv(Lq7Po0?fdLx8qkyzw;AP8-Dw~$OOQnC^A?#8U zo19gO7Fp}E?f^AW9HsT6d>7ZH_)nd$rqiXR8s$IZD6cr>-RW48WZRvjBqb%R>{`iC zw&QeOnWL)<*W(=GL)>><)-EnLT65$Vi$joa%hB~8-NY6*@uhQ1l)EcnL5Ox#J>9*? zQ~*e!y2^3mld*i(br#K@RHfN`KI_gbF38ImiQG7p%#CB18%GLqqX8qC8;6p)aSU_g zNI`B~`7m8`#ii>azlM@7&(oZfuDD9+9HZCb9Mg-;WLTtCnY8OKETn}cz3t0eG@!c< z$s2Opz>nV{;C2-y^MWVMTmduvAL5?-Nc0{*G zA>FSs`E+_51=6Wwg>Ah#5of8PI9CnD8EYucTSIa7wP{+{NzpyXQe6|^GQ~l;QK7SL zDX+UZmLSNOuTfnziO70ofrqST5J&e~q_PuobQFoRZH9#tNwmdy+Y~R&p)5B^i(a0o zs;uU_l#&(4Lr%Qmmct80F7C=iJul9qzOK?%I(frN%3D^nuoah#gP{buY}rKW6k&;5 zx1)26kA#PBG=NtZ8suecy}6?i_dJnQT_b#W(?J>5s0zbWoC>#|plLaOk3_d=9L)GR zStOyo9vi7j7T)4`E)y>96s9>$zLJiP5U0l|sw??{ov^$XA~|}(!p&7fh}Xx`bpFju zakrktETk5XR%G}&32FxvYuFDMz8Eg-AMNnbTrE9CL62Oy+YP}`!n`t=OvuwCQ|Yo3 z>no|OiBwv`OjMN@H4{~((0^2wQj1iTqQ$CeVW?^dLscnStg1d-P*qC!kE*6>X?#dj zR$|HOO7K4_Ea^q6Eb(HMjuW8TQ36z4;>D_N2?dpxq@vZAyAP@Scv?8sYn+Pk_(9J8 ztg=6Iv|w2~p89(Vq|s#y5fZ{!hNT z*4@pg2S+QbYg2ewETupY!<@Bn+4mCsF4Z zPEQ34rTh0jJc33x&MU4!`LGHM@z!wnwCaEvjQzseHWqv6*|=Fo5$ao^*I7J*fd|RNd770NpMwp6LiT z%#ZXVycTl|jq?MubtCD(ugVN7oj_&Ol#zS`U;iF3r7}NUJFct#D1QqN!_=;W1Q(~{Sl=A?B1}Cz zJC65`8fNPXd(de2KxkinuvT-`5bbpDqY>#eD&o|`E9okgt~Ntq*r%_~uU+tPx@D{~ zfAms!cGc~xs$i42$p+lc~vk z?JbX6?$?bTY|ubWW=dYSIo&3|b5evDoLrMxB^eDF{Regec-lIsuBpPd@7NSWpUGHSdD2H&H!^fnqyit~)LNiO+ z$9}cg2W7dAAGGk_;E?B#h@j`F15M@T{u#C%FtRvDqHK< z2C0x5NIZL@kGdqYbIUFCM0~wl;Byx8KnpEvrRnBnMWrrfaFVS&kS9HB63Xi~Y4_68 zU{(5@m5bHZ=f?fv%hD;U|Y%u@qM?hU5T^$Ft9{s1&zJqzyBEmv4At z*loH6p{O;5D%77P*Eq`mnyUlrGPAFRWy?WJSv>S^Y{7 zE%Ez>tmu0pDPC!EhZ7%yu4y+;YQDYrpIo}?`Q$+ui|Q`df+OqQGMPg+&-8Z3K|c-AI&q&!UJV_PUQ2ZD2M5KZwj zbtB|%hh=N&tZq1U1T7q9Xu_4x#u{=RDvQi?X+Tws3d5Vjzaq^?nt5*o&$ ze0&e#NgH+C=&ac!j`9@GID^Vug$S7hHG#KOozal%z z55zig%|&ApFSAJpl|g9KD9`il=81GCKQ=1M@%6zZFL9f0E(}?^ggUtmOp_7c&_dJK zRp>#Hf+&BtknSW~T-t&fC(v{)!?AIE7UM@yt=VXjER#kzCG-H+E3|+Q^GMEZgXa}) zjefLFP)A>J9UON=kM*Ok^Mw87gM)?-8(Ac;@%GhcUnm#iSrkUfbl#;+#m5Rgt;x3x zHR7%tX#Z8x*YL_ynQ}XD__C57BB-PD%(N`E65ZKLd(1zM-axWPX*l5L$YYX5YI>?( z${=nz`FfR>hQ5LC1}*uvgq9~Xi+qEEOUU1vrZ4@{<7B=(Q4-zOE1Ot6&8vfr575-p zeR1ChX!Vt5!aU=b{!=VmN?#9l#U4mPy4y=jY?J8WF&D#$DI99_+zqd%``Z+xr${Xy z6*L#OVP!mB9^iQ`MR(GZA?{N$-K3?I@s;$*N@z*GcR`KG&&Q-nGt>BDRnz!Z9>17D z9!jQxJ(miHd>K80T}O{Sd1)?NMMn=sLuFI{HTJvm`P}|fnHbdE(m-vRz9FWil#Be( zp2-uDwP-5Uk1pceB3pQ^Ln<|B<5Uu&$7U(RIgmI*DJA-nI zbipCgVJtG$hn4shAh9!qlkx%~^fei(qe{5#C=YrpgePy2#77E5v>cl#n3MW=1h^9O zB1DvN6f7pC$IXh=n(}Z75hCX$x;ISgU-4@{BCCcJ#WQgQbF-@AnSi2rChlv?#c@rG zK>ux1Y(X0dil@gtxwsYi-24q`;vLYC#^uvhc4I>t zm(PD|qBfx;s_->0QF|6ok22tA9h0wviTI+)g*aUw*jr-?aZE16<>fMkmHs$DHFjMcm3L(NioIs=3*(1ac9+HOtBO!n7pP2%j7~RhWH>BlBUJ>9v&<# zCM7VwrAs%B6NHZziuvYfp;)4kn6~+8WU6W`j-!znZY@W7V>|}pSNOyL#A6_OaZjv| z!;zedO;<|pX?U6&$Q!jHtY~rrxV~Mc0otb)!v6gegT>sJi>umOyY70 zM`$q#OcSDh6B!j&$DIfYnz-QnfK5+JRB(+@EVa-}_Zz=ksj%7N#6pxCwFu2 z;ZFR;6)uneQpAVgf92s0(&7r2hdX^1SGaQgmm=Aq^a`5Vf>w0Fq|`lXmE2t#O^RvV zHF^P85=x{t02h=?F_`~IL%7E)aITa{NP5WKnq;|Lu$Yvm0sKXlVnj$wg7QMJB;kTd zDOar^a~DiX-B*N?*=jT?mL}tG%+d2_xuOQNs_0V-4wj;{JJm?@CejNIltg;LVUkEs z7M_RPsCW+NRZlTbq$Xk4C#-S_I+AUq}sl7ih&NPlj_7>*b zH~O-@$f9_9G6VNgz9gp6q?nu9UfGv~5~)d;&e`%}za$po5#Z17e7h=c3XB&4-2Bc) z2@kkdt0lz7;{6zAi{3rulLH@9*dJ?!k8tXPU; z_HB?UmQtjlVfB)*w zs30K}Vt_EfN&)DuO^N2wOA2h zB44kSaNMIHAs#9r!4Yn3g9JwuNpQq|?skg4WHl;NkpxHV-w;tGA*wciV}rjh8n=(d ziU|3=tI_WCS_voR{BGBzR$@hj#q!nH!NyY+@pG?*P3El8WZwB{1!dq+B;yC*{3~Rm zOd(t-_ivajBtl995Uw7pjX<1I9CGiXE$*dhg&<|E@2f2YqqGLW;P}n9kv@c6?{-6d2*%@o2s))3%0nqjAEyhFBBga} z{Y6R~-vofF!~~Q)CW<6PHORqxf8$amQyPR~GoHU77?;tV;ftlahHf}LZk2|4*Eq$} zy zU-BGThfrMW5Of*3T8Cg<>ky2)YY0Zx@MXbx&n6P$%o9nmMIy;juCphS991;QQEoIS zN)=6Vl)EG=N)=5iYzloHcC;@vH=p2)T;nH_;{B3Ha+K?SiKHS8=)I!i;k&t`;w2Ia z5V}1pFYhiuLPCVlS04E(Qu+pO+!^9%QL+14EUiEByT2nN15tsQ$P=LnOk+ia^6Cim z5V4C#fWCnnmpGzeQkq=caNqajN3V4NaQi$8$NM`9$NM@8$NM=7JGDC!qOemJgq_+Q z0R`%Uuv5F9U!X1sJGC3;3e*MRWb@Ip*6}`+3?!Bm`e)4bE$q>*6egKm&^}2)K}#hC z1#OlTxE!L^O9~3wF)464L@k;WBpac~Q6{wy@q$8!l!DTRl!9W0l!Eewlw`r&cUSrG ztb)B6Cl$x!ThDOei$Qbq@p%hxBnqBfZ9Xg81+$=uNmCMSzc6I{B}Uri=Z-4)G-5e;ObOgm?t-7stt#-YFcZqaaHCn~hK#q9~@X z7U(Yvpgf8rkbD+|ic#VSK(eS{=ak`TXQIw_Y}5utloZV|O6M2Nh-yh{URDw0?PO_a<- zMG6;hp#qStPLtTCDBd z`}1K4@R?bK-8oF|;nQmz^YJ_Ps%W&R7;ep&n!-uBzOO$qzUXfO(2oNY2k1uvlGW9h{1*bzoBj(RNJ|!t zUID^)pz((WlD5S~$*i=N{6hlC4C17sSl99fF-=NhQLT!h$>bzntV+f5X;7EU(EnsY zvg#q;0Kh+~&;TPz5hkyZFMiw=BqcHU4Ti{1Kuk=ciQz;Di6w>n!wku+C6*KtO+USm zlxj37c0bIJ6l=6VOkb}pka8?3OitpYRt57tiH4!phG2{*^OhfVNS49{3#9T|uL7-$ zCdF>(;_ZsD7+|2rWAqj$0Z^|&n5&# zvVdQqD3SxF7s;U1eyySi9;ZgITs+86M?_2%M5+FU1xkGorTPOGDD^><(i_R#?^B@I z!YHR#mKBp*80Gfc8OiMZPiVvk7kAF^+ZqT&@yJ1XRI&l1U{dOSm?O$rv>Hu{3+gFi zjV8tPN?m-m)#dD>NpY^ISfd5v_y<9fMVHd}-vx=AQtTzikeV2QFfnp~Kl~9{I>g6gfL;nHU$4<028o$uQUcTEB>&qX2{M@)uL1IF z2b1Zpv$;jUV(IZJV6k+^yJf&)>5g}+>&4O?-*CF)-HLI;e8cI9#*;RuSGvHop7V_o z5(vF2nO?Y>Xl4y2q%_Nh={#rbVhN%9);)ejfW;P10O5yQ_}5$#Wx=$Dzy>LpHgO@M zpM*&`#VHA&_(x+B6eJ}u{?0T12uuPA;UaSWftVt42^Wzko~)1xlBtA?$oYq5isUZg zB61o{ipeFMkn7jNiqtkvDGn8>vqHtHtw}{{9;Xy{DpG%iiZy{I6={VyCE?^=468r2 zlW1#9OAcO`njE??H92r$YI4}Z)a0OrsmUP=Q1prInBLoW)762@PBk_WS1prInc)TEC0T8T8c2VPzH^(7N zM>bKc4!1(B&YZNm@UqUBN?p$ssiYy@3*>Xa=Kv0?@5|E7^zpE2)xUB5*<24;+%| z3l7ONmP2ALHkd>5)sr{s8*xOkOaz}roM{(V(c=bCv;^Ex?=$-lUyQgrALGXWx1#t= zSS1qgInp7>0H;m%+2!T^zQPm1XTgSse(}*~w8>m6+&@Y?+5oPb1wgnRA z_@PH}JXO8_Xp|sC^_cbhf%ICQ$L`V%0s6TK3qxCSx62=@tJT_i~Ze!WRdAJ4CWhwh6PMs3*w7$&yh)1?=0CQ z63v;O!3gB0NJcLDkwJsONOYmfLfUqOR_QK-SR8`s5JRjMF5V?HNiG|X@!`!vS0|Yo z1nUU7#9Ta<2<8h;s&olHw4gAMXsVoVhGB?h2O0-@={zD-4)=Lj<`6HJ%D>Y zBiU>VMlz$>*^Okg4H(IcW_LA`8SN!An%&exd&!Ju_w>+SGNXAE?4iA6*L>jzLET!I zLCpv=8w+VPJu7PNQZj)aQt@)*R8P8kd^E`5eM7>=zT1J@TrGz4nOHBG(LBT=^-Q#v?5ZIy5*Dwjx|*nT&!ZHD9oBFvMe+PfQJBYYEk!XD z(~liGS5Z2IAd7R=rDh?5$->)P_7#+@A4SLz*Rv%)=E*eE|9mQ&h~3bqn%?MBnU|f?r!p^xQJ>1Zb5!Q#=sCwb zM`d1)rE|P|IA_>Fi%i$OVPj`6X7*RGPx|BpW}ON7J~H!!+iT z4L`^irZJyv^g+HbjrpX@2KmA?vpU4BI`pD|c#GDwiA``>sBW;&XpaQw)+Cc;vV}IG zD5%>6p9RIVjvwG&f9!tq)0pOnNv7NH;hIHaK8Nn-=k~|UMyWp7?TH!eb;F$OT&N)x zrc}#!Jhb#1Bc1Uw*cjaDZUet(d#HZz7wX6r>vh#Ou1|`@#mVM+&f+4ROLxyAvD=bShVf zo65!K=I>(NR7U}HDej>vAweZOa2$8O#goAJpaV}kI_0!!4kOO{(c8xkk4kpn(@V&1 z9y*=N%r#DBo*q+{IfN+EO~|c6JlybX%8X*-q8a~+0Ph87>w9}su*2_bs{nIKD**e1 zue$;`Mc_ScemB~w4vXZl$?vSqr==b45W*4S?Z*k5$V3Cm&riFKX{LH$u`N!S$bkQPuV$#IcJE>DZ_r4bB5@d$9T%yvyVwL8O3MV zk5A&Mc-*2PA1*T+BqDhTa7u(VGY`rD!Vw~7aWfiNB$G|9CW?o|%_5u00l1jGhwz+k zGVq!Wy+dxwH~l*duegLM$ud^BDXXITA8HPn*C z8CG}e$IO&z9wR@wz@_A+Z}DC|r+Q!>q0cC25lvQos03TO;_-O1N`0c`vp$(sm66pa zTb}EanOi!xPqw_tCo{KnHlJ+yl22xC=}JC1Y%;uThPTXTOg0fsR&nfsZ%Ps)FN@J7 zS+;VCmZe;xWha+tS;-~3s`3Ckq^UuXO#D`6X+C%_T`5Fyndmw8JMrT1^tSqB9K{`i zSYpJx^U3ko2h|NQtC8%%bN!it22-L36}tT*u5Gjx6VeURJe%qbbw-L0G_JI>pTktH zwK?kKDoebp8Off)pO0_D^pdM_oK?&A0G0?ifH2AN?mvys!>9J} zV!-UWn}xBo^I%auX(wSUZSyf{Ct)n@;$zZI!WOFF7o5#HzSQ5}o=#ST2W2H!;lg-m z*)Beama@Y|o0I)Pv}F#oUh4^YJG%N*ms!M6`;mH2LI`4sDe$!!JrK|Dp_tP8qR^6F$EYPf|P-&DZM08onZ)S_( zP=m~tX6yvYlEiNTY#%}ieTeNyK?qBkf@%=LQWhaBWr`>ZQWhaWql7AgN*b&LVIlb9 zm&1*|lt$UmCR(}GuOu@!&tov3O|h6zPURAxzZ&bKDo2;>vQwsER+Gf$okGoIUW;#r z7(k%wdlK(8dK&0&`h%PIeD!`@* z7K>0jd3gJFP}fB2;!NolgQ?yGaN4KRaH5|O@cI4b`QeAY)Zcd*7Nl{Oz#dN?dRdw( z1p%i-=*&)t(!h_39C6>>!y_(YwCgsY<|NzTurl#0BNQSW;{=0+kD2nel?>*np{{o1 zb(0&IhJ+l8w!o;R&kN8PZslt^oUpUeD3){z#j>UW+_J1wD3Av$vTCy z3@=>Jsut7Y9&w4)H8rmCc_C&F#-^KU!c)hU_W_`+j9^nj z30#R&Wh`WES?res-sXCF_{&)zGmTl>0RQd58T~Pwl70BE`V$C4IHlTPJhm(Z**4v)R2zJIe@`2PF!|A$JntQv&uH8b zB2^MBl9 z4mWNHTRRn_lf!UfPiIX6r%PFsq}hyI2dGZm^Y!kwEh+|8_C%dy_BGXl173Fzp*Wo9 zO?v67q={hVRdSQF7tBP7FoD+h#IuW>!n%U3WxRQrb1+LBwU5{Ln-{khV1>O*4>0_$ z?!}j0PH>UxIJZi7d|IVDuB_4-uRK_#JC3W;8L#|RrCZ9^xKdVxx*4Md$QJv)q#4FN z*Q(>{4lTs^{I$l}?k~eKHY*<(dG*&nO464n1`+EEKW3TRLo#N({8UhE3XR%rIkboDuf=qv_ZEKIlh+wj|mJ8Ia!KK}Xqb!x_3o0GO7ge?Te zeCUuccBQ@T$-PUoS#5Wi^LKU@P{Yh(IZ?Ei;EJU(O3{_lls7};zs6l0wKuft^Sl&o=n#hGs6K8%n`Mk$DDj9TMmH~5VE^k0VFA+* z^=hw-7Ga1jW_s0VS<)=Z7KXJ2{wD~!hW3V|GOH&q`gR!*Lv~;mdbyRFKvNAwit`i`ZH0_p}1@k1G0L>L`wm|N1 zM>PFgT7DF-sO)KQ z?3lr$I>zwmj!8VaV;GO_n8%~fD}VE#&biBe(_|*>ER3a19n>t0rJaOnqrE)i`=Q(4@PgW{wKnIZbN1w_4ux|J zQJ9B9LXam!VIFd?AWw+GJX9Y+o)ASF;O%X{|BBCOf;;Lq#VF7Wmx_OuM59nMd{cX} z^Rt!2ZK^X$S`^Mq1#gSSbrq&Lg$wYh!dWz1Nqhmqt?m{6w7)t2_23>-z!)q9vBii_ z;oe0b@$&TgiuH)sy|RdXrF|myAJ>o{;;=GV22UPfTkZMq;I4xi=>Z0} zb7L_g)dIWwb~Am&JnY|Nx8K*hqTbbC{%)E-z7b~?w_CjIKJ$k?)Pth zJZ*nY>%-&2uiwAnQU?5JG-DYxMU};EnMUGTy6wfcck$=^+J zExJgo1DX0fKRrEeuc6y;Bkt1N3%X_;qp=y%7S0lBCpAjraudj8?~|sj;P{GnW@h{;e_3v1|qVyKO8n~CyAhI$l$Erj<)zQD6-nSRGhws!FaOo?R>hN1XV+c;^l zz1WyGhVw~36LsEpY27qEQ8PmHFMr3ff>Jk(A4x9oS7HDy)~yIMQX06kTq;2eEjrDave(eK~3o2fL} zz%GyV3nY`O@S7cCcSK%8r< zx~U2>pTLI;W4b3$BFN+G)Z?>sP4>I<66R^Eb|-`t_<#GN)oP-=&WEnLBk-{~zEN0L~O`UhU zI7VQn41O-UhwaY=I=IEMAQE?QxRD1QQ%)1_QkLsoU+ge28_1?l+Mc^8L%lU=A4l)s zY1S)lB{-o+8RcDz(6D2pnv6?Iq-iwNeVTV;6^YN##n?qu@hb*G7f<*12p3b*ok)5- ze*g9D>y)H*E}|;0#ptq(ZVtFh0yv22#9!BI>N)!D#rl&7v8Kb_)0f2exGh0PLfp5a z;^mD?fBW{Vh=*5~DxIZ{+MykjDo-M026-oJmqht49)=eEAC#^o&yv|b4UOowM-G1C z$}BL7fi7QWh%;CBeA-9cnfE_RtbV>;m-t8Y;RHdKTx<7vZ-R_yp`tSj))2hwV zaV)DmLR_GZ?rOik{f6UbV1G47jJnu@wL4xaWC8y zSj?eu%!rI6Q}BhpJUu0cIEcGx-q+)Re&q%2VKE>e?zUCc#pFo>z2rto6_st0w=L!( zXRG!3=Hk=k)peYtSza7&Ztsrwx`ky?K4#+%K`MHf8WgF0kV7u2RfWIK(-t$Hyp8_x zIWF_5#p;p%MPDa9I!g@O(Bg{@ilWsc;3*MZRMqXSi;?5@(=dLihuvq$G3G`whF@9H z*XYx?m!c1pfdl`PKU6r;T-R+}^aZB*fJZi>unY~iMyi7hd#PrcJMyhl||L|DR-^+5V|mXkuE*WZexZ2Jadrezq~vd3WqphhdmKr% zxciuf8X5EV0-b$SDJh9WlN~qgU${U?GZ!Oe#kIIC5Pk3 z21Gfhr2}KeRl$+RydU!kjeWNlv4AAt7&}-plo2ug-&H+&Vys~uI2T-FgXKtZ4p*|$ zB84Q%TcNDA1gtwGyP{32y81uM$cm`VlVre@E8;vRy{R=$_xG#pRRIuqx~xlcjBO*K zIkCxECWc$6l9K*^p@^`BQ&J@?%h6FKyS8mAxYWbb%fs8BvjQyugkqsk3Bpt`t=qQ5 zx|Q_Jr7`e`@oH5jS!n+U`_CFnZoG7R0t@buavZn`0ElB~_5x0iRlbav6f$1w(p z?hlWzI(gG~T~}B27>U`Q$^lcxYAnY%m(%#i$2+oCAr^XDu|t3&!^xczUiWbcwjP5P zVOtxmgb&e>)TUD*#^ggXk&;4T`8f}Q70GFH@I(Vk4Yy;8I_ zT0$>&iXdIgiYhIAT_B{41GGdkc0Y`{68f|(*>wX}IH?sc8+VMv1S5w73LDizH~c+6 zj9#a3j<@OtFA3DTw!(el=pn-yJmn~vAt*(0B+NX zj!J}H;rXZB1}l669EUh92>GO6h<4Pb_-!l0n53OOi1Q(scG z!!BFez-vh|4FyE>(H=cUc{#Rl_%hn>g_0OL<0irVUe|bE7bT|YWE>q4Hc4FXu-yaa zyxxo8Tn&n4(-cM9l?}I{v$eJj`psRJ6nR>3UFVca-IfQn-Tf;fH?e;}++=zofT=HicHQe~CJ$Rf^%F&E=pAZcnze`8Zr$`#>R zB#B)${7t`Z=%1(}O`xnWsE*^m#2=){#H#o3S7If*FUr2{6Uq|n&y!G<1qF~P6(Mu_ zC)C35s)c*}6(`!8B8JmECzdG%=PMd4)vH(pOjlXtTa4%1Si6 zIHuYnrKbv!b!p{BKBYR?6&C8oLd zYwv86i?Jro5=6JS8fY@W*(QrIr^5I*!V!XlPTu8%2>e|nmezE#7#Zec8{yM7J@CSK zb*#F&9V79zkOpIdw@WeqioSk(`=OI7428Q4^TOZoiJ49w(?ZN=Gla0=vrev>G99rc zCpPTO;$Tm-%yL!jwV8! zZ2U%xoYY#uUTus~eGhvIAPIaI|DvGrEdHf`?!`|XQm8F(2BZ=JzX^;E!W_B%upLl0OAatv|!<|X4#%vHL*>aNO@N43NTWV zngy+}(wJ2-;v#KV$)IC}fRJ3S4$-wkJ45dn%a(E9V3(crCYUXZ9LF}d^79q8W{Z4m z@ITR&epne*(_%%x#JseizCXwx%Aab*D-4FryShupk%shtPuS!ffsP|!6Lr>XRbZzX zyT#*<1_m-uE5wCjDA&fRJZ&*LPdHnRU8x4Uv%(P67|GeGMN&KbLlCs@6XYvdZSv)S zS#?`LFIW{B0%?ps_A%% zQA;~uMFBJ5xokexICVDERT>6SMS|r@92e>{#4w??Rns9?uqrv!9oiC%?ocgTh*pS` z0?mLkoRlfWJ3G`YR<}4{5u*!ln?&>5`7ZKf41oQvWGLvkf*i#hl;eH;Q*R}XlHvufXb3_SCIj=SjXg)CxwweluIK?@7;p@>8EB;>j){--COc8DO$H!)QX#2)6lF*jRTYPc$vm7LI#H!Cvgy*c>Dp2( z`o=NI{r}GfVK~W}xR1peCbA&~sn*HXq$TMq{a-9UP2*#65(z()_4$`I640)g4QO6t z(s7XdTiK*E*dYZdGLm6QM{-`ZhPJ|{_bwgA0aGxor8IG9#HF-5+w{3u1WR=d+UU$O21v7-(8*^)bG1n@!y^L zecU*|oqUc5@!yTc-<*s8)Nh%s{(Zi>T(7S5?~Aif>&@NW`hIn|zQ5J!mqM+L{_W&@ ze@o@j^t%i3-zQm0BmM3MCDgx@QAaq=V&zpu~k@05KvXSN+SXSN;i+ri&oeLCnOE4izco$qS( z>GtNR?7dm79s2rswc)%4LCd*xaM!4~D^)g)yCY`x`}~p&tAF1RkNzF5r_J@{W_^CI z^FLgyRySwI+lxyaR=QU9zBvDMb+C`a jre-z4r{5Ab)y$-e``dv{WcTl%_HU2k0}pX$+<*KpF^{YZ literal 380638 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 diff --git a/thirdparty/stb/src/Makefile b/thirdparty/stb/src/Makefile index 194ea5e..597616a 100644 --- a/thirdparty/stb/src/Makefile +++ b/thirdparty/stb/src/Makefile @@ -6,55 +6,22 @@ else all: unix endif +$(info Current OS is: $(OS)) + wasm: mkdir -p ../lib - $(CC) -c -Os --target=wasm32 --sysroot=$(shell odin root)/vendor/libc stb_image.c -o ../lib/stb_image_wasm.o -DSTBI_NO_STDIO - $(CC) -c -Os --target=wasm32 --sysroot=$(shell odin root)/vendor/libc stb_image_write.c -o ../lib/stb_image_write_wasm.o -DSTBI_WRITE_NO_STDIO - $(CC) -c -Os --target=wasm32 --sysroot=$(shell odin root)/vendor/libc stb_image_resize.c -o ../lib/stb_image_resize_wasm.o $(CC) -c -Os --target=wasm32 --sysroot=$(shell odin root)/vendor/libc stb_truetype.c -o ../lib/stb_truetype_wasm.o - # $(CC) -c -Os --target=wasm32 --sysroot=$(shell odin root)/vendor/libc stb_vorbis.c -o ../lib/stb_vorbis_wasm.o -DSTB_VORBIS_NO_STDIO - $(CC) -c -Os --target=wasm32 --sysroot=$(shell odin root)/vendor/libc stb_rect_pack.c -o ../lib/stb_rect_pack_wasm.o - $(CC) -c -Os --target=wasm32 stb_sprintf.c -o ../lib/stb_sprintf_wasm.o unix: mkdir -p ../lib - $(CC) -c -O2 -Os -fPIC stb_image.c stb_image_write.c stb_image_resize.c stb_truetype.c stb_rect_pack.c stb_vorbis.c stb_sprintf.c - $(AR) rcs ../lib/stb_image.a stb_image.o - $(AR) rcs ../lib/stb_image_write.a stb_image_write.o - $(AR) rcs ../lib/stb_image_resize.a stb_image_resize.o + $(CC) -c -O2 -Os -fPIC stb_truetype.c $(AR) rcs ../lib/stb_truetype.a stb_truetype.o - $(AR) rcs ../lib/stb_rect_pack.a stb_rect_pack.o - $(AR) rcs ../lib/stb_vorbis.a stb_vorbis.o - $(AR) rcs ../lib/stb_sprintf.a stb_sprintf.o - #$(CC) -fPIC -shared -Wl,-soname=stb_image.so -o ../lib/stb_image.so stb_image.o - #$(CC) -fPIC -shared -Wl,-soname=stb_image_write.so -o ../lib/stb_image_write.so stb_image_write.o - #$(CC) -fPIC -shared -Wl,-soname=stb_image_resize.so -o ../lib/stb_image_resize.so stb_image_resize.o #$(CC) -fPIC -shared -Wl,-soname=stb_truetype.so -o ../lib/stb_truetype.so stb_image_truetype.o - #$(CC) -fPIC -shared -Wl,-soname=stb_rect_pack.so -o ../lib/stb_rect_pack.so stb_rect_packl.o - #$(CC) -fPIC -shared -Wl,-soname=stb_vorbis.so -o ../lib/stb_vorbis.so stb_vorbisl.o rm *.o darwin: mkdir -p ../lib - $(CC) -arch x86_64 -c -O2 -Os -fPIC stb_image.c -o stb_image-x86_64.o -mmacosx-version-min=10.12 - $(CC) -arch arm64 -c -O2 -Os -fPIC stb_image.c -o stb_image-arm64.o -mmacosx-version-min=10.12 - lipo -create stb_image-x86_64.o stb_image-arm64.o -output ../lib/darwin/stb_image.a - $(CC) -arch x86_64 -c -O2 -Os -fPIC stb_image_write.c -o stb_image_write-x86_64.o -mmacosx-version-min=10.12 - $(CC) -arch arm64 -c -O2 -Os -fPIC stb_image_write.c -o stb_image_write-arm64.o -mmacosx-version-min=10.12 - lipo -create stb_image_write-x86_64.o stb_image_write-arm64.o -output ../lib/darwin/stb_image_write.a - $(CC) -arch x86_64 -c -O2 -Os -fPIC stb_image_resize.c -o stb_image_resize-x86_64.o -mmacosx-version-min=10.12 - $(CC) -arch arm64 -c -O2 -Os -fPIC stb_image_resize.c -o stb_image_resize-arm64.o -mmacosx-version-min=10.12 - lipo -create stb_image_resize-x86_64.o stb_image_resize-arm64.o -output ../lib/darwin/stb_image_resize.a $(CC) -arch x86_64 -c -O2 -Os -fPIC stb_truetype.c -o stb_truetype-x86_64.o -mmacosx-version-min=10.12 $(CC) -arch arm64 -c -O2 -Os -fPIC stb_truetype.c -o stb_truetype-arm64.o -mmacosx-version-min=10.12 lipo -create stb_truetype-x86_64.o stb_truetype-arm64.o -output ../lib/darwin/stb_truetype.a - $(CC) -arch x86_64 -c -O2 -Os -fPIC stb_rect_pack.c -o stb_rect_pack-x86_64.o -mmacosx-version-min=10.12 - $(CC) -arch arm64 -c -O2 -Os -fPIC stb_rect_pack.c -o stb_rect_pack-arm64.o -mmacosx-version-min=10.12 - lipo -create stb_rect_pack-x86_64.o stb_rect_pack-arm64.o -output ../lib/darwin/stb_rect_pack.a - $(CC) -arch x86_64 -c -O2 -Os -fPIC stb_vorbis.c -o stb_vorbis-x86_64.o -mmacosx-version-min=10.12 - $(CC) -arch arm64 -c -O2 -Os -fPIC stb_vorbis.c -o stb_vorbis-arm64.o -mmacosx-version-min=10.12 - lipo -create stb_vorbis-x86_64.o stb_vorbis-arm64.o -output ../lib/darwin/stb_vorbis.a - $(CC) -arch x86_64 -c -O2 -Os -fPIC stb_sprintf.c -o stb_sprintf-x86_64.o -mmacosx-version-min=10.12 - $(CC) -arch arm64 -c -O2 -Os -fPIC stb_sprintf.c -o stb_sprintf-arm64.o -mmacosx-version-min=10.12 - lipo -create stb_sprintf-x86_64.o stb_sprintf-arm64.o -output ../lib/darwin/stb_sprintf.a rm *.o diff --git a/thirdparty/stb/src/gb/gb.h b/thirdparty/stb/src/gb/gb.h deleted file mode 100644 index adeb554..0000000 --- a/thirdparty/stb/src/gb/gb.h +++ /dev/null @@ -1,10824 +0,0 @@ -/* gb.h - v0.33 - Ginger Bill's C Helper Library - public domain - - no warranty implied; use at your own risk - - This is a single header file with a bunch of useful stuff - to replace the C/C++ standard library - -=========================================================================== - YOU MUST - - #define GB_IMPLEMENTATION - - in EXACTLY _one_ C or C++ file that includes this header, BEFORE the - include like this: - - #define GB_IMPLEMENTATION - #include "gb.h" - - All other files should just #include "gb.h" without #define - - - If you want the platform layer, YOU MUST - - #define GB_PLATFORM - - BEFORE the include like this: - - #define GB_PLATFORM - #include "gb.h" - -=========================================================================== - -LICENSE - This software is dual-licensed to the public domain and under the following - license: you are granted a perpetual, irrevocable license to copy, modify, - publish, and distribute this file as you see fit. - -WARNING - - This library is _slightly_ experimental and features may not work as expected. - - This also means that many functions are not documented. - -CREDITS - Written by Ginger Bill - -TODOS - - Remove CRT dependency for people who want that - - But do I really? - - Or make it only depend on the really needed stuff? - - Older compiler support? - - How old do you wanna go? - - Only support C90+extension and C99 not pure C89. - - File handling - - All files to be UTF-8 (even on windows) - - Better Virtual Memory handling - - Generic Heap Allocator (tcmalloc/dlmalloc/?) - - Fixed Heap Allocator - - Better UTF support and conversion - - Free List, best fit rather than first fit - - More date & time functions - -VERSION HISTORY - 0.33 - Minor fixes - 0.32 - Minor fixes - 0.31 - Add gb_file_remove - 0.30 - Changes to gbThread (and gbMutex on Windows) - 0.29 - Add extras for gbString - 0.28 - Handle UCS2 correctly in Win32 part - 0.27 - OSX fixes and Linux gbAffinity - 0.26d - Minor changes to how gbFile works - 0.26c - gb_str_to_f* fix - 0.26b - Minor fixes - 0.26a - gbString Fix - 0.26 - Default allocator flags and generic hash table - 0.25a - Fix UTF-8 stuff - 0.25 - OS X gbPlatform Support (missing some things) - 0.24b - Compile on OSX (excluding platform part) - 0.24a - Minor additions - 0.24 - Enum convention change - 0.23 - Optional Windows.h removal (because I'm crazy) - 0.22a - Remove gbVideoMode from gb_platform_init_* - 0.22 - gbAffinity - (Missing Linux version) - 0.21 - Platform Layer Restructuring - 0.20 - Improve file io - 0.19 - Clipboard Text - 0.18a - Controller vibration - 0.18 - Raw keyboard and mouse input for WIN32 - 0.17d - Fixed printf bug for strings - 0.17c - Compile as 32 bit - 0.17b - Change formating style because why not? - 0.17a - Dropped C90 Support (For numerous reasons) - 0.17 - Instantiated Hash Table - 0.16a - Minor code layout changes - 0.16 - New file API and improved platform layer - 0.15d - Linux Experimental Support (DON'T USE IT PLEASE) - 0.15c - Linux Experimental Support (DON'T USE IT) - 0.15b - C90 Support - 0.15a - gb_atomic(32|64)_spin_(lock|unlock) - 0.15 - Recursive "Mutex"; Key States; gbRandom - 0.14 - Better File Handling and better printf (WIN32 Only) - 0.13 - Highly experimental platform layer (WIN32 Only) - 0.12b - Fix minor file bugs - 0.12a - Compile as C++ - 0.12 - New File Handing System! No stdio or stdlib! (WIN32 Only) - 0.11a - Add string precision and width (experimental) - 0.11 - Started making stdio & stdlib optional (Not tested much) - 0.10c - Fix gb_endian_swap32() - 0.10b - Probable timing bug for gb_time_now() - 0.10a - Work on multiple compilers - 0.10 - Scratch Memory Allocator - 0.09a - Faster Mutex and the Free List is slightly improved - 0.09 - Basic Virtual Memory System and Dreadful Free List allocator - 0.08a - Fix *_appendv bug - 0.08 - Huge Overhaul! - 0.07a - Fix alignment in gb_heap_allocator_proc - 0.07 - Hash Table and Hashing Functions - 0.06c - Better Documentation - 0.06b - OS X Support - 0.06a - Linux Support - 0.06 - Windows GCC Support and MSVC x86 Support - 0.05b - Formatting - 0.05a - Minor function name changes - 0.05 - Radix Sort for unsigned integers (TODO: Other primitives) - 0.04 - Better UTF support and search/sort procs - 0.03 - Completely change procedure naming convention - 0.02a - Bug fixes - 0.02 - Change naming convention and gbArray(Type) - 0.01 - Initial Version -*/ - - -#ifndef GB_INCLUDE_GB_H -#define GB_INCLUDE_GB_H - -#if defined(__cplusplus) -extern "C" { -#endif - -#if defined(__cplusplus) - #define GB_EXTERN extern "C" -#else - #define GB_EXTERN extern -#endif - -#if defined(_WIN32) - #define GB_DLL_EXPORT GB_EXTERN __declspec(dllexport) - #define GB_DLL_IMPORT GB_EXTERN __declspec(dllimport) -#else - #define GB_DLL_EXPORT GB_EXTERN __attribute__((visibility("default"))) - #define GB_DLL_IMPORT GB_EXTERN -#endif - -// NOTE(bill): Redefine for DLL, etc. -#ifndef GB_DEF - #ifdef GB_STATIC - #define GB_DEF static - #else - #define GB_DEF extern - #endif -#endif - -#if defined(_WIN64) || defined(__x86_64__) || defined(_M_X64) || defined(__64BIT__) || defined(__powerpc64__) || defined(__ppc64__) - #ifndef GB_ARCH_64_BIT - #define GB_ARCH_64_BIT 1 - #endif -#else - // NOTE(bill): I'm only supporting 32 bit and 64 bit systems - #ifndef GB_ARCH_32_BIT - #define GB_ARCH_32_BIT 1 - #endif -#endif - - -#ifndef GB_ENDIAN_ORDER -#define GB_ENDIAN_ORDER - // TODO(bill): Is the a good way or is it better to test for certain compilers and macros? - #define GB_IS_BIG_ENDIAN (!*(u8*)&(u16){1}) - #define GB_IS_LITTLE_ENDIAN (!GB_IS_BIG_ENDIAN) -#endif - -#if defined(_WIN32) || defined(_WIN64) - #ifndef GB_SYSTEM_WINDOWS - #define GB_SYSTEM_WINDOWS 1 - #endif -#elif defined(__APPLE__) && defined(__MACH__) - #ifndef GB_SYSTEM_OSX - #define GB_SYSTEM_OSX 1 - #endif -#elif defined(__unix__) - #ifndef GB_SYSTEM_UNIX - #define GB_SYSTEM_UNIX 1 - #endif - - #if defined(__linux__) - #ifndef GB_SYSTEM_LINUX - #define GB_SYSTEM_LINUX 1 - #endif - #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) - #ifndef GB_SYSTEM_FREEBSD - #define GB_SYSTEM_FREEBSD 1 - #endif - #else - #error This UNIX operating system is not supported - #endif -#else - #error This operating system is not supported -#endif - -#if defined(_MSC_VER) - #define GB_COMPILER_MSVC 1 -#elif defined(__GNUC__) - #define GB_COMPILER_GCC 1 -#elif defined(__clang__) - #define GB_COMPILER_CLANG 1 -#else - #error Unknown compiler -#endif - -#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__x86_64__) - #ifndef GB_CPU_X86 - #define GB_CPU_X86 1 - #endif - #ifndef GB_CACHE_LINE_SIZE - #define GB_CACHE_LINE_SIZE 64 - #endif - -#elif defined(_M_PPC) || defined(__powerpc__) || defined(__powerpc64__) - #ifndef GB_CPU_PPC - #define GB_CPU_PPC 1 - #endif - #ifndef GB_CACHE_LINE_SIZE - #define GB_CACHE_LINE_SIZE 128 - #endif - -#elif defined(__arm__) - #ifndef GB_CPU_ARM - #define GB_CPU_ARM 1 - #endif - #ifndef GB_CACHE_LINE_SIZE - #define GB_CACHE_LINE_SIZE 64 - #endif - -#elif defined(__MIPSEL__) || defined(__mips_isa_rev) - #ifndef GB_CPU_MIPS - #define GB_CPU_MIPS 1 - #endif - #ifndef GB_CACHE_LINE_SIZE - #define GB_CACHE_LINE_SIZE 64 - #endif - -#else - #error Unknown CPU Type -#endif - - - -#ifndef GB_STATIC_ASSERT - #define GB_STATIC_ASSERT3(cond, msg) typedef char static_assertion_##msg[(!!(cond))*2-1] - // NOTE(bill): Token pasting madness!! - #define GB_STATIC_ASSERT2(cond, line) GB_STATIC_ASSERT3(cond, static_assertion_at_line_##line) - #define GB_STATIC_ASSERT1(cond, line) GB_STATIC_ASSERT2(cond, line) - #define GB_STATIC_ASSERT(cond) GB_STATIC_ASSERT1(cond, __LINE__) -#endif - - -//////////////////////////////////////////////////////////////// -// -// Headers -// -// - -#if defined(_WIN32) && !defined(__MINGW32__) - #ifndef _CRT_SECURE_NO_WARNINGS - #define _CRT_SECURE_NO_WARNINGS - #endif -#endif - -#if defined(GB_SYSTEM_UNIX) - #define _GNU_SOURCE - #define _LARGEFILE64_SOURCE -#endif - - -// TODO(bill): How many of these headers do I really need? -// #include -#if !defined(GB_SYSTEM_WINDOWS) - #include - #include -#endif - - - -#if defined(GB_SYSTEM_WINDOWS) - #if !defined(GB_NO_WINDOWS_H) - #define NOMINMAX 1 - #define WIN32_LEAN_AND_MEAN 1 - #define WIN32_MEAN_AND_LEAN 1 - #define VC_EXTRALEAN 1 - #include - #undef NOMINMAX - #undef WIN32_LEAN_AND_MEAN - #undef WIN32_MEAN_AND_LEAN - #undef VC_EXTRALEAN - #endif - - #include // NOTE(bill): _aligned_*() - #include -#else - #include - #include - #include - #include - #ifndef _IOSC11_SOURCE - #define _IOSC11_SOURCE - #endif - #include // NOTE(bill): malloc on linux - #include - #if !defined(GB_SYSTEM_OSX) - #include - #endif - #include - #include - #include - #include - #include - - #if defined(GB_CPU_X86) - #include - #endif -#endif - -#if defined(GB_SYSTEM_OSX) - #include - #include - #include - #include - #include - #include - #include - #include -#endif - -#if defined(GB_SYSTEM_UNIX) - #include -#endif - - -//////////////////////////////////////////////////////////////// -// -// Base Types -// -// - -#if defined(GB_COMPILER_MSVC) - #if _MSC_VER < 1300 - typedef unsigned char u8; - typedef signed char i8; - typedef unsigned short u16; - typedef signed short i16; - typedef unsigned int u32; - typedef signed int i32; - #else - typedef unsigned __int8 u8; - typedef signed __int8 i8; - typedef unsigned __int16 u16; - typedef signed __int16 i16; - typedef unsigned __int32 u32; - typedef signed __int32 i32; - #endif - typedef unsigned __int64 u64; - typedef signed __int64 i64; -#else - #include - typedef uint8_t u8; - typedef int8_t i8; - typedef uint16_t u16; - typedef int16_t i16; - typedef uint32_t u32; - typedef int32_t i32; - typedef uint64_t u64; - typedef int64_t i64; -#endif - -GB_STATIC_ASSERT(sizeof(u8) == sizeof(i8)); -GB_STATIC_ASSERT(sizeof(u16) == sizeof(i16)); -GB_STATIC_ASSERT(sizeof(u32) == sizeof(i32)); -GB_STATIC_ASSERT(sizeof(u64) == sizeof(i64)); - -GB_STATIC_ASSERT(sizeof(u8) == 1); -GB_STATIC_ASSERT(sizeof(u16) == 2); -GB_STATIC_ASSERT(sizeof(u32) == 4); -GB_STATIC_ASSERT(sizeof(u64) == 8); - -typedef size_t usize; -typedef ptrdiff_t isize; - -GB_STATIC_ASSERT(sizeof(usize) == sizeof(isize)); - -// NOTE(bill): (u)intptr is only here for semantic reasons really as this library will only support 32/64 bit OSes. -// NOTE(bill): Are there any modern OSes (not 16 bit) where intptr != isize ? -#if defined(_WIN64) - typedef signed __int64 intptr; - typedef unsigned __int64 uintptr; -#elif defined(_WIN32) - // NOTE(bill); To mark types changing their size, e.g. 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 intptr; - typedef _W64 unsigned int uintptr; -#else - typedef uintptr_t uintptr; - typedef intptr_t intptr; -#endif - -GB_STATIC_ASSERT(sizeof(uintptr) == sizeof(intptr)); - -typedef float f32; -typedef double f64; - -GB_STATIC_ASSERT(sizeof(f32) == 4); -GB_STATIC_ASSERT(sizeof(f64) == 8); - -typedef i32 Rune; // NOTE(bill): Unicode codepoint -#define GB_RUNE_INVALID cast(Rune)(0xfffd) -#define GB_RUNE_MAX cast(Rune)(0x0010ffff) -#define GB_RUNE_BOM cast(Rune)(0xfeff) -#define GB_RUNE_EOF cast(Rune)(-1) - - -typedef i8 b8; -typedef i16 b16; -typedef i32 b32; // NOTE(bill): Prefer this!!! - -// NOTE(bill): Get true and false -#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 b8 bool; - #else - #include - #endif -#endif - -// NOTE(bill): These do are not prefixed with gb because the types are not. -#ifndef U8_MIN -#define U8_MIN 0u -#define U8_MAX 0xffu -#define I8_MIN (-0x7f - 1) -#define I8_MAX 0x7f - -#define U16_MIN 0u -#define U16_MAX 0xffffu -#define I16_MIN (-0x7fff - 1) -#define I16_MAX 0x7fff - -#define U32_MIN 0u -#define U32_MAX 0xffffffffu -#define I32_MIN (-0x7fffffff - 1) -#define I32_MAX 0x7fffffff - -#define U64_MIN 0ull -#define U64_MAX 0xffffffffffffffffull -#define I64_MIN (-0x7fffffffffffffffll - 1) -#define I64_MAX 0x7fffffffffffffffll - -#if defined(GB_ARCH_32_BIT) - #define USIZE_MIX U32_MIN - #define USIZE_MAX U32_MAX - - #define ISIZE_MIX S32_MIN - #define ISIZE_MAX S32_MAX -#elif defined(GB_ARCH_64_BIT) - #define USIZE_MIX U64_MIN - #define USIZE_MAX U64_MAX - - #define ISIZE_MIX I64_MIN - #define ISIZE_MAX I64_MAX -#else - #error Unknown architecture size. This library only supports 32 bit and 64 bit architectures. -#endif - -#define F32_MIN 1.17549435e-38f -#define F32_MAX 3.40282347e+38f - -#define F64_MIN 2.2250738585072014e-308 -#define F64_MAX 1.7976931348623157e+308 - -#endif - -#ifndef NULL - #if defined(__cplusplus) - #if __cplusplus >= 201103L - #define NULL nullptr - #else - #define NULL 0 - #endif - #else - #define NULL ((void *)0) - #endif -#endif - -// TODO(bill): Is this enough to get inline working? -#if !defined(__cplusplus) - #if defined(_MSC_VER) && _MSC_VER <= 1800 - #define inline __inline - #elif !defined(__STDC_VERSION__) - #define inline __inline__ - #else - #define inline - #endif -#endif - -#if !defined(gb_restrict) - #if defined(_MSC_VER) - #define gb_restrict __restrict - #elif defined(__STDC_VERSION__) - #define gb_restrict restrict - #else - #define gb_restrict - #endif -#endif - -// TODO(bill): Should force inline be a separate keyword and gb_inline be inline? -#if !defined(gb_inline) - #if defined(_MSC_VER) - #if _MSC_VER < 1300 - #define gb_inline - #else - #define gb_inline __forceinline - #endif - #else - #define gb_inline __attribute__ ((__always_inline__)) - #endif -#endif - -#if !defined(gb_no_inline) - #if defined(_MSC_VER) - #define gb_no_inline __declspec(noinline) - #else - #define gb_no_inline __attribute__ ((noinline)) - #endif -#endif - - -#if !defined(gb_thread_local) - #if defined(_MSC_VER) && _MSC_VER >= 1300 - #define gb_thread_local __declspec(thread) - #elif defined(__GNUC__) - #define gb_thread_local __thread - #else - #define gb_thread_local thread_local - #endif -#endif - - -// NOTE(bill): Easy to grep -// NOTE(bill): Not needed in macros -#ifndef cast -#define cast(Type) (Type) -#endif - -// NOTE(bill): Because a signed sizeof is more useful -#ifndef gb_size_of -#define gb_size_of(x) (isize)(sizeof(x)) -#endif - -#ifndef gb_count_of -#define gb_count_of(x) ((gb_size_of(x)/gb_size_of(0[x])) / ((isize)(!(gb_size_of(x) % gb_size_of(0[x]))))) -#endif - -#ifndef gb_offset_of -#define gb_offset_of(Type, element) ((isize)&(((Type *)0)->element)) -#endif - -#if defined(__cplusplus) -#ifndef gb_align_of - #if __cplusplus >= 201103L - #define gb_align_of(Type) (isize)alignof(Type) - #else -extern "C++" { - // NOTE(bill): Fucking Templates! - template struct gbAlignment_Trick { char c; T member; }; - #define gb_align_of(Type) gb_offset_of(gbAlignment_Trick, member) -} - #endif -#endif -#else - #ifndef gb_align_of - #define gb_align_of(Type) gb_offset_of(struct { char c; Type member; }, member) - #endif -#endif - -// NOTE(bill): I do wish I had a type_of that was portable -#ifndef gb_swap -#define gb_swap(Type, a, b) do { Type tmp = (a); (a) = (b); (b) = tmp; } while (0) -#endif - -// NOTE(bill): Because static means 3/4 different things in C/C++. Great design (!) -#ifndef gb_global -#define gb_global static // Global variables -#define gb_internal static // Internal linkage -#define gb_local_persist static // Local Persisting variables -#endif - - -#ifndef gb_unused - #if defined(_MSC_VER) - #define gb_unused(x) (__pragma(warning(suppress:4100))(x)) - #elif defined (__GCC__) - #define gb_unused(x) __attribute__((__unused__))(x) - #else - #define gb_unused(x) ((void)(gb_size_of(x))) - #endif -#endif - - - - -//////////////////////////////////////////////////////////////// -// -// Defer statement -// Akin to D's SCOPE_EXIT or -// similar to Go's defer but scope-based -// -// NOTE: C++11 (and above) only! -// -#if !defined(GB_NO_DEFER) && defined(__cplusplus) && ((defined(_MSC_VER) && _MSC_VER >= 1400) || (__cplusplus >= 201103L)) -extern "C++" { - // NOTE(bill): Stupid fucking templates - template struct gbRemoveReference { typedef T Type; }; - template struct gbRemoveReference { typedef T Type; }; - template struct gbRemoveReference { typedef T Type; }; - - /// NOTE(bill): "Move" semantics - invented because the C++ committee are idiots (as a collective not as indiviuals (well a least some aren't)) - template inline T &&gb_forward(typename gbRemoveReference::Type &t) { return static_cast(t); } - template inline T &&gb_forward(typename gbRemoveReference::Type &&t) { return static_cast(t); } - template inline T &&gb_move (T &&t) { return static_cast::Type &&>(t); } - template - struct gbprivDefer { - F f; - gbprivDefer(F &&f) : f(gb_forward(f)) {} - ~gbprivDefer() { f(); } - }; - template gbprivDefer gb__defer_func(F &&f) { return gbprivDefer(gb_forward(f)); } - - #define GB_DEFER_1(x, y) x##y - #define GB_DEFER_2(x, y) GB_DEFER_1(x, y) - #define GB_DEFER_3(x) GB_DEFER_2(x, __COUNTER__) - #define defer(code) auto GB_DEFER_3(_defer_) = gb__defer_func([&]()->void{code;}) -} - -// Example -#if 0 - gbMutex m; - gb_mutex_init(&m); - { - gb_mutex_lock(&m); - defer (gb_mutex_unlock(&m)); - - ... - } -#endif - -#endif - - -//////////////////////////////////////////////////////////////// -// -// Macro Fun! -// -// - -#ifndef GB_JOIN_MACROS -#define GB_JOIN_MACROS - #define GB_JOIN2_IND(a, b) a##b - - #define GB_JOIN2(a, b) GB_JOIN2_IND(a, b) - #define GB_JOIN3(a, b, c) GB_JOIN2(GB_JOIN2(a, b), c) - #define GB_JOIN4(a, b, c, d) GB_JOIN2(GB_JOIN2(GB_JOIN2(a, b), c), d) -#endif - - -#ifndef GB_BIT -#define GB_BIT(x) (1<<(x)) -#endif - -#ifndef gb_min -#define gb_min(a, b) ((a) < (b) ? (a) : (b)) -#endif - -#ifndef gb_max -#define gb_max(a, b) ((a) > (b) ? (a) : (b)) -#endif - -#ifndef gb_min3 -#define gb_min3(a, b, c) gb_min(gb_min(a, b), c) -#endif - -#ifndef gb_max3 -#define gb_max3(a, b, c) gb_max(gb_max(a, b), c) -#endif - -#ifndef gb_clamp -#define gb_clamp(x, lower, upper) gb_min(gb_max((x), (lower)), (upper)) -#endif - -#ifndef gb_clamp01 -#define gb_clamp01(x) gb_clamp((x), 0, 1) -#endif - -#ifndef gb_is_between -#define gb_is_between(x, lower, upper) (((lower) <= (x)) && ((x) <= (upper))) -#endif - -#ifndef gb_abs -#define gb_abs(x) ((x) < 0 ? -(x) : (x)) -#endif - -/* NOTE(bill): Very useful bit setting */ -#ifndef GB_MASK_SET -#define GB_MASK_SET(var, set, mask) do { \ - if (set) (var) |= (mask); \ - else (var) &= ~(mask); \ -} while (0) -#endif - - -// NOTE(bill): Some compilers support applying printf-style warnings to user functions. -#if defined(__clang__) || defined(__GNUC__) -#define GB_PRINTF_ARGS(FMT) __attribute__((format(printf, FMT, (FMT+1)))) -#else -#define GB_PRINTF_ARGS(FMT) -#endif - -//////////////////////////////////////////////////////////////// -// -// Debug -// -// - - -#ifndef GB_DEBUG_TRAP - #if defined(_MSC_VER) - #if _MSC_VER < 1300 - #define GB_DEBUG_TRAP() __asm int 3 /* Trap to debugger! */ - #else - #define GB_DEBUG_TRAP() __debugbreak() - #endif - #else - #define GB_DEBUG_TRAP() __builtin_trap() - #endif -#endif - -#ifndef GB_ASSERT_MSG -#define GB_ASSERT_MSG(cond, msg, ...) do { \ - if (!(cond)) { \ - gb_assert_handler("Assertion Failure", #cond, __FILE__, cast(i64)__LINE__, msg, ##__VA_ARGS__); \ - GB_DEBUG_TRAP(); \ - } \ -} while (0) -#endif - -#ifndef GB_ASSERT -#define GB_ASSERT(cond) GB_ASSERT_MSG(cond, NULL) -#endif - -#ifndef GB_ASSERT_NOT_NULL -#define GB_ASSERT_NOT_NULL(ptr) GB_ASSERT_MSG((ptr) != NULL, #ptr " must not be NULL") -#endif - -// NOTE(bill): Things that shouldn't happen with a message! -#ifndef GB_PANIC -#define GB_PANIC(msg, ...) do { \ - gb_assert_handler("Panic", NULL, __FILE__, cast(i64)__LINE__, msg, ##__VA_ARGS__); \ - GB_DEBUG_TRAP(); \ -} while (0) -#endif - -GB_DEF void gb_assert_handler(char const *prefix, char const *condition, char const *file, i32 line, char const *msg, ...); - - - -//////////////////////////////////////////////////////////////// -// -// Memory -// -// - - -GB_DEF b32 gb_is_power_of_two(isize x); - -GB_DEF void * gb_align_forward(void *ptr, isize alignment); - -GB_DEF void * gb_pointer_add (void *ptr, isize bytes); -GB_DEF void * gb_pointer_sub (void *ptr, isize bytes); -GB_DEF void const *gb_pointer_add_const(void const *ptr, isize bytes); -GB_DEF void const *gb_pointer_sub_const(void const *ptr, isize bytes); -GB_DEF isize gb_pointer_diff (void const *begin, void const *end); - - -GB_DEF void gb_zero_size(void *ptr, isize size); -#ifndef gb_zero_item -#define gb_zero_item(t) gb_zero_size((t), gb_size_of(*(t))) // NOTE(bill): Pass pointer of struct -#define gb_zero_array(a, count) gb_zero_size((a), gb_size_of(*(a))*count) -#endif - -GB_DEF void * gb_memcopy (void *dest, void const *source, isize size); -GB_DEF void * gb_memmove (void *dest, void const *source, isize size); -GB_DEF void * gb_memset (void *data, u8 byte_value, isize size); -GB_DEF i32 gb_memcompare(void const *s1, void const *s2, isize size); -GB_DEF void gb_memswap (void *i, void *j, isize size); -GB_DEF void const *gb_memchr (void const *data, u8 byte_value, isize size); -GB_DEF void const *gb_memrchr (void const *data, u8 byte_value, isize size); - - -#ifndef gb_memcopy_array -#define gb_memcopy_array(dst, src, count) gb_memcopy((dst), (src), gb_size_of(*(dst))*(count)) -#endif - -#ifndef gb_memmove_array -#define gb_memmove_array(dst, src, count) gb_memmove((dst), (src), gb_size_of(*(dst))*(count)) -#endif - -// NOTE(bill): Very similar to doing `*cast(T *)(&u)` -#ifndef GB_BIT_CAST -#define GB_BIT_CAST(dest, source) do { \ - GB_STATIC_ASSERT(gb_size_of(*(dest)) <= gb_size_of(source)); \ - gb_memcopy((dest), &(source), gb_size_of(*dest)); \ -} while (0) -#endif - - - - -#ifndef gb_kilobytes -#define gb_kilobytes(x) ( (x) * (i64)(1024)) -#define gb_megabytes(x) (gb_kilobytes(x) * (i64)(1024)) -#define gb_gigabytes(x) (gb_megabytes(x) * (i64)(1024)) -#define gb_terabytes(x) (gb_gigabytes(x) * (i64)(1024)) -#endif - - - - -// Atomics - -// TODO(bill): Be specific with memory order? -// e.g. relaxed, acquire, release, acquire_release - -#if defined(GB_COMPILER_MSVC) -typedef struct gbAtomic32 { i32 volatile value; } gbAtomic32; -typedef struct gbAtomic64 { i64 volatile value; } gbAtomic64; -typedef struct gbAtomicPtr { void *volatile value; } gbAtomicPtr; -#else - #if defined(GB_ARCH_32_BIT) - #define GB_ATOMIC_PTR_ALIGNMENT 4 - #elif defined(GB_ARCH_64_BIT) - #define GB_ATOMIC_PTR_ALIGNMENT 8 - #else - #error Unknown architecture - #endif - -typedef struct gbAtomic32 { i32 volatile value; } __attribute__ ((aligned(4))) gbAtomic32; -typedef struct gbAtomic64 { i64 volatile value; } __attribute__ ((aligned(8))) gbAtomic64; -typedef struct gbAtomicPtr { void *volatile value; } __attribute__ ((aligned(GB_ATOMIC_PTR_ALIGNMENT))) gbAtomicPtr; -#endif - -GB_DEF i32 gb_atomic32_load (gbAtomic32 const volatile *a); -GB_DEF void gb_atomic32_store (gbAtomic32 volatile *a, i32 value); -GB_DEF i32 gb_atomic32_compare_exchange(gbAtomic32 volatile *a, i32 expected, i32 desired); -GB_DEF i32 gb_atomic32_exchanged (gbAtomic32 volatile *a, i32 desired); -GB_DEF i32 gb_atomic32_fetch_add (gbAtomic32 volatile *a, i32 operand); -GB_DEF i32 gb_atomic32_fetch_and (gbAtomic32 volatile *a, i32 operand); -GB_DEF i32 gb_atomic32_fetch_or (gbAtomic32 volatile *a, i32 operand); -GB_DEF b32 gb_atomic32_spin_lock (gbAtomic32 volatile *a, isize time_out); // NOTE(bill): time_out = -1 as default -GB_DEF void gb_atomic32_spin_unlock (gbAtomic32 volatile *a); -GB_DEF b32 gb_atomic32_try_acquire_lock(gbAtomic32 volatile *a); - - -GB_DEF i64 gb_atomic64_load (gbAtomic64 const volatile *a); -GB_DEF void gb_atomic64_store (gbAtomic64 volatile *a, i64 value); -GB_DEF i64 gb_atomic64_compare_exchange(gbAtomic64 volatile *a, i64 expected, i64 desired); -GB_DEF i64 gb_atomic64_exchanged (gbAtomic64 volatile *a, i64 desired); -GB_DEF i64 gb_atomic64_fetch_add (gbAtomic64 volatile *a, i64 operand); -GB_DEF i64 gb_atomic64_fetch_and (gbAtomic64 volatile *a, i64 operand); -GB_DEF i64 gb_atomic64_fetch_or (gbAtomic64 volatile *a, i64 operand); -GB_DEF b32 gb_atomic64_spin_lock (gbAtomic64 volatile *a, isize time_out); // NOTE(bill): time_out = -1 as default -GB_DEF void gb_atomic64_spin_unlock (gbAtomic64 volatile *a); -GB_DEF b32 gb_atomic64_try_acquire_lock(gbAtomic64 volatile *a); - - -GB_DEF void *gb_atomic_ptr_load (gbAtomicPtr const volatile *a); -GB_DEF void gb_atomic_ptr_store (gbAtomicPtr volatile *a, void *value); -GB_DEF void *gb_atomic_ptr_compare_exchange(gbAtomicPtr volatile *a, void *expected, void *desired); -GB_DEF void *gb_atomic_ptr_exchanged (gbAtomicPtr volatile *a, void *desired); -GB_DEF void *gb_atomic_ptr_fetch_add (gbAtomicPtr volatile *a, void *operand); -GB_DEF void *gb_atomic_ptr_fetch_and (gbAtomicPtr volatile *a, void *operand); -GB_DEF void *gb_atomic_ptr_fetch_or (gbAtomicPtr volatile *a, void *operand); -GB_DEF b32 gb_atomic_ptr_spin_lock (gbAtomicPtr volatile *a, isize time_out); // NOTE(bill): time_out = -1 as default -GB_DEF void gb_atomic_ptr_spin_unlock (gbAtomicPtr volatile *a); -GB_DEF b32 gb_atomic_ptr_try_acquire_lock(gbAtomicPtr volatile *a); - - -// Fences -GB_DEF void gb_yield_thread(void); -GB_DEF void gb_mfence (void); -GB_DEF void gb_sfence (void); -GB_DEF void gb_lfence (void); - - -#if defined(GB_SYSTEM_WINDOWS) -typedef struct gbSemaphore { void *win32_handle; } gbSemaphore; -#elif defined(GB_SYSTEM_OSX) -typedef struct gbSemaphore { semaphore_t osx_handle; } gbSemaphore; -#elif defined(GB_SYSTEM_UNIX) -typedef struct gbSemaphore { sem_t unix_handle; } gbSemaphore; -#else -#error -#endif - -GB_DEF void gb_semaphore_init (gbSemaphore *s); -GB_DEF void gb_semaphore_destroy(gbSemaphore *s); -GB_DEF void gb_semaphore_post (gbSemaphore *s, i32 count); -GB_DEF void gb_semaphore_release(gbSemaphore *s); // NOTE(bill): gb_semaphore_post(s, 1) -GB_DEF void gb_semaphore_wait (gbSemaphore *s); - - -// Mutex -typedef struct gbMutex { -#if defined(GB_SYSTEM_WINDOWS) - CRITICAL_SECTION win32_critical_section; -#else - pthread_mutex_t pthread_mutex; - pthread_mutexattr_t pthread_mutexattr; -#endif -} gbMutex; - -GB_DEF void gb_mutex_init (gbMutex *m); -GB_DEF void gb_mutex_destroy (gbMutex *m); -GB_DEF void gb_mutex_lock (gbMutex *m); -GB_DEF b32 gb_mutex_try_lock(gbMutex *m); -GB_DEF void gb_mutex_unlock (gbMutex *m); - -// NOTE(bill): If you wanted a Scoped Mutex in C++, why not use the defer() construct? -// No need for a silly wrapper class and it's clear! -#if 0 -gbMutex m = {0}; -gb_mutex_init(&m); -{ - gb_mutex_lock(&m); - defer (gb_mutex_unlock(&m)); - - // Do whatever as the mutex is now scoped based! -} -#endif - - - -#define GB_THREAD_PROC(name) isize name(struct gbThread *thread) -typedef GB_THREAD_PROC(gbThreadProc); - -typedef struct gbThread { -#if defined(GB_SYSTEM_WINDOWS) - void * win32_handle; -#else - pthread_t posix_handle; -#endif - - gbThreadProc *proc; - void * user_data; - isize user_index; - isize return_value; - - gbSemaphore semaphore; - isize stack_size; - b32 volatile is_running; -} gbThread; - -GB_DEF void gb_thread_init (gbThread *t); -GB_DEF void gb_thread_destroy (gbThread *t); -GB_DEF void gb_thread_start (gbThread *t, gbThreadProc *proc, void *data); -GB_DEF void gb_thread_start_with_stack(gbThread *t, gbThreadProc *proc, void *data, isize stack_size); -GB_DEF void gb_thread_join (gbThread *t); -GB_DEF b32 gb_thread_is_running (gbThread const *t); -GB_DEF u32 gb_thread_current_id (void); -GB_DEF void gb_thread_set_name (gbThread *t, char const *name); - - -// NOTE(bill): Thread Merge Operation -// Based on Sean Barrett's stb_sync -typedef struct gbSync { - i32 target; // Target Number of threads - i32 current; // Threads to hit - i32 waiting; // Threads waiting - - gbMutex start; - gbMutex mutex; - gbSemaphore release; -} gbSync; - -GB_DEF void gb_sync_init (gbSync *s); -GB_DEF void gb_sync_destroy (gbSync *s); -GB_DEF void gb_sync_set_target (gbSync *s, i32 count); -GB_DEF void gb_sync_release (gbSync *s); -GB_DEF i32 gb_sync_reach (gbSync *s); -GB_DEF void gb_sync_reach_and_wait(gbSync *s); - - - -#if defined(GB_SYSTEM_WINDOWS) - -typedef struct gbAffinity { - b32 is_accurate; - isize core_count; - isize thread_count; - #define GB_WIN32_MAX_THREADS (8 * gb_size_of(usize)) - usize core_masks[GB_WIN32_MAX_THREADS]; - -} gbAffinity; - -#elif defined(GB_SYSTEM_OSX) -typedef struct gbAffinity { - b32 is_accurate; - isize core_count; - isize thread_count; - isize threads_per_core; -} gbAffinity; - -#elif defined(GB_SYSTEM_LINUX) -typedef struct gbAffinity { - b32 is_accurate; - isize core_count; - isize thread_count; - isize threads_per_core; -} gbAffinity; -#else -#error TODO(bill): Unknown system -#endif - -GB_DEF void gb_affinity_init (gbAffinity *a); -GB_DEF void gb_affinity_destroy(gbAffinity *a); -GB_DEF b32 gb_affinity_set (gbAffinity *a, isize core, isize thread); -GB_DEF isize gb_affinity_thread_count_for_core(gbAffinity *a, isize core); - - - - -//////////////////////////////////////////////////////////////// -// -// Virtual Memory -// -// - -typedef struct gbVirtualMemory { - void *data; - isize size; -} gbVirtualMemory; - -GB_DEF gbVirtualMemory gb_virtual_memory(void *data, isize size); -GB_DEF gbVirtualMemory gb_vm_alloc (void *addr, isize size); -GB_DEF b32 gb_vm_free (gbVirtualMemory vm); -GB_DEF gbVirtualMemory gb_vm_trim (gbVirtualMemory vm, isize lead_size, isize size); -GB_DEF b32 gb_vm_purge (gbVirtualMemory vm); -GB_DEF isize gb_virtual_memory_page_size(isize *alignment_out); - - - - -//////////////////////////////////////////////////////////////// -// -// Custom Allocation -// -// - -typedef enum gbAllocationType { - gbAllocation_Alloc, - gbAllocation_Free, - gbAllocation_FreeAll, - gbAllocation_Resize, -} gbAllocationType; - -// NOTE(bill): This is useful so you can define an allocator of the same type and parameters -#define GB_ALLOCATOR_PROC(name) \ -void *name(void *allocator_data, gbAllocationType type, \ - isize size, isize alignment, \ - void *old_memory, isize old_size, \ - u64 flags) -typedef GB_ALLOCATOR_PROC(gbAllocatorProc); - -typedef struct gbAllocator { - gbAllocatorProc *proc; - void * data; -} gbAllocator; - -typedef enum gbAllocatorFlag { - gbAllocatorFlag_ClearToZero = GB_BIT(0), -} gbAllocatorFlag; - -// TODO(bill): Is this a decent default alignment? -#ifndef GB_DEFAULT_MEMORY_ALIGNMENT -#define GB_DEFAULT_MEMORY_ALIGNMENT (2 * gb_size_of(void *)) -#endif - -#ifndef GB_DEFAULT_ALLOCATOR_FLAGS -#define GB_DEFAULT_ALLOCATOR_FLAGS (gbAllocatorFlag_ClearToZero) -#endif - -GB_DEF void *gb_alloc_align (gbAllocator a, isize size, isize alignment); -GB_DEF void *gb_alloc (gbAllocator a, isize size); -GB_DEF void gb_free (gbAllocator a, void *ptr); -GB_DEF void gb_free_all (gbAllocator a); -GB_DEF void *gb_resize (gbAllocator a, void *ptr, isize old_size, isize new_size); -GB_DEF void *gb_resize_align(gbAllocator a, void *ptr, isize old_size, isize new_size, isize alignment); -// TODO(bill): For gb_resize, should the use need to pass the old_size or only the new_size? - -GB_DEF void *gb_alloc_copy (gbAllocator a, void const *src, isize size); -GB_DEF void *gb_alloc_copy_align(gbAllocator a, void const *src, isize size, isize alignment); -GB_DEF char *gb_alloc_str (gbAllocator a, char const *str); -GB_DEF char *gb_alloc_str_len (gbAllocator a, char const *str, isize len); - - -// NOTE(bill): These are very useful and the type cast has saved me from numerous bugs -#ifndef gb_alloc_item -#define gb_alloc_item(allocator_, Type) (Type *)gb_alloc(allocator_, gb_size_of(Type)) -#define gb_alloc_array(allocator_, Type, count) (Type *)gb_alloc(allocator_, gb_size_of(Type) * (count)) -#endif - -// NOTE(bill): Use this if you don't need a "fancy" resize allocation -GB_DEF void *gb_default_resize_align(gbAllocator a, void *ptr, isize old_size, isize new_size, isize alignment); - - - -// TODO(bill): Probably use a custom heap allocator system that doesn't depend on malloc/free -// Base it off TCMalloc or something else? Or something entirely custom? -GB_DEF gbAllocator gb_heap_allocator(void); -GB_DEF GB_ALLOCATOR_PROC(gb_heap_allocator_proc); - -// NOTE(bill): Yep, I use my own allocator system! -#ifndef gb_malloc -#define gb_malloc(sz) gb_alloc(gb_heap_allocator(), sz) -#define gb_mfree(ptr) gb_free(gb_heap_allocator(), ptr) -#endif - - - -// -// Arena Allocator -// -typedef struct gbArena { - gbAllocator backing; - void * physical_start; - isize total_size; - isize total_allocated; - isize temp_count; -} gbArena; - -GB_DEF void gb_arena_init_from_memory (gbArena *arena, void *start, isize size); -GB_DEF void gb_arena_init_from_allocator(gbArena *arena, gbAllocator backing, isize size); -GB_DEF void gb_arena_init_sub (gbArena *arena, gbArena *parent_arena, isize size); -GB_DEF void gb_arena_free (gbArena *arena); - -GB_DEF isize gb_arena_alignment_of (gbArena *arena, isize alignment); -GB_DEF isize gb_arena_size_remaining(gbArena *arena, isize alignment); -GB_DEF void gb_arena_check (gbArena *arena); - - -// Allocation Types: alloc, free_all, resize -GB_DEF gbAllocator gb_arena_allocator(gbArena *arena); -GB_DEF GB_ALLOCATOR_PROC(gb_arena_allocator_proc); - - - -typedef struct gbTempArenaMemory { - gbArena *arena; - isize original_count; -} gbTempArenaMemory; - -GB_DEF gbTempArenaMemory gb_temp_arena_memory_begin(gbArena *arena); -GB_DEF void gb_temp_arena_memory_end (gbTempArenaMemory tmp_mem); - - - - - - - -// -// Pool Allocator -// - - -typedef struct gbPool { - gbAllocator backing; - void * physical_start; - void * free_list; - isize block_size; - isize block_align; - isize total_size; -} gbPool; - -GB_DEF void gb_pool_init (gbPool *pool, gbAllocator backing, isize num_blocks, isize block_size); -GB_DEF void gb_pool_init_align(gbPool *pool, gbAllocator backing, isize num_blocks, isize block_size, isize block_align); -GB_DEF void gb_pool_free (gbPool *pool); - -// Allocation Types: alloc, free -GB_DEF gbAllocator gb_pool_allocator(gbPool *pool); -GB_DEF GB_ALLOCATOR_PROC(gb_pool_allocator_proc); - - - -// NOTE(bill): Used for allocators to keep track of sizes -typedef struct gbAllocationHeader { - isize size; -} gbAllocationHeader; - -GB_DEF gbAllocationHeader *gb_allocation_header (void *data); -GB_DEF void gb_allocation_header_fill(gbAllocationHeader *header, void *data, isize size); - -// TODO(bill): Find better way of doing this without #if #elif etc. -#if defined(GB_ARCH_32_BIT) -#define GB_ISIZE_HIGH_BIT 0x80000000 -#elif defined(GB_ARCH_64_BIT) -#define GB_ISIZE_HIGH_BIT 0x8000000000000000ll -#else -#error -#endif - -// -// Free List Allocator -// - -// IMPORTANT TODO(bill): Thoroughly test the free list allocator! -// NOTE(bill): This is a very shitty free list as it just picks the first free block not the best size -// as I am just being lazy. Also, I will probably remove it later; it's only here because why not?! -// -// NOTE(bill): I may also complete remove this if I completely implement a fixed heap allocator - -typedef struct gbFreeListBlock gbFreeListBlock; -struct gbFreeListBlock { - gbFreeListBlock *next; - isize size; -}; - -typedef struct gbFreeList { - void * physical_start; - isize total_size; - - gbFreeListBlock *curr_block; - - isize total_allocated; - isize allocation_count; -} gbFreeList; - -GB_DEF void gb_free_list_init (gbFreeList *fl, void *start, isize size); -GB_DEF void gb_free_list_init_from_allocator(gbFreeList *fl, gbAllocator backing, isize size); - -// Allocation Types: alloc, free, free_all, resize -GB_DEF gbAllocator gb_free_list_allocator(gbFreeList *fl); -GB_DEF GB_ALLOCATOR_PROC(gb_free_list_allocator_proc); - - - -// -// Scratch Memory Allocator - Ring Buffer Based Arena -// - -typedef struct gbScratchMemory { - void *physical_start; - isize total_size; - void *alloc_point; - void *free_point; -} gbScratchMemory; - -GB_DEF void gb_scratch_memory_init (gbScratchMemory *s, void *start, isize size); -GB_DEF b32 gb_scratch_memory_is_in_use(gbScratchMemory *s, void *ptr); - - -// Allocation Types: alloc, free, free_all, resize -GB_DEF gbAllocator gb_scratch_allocator(gbScratchMemory *s); -GB_DEF GB_ALLOCATOR_PROC(gb_scratch_allocator_proc); - -// TODO(bill): Stack allocator -// TODO(bill): Fixed heap allocator -// TODO(bill): General heap allocator. Maybe a TCMalloc like clone? - - -//////////////////////////////////////////////////////////////// -// -// Sort & Search -// -// - -#define GB_COMPARE_PROC(name) int name(void const *a, void const *b) -typedef GB_COMPARE_PROC(gbCompareProc); - -#define GB_COMPARE_PROC_PTR(def) GB_COMPARE_PROC((*def)) - -// Producure pointers -// NOTE(bill): The offset parameter specifies the offset in the structure -// e.g. gb_i32_cmp(gb_offset_of(Thing, value)) -// Use 0 if it's just the type instead. - -GB_DEF GB_COMPARE_PROC_PTR(gb_i16_cmp (isize offset)); -GB_DEF GB_COMPARE_PROC_PTR(gb_i32_cmp (isize offset)); -GB_DEF GB_COMPARE_PROC_PTR(gb_i64_cmp (isize offset)); -GB_DEF GB_COMPARE_PROC_PTR(gb_isize_cmp(isize offset)); -GB_DEF GB_COMPARE_PROC_PTR(gb_str_cmp (isize offset)); -GB_DEF GB_COMPARE_PROC_PTR(gb_f32_cmp (isize offset)); -GB_DEF GB_COMPARE_PROC_PTR(gb_f64_cmp (isize offset)); -GB_DEF GB_COMPARE_PROC_PTR(gb_char_cmp (isize offset)); - -// TODO(bill): Better sorting algorithms -// NOTE(bill): Uses quick sort for large arrays but insertion sort for small -#define gb_sort_array(array, count, compare_proc) gb_sort(array, count, gb_size_of(*(array)), compare_proc) -GB_DEF void gb_sort(void *base, isize count, isize size, gbCompareProc compare_proc); - -// NOTE(bill): the count of temp == count of items -#define gb_radix_sort(Type) gb_radix_sort_##Type -#define GB_RADIX_SORT_PROC(Type) void gb_radix_sort(Type)(Type *items, Type *temp, isize count) - -GB_DEF GB_RADIX_SORT_PROC(u8); -GB_DEF GB_RADIX_SORT_PROC(u16); -GB_DEF GB_RADIX_SORT_PROC(u32); -GB_DEF GB_RADIX_SORT_PROC(u64); - - -// NOTE(bill): Returns index or -1 if not found -#define gb_binary_search_array(array, count, key, compare_proc) gb_binary_search(array, count, gb_size_of(*(array)), key, compare_proc) -GB_DEF isize gb_binary_search(void const *base, isize count, isize size, void const *key, gbCompareProc compare_proc); - -#define gb_shuffle_array(array, count) gb_shuffle(array, count, gb_size_of(*(array))) -GB_DEF void gb_shuffle(void *base, isize count, isize size); - -#define gb_reverse_array(array, count) gb_reverse(array, count, gb_size_of(*(array))) -GB_DEF void gb_reverse(void *base, isize count, isize size); - -//////////////////////////////////////////////////////////////// -// -// Char Functions -// -// - -GB_DEF char gb_char_to_lower (char c); -GB_DEF char gb_char_to_upper (char c); -GB_DEF b32 gb_char_is_space (char c); -GB_DEF b32 gb_char_is_digit (char c); -GB_DEF b32 gb_char_is_hex_digit (char c); -GB_DEF b32 gb_char_is_alpha (char c); -GB_DEF b32 gb_char_is_alphanumeric(char c); -GB_DEF i32 gb_digit_to_int (char c); -GB_DEF i32 gb_hex_digit_to_int (char c); - -// NOTE(bill): ASCII only -GB_DEF void gb_str_to_lower(char *str); -GB_DEF void gb_str_to_upper(char *str); - -GB_DEF isize gb_strlen (char const *str); -GB_DEF isize gb_strnlen(char const *str, isize max_len); -GB_DEF i32 gb_strcmp (char const *s1, char const *s2); -GB_DEF i32 gb_strncmp(char const *s1, char const *s2, isize len); -GB_DEF char *gb_strcpy (char *dest, char const *source); -GB_DEF char *gb_strncpy(char *dest, char const *source, isize len); -GB_DEF isize gb_strlcpy(char *dest, char const *source, isize len); -GB_DEF char *gb_strrev (char *str); // NOTE(bill): ASCII only - -// NOTE(bill): A less fucking crazy strtok! -GB_DEF char const *gb_strtok(char *output, char const *src, char const *delimit); - -GB_DEF b32 gb_str_has_prefix(char const *str, char const *prefix); -GB_DEF b32 gb_str_has_suffix(char const *str, char const *suffix); - -GB_DEF char const *gb_char_first_occurence(char const *str, char c); -GB_DEF char const *gb_char_last_occurence (char const *str, char c); - -GB_DEF void gb_str_concat(char *dest, isize dest_len, - char const *src_a, isize src_a_len, - char const *src_b, isize src_b_len); - -GB_DEF u64 gb_str_to_u64(char const *str, char **end_ptr, i32 base); // TODO(bill): Support more than just decimal and hexadecimal -GB_DEF i64 gb_str_to_i64(char const *str, char **end_ptr, i32 base); // TODO(bill): Support more than just decimal and hexadecimal -GB_DEF f32 gb_str_to_f32(char const *str, char **end_ptr); -GB_DEF f64 gb_str_to_f64(char const *str, char **end_ptr); -GB_DEF void gb_i64_to_str(i64 value, char *string, i32 base); -GB_DEF void gb_u64_to_str(u64 value, char *string, i32 base); - - -//////////////////////////////////////////////////////////////// -// -// UTF-8 Handling -// -// - -// NOTE(bill): Does not check if utf-8 string is valid -GB_DEF isize gb_utf8_strlen (u8 const *str); -GB_DEF isize gb_utf8_strnlen(u8 const *str, isize max_len); - -// NOTE(bill): Windows doesn't handle 8 bit filenames well ('cause Micro$hit) -GB_DEF u16 *gb_utf8_to_ucs2 (u16 *buffer, isize len, u8 const *str); -GB_DEF u8 * gb_ucs2_to_utf8 (u8 *buffer, isize len, u16 const *str); -GB_DEF u16 *gb_utf8_to_ucs2_buf(u8 const *str); // NOTE(bill): Uses locally persisting buffer -GB_DEF u8 * gb_ucs2_to_utf8_buf(u16 const *str); // NOTE(bill): Uses locally persisting buffer - -// NOTE(bill): Returns size of codepoint in bytes -GB_DEF isize gb_utf8_decode (u8 const *str, isize str_len, Rune *codepoint); -GB_DEF isize gb_utf8_codepoint_size(u8 const *str, isize str_len); -GB_DEF isize gb_utf8_encode_rune (u8 buf[4], Rune r); - -//////////////////////////////////////////////////////////////// -// -// gbString - C Read-Only-Compatible -// -// -/* -Reasoning: - - By default, strings in C are null terminated which means you have to count - the number of character up to the null character to calculate the length. - Many "better" C string libraries will create a struct for a string. - i.e. - - struct String { - Allocator allocator; - size_t length; - size_t capacity; - char * cstring; - }; - - This library tries to augment normal C strings in a better way that is still - compatible with C-style strings. - - +--------+-----------------------+-----------------+ - | Header | Binary C-style String | Null Terminator | - +--------+-----------------------+-----------------+ - | - +-> Pointer returned by functions - - Due to the meta-data being stored before the string pointer and every gb string - having an implicit null terminator, gb strings are full compatible with c-style - strings and read-only functions. - -Advantages: - - * gb strings can be passed to C-style string functions without accessing a struct - member of calling a function, i.e. - - gb_printf("%s\n", gb_str); - - Many other libraries do either of these: - - gb_printf("%s\n", string->cstr); - gb_printf("%s\n", get_cstring(string)); - - * You can access each character just like a C-style string: - - gb_printf("%c %c\n", str[0], str[13]); - - * gb strings are singularly allocated. The meta-data is next to the character - array which is better for the cache. - -Disadvantages: - - * In the C version of these functions, many return the new string. i.e. - str = gb_string_appendc(str, "another string"); - This could be changed to gb_string_appendc(&str, "another string"); but I'm still not sure. - - * This is incompatible with "gb_string.h" strings -*/ - -#if 0 -#define GB_IMPLEMENTATION -#include "gb.h" -int main(int argc, char **argv) { - gbString str = gb_string_make("Hello"); - gbString other_str = gb_string_make_length(", ", 2); - str = gb_string_append(str, other_str); - str = gb_string_appendc(str, "world!"); - - gb_printf("%s\n", str); // Hello, world! - - gb_printf("str length = %d\n", gb_string_length(str)); - - str = gb_string_set(str, "Potato soup"); - gb_printf("%s\n", str); // Potato soup - - str = gb_string_set(str, "Hello"); - other_str = gb_string_set(other_str, "Pizza"); - if (gb_strings_are_equal(str, other_str)) - gb_printf("Not called\n"); - else - gb_printf("Called\n"); - - str = gb_string_set(str, "Ab.;!...AHello World ??"); - str = gb_string_trim(str, "Ab.;!. ?"); - gb_printf("%s\n", str); // "Hello World" - - gb_string_free(str); - gb_string_free(other_str); - - return 0; -} -#endif - -// TODO(bill): Should this be a wrapper to gbArray(char) or this extra type safety better? -typedef char *gbString; - -// NOTE(bill): If you only need a small string, just use a standard c string or change the size from isize to u16, etc. -typedef struct gbStringHeader { - gbAllocator allocator; - isize length; - isize capacity; -} gbStringHeader; - -#define GB_STRING_HEADER(str) (cast(gbStringHeader *)(str) - 1) - -GB_DEF gbString gb_string_make_reserve (gbAllocator a, isize capacity); -GB_DEF gbString gb_string_make (gbAllocator a, char const *str); -GB_DEF gbString gb_string_make_length (gbAllocator a, void const *str, isize num_bytes); -GB_DEF void gb_string_free (gbString str); -GB_DEF gbString gb_string_duplicate (gbAllocator a, gbString const str); -GB_DEF isize gb_string_length (gbString const str); -GB_DEF isize gb_string_capacity (gbString const str); -GB_DEF isize gb_string_available_space(gbString const str); -GB_DEF void gb_string_clear (gbString str); -GB_DEF gbString gb_string_append (gbString str, gbString const other); -GB_DEF gbString gb_string_append_length (gbString str, void const *other, isize num_bytes); -GB_DEF gbString gb_string_appendc (gbString str, char const *other); -GB_DEF gbString gb_string_append_rune (gbString str, Rune r); -GB_DEF gbString gb_string_append_fmt (gbString str, char const *fmt, ...); -GB_DEF gbString gb_string_set (gbString str, char const *cstr); -GB_DEF gbString gb_string_make_space_for (gbString str, isize add_len); -GB_DEF isize gb_string_allocation_size(gbString const str); -GB_DEF b32 gb_string_are_equal (gbString const lhs, gbString const rhs); -GB_DEF gbString gb_string_trim (gbString str, char const *cut_set); -GB_DEF gbString gb_string_trim_space (gbString str); // Whitespace ` \t\r\n\v\f` - - - -//////////////////////////////////////////////////////////////// -// -// Fixed Capacity Buffer (POD Types) -// -// -// gbBuffer(Type) works like gbString or gbArray where the actual type is just a pointer to the first -// element. -// - -typedef struct gbBufferHeader { - isize count; - isize capacity; -} gbBufferHeader; - -#define gbBuffer(Type) Type * - -#define GB_BUFFER_HEADER(x) (cast(gbBufferHeader *)(x) - 1) -#define gb_buffer_count(x) (GB_BUFFER_HEADER(x)->count) -#define gb_buffer_capacity(x) (GB_BUFFER_HEADER(x)->capacity) - -#define gb_buffer_init(x, allocator, cap) do { \ - void **nx = cast(void **)&(x); \ - gbBufferHeader *gb__bh = cast(gbBufferHeader *)gb_alloc((allocator), (cap)*gb_size_of(*(x))); \ - gb__bh->count = 0; \ - gb__bh->capacity = cap; \ - *nx = cast(void *)(gb__bh+1); \ -} while (0) - - -#define gb_buffer_free(x, allocator) (gb_free(allocator, GB_BUFFER_HEADER(x))) - -#define gb_buffer_append(x, item) do { (x)[gb_buffer_count(x)++] = (item); } while (0) - -#define gb_buffer_appendv(x, items, item_count) do { \ - GB_ASSERT(gb_size_of(*(items)) == gb_size_of(*(x))); \ - GB_ASSERT(gb_buffer_count(x)+item_count <= gb_buffer_capacity(x)); \ - gb_memcopy(&(x)[gb_buffer_count(x)], (items), gb_size_of(*(x))*(item_count)); \ - gb_buffer_count(x) += (item_count); \ -} while (0) - -#define gb_buffer_pop(x) do { GB_ASSERT(gb_buffer_count(x) > 0); gb_buffer_count(x)--; } while (0) -#define gb_buffer_clear(x) do { gb_buffer_count(x) = 0; } while (0) - - - -//////////////////////////////////////////////////////////////// -// -// Dynamic Array (POD Types) -// -// NOTE(bill): I know this is a macro hell but C is an old (and shit) language with no proper arrays -// Also why the fuck not?! It fucking works! And it has custom allocation, which is already better than C++! -// -// gbArray(Type) works like gbString or gbBuffer where the actual type is just a pointer to the first -// element. -// - - - -// Available Procedures for gbArray(Type) -// gb_array_init -// gb_array_free -// gb_array_set_capacity -// gb_array_grow -// gb_array_append -// gb_array_appendv -// gb_array_pop -// gb_array_clear -// gb_array_resize -// gb_array_reserve -// - -#if 0 // Example -void foo(void) { - isize i; - int test_values[] = {4, 2, 1, 7}; - gbAllocator a = gb_heap_allocator(); - gbArray(int) items; - - gb_array_init(items, a); - - gb_array_append(items, 1); - gb_array_append(items, 4); - gb_array_append(items, 9); - gb_array_append(items, 16); - - items[1] = 3; // Manually set value - // NOTE: No array bounds checking - - for (i = 0; i < items.count; i++) - gb_printf("%d\n", items[i]); - // 1 - // 3 - // 9 - // 16 - - gb_array_clear(items); - - gb_array_appendv(items, test_values, gb_count_of(test_values)); - for (i = 0; i < items.count; i++) - gb_printf("%d\n", items[i]); - // 4 - // 2 - // 1 - // 7 - - gb_array_free(items); -} -#endif - -typedef struct gbArrayHeader { - gbAllocator allocator; - isize count; - isize capacity; -} gbArrayHeader; - -// NOTE(bill): This thing is magic! -#define gbArray(Type) Type * - -#ifndef GB_ARRAY_GROW_FORMULA -#define GB_ARRAY_GROW_FORMULA(x) (2*(x) + 8) -#endif - -GB_STATIC_ASSERT(GB_ARRAY_GROW_FORMULA(0) > 0); - -#define GB_ARRAY_HEADER(x) (cast(gbArrayHeader *)(x) - 1) -#define gb_array_allocator(x) (GB_ARRAY_HEADER(x)->allocator) -#define gb_array_count(x) (GB_ARRAY_HEADER(x)->count) -#define gb_array_capacity(x) (GB_ARRAY_HEADER(x)->capacity) - -// TODO(bill): Have proper alignment! -#define gb_array_init_reserve(x, allocator_, cap) do { \ - void **gb__array_ = cast(void **)&(x); \ - gbArrayHeader *gb__ah = cast(gbArrayHeader *)gb_alloc(allocator_, gb_size_of(gbArrayHeader)+gb_size_of(*(x))*(cap)); \ - gb__ah->allocator = allocator_; \ - gb__ah->count = 0; \ - gb__ah->capacity = cap; \ - *gb__array_ = cast(void *)(gb__ah+1); \ -} while (0) - -// NOTE(bill): Give it an initial default capacity -#define gb_array_init(x, allocator) gb_array_init_reserve(x, allocator, GB_ARRAY_GROW_FORMULA(0)) - -#define gb_array_free(x) do { \ - gbArrayHeader *gb__ah = GB_ARRAY_HEADER(x); \ - gb_free(gb__ah->allocator, gb__ah); \ -} while (0) - -#define gb_array_set_capacity(x, capacity) do { \ - if (x) { \ - void **gb__array_ = cast(void **)&(x); \ - *gb__array_ = gb__array_set_capacity((x), (capacity), gb_size_of(*(x))); \ - } \ -} while (0) - -// NOTE(bill): Do not use the thing below directly, use the macro -GB_DEF void *gb__array_set_capacity(void *array, isize capacity, isize element_size); - - -// TODO(bill): Decide on a decent growing formula for gbArray -#define gb_array_grow(x, min_capacity) do { \ - isize new_capacity = GB_ARRAY_GROW_FORMULA(gb_array_capacity(x)); \ - if (new_capacity < (min_capacity)) \ - new_capacity = (min_capacity); \ - gb_array_set_capacity(x, new_capacity); \ -} while (0) - - -#define gb_array_append(x, item) do { \ - if (gb_array_capacity(x) < gb_array_count(x)+1) \ - gb_array_grow(x, 0); \ - (x)[gb_array_count(x)++] = (item); \ -} while (0) - -#define gb_array_appendv(x, items, item_count) do { \ - gbArrayHeader *gb__ah = GB_ARRAY_HEADER(x); \ - GB_ASSERT(gb_size_of((items)[0]) == gb_size_of((x)[0])); \ - if (gb__ah->capacity < gb__ah->count+(item_count)) \ - gb_array_grow(x, gb__ah->count+(item_count)); \ - gb_memcopy(&(x)[gb__ah->count], (items), gb_size_of((x)[0])*(item_count));\ - gb__ah->count += (item_count); \ -} while (0) - - - -#define gb_array_pop(x) do { GB_ASSERT(GB_ARRAY_HEADER(x)->count > 0); GB_ARRAY_HEADER(x)->count--; } while (0) -#define gb_array_clear(x) do { GB_ARRAY_HEADER(x)->count = 0; } while (0) - -#define gb_array_resize(x, new_count) do { \ - if (GB_ARRAY_HEADER(x)->capacity < (new_count)) \ - gb_array_grow(x, (new_count)); \ - GB_ARRAY_HEADER(x)->count = (new_count); \ -} while (0) - - -#define gb_array_reserve(x, new_capacity) do { \ - if (GB_ARRAY_HEADER(x)->capacity < (new_capacity)) \ - gb_array_set_capacity(x, new_capacity); \ -} while (0) - - - - - -//////////////////////////////////////////////////////////////// -// -// Hashing and Checksum Functions -// -// - -GB_EXTERN u32 gb_adler32(void const *data, isize len); - -GB_EXTERN u32 gb_crc32(void const *data, isize len); -GB_EXTERN u64 gb_crc64(void const *data, isize len); - -GB_EXTERN u32 gb_fnv32 (void const *data, isize len); -GB_EXTERN u64 gb_fnv64 (void const *data, isize len); -GB_EXTERN u32 gb_fnv32a(void const *data, isize len); -GB_EXTERN u64 gb_fnv64a(void const *data, isize len); - -// NOTE(bill): Default seed of 0x9747b28c -// NOTE(bill): I prefer using murmur64 for most hashes -GB_EXTERN u32 gb_murmur32(void const *data, isize len); -GB_EXTERN u64 gb_murmur64(void const *data, isize len); - -GB_EXTERN u32 gb_murmur32_seed(void const *data, isize len, u32 seed); -GB_EXTERN u64 gb_murmur64_seed(void const *data, isize len, u64 seed); - - -//////////////////////////////////////////////////////////////// -// -// Instantiated Hash Table -// -// This is an attempt to implement a templated hash table -// NOTE(bill): The key is aways a u64 for simplicity and you will _probably_ _never_ need anything bigger. -// -// Hash table type and function declaration, call: GB_TABLE_DECLARE(PREFIX, NAME, N, VALUE) -// Hash table function definitions, call: GB_TABLE_DEFINE(NAME, N, VALUE) -// -// PREFIX - a prefix for function prototypes e.g. extern, static, etc. -// NAME - Name of the Hash Table -// FUNC - the name will prefix function names -// VALUE - the type of the value to be stored -// -// NOTE(bill): I really wish C had decent metaprogramming capabilities (and no I don't mean C++'s templates either) -// - -typedef struct gbHashTableFindResult { - isize hash_index; - isize entry_prev; - isize entry_index; -} gbHashTableFindResult; - -#define GB_TABLE(PREFIX, NAME, FUNC, VALUE) \ - GB_TABLE_DECLARE(PREFIX, NAME, FUNC, VALUE); \ - GB_TABLE_DEFINE(NAME, FUNC, VALUE); - -#define GB_TABLE_DECLARE(PREFIX, NAME, FUNC, VALUE) \ -typedef struct GB_JOIN2(NAME,Entry) { \ - u64 key; \ - isize next; \ - VALUE value; \ -} GB_JOIN2(NAME,Entry); \ -\ -typedef struct NAME { \ - gbArray(isize) hashes; \ - gbArray(GB_JOIN2(NAME,Entry)) entries; \ -} NAME; \ -\ -PREFIX void GB_JOIN2(FUNC,init) (NAME *h, gbAllocator a); \ -PREFIX void GB_JOIN2(FUNC,destroy) (NAME *h); \ -PREFIX VALUE * GB_JOIN2(FUNC,get) (NAME *h, u64 key); \ -PREFIX void GB_JOIN2(FUNC,set) (NAME *h, u64 key, VALUE value); \ -PREFIX void GB_JOIN2(FUNC,grow) (NAME *h); \ -PREFIX void GB_JOIN2(FUNC,rehash) (NAME *h, isize new_count); \ - - - - - -#define GB_TABLE_DEFINE(NAME, FUNC, VALUE) \ -void GB_JOIN2(FUNC,init)(NAME *h, gbAllocator a) { \ - gb_array_init(h->hashes, a); \ - gb_array_init(h->entries, a); \ -} \ -\ -void GB_JOIN2(FUNC,destroy)(NAME *h) { \ - if (h->entries) gb_array_free(h->entries); \ - if (h->hashes) gb_array_free(h->hashes); \ -} \ -\ -gb_internal isize GB_JOIN2(FUNC,_add_entry)(NAME *h, u64 key) { \ - isize index; \ - GB_JOIN2(NAME,Entry) e = {0}; \ - e.key = key; \ - e.next = -1; \ - index = gb_array_count(h->entries); \ - gb_array_append(h->entries, e); \ - return index; \ -} \ -\ -gb_internal gbHashTableFindResult GB_JOIN2(FUNC,_find)(NAME *h, u64 key) { \ - gbHashTableFindResult r = {-1, -1, -1}; \ - if (gb_array_count(h->hashes) > 0) { \ - r.hash_index = key % gb_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; \ -} \ -\ -gb_internal b32 GB_JOIN2(FUNC,_full)(NAME *h) { \ - return 0.75f * gb_array_count(h->hashes) < gb_array_count(h->entries); \ -} \ -\ -void GB_JOIN2(FUNC,grow)(NAME *h) { \ - isize new_count = GB_ARRAY_GROW_FORMULA(gb_array_count(h->entries)); \ - GB_JOIN2(FUNC,rehash)(h, new_count); \ -} \ -\ -void GB_JOIN2(FUNC,rehash)(NAME *h, isize new_count) { \ - isize i, j; \ - NAME nh = {0}; \ - GB_JOIN2(FUNC,init)(&nh, gb_array_allocator(h->hashes)); \ - gb_array_resize(nh.hashes, new_count); \ - gb_array_reserve(nh.entries, gb_array_count(h->entries)); \ - for (i = 0; i < new_count; i++) \ - nh.hashes[i] = -1; \ - for (i = 0; i < gb_array_count(h->entries); i++) { \ - GB_JOIN2(NAME,Entry) *e; \ - gbHashTableFindResult fr; \ - if (gb_array_count(nh.hashes) == 0) \ - GB_JOIN2(FUNC,grow)(&nh); \ - e = &h->entries[i]; \ - fr = GB_JOIN2(FUNC,_find)(&nh, e->key); \ - j = GB_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; \ - if (GB_JOIN2(FUNC,_full)(&nh)) \ - GB_JOIN2(FUNC,grow)(&nh); \ - } \ - GB_JOIN2(FUNC,destroy)(h); \ - h->hashes = nh.hashes; \ - h->entries = nh.entries; \ -} \ -\ -VALUE *GB_JOIN2(FUNC,get)(NAME *h, u64 key) { \ - isize index = GB_JOIN2(FUNC,_find)(h, key).entry_index; \ - if (index >= 0) \ - return &h->entries[index].value; \ - return NULL; \ -} \ -\ -void GB_JOIN2(FUNC,set)(NAME *h, u64 key, VALUE value) { \ - isize index; \ - gbHashTableFindResult fr; \ - if (gb_array_count(h->hashes) == 0) \ - GB_JOIN2(FUNC,grow)(h); \ - fr = GB_JOIN2(FUNC,_find)(h, key); \ - if (fr.entry_index >= 0) { \ - index = fr.entry_index; \ - } else { \ - index = GB_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 (GB_JOIN2(FUNC,_full)(h)) \ - GB_JOIN2(FUNC,grow)(h); \ -} \ - - - - -//////////////////////////////////////////////////////////////// -// -// File Handling -// - - -typedef u32 gbFileMode; -typedef enum gbFileModeFlag { - gbFileMode_Read = GB_BIT(0), - gbFileMode_Write = GB_BIT(1), - gbFileMode_Append = GB_BIT(2), - gbFileMode_Rw = GB_BIT(3), - - gbFileMode_Modes = gbFileMode_Read | gbFileMode_Write | gbFileMode_Append | gbFileMode_Rw, -} gbFileModeFlag; - -// NOTE(bill): Only used internally and for the file operations -typedef enum gbSeekWhenceType { - gbSeekWhence_Begin = 0, - gbSeekWhence_Current = 1, - gbSeekWhence_End = 2, -} gbSeekWhenceType; - -typedef enum gbFileError { - gbFileError_None, - gbFileError_Invalid, - gbFileError_InvalidFilename, - gbFileError_Exists, - gbFileError_NotExists, - gbFileError_Permission, - gbFileError_TruncationFailure, -} gbFileError; - -typedef union gbFileDescriptor { - void * p; - intptr i; - uintptr u; -} gbFileDescriptor; - -typedef struct gbFileOperations gbFileOperations; - -#define GB_FILE_OPEN_PROC(name) gbFileError name(gbFileDescriptor *fd, gbFileOperations *ops, gbFileMode mode, char const *filename) -#define GB_FILE_READ_AT_PROC(name) b32 name(gbFileDescriptor fd, void *buffer, isize size, i64 offset, isize *bytes_read) -#define GB_FILE_WRITE_AT_PROC(name) b32 name(gbFileDescriptor fd, void const *buffer, isize size, i64 offset, isize *bytes_written) -#define GB_FILE_SEEK_PROC(name) b32 name(gbFileDescriptor fd, i64 offset, gbSeekWhenceType whence, i64 *new_offset) -#define GB_FILE_CLOSE_PROC(name) void name(gbFileDescriptor fd) -typedef GB_FILE_OPEN_PROC(gbFileOpenProc); -typedef GB_FILE_READ_AT_PROC(gbFileReadProc); -typedef GB_FILE_WRITE_AT_PROC(gbFileWriteProc); -typedef GB_FILE_SEEK_PROC(gbFileSeekProc); -typedef GB_FILE_CLOSE_PROC(gbFileCloseProc); - -struct gbFileOperations { - gbFileReadProc *read_at; - gbFileWriteProc *write_at; - gbFileSeekProc *seek; - gbFileCloseProc *close; -}; - -extern gbFileOperations const gbDefaultFileOperations; - - -// typedef struct gbDirInfo { -// u8 *buf; -// isize buf_count; -// isize buf_pos; -// } gbDirInfo; - -typedef u64 gbFileTime; - -typedef struct gbFile { - gbFileOperations ops; - gbFileDescriptor fd; - char const * filename; - gbFileTime last_write_time; - // gbDirInfo * dir_info; // TODO(bill): Get directory info -} gbFile; - -// TODO(bill): gbAsyncFile - -typedef enum gbFileStandardType { - gbFileStandard_Input, - gbFileStandard_Output, - gbFileStandard_Error, - - gbFileStandard_Count, -} gbFileStandardType; - -GB_DEF gbFile *const gb_file_get_standard(gbFileStandardType std); - -GB_DEF gbFileError gb_file_create (gbFile *file, char const *filename); -GB_DEF gbFileError gb_file_open (gbFile *file, char const *filename); -GB_DEF gbFileError gb_file_open_mode (gbFile *file, gbFileMode mode, char const *filename); -GB_DEF gbFileError gb_file_new (gbFile *file, gbFileDescriptor fd, gbFileOperations ops, char const *filename); -GB_DEF b32 gb_file_read_at_check (gbFile *file, void *buffer, isize size, i64 offset, isize *bytes_read); -GB_DEF b32 gb_file_write_at_check(gbFile *file, void const *buffer, isize size, i64 offset, isize *bytes_written); -GB_DEF b32 gb_file_read_at (gbFile *file, void *buffer, isize size, i64 offset); -GB_DEF b32 gb_file_write_at (gbFile *file, void const *buffer, isize size, i64 offset); -GB_DEF i64 gb_file_seek (gbFile *file, i64 offset); -GB_DEF i64 gb_file_seek_to_end (gbFile *file); -GB_DEF i64 gb_file_skip (gbFile *file, i64 bytes); // NOTE(bill): Skips a certain amount of bytes -GB_DEF i64 gb_file_tell (gbFile *file); -GB_DEF gbFileError gb_file_close (gbFile *file); -GB_DEF b32 gb_file_read (gbFile *file, void *buffer, isize size); -GB_DEF b32 gb_file_write (gbFile *file, void const *buffer, isize size); -GB_DEF i64 gb_file_size (gbFile *file); -GB_DEF char const *gb_file_name (gbFile *file); -GB_DEF gbFileError gb_file_truncate (gbFile *file, i64 size); -GB_DEF b32 gb_file_has_changed (gbFile *file); // NOTE(bill): Changed since lasted checked -// TODO(bill): -// gbFileError gb_file_temp(gbFile *file); -// - -typedef struct gbFileContents { - gbAllocator allocator; - void * data; - isize size; -} gbFileContents; - - -GB_DEF gbFileContents gb_file_read_contents(gbAllocator a, b32 zero_terminate, char const *filepath); -GB_DEF void gb_file_free_contents(gbFileContents *fc); - - -// TODO(bill): Should these have different na,es as they do not take in a gbFile * ??? -GB_DEF b32 gb_file_exists (char const *filepath); -GB_DEF gbFileTime gb_file_last_write_time(char const *filepath); -GB_DEF b32 gb_file_copy (char const *existing_filename, char const *new_filename, b32 fail_if_exists); -GB_DEF b32 gb_file_move (char const *existing_filename, char const *new_filename); -GB_DEF b32 gb_file_remove (char const *filename); - - -#ifndef GB_PATH_SEPARATOR - #if defined(GB_SYSTEM_WINDOWS) - #define GB_PATH_SEPARATOR '\\' - #else - #define GB_PATH_SEPARATOR '/' - #endif -#endif - -GB_DEF b32 gb_path_is_absolute (char const *path); -GB_DEF b32 gb_path_is_relative (char const *path); -GB_DEF b32 gb_path_is_root (char const *path); -GB_DEF char const *gb_path_base_name (char const *path); -GB_DEF char const *gb_path_extension (char const *path); -GB_DEF char * gb_path_get_full_name(gbAllocator a, char const *path); - - -//////////////////////////////////////////////////////////////// -// -// Printing -// -// - -GB_DEF isize gb_printf (char const *fmt, ...) GB_PRINTF_ARGS(1); -GB_DEF isize gb_printf_va (char const *fmt, va_list va); -GB_DEF isize gb_printf_err (char const *fmt, ...) GB_PRINTF_ARGS(1); -GB_DEF isize gb_printf_err_va (char const *fmt, va_list va); -GB_DEF isize gb_fprintf (gbFile *f, char const *fmt, ...) GB_PRINTF_ARGS(2); -GB_DEF isize gb_fprintf_va (gbFile *f, char const *fmt, va_list va); - -GB_DEF char *gb_bprintf (char const *fmt, ...) GB_PRINTF_ARGS(1); // NOTE(bill): A locally persisting buffer is used internally -GB_DEF char *gb_bprintf_va (char const *fmt, va_list va); // NOTE(bill): A locally persisting buffer is used internally -GB_DEF isize gb_snprintf (char *str, isize n, char const *fmt, ...) GB_PRINTF_ARGS(3); -GB_DEF isize gb_snprintf_va(char *str, isize n, char const *fmt, va_list va); - -//////////////////////////////////////////////////////////////// -// -// DLL Handling -// -// - -typedef void *gbDllHandle; -typedef void (*gbDllProc)(void); - -GB_DEF gbDllHandle gb_dll_load (char const *filepath); -GB_DEF void gb_dll_unload (gbDllHandle dll); -GB_DEF gbDllProc gb_dll_proc_address(gbDllHandle dll, char const *proc_name); - - -//////////////////////////////////////////////////////////////// -// -// Time -// -// - -GB_DEF u64 gb_rdtsc (void); -GB_DEF f64 gb_time_now (void); // NOTE(bill): This is only for relative time e.g. game loops -GB_DEF u64 gb_utc_time_now(void); // NOTE(bill): Number of microseconds since 1601-01-01 UTC -GB_DEF void gb_sleep_ms (u32 ms); - - -//////////////////////////////////////////////////////////////// -// -// Miscellany -// -// - -typedef struct gbRandom { - u32 offsets[8]; - u32 value; -} gbRandom; - -// NOTE(bill): Generates from numerous sources to produce a decent pseudo-random seed -GB_DEF void gb_random_init (gbRandom *r); -GB_DEF u32 gb_random_gen_u32 (gbRandom *r); -GB_DEF u32 gb_random_gen_u32_unique(gbRandom *r); -GB_DEF u64 gb_random_gen_u64 (gbRandom *r); // NOTE(bill): (gb_random_gen_u32() << 32) | gb_random_gen_u32() -GB_DEF isize gb_random_gen_isize (gbRandom *r); -GB_DEF i64 gb_random_range_i64 (gbRandom *r, i64 lower_inc, i64 higher_inc); -GB_DEF isize gb_random_range_isize (gbRandom *r, isize lower_inc, isize higher_inc); -GB_DEF f64 gb_random_range_f64 (gbRandom *r, f64 lower_inc, f64 higher_inc); - - - - -GB_DEF void gb_exit (u32 code); -GB_DEF void gb_yield (void); -GB_DEF void gb_set_env (char const *name, char const *value); -GB_DEF void gb_unset_env(char const *name); - -GB_DEF u16 gb_endian_swap16(u16 i); -GB_DEF u32 gb_endian_swap32(u32 i); -GB_DEF u64 gb_endian_swap64(u64 i); - -GB_DEF isize gb_count_set_bits(u64 mask); - -//////////////////////////////////////////////////////////////// -// -// Platform Stuff -// -// - -#if defined(GB_PLATFORM) - -// NOTE(bill): -// Coordiate system - +ve x - left to right -// - +ve y - bottom to top -// - Relative to window - -// TODO(bill): Proper documentation for this with code examples - -// Window Support - Complete -// OS X Support - Missing: -// * Sofware framebuffer -// * (show|hide) window -// * show_cursor -// * toggle (fullscreen|borderless) -// * set window position -// * Clipboard -// * GameControllers -// Linux Support - None -// Other OS Support - None - -#ifndef GB_MAX_GAME_CONTROLLER_COUNT -#define GB_MAX_GAME_CONTROLLER_COUNT 4 -#endif - -typedef enum gbKeyType { - gbKey_Unknown = 0, // Unhandled key - - // NOTE(bill): Allow the basic printable keys to be aliased with their chars - gbKey_0 = '0', - gbKey_1, - gbKey_2, - gbKey_3, - gbKey_4, - gbKey_5, - gbKey_6, - gbKey_7, - gbKey_8, - gbKey_9, - - gbKey_A = 'A', - gbKey_B, - gbKey_C, - gbKey_D, - gbKey_E, - gbKey_F, - gbKey_G, - gbKey_H, - gbKey_I, - gbKey_J, - gbKey_K, - gbKey_L, - gbKey_M, - gbKey_N, - gbKey_O, - gbKey_P, - gbKey_Q, - gbKey_R, - gbKey_S, - gbKey_T, - gbKey_U, - gbKey_V, - gbKey_W, - gbKey_X, - gbKey_Y, - gbKey_Z, - - gbKey_Lbracket = '[', - gbKey_Rbracket = ']', - gbKey_Semicolon = ';', - gbKey_Comma = ',', - gbKey_Period = '.', - gbKey_Quote = '\'', - gbKey_Slash = '/', - gbKey_Backslash = '\\', - gbKey_Grave = '`', - gbKey_Equals = '=', - gbKey_Minus = '-', - gbKey_Space = ' ', - - gbKey__Pad = 128, // NOTE(bill): make sure ASCII is reserved - - gbKey_Escape, // Escape - gbKey_Lcontrol, // Left Control - gbKey_Lshift, // Left Shift - gbKey_Lalt, // Left Alt - gbKey_Lsystem, // Left OS specific: window (Windows and Linux), apple/cmd (MacOS X), ... - gbKey_Rcontrol, // Right Control - gbKey_Rshift, // Right Shift - gbKey_Ralt, // Right Alt - gbKey_Rsystem, // Right OS specific: window (Windows and Linux), apple/cmd (MacOS X), ... - gbKey_Menu, // Menu - gbKey_Return, // Return - gbKey_Backspace, // Backspace - gbKey_Tab, // Tabulation - gbKey_Pageup, // Page up - gbKey_Pagedown, // Page down - gbKey_End, // End - gbKey_Home, // Home - gbKey_Insert, // Insert - gbKey_Delete, // Delete - gbKey_Plus, // + - gbKey_Subtract, // - - gbKey_Multiply, // * - gbKey_Divide, // / - gbKey_Left, // Left arrow - gbKey_Right, // Right arrow - gbKey_Up, // Up arrow - gbKey_Down, // Down arrow - gbKey_Numpad0, // Numpad 0 - gbKey_Numpad1, // Numpad 1 - gbKey_Numpad2, // Numpad 2 - gbKey_Numpad3, // Numpad 3 - gbKey_Numpad4, // Numpad 4 - gbKey_Numpad5, // Numpad 5 - gbKey_Numpad6, // Numpad 6 - gbKey_Numpad7, // Numpad 7 - gbKey_Numpad8, // Numpad 8 - gbKey_Numpad9, // Numpad 9 - gbKey_NumpadDot, // Numpad . - gbKey_NumpadEnter, // Numpad Enter - gbKey_F1, // F1 - gbKey_F2, // F2 - gbKey_F3, // F3 - gbKey_F4, // F4 - gbKey_F5, // F5 - gbKey_F6, // F6 - gbKey_F7, // F7 - gbKey_F8, // F8 - gbKey_F9, // F8 - gbKey_F10, // F10 - gbKey_F11, // F11 - gbKey_F12, // F12 - gbKey_F13, // F13 - gbKey_F14, // F14 - gbKey_F15, // F15 - gbKey_Pause, // Pause - - gbKey_Count, -} gbKeyType; - -/* TODO(bill): Change name? */ -typedef u8 gbKeyState; -typedef enum gbKeyStateFlag { - gbKeyState_Down = GB_BIT(0), - gbKeyState_Pressed = GB_BIT(1), - gbKeyState_Released = GB_BIT(2) -} gbKeyStateFlag; - -GB_DEF void gb_key_state_update(gbKeyState *s, b32 is_down); - -typedef enum gbMouseButtonType { - gbMouseButton_Left, - gbMouseButton_Middle, - gbMouseButton_Right, - gbMouseButton_X1, - gbMouseButton_X2, - - gbMouseButton_Count -} gbMouseButtonType; - -typedef enum gbControllerAxisType { - gbControllerAxis_LeftX, - gbControllerAxis_LeftY, - gbControllerAxis_RightX, - gbControllerAxis_RightY, - gbControllerAxis_LeftTrigger, - gbControllerAxis_RightTrigger, - - gbControllerAxis_Count -} gbControllerAxisType; - -typedef enum gbControllerButtonType { - gbControllerButton_Up, - gbControllerButton_Down, - gbControllerButton_Left, - gbControllerButton_Right, - gbControllerButton_A, - gbControllerButton_B, - gbControllerButton_X, - gbControllerButton_Y, - gbControllerButton_LeftShoulder, - gbControllerButton_RightShoulder, - gbControllerButton_Back, - gbControllerButton_Start, - gbControllerButton_LeftThumb, - gbControllerButton_RightThumb, - - gbControllerButton_Count -} gbControllerButtonType; - -typedef struct gbGameController { - b16 is_connected, is_analog; - - f32 axes[gbControllerAxis_Count]; - gbKeyState buttons[gbControllerButton_Count]; -} gbGameController; - -#if defined(GB_SYSTEM_WINDOWS) - typedef struct _XINPUT_GAMEPAD XINPUT_GAMEPAD; - typedef struct _XINPUT_STATE XINPUT_STATE; - typedef struct _XINPUT_VIBRATION XINPUT_VIBRATION; - - #define GB_XINPUT_GET_STATE(name) unsigned long __stdcall name(unsigned long dwUserIndex, XINPUT_STATE *pState) - typedef GB_XINPUT_GET_STATE(gbXInputGetStateProc); - - #define GB_XINPUT_SET_STATE(name) unsigned long __stdcall name(unsigned long dwUserIndex, XINPUT_VIBRATION *pVibration) - typedef GB_XINPUT_SET_STATE(gbXInputSetStateProc); -#endif - - -typedef enum gbWindowFlag { - gbWindow_Fullscreen = GB_BIT(0), - gbWindow_Hidden = GB_BIT(1), - gbWindow_Borderless = GB_BIT(2), - gbWindow_Resizable = GB_BIT(3), - gbWindow_Minimized = GB_BIT(4), - gbWindow_Maximized = GB_BIT(5), - gbWindow_FullscreenDesktop = gbWindow_Fullscreen | gbWindow_Borderless, -} gbWindowFlag; - -typedef enum gbRendererType { - gbRenderer_Opengl, - gbRenderer_Software, - - gbRenderer_Count, -} gbRendererType; - - - -#if defined(GB_SYSTEM_WINDOWS) && !defined(_WINDOWS_) -typedef struct tagBITMAPINFOHEADER { - unsigned long biSize; - long biWidth; - long biHeight; - u16 biPlanes; - u16 biBitCount; - unsigned long biCompression; - unsigned long biSizeImage; - long biXPelsPerMeter; - long biYPelsPerMeter; - unsigned long biClrUsed; - unsigned long biClrImportant; -} BITMAPINFOHEADER, *PBITMAPINFOHEADER; -typedef struct tagRGBQUAD { - u8 rgbBlue; - u8 rgbGreen; - u8 rgbRed; - u8 rgbReserved; -} RGBQUAD; -typedef struct tagBITMAPINFO { - BITMAPINFOHEADER bmiHeader; - RGBQUAD bmiColors[1]; -} BITMAPINFO, *PBITMAPINFO; -#endif - -typedef struct gbPlatform { - b32 is_initialized; - - void *window_handle; - i32 window_x, window_y; - i32 window_width, window_height; - u32 window_flags; - b16 window_is_closed, window_has_focus; - -#if defined(GB_SYSTEM_WINDOWS) - void *win32_dc; -#elif defined(GB_SYSTEM_OSX) - void *osx_autorelease_pool; // TODO(bill): Is this really needed? -#endif - - gbRendererType renderer_type; - union { - struct { - void * context; - i32 major; - i32 minor; - b16 core, compatible; - gbDllHandle dll_handle; - } opengl; - - // NOTE(bill): Software rendering - struct { -#if defined(GB_SYSTEM_WINDOWS) - BITMAPINFO win32_bmi; -#endif - void * memory; - isize memory_size; - i32 pitch; - i32 bits_per_pixel; - } sw_framebuffer; - }; - - gbKeyState keys[gbKey_Count]; - struct { - gbKeyState control; - gbKeyState alt; - gbKeyState shift; - } key_modifiers; - - Rune char_buffer[256]; - isize char_buffer_count; - - b32 mouse_clip; - i32 mouse_x, mouse_y; - i32 mouse_dx, mouse_dy; // NOTE(bill): Not raw mouse movement - i32 mouse_raw_dx, mouse_raw_dy; // NOTE(bill): Raw mouse movement - f32 mouse_wheel_delta; - gbKeyState mouse_buttons[gbMouseButton_Count]; - - gbGameController game_controllers[GB_MAX_GAME_CONTROLLER_COUNT]; - - f64 curr_time; - f64 dt_for_frame; - b32 quit_requested; - -#if defined(GB_SYSTEM_WINDOWS) - struct { - gbXInputGetStateProc *get_state; - gbXInputSetStateProc *set_state; - } xinput; -#endif -} gbPlatform; - - -typedef struct gbVideoMode { - i32 width, height; - i32 bits_per_pixel; -} gbVideoMode; - -GB_DEF gbVideoMode gb_video_mode (i32 width, i32 height, i32 bits_per_pixel); -GB_DEF b32 gb_video_mode_is_valid (gbVideoMode mode); -GB_DEF gbVideoMode gb_video_mode_get_desktop (void); -GB_DEF isize gb_video_mode_get_fullscreen_modes(gbVideoMode *modes, isize max_mode_count); // NOTE(bill): returns mode count -GB_DEF GB_COMPARE_PROC(gb_video_mode_cmp); // NOTE(bill): Sort smallest to largest (Ascending) -GB_DEF GB_COMPARE_PROC(gb_video_mode_dsc_cmp); // NOTE(bill): Sort largest to smallest (Descending) - - -// NOTE(bill): Software rendering -GB_DEF b32 gb_platform_init_with_software (gbPlatform *p, char const *window_title, i32 width, i32 height, u32 window_flags); -// NOTE(bill): OpenGL Rendering -GB_DEF b32 gb_platform_init_with_opengl (gbPlatform *p, char const *window_title, i32 width, i32 height, u32 window_flags, i32 major, i32 minor, b32 core, b32 compatible); -GB_DEF void gb_platform_update (gbPlatform *p); -GB_DEF void gb_platform_display (gbPlatform *p); -GB_DEF void gb_platform_destroy (gbPlatform *p); -GB_DEF void gb_platform_show_cursor (gbPlatform *p, b32 show); -GB_DEF void gb_platform_set_mouse_position (gbPlatform *p, i32 x, i32 y); -GB_DEF void gb_platform_set_controller_vibration (gbPlatform *p, isize index, f32 left_motor, f32 right_motor); -GB_DEF b32 gb_platform_has_clipboard_text (gbPlatform *p); -GB_DEF void gb_platform_set_clipboard_text (gbPlatform *p, char const *str); -GB_DEF char *gb_platform_get_clipboard_text (gbPlatform *p, gbAllocator a); -GB_DEF void gb_platform_set_window_position (gbPlatform *p, i32 x, i32 y); -GB_DEF void gb_platform_set_window_title (gbPlatform *p, char const *title, ...) GB_PRINTF_ARGS(2); -GB_DEF void gb_platform_toggle_fullscreen (gbPlatform *p, b32 fullscreen_desktop); -GB_DEF void gb_platform_toggle_borderless (gbPlatform *p); -GB_DEF void gb_platform_make_opengl_context_current(gbPlatform *p); -GB_DEF void gb_platform_show_window (gbPlatform *p); -GB_DEF void gb_platform_hide_window (gbPlatform *p); - - -#endif // GB_PLATFORM - -#if defined(__cplusplus) -} -#endif - -#endif // GB_INCLUDE_GB_H - - - - - - -//////////////////////////////////////////////////////////////// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// Implementation -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// It's turtles all the way down! -//////////////////////////////////////////////////////////////// -#if defined(GB_IMPLEMENTATION) && !defined(GB_IMPLEMENTATION_DONE) -#define GB_IMPLEMENTATION_DONE - -#if defined(__cplusplus) -extern "C" { -#endif - - -#if defined(GB_COMPILER_MSVC) && !defined(_WINDOWS_) - //////////////////////////////////////////////////////////////// - // - // Bill's Mini Windows.h - // - // - - #define WINAPI __stdcall - #define WINAPIV __cdecl - #define CALLBACK __stdcall - #define MAX_PATH 260 - #define CCHDEVICENAME 32 - #define CCHFORMNAME 32 - - typedef unsigned long DWORD; - typedef int WINBOOL; - #ifndef XFree86Server - #ifndef __OBJC__ - typedef WINBOOL BOOL; - #else - #define BOOL WINBOOL - #endif - typedef unsigned char BYTE; - #endif - typedef unsigned short WORD; - typedef float FLOAT; - typedef int INT; - typedef unsigned int UINT; - typedef short SHORT; - typedef long LONG; - typedef long long LONGLONG; - typedef unsigned short USHORT; - typedef unsigned long ULONG; - typedef unsigned long long ULONGLONG; - - typedef UINT WPARAM; - typedef LONG LPARAM; - typedef LONG LRESULT; - #ifndef _HRESULT_DEFINED - typedef LONG HRESULT; - #define _HRESULT_DEFINED - #endif - #ifndef XFree86Server - typedef WORD ATOM; - #endif /* XFree86Server */ - typedef void *HANDLE; - typedef HANDLE HGLOBAL; - typedef HANDLE HLOCAL; - typedef HANDLE GLOBALHANDLE; - typedef HANDLE LOCALHANDLE; - typedef void *HGDIOBJ; - - #define DECLARE_HANDLE(name) typedef HANDLE name - DECLARE_HANDLE(HACCEL); - DECLARE_HANDLE(HBITMAP); - DECLARE_HANDLE(HBRUSH); - DECLARE_HANDLE(HCOLORSPACE); - DECLARE_HANDLE(HDC); - DECLARE_HANDLE(HGLRC); - DECLARE_HANDLE(HDESK); - DECLARE_HANDLE(HENHMETAFILE); - DECLARE_HANDLE(HFONT); - DECLARE_HANDLE(HICON); - DECLARE_HANDLE(HKEY); - typedef HKEY *PHKEY; - DECLARE_HANDLE(HMENU); - DECLARE_HANDLE(HMETAFILE); - DECLARE_HANDLE(HINSTANCE); - typedef HINSTANCE HMODULE; - DECLARE_HANDLE(HPALETTE); - DECLARE_HANDLE(HPEN); - DECLARE_HANDLE(HRGN); - DECLARE_HANDLE(HRSRC); - DECLARE_HANDLE(HSTR); - DECLARE_HANDLE(HTASK); - DECLARE_HANDLE(HWND); - DECLARE_HANDLE(HWINSTA); - DECLARE_HANDLE(HKL); - DECLARE_HANDLE(HRAWINPUT); - DECLARE_HANDLE(HMONITOR); - #undef DECLARE_HANDLE - - typedef int HFILE; - typedef HICON HCURSOR; - typedef DWORD COLORREF; - typedef int (WINAPI *FARPROC)(); - typedef int (WINAPI *NEARPROC)(); - typedef int (WINAPI *PROC)(); - typedef LRESULT (CALLBACK *WNDPROC)(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); - - #if defined(_WIN64) - typedef unsigned __int64 ULONG_PTR; - typedef signed __int64 LONG_PTR; - #else - typedef unsigned long ULONG_PTR; - typedef signed long LONG_PTR; - #endif - typedef ULONG_PTR DWORD_PTR; - - typedef struct tagRECT { - LONG left; - LONG top; - LONG right; - LONG bottom; - } RECT; - typedef struct tagRECTL { - LONG left; - LONG top; - LONG right; - LONG bottom; - } RECTL; - typedef struct tagPOINT { - LONG x; - LONG y; - } POINT; - typedef struct tagSIZE { - LONG cx; - LONG cy; - } SIZE; - typedef struct tagPOINTS { - SHORT x; - SHORT y; - } POINTS; - typedef struct _SECURITY_ATTRIBUTES { - DWORD nLength; - HANDLE lpSecurityDescriptor; - BOOL bInheritHandle; - } SECURITY_ATTRIBUTES; - typedef enum _LOGICAL_PROCESSOR_RELATIONSHIP { - RelationProcessorCore, - RelationNumaNode, - RelationCache, - RelationProcessorPackage, - RelationGroup, - RelationAll = 0xffff - } LOGICAL_PROCESSOR_RELATIONSHIP; - typedef enum _PROCESSOR_CACHE_TYPE { - CacheUnified, - CacheInstruction, - CacheData, - CacheTrace - } PROCESSOR_CACHE_TYPE; - typedef struct _CACHE_DESCRIPTOR { - BYTE Level; - BYTE Associativity; - WORD LineSize; - DWORD Size; - PROCESSOR_CACHE_TYPE Type; - } CACHE_DESCRIPTOR; - typedef struct _SYSTEM_LOGICAL_PROCESSOR_INFORMATION { - ULONG_PTR ProcessorMask; - LOGICAL_PROCESSOR_RELATIONSHIP Relationship; - union { - struct { - BYTE Flags; - } ProcessorCore; - struct { - DWORD NodeNumber; - } NumaNode; - CACHE_DESCRIPTOR Cache; - ULONGLONG Reserved[2]; - }; - } SYSTEM_LOGICAL_PROCESSOR_INFORMATION; - typedef struct _MEMORY_BASIC_INFORMATION { - void *BaseAddress; - void *AllocationBase; - DWORD AllocationProtect; - usize RegionSize; - DWORD State; - DWORD Protect; - DWORD Type; - } MEMORY_BASIC_INFORMATION; - typedef struct _SYSTEM_INFO { - union { - DWORD dwOemId; - struct { - WORD wProcessorArchitecture; - WORD wReserved; - }; - }; - DWORD dwPageSize; - void * lpMinimumApplicationAddress; - void * lpMaximumApplicationAddress; - DWORD_PTR dwActiveProcessorMask; - DWORD dwNumberOfProcessors; - DWORD dwProcessorType; - DWORD dwAllocationGranularity; - WORD wProcessorLevel; - WORD wProcessorRevision; - } SYSTEM_INFO; - typedef union _LARGE_INTEGER { - struct { - DWORD LowPart; - LONG HighPart; - }; - struct { - DWORD LowPart; - LONG HighPart; - } u; - LONGLONG QuadPart; - } LARGE_INTEGER; - typedef union _ULARGE_INTEGER { - struct { - DWORD LowPart; - DWORD HighPart; - }; - struct { - DWORD LowPart; - DWORD HighPart; - } u; - ULONGLONG QuadPart; - } ULARGE_INTEGER; - - typedef struct _OVERLAPPED { - ULONG_PTR Internal; - ULONG_PTR InternalHigh; - union { - struct { - DWORD Offset; - DWORD OffsetHigh; - }; - void *Pointer; - }; - HANDLE hEvent; - } OVERLAPPED; - typedef struct _FILETIME { - DWORD dwLowDateTime; - DWORD dwHighDateTime; - } FILETIME; - typedef struct _WIN32_FIND_DATAW { - DWORD dwFileAttributes; - FILETIME ftCreationTime; - FILETIME ftLastAccessTime; - FILETIME ftLastWriteTime; - DWORD nFileSizeHigh; - DWORD nFileSizeLow; - DWORD dwReserved0; - DWORD dwReserved1; - wchar_t cFileName[MAX_PATH]; - wchar_t cAlternateFileName[14]; - } WIN32_FIND_DATAW; - typedef struct _WIN32_FILE_ATTRIBUTE_DATA { - DWORD dwFileAttributes; - FILETIME ftCreationTime; - FILETIME ftLastAccessTime; - FILETIME ftLastWriteTime; - DWORD nFileSizeHigh; - DWORD nFileSizeLow; - } WIN32_FILE_ATTRIBUTE_DATA; - typedef enum _GET_FILEEX_INFO_LEVELS { - GetFileExInfoStandard, - GetFileExMaxInfoLevel - } GET_FILEEX_INFO_LEVELS; - typedef struct tagRAWINPUTHEADER { - DWORD dwType; - DWORD dwSize; - HANDLE hDevice; - WPARAM wParam; - } RAWINPUTHEADER; - typedef struct tagRAWINPUTDEVICE { - USHORT usUsagePage; - USHORT usUsage; - DWORD dwFlags; - HWND hwndTarget; - } RAWINPUTDEVICE; - typedef struct tagRAWMOUSE { - WORD usFlags; - union { - ULONG ulButtons; - struct { - WORD usButtonFlags; - WORD usButtonData; - }; - }; - ULONG ulRawButtons; - LONG lLastX; - LONG lLastY; - ULONG ulExtraInformation; - } RAWMOUSE; - typedef struct tagRAWKEYBOARD { - WORD MakeCode; - WORD Flags; - WORD Reserved; - WORD VKey; - UINT Message; - ULONG ExtraInformation; - } RAWKEYBOARD; - typedef struct tagRAWHID { - DWORD dwSizeHid; - DWORD dwCount; - BYTE bRawData[1]; - } RAWHID; - typedef struct tagRAWINPUT { - RAWINPUTHEADER header; - union { - RAWMOUSE mouse; - RAWKEYBOARD keyboard; - RAWHID hid; - } data; - } RAWINPUT; - typedef struct tagWNDCLASSEXW { - UINT cbSize; - UINT style; - WNDPROC lpfnWndProc; - INT cbClsExtra; - INT cbWndExtra; - HINSTANCE hInstance; - HICON hIcon; - HCURSOR hCursor; - HANDLE hbrBackground; - wchar_t const *lpszMenuName; - wchar_t const *lpszClassName; - HICON hIconSm; - } WNDCLASSEXW; - typedef struct _POINTL { - LONG x; - LONG y; - } POINTL; - typedef struct _devicemodew { - wchar_t dmDeviceName[CCHDEVICENAME]; - WORD dmSpecVersion; - WORD dmDriverVersion; - WORD dmSize; - WORD dmDriverExtra; - DWORD dmFields; - union { - struct { - short dmOrientation; - short dmPaperSize; - short dmPaperLength; - short dmPaperWidth; - short dmScale; - short dmCopies; - short dmDefaultSource; - short dmPrintQuality; - }; - struct { - POINTL dmPosition; - DWORD dmDisplayOrientation; - DWORD dmDisplayFixedOutput; - }; - }; - short dmColor; - short dmDuplex; - short dmYResolution; - short dmTTOption; - short dmCollate; - wchar_t dmFormName[CCHFORMNAME]; - WORD dmLogPixels; - DWORD dmBitsPerPel; - DWORD dmPelsWidth; - DWORD dmPelsHeight; - union { - DWORD dmDisplayFlags; - DWORD dmNup; - }; - DWORD dmDisplayFrequency; - #if (WINVER >= 0x0400) - DWORD dmICMMethod; - DWORD dmICMIntent; - DWORD dmMediaType; - DWORD dmDitherType; - DWORD dmReserved1; - DWORD dmReserved2; - #if (WINVER >= 0x0500) || (_WIN32_WINNT >= 0x0400) - DWORD dmPanningWidth; - DWORD dmPanningHeight; - #endif - #endif - } DEVMODEW; - typedef struct tagPIXELFORMATDESCRIPTOR { - WORD nSize; - WORD nVersion; - DWORD dwFlags; - BYTE iPixelType; - BYTE cColorBits; - BYTE cRedBits; - BYTE cRedShift; - BYTE cGreenBits; - BYTE cGreenShift; - BYTE cBlueBits; - BYTE cBlueShift; - BYTE cAlphaBits; - BYTE cAlphaShift; - BYTE cAccumBits; - BYTE cAccumRedBits; - BYTE cAccumGreenBits; - BYTE cAccumBlueBits; - BYTE cAccumAlphaBits; - BYTE cDepthBits; - BYTE cStencilBits; - BYTE cAuxBuffers; - BYTE iLayerType; - BYTE bReserved; - DWORD dwLayerMask; - DWORD dwVisibleMask; - DWORD dwDamageMask; - } PIXELFORMATDESCRIPTOR; - typedef struct tagMSG { // msg - HWND hwnd; - UINT message; - WPARAM wParam; - LPARAM lParam; - DWORD time; - POINT pt; - } MSG; - typedef struct tagWINDOWPLACEMENT { - UINT length; - UINT flags; - UINT showCmd; - POINT ptMinPosition; - POINT ptMaxPosition; - RECT rcNormalPosition; - } WINDOWPLACEMENT; - typedef struct tagMONITORINFO { - DWORD cbSize; - RECT rcMonitor; - RECT rcWork; - DWORD dwFlags; - } MONITORINFO; - - #define INFINITE 0xffffffffl - #define INVALID_HANDLE_VALUE ((void *)(intptr)(-1)) - - - typedef DWORD WINAPI THREAD_START_ROUTINE(void *parameter); - - GB_DLL_IMPORT DWORD WINAPI GetLastError (void); - GB_DLL_IMPORT BOOL WINAPI CloseHandle (HANDLE object); - GB_DLL_IMPORT HANDLE WINAPI CreateSemaphoreA (SECURITY_ATTRIBUTES *semaphore_attributes, LONG initial_count, - LONG maximum_count, char const *name); - GB_DLL_IMPORT BOOL WINAPI ReleaseSemaphore (HANDLE semaphore, LONG release_count, LONG *previous_count); - GB_DLL_IMPORT DWORD WINAPI WaitForSingleObject(HANDLE handle, DWORD milliseconds); - GB_DLL_IMPORT HANDLE WINAPI CreateThread (SECURITY_ATTRIBUTES *semaphore_attributes, usize stack_size, - THREAD_START_ROUTINE *start_address, void *parameter, - DWORD creation_flags, DWORD *thread_id); - GB_DLL_IMPORT DWORD WINAPI GetThreadId (HANDLE handle); - GB_DLL_IMPORT void WINAPI RaiseException (DWORD, DWORD, DWORD, ULONG_PTR const *); - - - GB_DLL_IMPORT BOOL WINAPI GetLogicalProcessorInformation(SYSTEM_LOGICAL_PROCESSOR_INFORMATION *buffer, DWORD *return_length); - GB_DLL_IMPORT DWORD_PTR WINAPI SetThreadAffinityMask(HANDLE thread, DWORD_PTR check_mask); - GB_DLL_IMPORT HANDLE WINAPI GetCurrentThread(void); - - #define PAGE_NOACCESS 0x01 - #define PAGE_READONLY 0x02 - #define PAGE_READWRITE 0x04 - #define PAGE_WRITECOPY 0x08 - #define PAGE_EXECUTE 0x10 - #define PAGE_EXECUTE_READ 0x20 - #define PAGE_EXECUTE_READWRITE 0x40 - #define PAGE_EXECUTE_WRITECOPY 0x80 - #define PAGE_GUARD 0x100 - #define PAGE_NOCACHE 0x200 - #define PAGE_WRITECOMBINE 0x400 - - #define MEM_COMMIT 0x1000 - #define MEM_RESERVE 0x2000 - #define MEM_DECOMMIT 0x4000 - #define MEM_RELEASE 0x8000 - #define MEM_FREE 0x10000 - #define MEM_PRIVATE 0x20000 - #define MEM_MAPPED 0x40000 - #define MEM_RESET 0x80000 - #define MEM_TOP_DOWN 0x100000 - #define MEM_LARGE_PAGES 0x20000000 - #define MEM_4MB_PAGES 0x80000000 - - - - - GB_DLL_IMPORT void * WINAPI VirtualAlloc (void *addr, usize size, DWORD allocation_type, DWORD protect); - GB_DLL_IMPORT usize WINAPI VirtualQuery (void const *address, MEMORY_BASIC_INFORMATION *buffer, usize length); - GB_DLL_IMPORT BOOL WINAPI VirtualFree (void *address, usize size, DWORD free_type); - GB_DLL_IMPORT void WINAPI GetSystemInfo(SYSTEM_INFO *system_info); - - - #ifndef VK_UNKNOWN - #define VK_UNKNOWN 0 - #define VK_LBUTTON 0x01 - #define VK_RBUTTON 0x02 - #define VK_CANCEL 0x03 - #define VK_MBUTTON 0x04 - #define VK_XBUTTON1 0x05 - #define VK_XBUTTON2 0x06 - #define VK_BACK 0x08 - #define VK_TAB 0x09 - #define VK_CLEAR 0x0C - #define VK_RETURN 0x0D - #define VK_SHIFT 0x10 - #define VK_CONTROL 0x11 // CTRL key - #define VK_MENU 0x12 // ALT key - #define VK_PAUSE 0x13 // PAUSE key - #define VK_CAPITAL 0x14 // CAPS LOCK key - #define VK_KANA 0x15 // Input Method Editor (IME) Kana mode - #define VK_HANGUL 0x15 // IME Hangul mode - #define VK_JUNJA 0x17 // IME Junja mode - #define VK_FINAL 0x18 // IME final mode - #define VK_HANJA 0x19 // IME Hanja mode - #define VK_KANJI 0x19 // IME Kanji mode - #define VK_ESCAPE 0x1B // ESC key - #define VK_CONVERT 0x1C // IME convert - #define VK_NONCONVERT 0x1D // IME nonconvert - #define VK_ACCEPT 0x1E // IME accept - #define VK_MODECHANGE 0x1F // IME mode change request - #define VK_SPACE 0x20 // SPACE key - #define VK_PRIOR 0x21 // PAGE UP key - #define VK_NEXT 0x22 // PAGE DOWN key - #define VK_END 0x23 // END key - #define VK_HOME 0x24 // HOME key - #define VK_LEFT 0x25 // LEFT ARROW key - #define VK_UP 0x26 // UP ARROW key - #define VK_RIGHT 0x27 // RIGHT ARROW key - #define VK_DOWN 0x28 // DOWN ARROW key - #define VK_SELECT 0x29 // SELECT key - #define VK_PRINT 0x2A // PRINT key - #define VK_EXECUTE 0x2B // EXECUTE key - #define VK_SNAPSHOT 0x2C // PRINT SCREEN key - #define VK_INSERT 0x2D // INS key - #define VK_DELETE 0x2E // DEL key - #define VK_HELP 0x2F // HELP key - #define VK_0 0x30 - #define VK_1 0x31 - #define VK_2 0x32 - #define VK_3 0x33 - #define VK_4 0x34 - #define VK_5 0x35 - #define VK_6 0x36 - #define VK_7 0x37 - #define VK_8 0x38 - #define VK_9 0x39 - #define VK_A 0x41 - #define VK_B 0x42 - #define VK_C 0x43 - #define VK_D 0x44 - #define VK_E 0x45 - #define VK_F 0x46 - #define VK_G 0x47 - #define VK_H 0x48 - #define VK_I 0x49 - #define VK_J 0x4A - #define VK_K 0x4B - #define VK_L 0x4C - #define VK_M 0x4D - #define VK_N 0x4E - #define VK_O 0x4F - #define VK_P 0x50 - #define VK_Q 0x51 - #define VK_R 0x52 - #define VK_S 0x53 - #define VK_T 0x54 - #define VK_U 0x55 - #define VK_V 0x56 - #define VK_W 0x57 - #define VK_X 0x58 - #define VK_Y 0x59 - #define VK_Z 0x5A - #define VK_LWIN 0x5B // Left Windows key (Microsoft Natural keyboard) - #define VK_RWIN 0x5C // Right Windows key (Natural keyboard) - #define VK_APPS 0x5D // Applications key (Natural keyboard) - #define VK_SLEEP 0x5F // Computer Sleep key - // Num pad keys - #define VK_NUMPAD0 0x60 - #define VK_NUMPAD1 0x61 - #define VK_NUMPAD2 0x62 - #define VK_NUMPAD3 0x63 - #define VK_NUMPAD4 0x64 - #define VK_NUMPAD5 0x65 - #define VK_NUMPAD6 0x66 - #define VK_NUMPAD7 0x67 - #define VK_NUMPAD8 0x68 - #define VK_NUMPAD9 0x69 - #define VK_MULTIPLY 0x6A - #define VK_ADD 0x6B - #define VK_SEPARATOR 0x6C - #define VK_SUBTRACT 0x6D - #define VK_DECIMAL 0x6E - #define VK_DIVIDE 0x6F - #define VK_F1 0x70 - #define VK_F2 0x71 - #define VK_F3 0x72 - #define VK_F4 0x73 - #define VK_F5 0x74 - #define VK_F6 0x75 - #define VK_F7 0x76 - #define VK_F8 0x77 - #define VK_F9 0x78 - #define VK_F10 0x79 - #define VK_F11 0x7A - #define VK_F12 0x7B - #define VK_F13 0x7C - #define VK_F14 0x7D - #define VK_F15 0x7E - #define VK_F16 0x7F - #define VK_F17 0x80 - #define VK_F18 0x81 - #define VK_F19 0x82 - #define VK_F20 0x83 - #define VK_F21 0x84 - #define VK_F22 0x85 - #define VK_F23 0x86 - #define VK_F24 0x87 - #define VK_NUMLOCK 0x90 - #define VK_SCROLL 0x91 - #define VK_LSHIFT 0xA0 - #define VK_RSHIFT 0xA1 - #define VK_LCONTROL 0xA2 - #define VK_RCONTROL 0xA3 - #define VK_LMENU 0xA4 - #define VK_RMENU 0xA5 - #define VK_BROWSER_BACK 0xA6 // Windows 2000/XP: Browser Back key - #define VK_BROWSER_FORWARD 0xA7 // Windows 2000/XP: Browser Forward key - #define VK_BROWSER_REFRESH 0xA8 // Windows 2000/XP: Browser Refresh key - #define VK_BROWSER_STOP 0xA9 // Windows 2000/XP: Browser Stop key - #define VK_BROWSER_SEARCH 0xAA // Windows 2000/XP: Browser Search key - #define VK_BROWSER_FAVORITES 0xAB // Windows 2000/XP: Browser Favorites key - #define VK_BROWSER_HOME 0xAC // Windows 2000/XP: Browser Start and Home key - #define VK_VOLUME_MUTE 0xAD // Windows 2000/XP: Volume Mute key - #define VK_VOLUME_DOWN 0xAE // Windows 2000/XP: Volume Down key - #define VK_VOLUME_UP 0xAF // Windows 2000/XP: Volume Up key - #define VK_MEDIA_NEXT_TRACK 0xB0 // Windows 2000/XP: Next Track key - #define VK_MEDIA_PREV_TRACK 0xB1 // Windows 2000/XP: Previous Track key - #define VK_MEDIA_STOP 0xB2 // Windows 2000/XP: Stop Media key - #define VK_MEDIA_PLAY_PAUSE 0xB3 // Windows 2000/XP: Play/Pause Media key - #define VK_MEDIA_LAUNCH_MAIL 0xB4 // Windows 2000/XP: Start Mail key - #define VK_MEDIA_LAUNCH_MEDIA_SELECT 0xB5 // Windows 2000/XP: Select Media key - #define VK_MEDIA_LAUNCH_APP1 0xB6 // VK_LAUNCH_APP1 (B6) Windows 2000/XP: Start Application 1 key - #define VK_MEDIA_LAUNCH_APP2 0xB7 // VK_LAUNCH_APP2 (B7) Windows 2000/XP: Start Application 2 key - #define VK_OEM_1 0xBA - #define VK_OEM_PLUS 0xBB - #define VK_OEM_COMMA 0xBC - #define VK_OEM_MINUS 0xBD - #define VK_OEM_PERIOD 0xBE - #define VK_OEM_2 0xBF - #define VK_OEM_3 0xC0 - #define VK_OEM_4 0xDB - #define VK_OEM_5 0xDC - #define VK_OEM_6 0xDD - #define VK_OEM_7 0xDE - #define VK_OEM_8 0xDF - #define VK_OEM_102 0xE2 - #define VK_PROCESSKEY 0xE5 - #define VK_PACKET 0xE7 - #define VK_ATTN 0xF6 // Attn key - #define VK_CRSEL 0xF7 // CrSel key - #define VK_EXSEL 0xF8 // ExSel key - #define VK_EREOF 0xF9 // Erase EOF key - #define VK_PLAY 0xFA // Play key - #define VK_ZOOM 0xFB // Zoom key - #define VK_NONAME 0xFC // Reserved for future use - #define VK_PA1 0xFD // VK_PA1 (FD) PA1 key - #define VK_OEM_CLEAR 0xFE // Clear key - #endif // VK_UNKNOWN - - - - #define GENERIC_READ 0x80000000 - #define GENERIC_WRITE 0x40000000 - #define GENERIC_EXECUTE 0x20000000 - #define GENERIC_ALL 0x10000000 - #define FILE_SHARE_READ 0x00000001 - #define FILE_SHARE_WRITE 0x00000002 - #define FILE_SHARE_DELETE 0x00000004 - #define CREATE_NEW 1 - #define CREATE_ALWAYS 2 - #define OPEN_EXISTING 3 - #define OPEN_ALWAYS 4 - #define TRUNCATE_EXISTING 5 - #define FILE_ATTRIBUTE_READONLY 0x00000001 - #define FILE_ATTRIBUTE_NORMAL 0x00000080 - #define FILE_ATTRIBUTE_TEMPORARY 0x00000100 - #define ERROR_FILE_NOT_FOUND 2l - #define ERROR_ACCESS_DENIED 5L - #define ERROR_NO_MORE_FILES 18l - #define ERROR_FILE_EXISTS 80l - #define ERROR_ALREADY_EXISTS 183l - #define STD_INPUT_HANDLE ((DWORD)-10) - #define STD_OUTPUT_HANDLE ((DWORD)-11) - #define STD_ERROR_HANDLE ((DWORD)-12) - - GB_DLL_IMPORT int MultiByteToWideChar(UINT code_page, DWORD flags, char const * multi_byte_str, int multi_byte_len, wchar_t const *wide_char_str, int wide_char_len); - GB_DLL_IMPORT int WideCharToMultiByte(UINT code_page, DWORD flags, wchar_t const *wide_char_str, int wide_char_len, char const * multi_byte_str, int multi_byte_len); - GB_DLL_IMPORT BOOL WINAPI SetFilePointerEx(HANDLE file, LARGE_INTEGER distance_to_move, - LARGE_INTEGER *new_file_pointer, DWORD move_method); - GB_DLL_IMPORT BOOL WINAPI ReadFile (HANDLE file, void *buffer, DWORD bytes_to_read, DWORD *bytes_read, OVERLAPPED *overlapped); - GB_DLL_IMPORT BOOL WINAPI WriteFile (HANDLE file, void const *buffer, DWORD bytes_to_write, DWORD *bytes_written, OVERLAPPED *overlapped); - GB_DLL_IMPORT HANDLE WINAPI CreateFileW (wchar_t const *path, DWORD desired_access, DWORD share_mode, - SECURITY_ATTRIBUTES *, DWORD creation_disposition, - DWORD flags_and_attributes, HANDLE template_file); - GB_DLL_IMPORT HANDLE WINAPI GetStdHandle (DWORD std_handle); - GB_DLL_IMPORT BOOL WINAPI GetFileSizeEx (HANDLE file, LARGE_INTEGER *size); - GB_DLL_IMPORT BOOL WINAPI SetEndOfFile (HANDLE file); - GB_DLL_IMPORT HANDLE WINAPI FindFirstFileW (wchar_t const *path, WIN32_FIND_DATAW *data); - GB_DLL_IMPORT BOOL WINAPI FindClose (HANDLE find_file); - GB_DLL_IMPORT BOOL WINAPI GetFileAttributesExW(wchar_t const *path, GET_FILEEX_INFO_LEVELS info_level_id, WIN32_FILE_ATTRIBUTE_DATA *data); - GB_DLL_IMPORT BOOL WINAPI CopyFileW(wchar_t const *old_f, wchar_t const *new_f, BOOL fail_if_exists); - GB_DLL_IMPORT BOOL WINAPI MoveFileW(wchar_t const *old_f, wchar_t const *new_f); - - GB_DLL_IMPORT HMODULE WINAPI LoadLibraryA (char const *filename); - GB_DLL_IMPORT BOOL WINAPI FreeLibrary (HMODULE module); - GB_DLL_IMPORT FARPROC WINAPI GetProcAddress(HMODULE module, char const *name); - - GB_DLL_IMPORT BOOL WINAPI QueryPerformanceFrequency(LARGE_INTEGER *frequency); - GB_DLL_IMPORT BOOL WINAPI QueryPerformanceCounter (LARGE_INTEGER *counter); - GB_DLL_IMPORT void WINAPI GetSystemTimeAsFileTime (FILETIME *system_time_as_file_time); - GB_DLL_IMPORT void WINAPI Sleep(DWORD milliseconds); - GB_DLL_IMPORT void WINAPI ExitProcess(UINT exit_code); - - GB_DLL_IMPORT BOOL WINAPI SetEnvironmentVariableA(char const *name, char const *value); - - - #define WM_NULL 0x0000 - #define WM_CREATE 0x0001 - #define WM_DESTROY 0x0002 - #define WM_MOVE 0x0003 - #define WM_SIZE 0x0005 - #define WM_ACTIVATE 0x0006 - #define WM_SETFOCUS 0x0007 - #define WM_KILLFOCUS 0x0008 - #define WM_ENABLE 0x000A - #define WM_SETREDRAW 0x000B - #define WM_SETTEXT 0x000C - #define WM_GETTEXT 0x000D - #define WM_GETTEXTLENGTH 0x000E - #define WM_PAINT 0x000F - #define WM_CLOSE 0x0010 - #define WM_QUERYENDSESSION 0x0011 - #define WM_QUERYOPEN 0x0013 - #define WM_ENDSESSION 0x0016 - #define WM_QUIT 0x0012 - #define WM_ERASEBKGND 0x0014 - #define WM_SYSCOLORCHANGE 0x0015 - #define WM_SHOWWINDOW 0x0018 - #define WM_WININICHANGE 0x001A - #define WM_SETTINGCHANGE WM_WININICHANGE - #define WM_DEVMODECHANGE 0x001B - #define WM_ACTIVATEAPP 0x001C - #define WM_FONTCHANGE 0x001D - #define WM_TIMECHANGE 0x001E - #define WM_CANCELMODE 0x001F - #define WM_SETCURSOR 0x0020 - #define WM_MOUSEACTIVATE 0x0021 - #define WM_CHILDACTIVATE 0x0022 - #define WM_QUEUESYNC 0x0023 - #define WM_GETMINMAXINFO 0x0024 - #define WM_PAINTICON 0x0026 - #define WM_ICONERASEBKGND 0x0027 - #define WM_NEXTDLGCTL 0x0028 - #define WM_SPOOLERSTATUS 0x002A - #define WM_DRAWITEM 0x002B - #define WM_MEASUREITEM 0x002C - #define WM_DELETEITEM 0x002D - #define WM_VKEYTOITEM 0x002E - #define WM_CHARTOITEM 0x002F - #define WM_SETFONT 0x0030 - #define WM_GETFONT 0x0031 - #define WM_SETHOTKEY 0x0032 - #define WM_GETHOTKEY 0x0033 - #define WM_QUERYDRAGICON 0x0037 - #define WM_COMPAREITEM 0x0039 - #define WM_GETOBJECT 0x003D - #define WM_COMPACTING 0x0041 - #define WM_COMMNOTIFY 0x0044 /* no longer suported */ - #define WM_WINDOWPOSCHANGING 0x0046 - #define WM_WINDOWPOSCHANGED 0x0047 - #define WM_POWER 0x0048 - #define WM_COPYDATA 0x004A - #define WM_CANCELJOURNAL 0x004B - #define WM_NOTIFY 0x004E - #define WM_INPUTLANGCHANGEREQUEST 0x0050 - #define WM_INPUTLANGCHANGE 0x0051 - #define WM_TCARD 0x0052 - #define WM_HELP 0x0053 - #define WM_USERCHANGED 0x0054 - #define WM_NOTIFYFORMAT 0x0055 - #define WM_CONTEXTMENU 0x007B - #define WM_STYLECHANGING 0x007C - #define WM_STYLECHANGED 0x007D - #define WM_DISPLAYCHANGE 0x007E - #define WM_GETICON 0x007F - #define WM_SETICON 0x0080 - #define WM_INPUT 0x00FF - #define WM_KEYFIRST 0x0100 - #define WM_KEYDOWN 0x0100 - #define WM_KEYUP 0x0101 - #define WM_CHAR 0x0102 - #define WM_DEADCHAR 0x0103 - #define WM_SYSKEYDOWN 0x0104 - #define WM_SYSKEYUP 0x0105 - #define WM_SYSCHAR 0x0106 - #define WM_SYSDEADCHAR 0x0107 - #define WM_UNICHAR 0x0109 - #define WM_KEYLAST 0x0109 - #define WM_APP 0x8000 - - - #define RID_INPUT 0x10000003 - - #define RIM_TYPEMOUSE 0x00000000 - #define RIM_TYPEKEYBOARD 0x00000001 - #define RIM_TYPEHID 0x00000002 - - #define RI_KEY_MAKE 0x0000 - #define RI_KEY_BREAK 0x0001 - #define RI_KEY_E0 0x0002 - #define RI_KEY_E1 0x0004 - #define RI_MOUSE_WHEEL 0x0400 - - #define RIDEV_NOLEGACY 0x00000030 - - #define MAPVK_VK_TO_VSC 0 - #define MAPVK_VSC_TO_VK 1 - #define MAPVK_VK_TO_CHAR 2 - #define MAPVK_VSC_TO_VK_EX 3 - - GB_DLL_IMPORT BOOL WINAPI RegisterRawInputDevices(RAWINPUTDEVICE const *raw_input_devices, UINT num_devices, UINT size); - GB_DLL_IMPORT UINT WINAPI GetRawInputData(HRAWINPUT raw_input, UINT ui_command, void *data, UINT *size, UINT size_header); - GB_DLL_IMPORT UINT WINAPI MapVirtualKeyW(UINT code, UINT map_type); - - - #define CS_DBLCLKS 0x0008 - #define CS_VREDRAW 0x0001 - #define CS_HREDRAW 0x0002 - - #define MB_OK 0x0000l - #define MB_ICONSTOP 0x0010l - #define MB_YESNO 0x0004l - #define MB_HELP 0x4000l - #define MB_ICONEXCLAMATION 0x0030l - - GB_DLL_IMPORT LRESULT WINAPI DefWindowProcW(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam); - GB_DLL_IMPORT HGDIOBJ WINAPI GetStockObject(int object); - GB_DLL_IMPORT HMODULE WINAPI GetModuleHandleW(wchar_t const *); - GB_DLL_IMPORT ATOM WINAPI RegisterClassExW(WNDCLASSEXW const *wcx); // u16 == ATOM - GB_DLL_IMPORT int WINAPI MessageBoxW(void *wnd, wchar_t const *text, wchar_t const *caption, unsigned int type); - - - #define DM_BITSPERPEL 0x00040000l - #define DM_PELSWIDTH 0x00080000l - #define DM_PELSHEIGHT 0x00100000l - - #define CDS_FULLSCREEN 0x4 - #define DISP_CHANGE_SUCCESSFUL 0 - #define IDYES 6 - - #define WS_VISIBLE 0x10000000 - #define WS_THICKFRAME 0x00040000 - #define WS_MAXIMIZE 0x01000000 - #define WS_MAXIMIZEBOX 0x00010000 - #define WS_MINIMIZE 0x20000000 - #define WS_MINIMIZEBOX 0x00020000 - #define WS_POPUP 0x80000000 - #define WS_OVERLAPPED 0 - #define WS_OVERLAPPEDWINDOW 0xcf0000 - #define CW_USEDEFAULT 0x80000000 - #define WS_BORDER 0x800000 - #define WS_CAPTION 0xc00000 - #define WS_SYSMENU 0x80000 - - #define HWND_NOTOPMOST (HWND)(-2) - #define HWND_TOPMOST (HWND)(-1) - #define HWND_TOP (HWND)(+0) - #define HWND_BOTTOM (HWND)(+1) - #define SWP_NOSIZE 0x0001 - #define SWP_NOMOVE 0x0002 - #define SWP_NOZORDER 0x0004 - #define SWP_NOREDRAW 0x0008 - #define SWP_NOACTIVATE 0x0010 - #define SWP_FRAMECHANGED 0x0020 - #define SWP_SHOWWINDOW 0x0040 - #define SWP_HIDEWINDOW 0x0080 - #define SWP_NOCOPYBITS 0x0100 - #define SWP_NOOWNERZORDER 0x0200 - #define SWP_NOSENDCHANGING 0x0400 - - #define SW_HIDE 0 - #define SW_SHOWNORMAL 1 - #define SW_NORMAL 1 - #define SW_SHOWMINIMIZED 2 - #define SW_SHOWMAXIMIZED 3 - #define SW_MAXIMIZE 3 - #define SW_SHOWNOACTIVATE 4 - #define SW_SHOW 5 - #define SW_MINIMIZE 6 - #define SW_SHOWMINNOACTIVE 7 - #define SW_SHOWNA 8 - #define SW_RESTORE 9 - #define SW_SHOWDEFAULT 10 - #define SW_FORCEMINIMIZE 11 - #define SW_MAX 11 - - #define ENUM_CURRENT_SETTINGS cast(DWORD)-1 - #define ENUM_REGISTRY_SETTINGS cast(DWORD)-2 - - GB_DLL_IMPORT LONG WINAPI ChangeDisplaySettingsW(DEVMODEW *dev_mode, DWORD flags); - GB_DLL_IMPORT BOOL WINAPI AdjustWindowRect(RECT *rect, DWORD style, BOOL enu); - GB_DLL_IMPORT HWND WINAPI CreateWindowExW(DWORD ex_style, wchar_t const *class_name, wchar_t const *window_name, - DWORD style, int x, int y, int width, int height, HWND wnd_parent, - HMENU menu, HINSTANCE instance, void *param); - GB_DLL_IMPORT HMODULE WINAPI GetModuleHandleW(wchar_t const *); - GB_DLL_IMPORT HDC GetDC(HANDLE); - GB_DLL_IMPORT BOOL WINAPI GetWindowPlacement(HWND hWnd, WINDOWPLACEMENT *lpwndpl); - GB_DLL_IMPORT BOOL GetMonitorInfoW(HMONITOR hMonitor, MONITORINFO *lpmi); - GB_DLL_IMPORT HMONITOR MonitorFromWindow(HWND hwnd, DWORD dwFlags); - GB_DLL_IMPORT LONG WINAPI SetWindowLongW(HWND hWnd, int nIndex, LONG dwNewLong); - GB_DLL_IMPORT BOOL WINAPI SetWindowPos(HWND hWnd, HWND hWndInsertAfter, int X, int Y, int cx, int cy, UINT uFlags); - GB_DLL_IMPORT BOOL WINAPI SetWindowPlacement(HWND hWnd, WINDOWPLACEMENT const *lpwndpl); - GB_DLL_IMPORT BOOL WINAPI ShowWindow(HWND hWnd, int nCmdShow); - GB_DLL_IMPORT LONG_PTR WINAPI GetWindowLongPtrW(HWND wnd, int index); - - GB_DLL_IMPORT BOOL EnumDisplaySettingsW(wchar_t const *lpszDeviceName, DWORD iModeNum, DEVMODEW *lpDevMode); - GB_DLL_IMPORT void * WINAPI GlobalLock(HGLOBAL hMem); - GB_DLL_IMPORT BOOL WINAPI GlobalUnlock(HGLOBAL hMem); - GB_DLL_IMPORT HGLOBAL WINAPI GlobalAlloc(UINT uFlags, usize dwBytes); - GB_DLL_IMPORT HANDLE WINAPI GetClipboardData(UINT uFormat); - GB_DLL_IMPORT BOOL WINAPI IsClipboardFormatAvailable(UINT format); - GB_DLL_IMPORT BOOL WINAPI OpenClipboard(HWND hWndNewOwner); - GB_DLL_IMPORT BOOL WINAPI EmptyClipboard(void); - GB_DLL_IMPORT BOOL WINAPI CloseClipboard(void); - GB_DLL_IMPORT HANDLE WINAPI SetClipboardData(UINT uFormat, HANDLE hMem); - - #define PFD_TYPE_RGBA 0 - #define PFD_TYPE_COLORINDEX 1 - #define PFD_MAIN_PLANE 0 - #define PFD_OVERLAY_PLANE 1 - #define PFD_UNDERLAY_PLANE (-1) - #define PFD_DOUBLEBUFFER 1 - #define PFD_STEREO 2 - #define PFD_DRAW_TO_WINDOW 4 - #define PFD_DRAW_TO_BITMAP 8 - #define PFD_SUPPORT_GDI 16 - #define PFD_SUPPORT_OPENGL 32 - #define PFD_GENERIC_FORMAT 64 - #define PFD_NEED_PALETTE 128 - #define PFD_NEED_SYSTEM_PALETTE 0x00000100 - #define PFD_SWAP_EXCHANGE 0x00000200 - #define PFD_SWAP_COPY 0x00000400 - #define PFD_SWAP_LAYER_BUFFERS 0x00000800 - #define PFD_GENERIC_ACCELERATED 0x00001000 - #define PFD_DEPTH_DONTCARE 0x20000000 - #define PFD_DOUBLEBUFFER_DONTCARE 0x40000000 - #define PFD_STEREO_DONTCARE 0x80000000 - - #define GWLP_USERDATA -21 - - #define GWL_ID -12 - #define GWL_STYLE -16 - - GB_DLL_IMPORT BOOL WINAPI SetPixelFormat (HDC hdc, int pixel_format, PIXELFORMATDESCRIPTOR const *pfd); - GB_DLL_IMPORT int WINAPI ChoosePixelFormat(HDC hdc, PIXELFORMATDESCRIPTOR const *pfd); - GB_DLL_IMPORT HGLRC WINAPI wglCreateContext (HDC hdc); - GB_DLL_IMPORT BOOL WINAPI wglMakeCurrent (HDC hdc, HGLRC hglrc); - GB_DLL_IMPORT PROC WINAPI wglGetProcAddress(char const *str); - GB_DLL_IMPORT BOOL WINAPI wglDeleteContext (HGLRC hglrc); - - GB_DLL_IMPORT BOOL WINAPI SetForegroundWindow(HWND hWnd); - GB_DLL_IMPORT HWND WINAPI SetFocus(HWND hWnd); - GB_DLL_IMPORT LONG_PTR WINAPI SetWindowLongPtrW(HWND hWnd, int nIndex, LONG_PTR dwNewLong); - GB_DLL_IMPORT BOOL WINAPI GetClientRect(HWND hWnd, RECT *lpRect); - GB_DLL_IMPORT BOOL WINAPI IsIconic(HWND hWnd); - GB_DLL_IMPORT HWND WINAPI GetFocus(void); - GB_DLL_IMPORT int WINAPI ShowCursor(BOOL bShow); - GB_DLL_IMPORT SHORT WINAPI GetAsyncKeyState(int key); - GB_DLL_IMPORT BOOL WINAPI GetCursorPos(POINT *lpPoint); - GB_DLL_IMPORT BOOL WINAPI SetCursorPos(int x, int y); - GB_DLL_IMPORT BOOL ScreenToClient(HWND hWnd, POINT *lpPoint); - GB_DLL_IMPORT BOOL ClientToScreen(HWND hWnd, POINT *lpPoint); - GB_DLL_IMPORT BOOL WINAPI MoveWindow(HWND hWnd, int X, int Y, int nWidth, int nHeight, BOOL bRepaint); - GB_DLL_IMPORT BOOL WINAPI SetWindowTextW(HWND hWnd, wchar_t const *lpString); - GB_DLL_IMPORT DWORD WINAPI GetWindowLongW(HWND hWnd, int nIndex); - - - - - #define PM_NOREMOVE 0 - #define PM_REMOVE 1 - - GB_DLL_IMPORT BOOL WINAPI PeekMessageW(MSG *lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg); - GB_DLL_IMPORT BOOL WINAPI TranslateMessage(MSG const *lpMsg); - GB_DLL_IMPORT LRESULT WINAPI DispatchMessageW(MSG const *lpMsg); - - typedef enum - { - DIB_RGB_COLORS = 0x00, - DIB_PAL_COLORS = 0x01, - DIB_PAL_INDICES = 0x02 - } DIBColors; - - #define SRCCOPY (u32)0x00CC0020 - #define SRCPAINT (u32)0x00EE0086 - #define SRCAND (u32)0x008800C6 - #define SRCINVERT (u32)0x00660046 - #define SRCERASE (u32)0x00440328 - #define NOTSRCCOPY (u32)0x00330008 - #define NOTSRCERASE (u32)0x001100A6 - #define MERGECOPY (u32)0x00C000CA - #define MERGEPAINT (u32)0x00BB0226 - #define PATCOPY (u32)0x00F00021 - #define PATPAINT (u32)0x00FB0A09 - #define PATINVERT (u32)0x005A0049 - #define DSTINVERT (u32)0x00550009 - #define BLACKNESS (u32)0x00000042 - #define WHITENESS (u32)0x00FF0062 - - GB_DLL_IMPORT BOOL WINAPI SwapBuffers(HDC hdc); - GB_DLL_IMPORT BOOL WINAPI DestroyWindow(HWND hWnd); - GB_DLL_IMPORT int StretchDIBits(HDC hdc, int XDest, int YDest, int nDestWidth, int nDestHeight, - int XSrc, int YSrc, int nSrcWidth, int nSrcHeight, - void const *lpBits, /*BITMAPINFO*/void const *lpBitsInfo, UINT iUsage, DWORD dwRop); - // IMPORTANT TODO(bill): FIX THIS!!!! -#endif // Bill's Mini Windows.h - - - -#if defined(__GCC__) || defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wattributes" -#pragma GCC diagnostic ignored "-Wmissing-braces" -#endif - -#if defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable:4201) -#pragma warning(disable:4127) // Conditional expression is constant -#endif - -void gb_assert_handler(char const *prefix, char const *condition, char const *file, i32 line, char const *msg, ...) { - gb_printf_err("%s(%d): %s: ", file, line, prefix); - if (condition) - gb_printf_err( "`%s` ", condition); - if (msg) { - va_list va; - va_start(va, msg); - gb_printf_err_va(msg, va); - va_end(va); - } - gb_printf_err("\n"); -} - -b32 gb_is_power_of_two(isize x) { - if (x <= 0) - return false; - return !(x & (x-1)); -} - -gb_inline void *gb_align_forward(void *ptr, isize alignment) { - uintptr p; - - GB_ASSERT(gb_is_power_of_two(alignment)); - - p = cast(uintptr)ptr; - return cast(void *)((p + (alignment-1)) &~ (alignment-1)); -} - - - -gb_inline void * gb_pointer_add (void *ptr, isize bytes) { return cast(void *)(cast(u8 *)ptr + bytes); } -gb_inline void * gb_pointer_sub (void *ptr, isize bytes) { return cast(void *)(cast(u8 *)ptr - bytes); } -gb_inline void const *gb_pointer_add_const(void const *ptr, isize bytes) { return cast(void const *)(cast(u8 const *)ptr + bytes); } -gb_inline void const *gb_pointer_sub_const(void const *ptr, isize bytes) { return cast(void const *)(cast(u8 const *)ptr - bytes); } -gb_inline isize gb_pointer_diff (void const *begin, void const *end) { return cast(isize)(cast(u8 const *)end - cast(u8 const *)begin); } - -gb_inline void gb_zero_size(void *ptr, isize size) { gb_memset(ptr, 0, size); } - - -#if defined(_MSC_VER) -#pragma intrinsic(__movsb) -#endif - -gb_inline void *gb_memcopy(void *dest, void const *source, isize n) { -#if defined(_MSC_VER) - if (dest == NULL) { - return NULL; - } - // TODO(bill): Is this good enough? - __movsb(cast(u8 *)dest, cast(u8 *)source, n); -// #elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX) - // NOTE(zangent): I assume there's a reason this isn't being used elsewhere, - // but casting pointers as arguments to an __asm__ call is considered an - // error on MacOS and (I think) Linux - // TODO(zangent): Figure out how to refactor the asm code so it works on MacOS, - // since this is probably not the way the author intended this to work. - // memcpy(dest, source, n); -#elif defined(GB_CPU_X86) - if (dest == NULL) { - return NULL; - } - - void *dest_copy = dest; - __asm__ __volatile__("rep movsb" : "+D"(dest_copy), "+S"(source), "+c"(n) : : "memory"); -#else - u8 *d = cast(u8 *)dest; - u8 const *s = cast(u8 const *)source; - u32 w, x; - - if (dest == NULL) { - return NULL; - } - - for (; cast(uintptr)s % 4 && n; n--) { - *d++ = *s++; - } - - if (cast(uintptr)d % 4 == 0) { - for (; n >= 16; - s += 16, d += 16, n -= 16) { - *cast(u32 *)(d+ 0) = *cast(u32 *)(s+ 0); - *cast(u32 *)(d+ 4) = *cast(u32 *)(s+ 4); - *cast(u32 *)(d+ 8) = *cast(u32 *)(s+ 8); - *cast(u32 *)(d+12) = *cast(u32 *)(s+12); - } - if (n & 8) { - *cast(u32 *)(d+0) = *cast(u32 *)(s+0); - *cast(u32 *)(d+4) = *cast(u32 *)(s+4); - d += 8; - s += 8; - } - if (n&4) { - *cast(u32 *)(d+0) = *cast(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(uintptr)d % 4) { - case 1: { - w = *cast(u32 *)s; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - n -= 3; - while (n > 16) { - x = *cast(u32 *)(s+1); - *cast(u32 *)(d+0) = (w LS 24) | (x RS 8); - w = *cast(u32 *)(s+5); - *cast(u32 *)(d+4) = (x LS 24) | (w RS 8); - x = *cast(u32 *)(s+9); - *cast(u32 *)(d+8) = (w LS 24) | (x RS 8); - w = *cast(u32 *)(s+13); - *cast(u32 *)(d+12) = (x LS 24) | (w RS 8); - - s += 16; - d += 16; - n -= 16; - } - } break; - case 2: { - w = *cast(u32 *)s; - *d++ = *s++; - *d++ = *s++; - n -= 2; - while (n > 17) { - x = *cast(u32 *)(s+2); - *cast(u32 *)(d+0) = (w LS 16) | (x RS 16); - w = *cast(u32 *)(s+6); - *cast(u32 *)(d+4) = (x LS 16) | (w RS 16); - x = *cast(u32 *)(s+10); - *cast(u32 *)(d+8) = (w LS 16) | (x RS 16); - w = *cast(u32 *)(s+14); - *cast(u32 *)(d+12) = (x LS 16) | (w RS 16); - - s += 16; - d += 16; - n -= 16; - } - } break; - case 3: { - w = *cast(u32 *)s; - *d++ = *s++; - n -= 1; - while (n > 18) { - x = *cast(u32 *)(s+3); - *cast(u32 *)(d+0) = (w LS 8) | (x RS 24); - w = *cast(u32 *)(s+7); - *cast(u32 *)(d+4) = (x LS 8) | (w RS 24); - x = *cast(u32 *)(s+11); - *cast(u32 *)(d+8) = (w LS 8) | (x RS 24); - w = *cast(u32 *)(s+15); - *cast(u32 *)(d+12) = (x LS 8) | (w RS 24); - - s += 16; - d += 16; - n -= 16; - } - } break; - default: break; // NOTE(bill): 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 - return dest; -} - -gb_inline void *gb_memmove(void *dest, void const *source, isize n) { - u8 *d = cast(u8 *)dest; - u8 const *s = cast(u8 const *)source; - - if (dest == NULL) { - return NULL; - } - - if (d == s) { - return d; - } - if (s+n <= d || d+n <= s) { // NOTE(bill): Non-overlapping - return gb_memcopy(d, s, n); - } - - if (d < s) { - if (cast(uintptr)s % gb_size_of(isize) == cast(uintptr)d % gb_size_of(isize)) { - while (cast(uintptr)d % gb_size_of(isize)) { - if (!n--) return dest; - *d++ = *s++; - } - while (n>=gb_size_of(isize)) { - *cast(isize *)d = *cast(isize *)s; - n -= gb_size_of(isize); - d += gb_size_of(isize); - s += gb_size_of(isize); - } - } - for (; n; n--) *d++ = *s++; - } else { - if ((cast(uintptr)s % gb_size_of(isize)) == (cast(uintptr)d % gb_size_of(isize))) { - while (cast(uintptr)(d+n) % gb_size_of(isize)) { - if (!n--) - return dest; - d[n] = s[n]; - } - while (n >= gb_size_of(isize)) { - n -= gb_size_of(isize); - *cast(isize *)(d+n) = *cast(isize *)(s+n); - } - } - while (n) n--, d[n] = s[n]; - } - - return dest; -} - -gb_inline void *gb_memset(void *dest, u8 c, isize n) { - u8 *s = cast(u8 *)dest; - isize k; - u32 c32 = ((u32)-1)/255 * c; - - if (dest == NULL) { - return NULL; - } - - 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(intptr)s & 3; - s += k; - n -= k; - n &= -4; - - *cast(u32 *)(s+0) = c32; - *cast(u32 *)(s+n-4) = c32; - if (n < 9) { - return dest; - } - *cast(u32 *)(s + 4) = c32; - *cast(u32 *)(s + 8) = c32; - *cast(u32 *)(s+n-12) = c32; - *cast(u32 *)(s+n- 8) = c32; - if (n < 25) { - return dest; - } - *cast(u32 *)(s + 12) = c32; - *cast(u32 *)(s + 16) = c32; - *cast(u32 *)(s + 20) = c32; - *cast(u32 *)(s + 24) = c32; - *cast(u32 *)(s+n-28) = c32; - *cast(u32 *)(s+n-24) = c32; - *cast(u32 *)(s+n-20) = c32; - *cast(u32 *)(s+n-16) = c32; - - k = 24 + (cast(uintptr)s & 4); - s += k; - n -= k; - - - { - u64 c64 = (cast(u64)c32 << 32) | c32; - while (n > 31) { - *cast(u64 *)(s+0) = c64; - *cast(u64 *)(s+8) = c64; - *cast(u64 *)(s+16) = c64; - *cast(u64 *)(s+24) = c64; - - n -= 32; - s += 32; - } - } - - return dest; -} - -gb_inline i32 gb_memcompare(void const *s1, void const *s2, isize size) { - // TODO(bill): Heavily optimize - u8 const *s1p8 = cast(u8 const *)s1; - u8 const *s2p8 = cast(u8 const *)s2; - - if (s1 == NULL || s2 == NULL) { - return 0; - } - - while (size--) { - if (*s1p8 != *s2p8) { - return (*s1p8 - *s2p8); - } - s1p8++, s2p8++; - } - return 0; -} - -void gb_memswap(void *i, void *j, isize size) { - if (i == j) return; - - if (size == 4) { - gb_swap(u32, *cast(u32 *)i, *cast(u32 *)j); - } else if (size == 8) { - gb_swap(u64, *cast(u64 *)i, *cast(u64 *)j); - } else if (size < 8) { - u8 *a = cast(u8 *)i; - u8 *b = cast(u8 *)j; - if (a != b) { - while (size--) { - gb_swap(u8, *a, *b); - a++, b++; - } - } - } else { - char buffer[256]; - - // TODO(bill): Is the recursion ever a problem? - while (size > gb_size_of(buffer)) { - gb_memswap(i, j, gb_size_of(buffer)); - i = gb_pointer_add(i, gb_size_of(buffer)); - j = gb_pointer_add(j, gb_size_of(buffer)); - size -= gb_size_of(buffer); - } - - gb_memcopy(buffer, i, size); - gb_memcopy(i, j, size); - gb_memcopy(j, buffer, size); - } -} - -#define GB__ONES (cast(usize)-1/U8_MAX) -#define GB__HIGHS (GB__ONES * (U8_MAX/2+1)) -#define GB__HAS_ZERO(x) ((x)-GB__ONES & ~(x) & GB__HIGHS) - - -void const *gb_memchr(void const *data, u8 c, isize n) { - u8 const *s = cast(u8 const *)data; - while ((cast(uintptr)s & (sizeof(usize)-1)) && - n && *s != c) { - s++; - n--; - } - if (n && *s != c) { - isize const *w; - isize k = GB__ONES * c; - w = cast(isize const *)s; - while (n >= gb_size_of(isize) && !GB__HAS_ZERO(*w ^ k)) { - w++; - n -= gb_size_of(isize); - } - s = cast(u8 const *)w; - while (n && *s != c) { - s++; - n--; - } - } - - return n ? cast(void const *)s : NULL; -} - - -void const *gb_memrchr(void const *data, u8 c, isize n) { - u8 const *s = cast(u8 const *)data; - while (n--) { - if (s[n] == c) - return cast(void const *)(s + n); - } - return NULL; -} - - - -gb_inline void *gb_alloc_align (gbAllocator a, isize size, isize alignment) { return a.proc(a.data, gbAllocation_Alloc, size, alignment, NULL, 0, GB_DEFAULT_ALLOCATOR_FLAGS); } -gb_inline void *gb_alloc (gbAllocator a, isize size) { return gb_alloc_align(a, size, GB_DEFAULT_MEMORY_ALIGNMENT); } -gb_inline void gb_free (gbAllocator a, void *ptr) { if (ptr != NULL) a.proc(a.data, gbAllocation_Free, 0, 0, ptr, 0, GB_DEFAULT_ALLOCATOR_FLAGS); } -gb_inline void gb_free_all (gbAllocator a) { a.proc(a.data, gbAllocation_FreeAll, 0, 0, NULL, 0, GB_DEFAULT_ALLOCATOR_FLAGS); } -gb_inline void *gb_resize (gbAllocator a, void *ptr, isize old_size, isize new_size) { return gb_resize_align(a, ptr, old_size, new_size, GB_DEFAULT_MEMORY_ALIGNMENT); } -gb_inline void *gb_resize_align(gbAllocator a, void *ptr, isize old_size, isize new_size, isize alignment) { return a.proc(a.data, gbAllocation_Resize, new_size, alignment, ptr, old_size, GB_DEFAULT_ALLOCATOR_FLAGS); } - -gb_inline void *gb_alloc_copy (gbAllocator a, void const *src, isize size) { - return gb_memcopy(gb_alloc(a, size), src, size); -} -gb_inline void *gb_alloc_copy_align(gbAllocator a, void const *src, isize size, isize alignment) { - return gb_memcopy(gb_alloc_align(a, size, alignment), src, size); -} - -gb_inline char *gb_alloc_str(gbAllocator a, char const *str) { - return gb_alloc_str_len(a, str, gb_strlen(str)); -} - -gb_inline char *gb_alloc_str_len(gbAllocator a, char const *str, isize len) { - char *result; - result = cast(char *)gb_alloc_copy(a, str, len+1); - result[len] = '\0'; - return result; -} - - -gb_inline void *gb_default_resize_align(gbAllocator a, void *old_memory, isize old_size, isize new_size, isize alignment) { - if (!old_memory) return gb_alloc_align(a, new_size, alignment); - - if (new_size == 0) { - gb_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 = gb_alloc_align(a, new_size, alignment); - if (!new_memory) return NULL; - gb_memmove(new_memory, old_memory, gb_min(new_size, old_size)); - gb_free(a, old_memory); - return new_memory; - } -} - - - - -//////////////////////////////////////////////////////////////// -// -// Concurrency -// -// -// IMPORTANT TODO(bill): Use compiler intrinsics for the atomics - -#if defined(GB_COMPILER_MSVC) && !defined(GB_COMPILER_CLANG) -gb_inline i32 gb_atomic32_load (gbAtomic32 const volatile *a) { return a->value; } -gb_inline void gb_atomic32_store(gbAtomic32 volatile *a, i32 value) { a->value = value; } - -gb_inline i32 gb_atomic32_compare_exchange(gbAtomic32 volatile *a, i32 expected, i32 desired) { - return _InterlockedCompareExchange(cast(long volatile *)a, desired, expected); -} -gb_inline i32 gb_atomic32_exchanged(gbAtomic32 volatile *a, i32 desired) { - return _InterlockedExchange(cast(long volatile *)a, desired); -} -gb_inline i32 gb_atomic32_fetch_add(gbAtomic32 volatile *a, i32 operand) { - return _InterlockedExchangeAdd(cast(long volatile *)a, operand); -} -gb_inline i32 gb_atomic32_fetch_and(gbAtomic32 volatile *a, i32 operand) { - return _InterlockedAnd(cast(long volatile *)a, operand); -} -gb_inline i32 gb_atomic32_fetch_or(gbAtomic32 volatile *a, i32 operand) { - return _InterlockedOr(cast(long volatile *)a, operand); -} - -gb_inline i64 gb_atomic64_load(gbAtomic64 const volatile *a) { -#if defined(GB_ARCH_64_BIT) - return a->value; -#elif GB_CPU_X86 - // NOTE(bill): The most compatible way to get an atomic 64-bit load on x86 is with cmpxchg8b - 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(bill): atomics for this CPU -#endif -} - -gb_inline void gb_atomic64_store(gbAtomic64 volatile *a, i64 value) { -#if defined(GB_ARCH_64_BIT) - a->value = value; -#elif GB_CPU_X86 - // NOTE(bill): 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(bill): atomics for this CPU -#endif -} - -gb_inline i64 gb_atomic64_compare_exchange(gbAtomic64 volatile *a, i64 expected, i64 desired) { - return _InterlockedCompareExchange64(cast(i64 volatile *)a, desired, expected); -} - -gb_inline i64 gb_atomic64_exchanged(gbAtomic64 volatile *a, i64 desired) { -#if defined(GB_ARCH_64_BIT) - return _InterlockedExchange64(cast(i64 volatile *)a, desired); -#elif GB_CPU_X86 - i64 expected = a->value; - for (;;) { - i64 original = _InterlockedCompareExchange64(cast(i64 volatile *)a, desired, expected); - if (original == expected) - return original; - expected = original; - } -#else -#error TODO(bill): atomics for this CPU -#endif -} - -gb_inline i64 gb_atomic64_fetch_add(gbAtomic64 volatile *a, i64 operand) { -#if defined(GB_ARCH_64_BIT) - return _InterlockedExchangeAdd64(cast(i64 volatile *)a, operand); -#elif GB_CPU_X86 - i64 expected = a->value; - for (;;) { - i64 original = _InterlockedCompareExchange64(cast(i64 volatile *)a, expected + operand, expected); - if (original == expected) - return original; - expected = original; - } -#else -#error TODO(bill): atomics for this CPU -#endif -} - -gb_inline i64 gb_atomic64_fetch_and(gbAtomic64 volatile *a, i64 operand) { -#if defined(GB_ARCH_64_BIT) - return _InterlockedAnd64(cast(i64 volatile *)a, operand); -#elif GB_CPU_X86 - i64 expected = a->value; - for (;;) { - i64 original = _InterlockedCompareExchange64(cast(i64 volatile *)a, expected & operand, expected); - if (original == expected) - return original; - expected = original; - } -#else -#error TODO(bill): atomics for this CPU -#endif -} - -gb_inline i64 gb_atomic64_fetch_or(gbAtomic64 volatile *a, i64 operand) { -#if defined(GB_ARCH_64_BIT) - return _InterlockedOr64(cast(i64 volatile *)a, operand); -#elif GB_CPU_X86 - i64 expected = a->value; - for (;;) { - i64 original = _InterlockedCompareExchange64(cast(i64 volatile *)a, expected | operand, expected); - if (original == expected) - return original; - expected = original; - } -#else -#error TODO(bill): atomics for this CPU -#endif -} - - - -#elif defined(GB_CPU_X86) - -gb_inline i32 gb_atomic32_load (gbAtomic32 const volatile *a) { return a->value; } -gb_inline void gb_atomic32_store(gbAtomic32 volatile *a, i32 value) { a->value = value; } - -gb_inline i32 gb_atomic32_compare_exchange(gbAtomic32 volatile *a, i32 expected, i32 desired) { - i32 original; - __asm__ volatile( - "lock; cmpxchgl %2, %1" - : "=a"(original), "+m"(a->value) - : "q"(desired), "0"(expected) - ); - return original; -} - -gb_inline i32 gb_atomic32_exchanged(gbAtomic32 volatile *a, i32 desired) { - // NOTE(bill): No lock prefix is necessary for xchgl - i32 original; - __asm__ volatile( - "xchgl %0, %1" - : "=r"(original), "+m"(a->value) - : "0"(desired) - ); - return original; -} - -gb_inline i32 gb_atomic32_fetch_add(gbAtomic32 volatile *a, i32 operand) { - i32 original; - __asm__ volatile( - "lock; xaddl %0, %1" - : "=r"(original), "+m"(a->value) - : "0"(operand) - ); - return original; -} - -gb_inline i32 gb_atomic32_fetch_and(gbAtomic32 volatile *a, i32 operand) { - i32 original; - i32 tmp; - __asm__ volatile( - "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; -} - -gb_inline i32 gb_atomic32_fetch_or(gbAtomic32 volatile *a, i32 operand) { - i32 original; - i32 temp; - __asm__ volatile( - "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; -} - - -gb_inline i64 gb_atomic64_load(gbAtomic64 const volatile *a) { -#if defined(GB_ARCH_64_BIT) - return a->value; -#else - i64 original; - __asm__ volatile( - "movl %%ebx, %%eax\n" - "movl %%ecx, %%edx\n" - "lock; cmpxchg8b %1" - : "=&A"(original) - : "m"(a->value) - ); - return original; -#endif -} - -gb_inline void gb_atomic64_store(gbAtomic64 volatile *a, i64 value) { -#if defined(GB_ARCH_64_BIT) - a->value = value; -#else - i64 expected = a->value; - __asm__ volatile( - "1: cmpxchg8b %0\n" - " jne 1b" - : "=m"(a->value) - : "b"((i32)value), "c"((i32)(value >> 32)), "A"(expected) - ); -#endif -} - -gb_inline i64 gb_atomic64_compare_exchange(gbAtomic64 volatile *a, i64 expected, i64 desired) { -#if defined(GB_ARCH_64_BIT) - i64 original; - __asm__ volatile( - "lock; cmpxchgq %2, %1" - : "=a"(original), "+m"(a->value) - : "q"(desired), "0"(expected) - ); - return original; -#else - i64 original; - __asm__ volatile( - "lock; cmpxchg8b %1" - : "=A"(original), "+m"(a->value) - : "b"((i32)desired), "c"((i32)(desired >> 32)), "0"(expected) - ); - return original; -#endif -} - -gb_inline i64 gb_atomic64_exchanged(gbAtomic64 volatile *a, i64 desired) { -#if defined(GB_ARCH_64_BIT) - i64 original; - __asm__ volatile( - "xchgq %0, %1" - : "=r"(original), "+m"(a->value) - : "0"(desired) - ); - return original; -#else - i64 original = a->value; - for (;;) { - i64 previous = gb_atomic64_compare_exchange(a, original, desired); - if (original == previous) - return original; - original = previous; - } -#endif -} - -gb_inline i64 gb_atomic64_fetch_add(gbAtomic64 volatile *a, i64 operand) { -#if defined(GB_ARCH_64_BIT) - i64 original; - __asm__ volatile( - "lock; xaddq %0, %1" - : "=r"(original), "+m"(a->value) - : "0"(operand) - ); - return original; -#else - for (;;) { - i64 original = a->value; - if (gb_atomic64_compare_exchange(a, original, original + operand) == original) - return original; - } -#endif -} - -gb_inline i64 gb_atomic64_fetch_and(gbAtomic64 volatile *a, i64 operand) { -#if defined(GB_ARCH_64_BIT) - i64 original; - i64 tmp; - __asm__ volatile( - "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 (;;) { - i64 original = a->value; - if (gb_atomic64_compare_exchange(a, original, original & operand) == original) - return original; - } -#endif -} - -gb_inline i64 gb_atomic64_fetch_or(gbAtomic64 volatile *a, i64 operand) { -#if defined(GB_ARCH_64_BIT) - i64 original; - i64 temp; - __asm__ volatile( - "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 (;;) { - i64 original = a->value; - if (gb_atomic64_compare_exchange(a, original, original | operand) == original) - return original; - } -#endif -} - -#else -#error TODO(bill): Implement Atomics for this CPU -#endif - -gb_inline b32 gb_atomic32_spin_lock(gbAtomic32 volatile *a, isize time_out) { - i32 old_value = gb_atomic32_compare_exchange(a, 1, 0); - i32 counter = 0; - while (old_value != 0 && (time_out < 0 || counter++ < time_out)) { - gb_yield_thread(); - old_value = gb_atomic32_compare_exchange(a, 1, 0); - gb_mfence(); - } - return old_value == 0; -} -gb_inline void gb_atomic32_spin_unlock(gbAtomic32 volatile *a) { - gb_atomic32_store(a, 0); - gb_mfence(); -} - -gb_inline b32 gb_atomic64_spin_lock(gbAtomic64 volatile *a, isize time_out) { - i64 old_value = gb_atomic64_compare_exchange(a, 1, 0); - i64 counter = 0; - while (old_value != 0 && (time_out < 0 || counter++ < time_out)) { - gb_yield_thread(); - old_value = gb_atomic64_compare_exchange(a, 1, 0); - gb_mfence(); - } - return old_value == 0; -} - -gb_inline void gb_atomic64_spin_unlock(gbAtomic64 volatile *a) { - gb_atomic64_store(a, 0); - gb_mfence(); -} - -gb_inline b32 gb_atomic32_try_acquire_lock(gbAtomic32 volatile *a) { - i32 old_value; - gb_yield_thread(); - old_value = gb_atomic32_compare_exchange(a, 1, 0); - gb_mfence(); - return old_value == 0; -} - -gb_inline b32 gb_atomic64_try_acquire_lock(gbAtomic64 volatile *a) { - i64 old_value; - gb_yield_thread(); - old_value = gb_atomic64_compare_exchange(a, 1, 0); - gb_mfence(); - return old_value == 0; -} - - - -#if defined(GB_ARCH_32_BIT) - -gb_inline void *gb_atomic_ptr_load(gbAtomicPtr const volatile *a) { - return cast(void *)cast(intptr)gb_atomic32_load(cast(gbAtomic32 const volatile *)a); -} -gb_inline void gb_atomic_ptr_store(gbAtomicPtr volatile *a, void *value) { - gb_atomic32_store(cast(gbAtomic32 volatile *)a, cast(i32)cast(intptr)value); -} -gb_inline void *gb_atomic_ptr_compare_exchange(gbAtomicPtr volatile *a, void *expected, void *desired) { - return cast(void *)cast(intptr)gb_atomic32_compare_exchange(cast(gbAtomic32 volatile *)a, cast(i32)cast(intptr)expected, cast(i32)cast(intptr)desired); -} -gb_inline void *gb_atomic_ptr_exchanged(gbAtomicPtr volatile *a, void *desired) { - return cast(void *)cast(intptr)gb_atomic32_exchanged(cast(gbAtomic32 volatile *)a, cast(i32)cast(intptr)desired); -} -gb_inline void *gb_atomic_ptr_fetch_add(gbAtomicPtr volatile *a, void *operand) { - return cast(void *)cast(intptr)gb_atomic32_fetch_add(cast(gbAtomic32 volatile *)a, cast(i32)cast(intptr)operand); -} -gb_inline void *gb_atomic_ptr_fetch_and(gbAtomicPtr volatile *a, void *operand) { - return cast(void *)cast(intptr)gb_atomic32_fetch_and(cast(gbAtomic32 volatile *)a, cast(i32)cast(intptr)operand); -} -gb_inline void *gb_atomic_ptr_fetch_or(gbAtomicPtr volatile *a, void *operand) { - return cast(void *)cast(intptr)gb_atomic32_fetch_or(cast(gbAtomic32 volatile *)a, cast(i32)cast(intptr)operand); -} -gb_inline b32 gb_atomic_ptr_spin_lock(gbAtomicPtr volatile *a, isize time_out) { - return gb_atomic32_spin_lock(cast(gbAtomic32 volatile *)a, time_out); -} -gb_inline void gb_atomic_ptr_spin_unlock(gbAtomicPtr volatile *a) { - gb_atomic32_spin_unlock(cast(gbAtomic32 volatile *)a); -} -gb_inline b32 gb_atomic_ptr_try_acquire_lock(gbAtomicPtr volatile *a) { - return gb_atomic32_try_acquire_lock(cast(gbAtomic32 volatile *)a); -} - -#elif defined(GB_ARCH_64_BIT) - -gb_inline void *gb_atomic_ptr_load(gbAtomicPtr const volatile *a) { - return cast(void *)cast(intptr)gb_atomic64_load(cast(gbAtomic64 const volatile *)a); -} -gb_inline void gb_atomic_ptr_store(gbAtomicPtr volatile *a, void *value) { - gb_atomic64_store(cast(gbAtomic64 volatile *)a, cast(i64)cast(intptr)value); -} -gb_inline void *gb_atomic_ptr_compare_exchange(gbAtomicPtr volatile *a, void *expected, void *desired) { - return cast(void *)cast(intptr)gb_atomic64_compare_exchange(cast(gbAtomic64 volatile *)a, cast(i64)cast(intptr)expected, cast(i64)cast(intptr)desired); -} -gb_inline void *gb_atomic_ptr_exchanged(gbAtomicPtr volatile *a, void *desired) { - return cast(void *)cast(intptr)gb_atomic64_exchanged(cast(gbAtomic64 volatile *)a, cast(i64)cast(intptr)desired); -} -gb_inline void *gb_atomic_ptr_fetch_add(gbAtomicPtr volatile *a, void *operand) { - return cast(void *)cast(intptr)gb_atomic64_fetch_add(cast(gbAtomic64 volatile *)a, cast(i64)cast(intptr)operand); -} -gb_inline void *gb_atomic_ptr_fetch_and(gbAtomicPtr volatile *a, void *operand) { - return cast(void *)cast(intptr)gb_atomic64_fetch_and(cast(gbAtomic64 volatile *)a, cast(i64)cast(intptr)operand); -} -gb_inline void *gb_atomic_ptr_fetch_or(gbAtomicPtr volatile *a, void *operand) { - return cast(void *)cast(intptr)gb_atomic64_fetch_or(cast(gbAtomic64 volatile *)a, cast(i64)cast(intptr)operand); -} -gb_inline b32 gb_atomic_ptr_spin_lock(gbAtomicPtr volatile *a, isize time_out) { - return gb_atomic64_spin_lock(cast(gbAtomic64 volatile *)a, time_out); -} -gb_inline void gb_atomic_ptr_spin_unlock(gbAtomicPtr volatile *a) { - gb_atomic64_spin_unlock(cast(gbAtomic64 volatile *)a); -} -gb_inline b32 gb_atomic_ptr_try_acquire_lock(gbAtomicPtr volatile *a) { - return gb_atomic64_try_acquire_lock(cast(gbAtomic64 volatile *)a); -} -#endif - - -gb_inline void gb_yield_thread(void) { -#if defined(GB_SYSTEM_WINDOWS) - _mm_pause(); -#elif defined(GB_SYSTEM_OSX) - __asm__ volatile ("" : : : "memory"); -#elif defined(GB_CPU_X86) - _mm_pause(); -#else -#error Unknown architecture -#endif -} - -gb_inline void gb_mfence(void) { -#if defined(GB_SYSTEM_WINDOWS) - _ReadWriteBarrier(); -#elif defined(GB_SYSTEM_OSX) - __sync_synchronize(); -#elif defined(GB_CPU_X86) - _mm_mfence(); -#else -#error Unknown architecture -#endif -} - -gb_inline void gb_sfence(void) { -#if defined(GB_SYSTEM_WINDOWS) - _WriteBarrier(); -#elif defined(GB_SYSTEM_OSX) - __asm__ volatile ("" : : : "memory"); -#elif defined(GB_CPU_X86) - _mm_sfence(); -#else -#error Unknown architecture -#endif -} - -gb_inline void gb_lfence(void) { -#if defined(GB_SYSTEM_WINDOWS) - _ReadBarrier(); -#elif defined(GB_SYSTEM_OSX) - __asm__ volatile ("" : : : "memory"); -#elif defined(GB_CPU_X86) - _mm_lfence(); -#else -#error Unknown architecture -#endif -} - - -gb_inline void gb_semaphore_release(gbSemaphore *s) { gb_semaphore_post(s, 1); } - -#if defined(GB_SYSTEM_WINDOWS) - gb_inline void gb_semaphore_init (gbSemaphore *s) { s->win32_handle = CreateSemaphoreA(NULL, 0, I32_MAX, NULL); } - gb_inline void gb_semaphore_destroy(gbSemaphore *s) { CloseHandle(s->win32_handle); } - gb_inline void gb_semaphore_post (gbSemaphore *s, i32 count) { ReleaseSemaphore(s->win32_handle, count, NULL); } - gb_inline void gb_semaphore_wait (gbSemaphore *s) { WaitForSingleObject(s->win32_handle, INFINITE); } - -#elif defined(GB_SYSTEM_OSX) - gb_inline void gb_semaphore_init (gbSemaphore *s) { semaphore_create(mach_task_self(), &s->osx_handle, SYNC_POLICY_FIFO, 0); } - gb_inline void gb_semaphore_destroy(gbSemaphore *s) { semaphore_destroy(mach_task_self(), s->osx_handle); } - gb_inline void gb_semaphore_post (gbSemaphore *s, i32 count) { while (count --> 0) semaphore_signal(s->osx_handle); } - gb_inline void gb_semaphore_wait (gbSemaphore *s) { semaphore_wait(s->osx_handle); } - -#elif defined(GB_SYSTEM_UNIX) - gb_inline void gb_semaphore_init (gbSemaphore *s) { sem_init(&s->unix_handle, 0, 0); } - gb_inline void gb_semaphore_destroy(gbSemaphore *s) { sem_destroy(&s->unix_handle); } - gb_inline void gb_semaphore_post (gbSemaphore *s, i32 count) { while (count --> 0) sem_post(&s->unix_handle); } - gb_inline void gb_semaphore_wait (gbSemaphore *s) { int i; do { i = sem_wait(&s->unix_handle); } while (i == -1 && errno == EINTR); } - -#else -#error -#endif - -gb_inline void gb_mutex_init(gbMutex *m) { -#if defined(GB_SYSTEM_WINDOWS) - InitializeCriticalSection(&m->win32_critical_section); -#else - pthread_mutexattr_init(&m->pthread_mutexattr); - pthread_mutexattr_settype(&m->pthread_mutexattr, PTHREAD_MUTEX_RECURSIVE); - pthread_mutex_init(&m->pthread_mutex, &m->pthread_mutexattr); -#endif -} - -gb_inline void gb_mutex_destroy(gbMutex *m) { -#if defined(GB_SYSTEM_WINDOWS) - DeleteCriticalSection(&m->win32_critical_section); -#else - pthread_mutex_destroy(&m->pthread_mutex); -#endif -} - -gb_inline void gb_mutex_lock(gbMutex *m) { -#if defined(GB_SYSTEM_WINDOWS) - EnterCriticalSection(&m->win32_critical_section); -#else - pthread_mutex_lock(&m->pthread_mutex); -#endif -} - -gb_inline b32 gb_mutex_try_lock(gbMutex *m) { -#if defined(GB_SYSTEM_WINDOWS) - return TryEnterCriticalSection(&m->win32_critical_section) != 0; -#else - return pthread_mutex_trylock(&m->pthread_mutex) == 0; -#endif -} - -gb_inline void gb_mutex_unlock(gbMutex *m) { -#if defined(GB_SYSTEM_WINDOWS) - LeaveCriticalSection(&m->win32_critical_section); -#else - pthread_mutex_unlock(&m->pthread_mutex); -#endif -} - - - - - - - -void gb_thread_init(gbThread *t) { - gb_zero_item(t); -#if defined(GB_SYSTEM_WINDOWS) - t->win32_handle = INVALID_HANDLE_VALUE; -#else - t->posix_handle = 0; -#endif - gb_semaphore_init(&t->semaphore); -} - -void gb_thread_destroy(gbThread *t) { - if (t->is_running) gb_thread_join(t); - gb_semaphore_destroy(&t->semaphore); -} - - -gb_inline void gb__thread_run(gbThread *t) { - gb_semaphore_release(&t->semaphore); - t->return_value = t->proc(t); -} - -#if defined(GB_SYSTEM_WINDOWS) - gb_inline DWORD __stdcall gb__thread_proc(void *arg) { - gbThread *t = cast(gbThread *)arg; - gb__thread_run(t); - t->is_running = false; - return 0; - } -#else - gb_inline void * gb__thread_proc(void *arg) { - gbThread *t = cast(gbThread *)arg; - gb__thread_run(t); - t->is_running = false; - return NULL; - } -#endif - -gb_inline void gb_thread_start(gbThread *t, gbThreadProc *proc, void *user_data) { gb_thread_start_with_stack(t, proc, user_data, 0); } - -gb_inline void gb_thread_start_with_stack(gbThread *t, gbThreadProc *proc, void *user_data, isize stack_size) { - GB_ASSERT(!t->is_running); - GB_ASSERT(proc != NULL); - t->proc = proc; - t->user_data = user_data; - t->stack_size = stack_size; - t->is_running = true; - -#if defined(GB_SYSTEM_WINDOWS) - t->win32_handle = CreateThread(NULL, stack_size, gb__thread_proc, t, 0, NULL); - GB_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, gb__thread_proc, t); - pthread_attr_destroy(&attr); - } -#endif - - gb_semaphore_wait(&t->semaphore); -} - -gb_inline void gb_thread_join(gbThread *t) { - if (!t->is_running) return; - -#if defined(GB_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; -} - -gb_inline b32 gb_thread_is_running(gbThread const *t) { return t->is_running != 0; } - -gb_inline u32 gb_thread_current_id(void) { - u32 thread_id; -#if defined(GB_SYSTEM_WINDOWS) - #if defined(GB_ARCH_32_BIT) && defined(GB_CPU_X86) - thread_id = (cast(u32 *)__readfsdword(24))[9]; - #elif defined(GB_ARCH_64_BIT) && defined(GB_CPU_X86) - thread_id = (cast(u32 *)__readgsqword(48))[18]; - #else - thread_id = GetCurrentThreadId(); - #endif - -#elif defined(GB_SYSTEM_OSX) && defined(GB_ARCH_64_BIT) - thread_id = pthread_mach_thread_np(pthread_self()); -#elif defined(GB_ARCH_32_BIT) && defined(GB_CPU_X86) - __asm__("mov %%gs:0x08,%0" : "=r"(thread_id)); -#elif defined(GB_ARCH_64_BIT) && defined(GB_CPU_X86) - __asm__("mov %%fs:0x10,%0" : "=r"(thread_id)); -#else - #error Unsupported architecture for gb_thread_current_id() -#endif - - return thread_id; -} - - - -void gb_thread_set_name(gbThread *t, char const *name) { -#if defined(GB_COMPILER_MSVC) - #pragma pack(push, 8) - typedef struct { - DWORD type; - char const *name; - DWORD id; - DWORD flags; - } gbprivThreadName; - #pragma pack(pop) - gbprivThreadName tn; - tn.type = 0x1000; - tn.name = name; - tn.id = GetThreadId(cast(HANDLE)t->win32_handle); - tn.flags = 0; - - __try { - RaiseException(0x406d1388, 0, gb_size_of(tn)/4, cast(ULONG_PTR *)&tn); - } __except(1 /*EXCEPTION_EXECUTE_HANDLER*/) { - } - -#elif defined(GB_SYSTEM_WINDOWS) && !defined(GB_COMPILER_MSVC) - // IMPORTANT TODO(bill): Set thread name for GCC/Clang on windows - return; -#elif defined(GB_SYSTEM_OSX) - // TODO(bill): Test if this works - pthread_setname_np(name); -#else - // TODO(bill): Test if this works - pthread_setname_np(t->posix_handle, name); -#endif -} - - - - -void gb_sync_init(gbSync *s) { - gb_zero_item(s); - gb_mutex_init(&s->mutex); - gb_mutex_init(&s->start); - gb_semaphore_init(&s->release); -} - -void gb_sync_destroy(gbSync *s) { - if (s->waiting) - GB_PANIC("Cannot destroy while threads are waiting!"); - - gb_mutex_destroy(&s->mutex); - gb_mutex_destroy(&s->start); - gb_semaphore_destroy(&s->release); -} - -void gb_sync_set_target(gbSync *s, i32 count) { - gb_mutex_lock(&s->start); - - gb_mutex_lock(&s->mutex); - GB_ASSERT(s->target == 0); - s->target = count; - s->current = 0; - s->waiting = 0; - gb_mutex_unlock(&s->mutex); -} - -void gb_sync_release(gbSync *s) { - if (s->waiting) { - gb_semaphore_release(&s->release); - } else { - s->target = 0; - gb_mutex_unlock(&s->start); - } -} - -i32 gb_sync_reach(gbSync *s) { - i32 n; - gb_mutex_lock(&s->mutex); - GB_ASSERT(s->current < s->target); - n = ++s->current; // NOTE(bill): Record this value to avoid possible race if `return s->current` was done - if (s->current == s->target) - gb_sync_release(s); - gb_mutex_unlock(&s->mutex); - return n; -} - -void gb_sync_reach_and_wait(gbSync *s) { - gb_mutex_lock(&s->mutex); - GB_ASSERT(s->current < s->target); - s->current++; - if (s->current == s->target) { - gb_sync_release(s); - gb_mutex_unlock(&s->mutex); - } else { - s->waiting++; // NOTE(bill): Waiting, so one more waiter - gb_mutex_unlock(&s->mutex); // NOTE(bill): Release the mutex to other threads - - gb_semaphore_wait(&s->release); // NOTE(bill): Wait for merge completion - - gb_mutex_lock(&s->mutex); // NOTE(bill): On merge completion, lock mutex - s->waiting--; // NOTE(bill): Done waiting - gb_sync_release(s); // NOTE(bill): Restart the next waiter - gb_mutex_unlock(&s->mutex); - } -} - - - - - - - - -gb_inline gbAllocator gb_heap_allocator(void) { - gbAllocator a; - a.proc = gb_heap_allocator_proc; - a.data = NULL; - return a; -} - -GB_ALLOCATOR_PROC(gb_heap_allocator_proc) { - void *ptr = NULL; - gb_unused(allocator_data); - gb_unused(old_size); -// TODO(bill): Throughly test! - switch (type) { -#if defined(GB_COMPILER_MSVC) - case gbAllocation_Alloc: - ptr = _aligned_malloc(size, alignment); - if (flags & gbAllocatorFlag_ClearToZero) - gb_zero_size(ptr, size); - break; - case gbAllocation_Free: - _aligned_free(old_memory); - break; - case gbAllocation_Resize: - ptr = _aligned_realloc(old_memory, size, alignment); - break; - -#elif defined(GB_SYSTEM_LINUX) - // TODO(bill): *nix version that's decent - case gbAllocation_Alloc: { - ptr = aligned_alloc(alignment, size); - // ptr = malloc(size+alignment); - - if (flags & gbAllocatorFlag_ClearToZero) { - gb_zero_size(ptr, size); - } - } break; - - case gbAllocation_Free: { - free(old_memory); - } break; - - case gbAllocation_Resize: { - // ptr = realloc(old_memory, size); - ptr = gb_default_resize_align(gb_heap_allocator(), old_memory, old_size, size, alignment); - } break; -#else - // TODO(bill): *nix version that's decent - case gbAllocation_Alloc: { - posix_memalign(&ptr, alignment, size); - - if (flags & gbAllocatorFlag_ClearToZero) { - gb_zero_size(ptr, size); - } - } break; - - case gbAllocation_Free: { - free(old_memory); - } break; - - case gbAllocation_Resize: { - ptr = gb_default_resize_align(gb_heap_allocator(), old_memory, old_size, size, alignment); - } break; -#endif - - case gbAllocation_FreeAll: - break; - } - - return ptr; -} - - -#if defined(GB_SYSTEM_WINDOWS) -void gb_affinity_init(gbAffinity *a) { - SYSTEM_LOGICAL_PROCESSOR_INFORMATION *start_processor_info = NULL; - DWORD length = 0; - b32 result = GetLogicalProcessorInformation(NULL, &length); - - gb_zero_item(a); - - if (!result && GetLastError() == 122l /*ERROR_INSUFFICIENT_BUFFER*/ && length > 0) { - start_processor_info = cast(SYSTEM_LOGICAL_PROCESSOR_INFORMATION *)gb_alloc(gb_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 *)gb_pointer_add(start_processor_info, length); - - for (processor_info = start_processor_info; - processor_info < end_processor_info; - processor_info++) { - if (processor_info->Relationship == RelationProcessorCore) { - isize thread = gb_count_set_bits(processor_info->ProcessorMask); - if (thread == 0) { - a->is_accurate = false; - } else if (a->thread_count + thread > GB_WIN32_MAX_THREADS) { - a->is_accurate = false; - } else { - GB_ASSERT(a->core_count <= a->thread_count && - a->thread_count < GB_WIN32_MAX_THREADS); - a->core_masks[a->core_count++] = processor_info->ProcessorMask; - a->thread_count += thread; - } - } - } - } - - gb_free(gb_heap_allocator(), start_processor_info); - } - - GB_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 gb_affinity_destroy(gbAffinity *a) { - gb_unused(a); -} - - -b32 gb_affinity_set(gbAffinity *a, isize core, isize thread) { - usize available_mask, check_mask = 1; - GB_ASSERT(thread < gb_affinity_thread_count_for_core(a, core)); - - available_mask = a->core_masks[core]; - for (;;) { - if ((available_mask & check_mask) != 0) { - if (thread-- == 0) { - usize result = SetThreadAffinityMask(GetCurrentThread(), check_mask); - return result != 0; - } - } - check_mask <<= 1; // NOTE(bill): Onto the next bit - } -} - -isize gb_affinity_thread_count_for_core(gbAffinity *a, isize core) { - GB_ASSERT(core >= 0 && core < a->core_count); - return gb_count_set_bits(a->core_masks[core]); -} - -#elif defined(GB_SYSTEM_OSX) -void gb_affinity_init(gbAffinity *a) { - usize count = 0; - usize count_size = sizeof(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 gb_affinity_destroy(gbAffinity *a) { - gb_unused(a); -} - -b32 gb_affinity_set(gbAffinity *a, isize core, isize thread_index) { - isize index; - thread_t thread; - thread_affinity_policy_data_t info; - kern_return_t result; - - GB_ASSERT(core < a->core_count); - GB_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; -} - -isize gb_affinity_thread_count_for_core(gbAffinity *a, isize core) { - GB_ASSERT(core >= 0 && core < a->core_count); - return a->threads_per_core; -} - -#elif defined(GB_SYSTEM_LINUX) -// IMPORTANT TODO(bill): This gbAffinity stuff for linux needs be improved a lot! -// NOTE(zangent): I have to read /proc/cpuinfo to get the number of threads per core. -#include - -void gb_affinity_init(gbAffinity *a) { - b32 accurate = true; - 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. - char 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 gb_affinity_destroy(gbAffinity *a) { - gb_unused(a); -} - -b32 gb_affinity_set(gbAffinity *a, isize core, isize thread_index) { - return true; -} - -isize gb_affinity_thread_count_for_core(gbAffinity *a, isize core) { - GB_ASSERT(0 <= core && core < a->core_count); - return a->threads_per_core; -} -#else -#error TODO(bill): Unknown system -#endif - - - - - - - - - -//////////////////////////////////////////////////////////////// -// -// Virtual Memory -// -// - -gbVirtualMemory gb_virtual_memory(void *data, isize size) { - gbVirtualMemory vm; - vm.data = data; - vm.size = size; - return vm; -} - - -#if defined(GB_SYSTEM_WINDOWS) -gb_inline gbVirtualMemory gb_vm_alloc(void *addr, isize size) { - gbVirtualMemory vm; - GB_ASSERT(size > 0); - vm.data = VirtualAlloc(addr, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); - vm.size = size; - return vm; -} - -gb_inline b32 gb_vm_free(gbVirtualMemory vm) { - MEMORY_BASIC_INFORMATION info; - while (vm.size > 0) { - if (VirtualQuery(vm.data, &info, gb_size_of(info)) == 0) - return false; - if (info.BaseAddress != vm.data || - info.AllocationBase != vm.data || - info.State != MEM_COMMIT || info.RegionSize > cast(usize)vm.size) { - return false; - } - if (VirtualFree(vm.data, 0, MEM_RELEASE) == 0) - return false; - vm.data = gb_pointer_add(vm.data, info.RegionSize); - vm.size -= info.RegionSize; - } - return true; -} - -gb_inline gbVirtualMemory gb_vm_trim(gbVirtualMemory vm, isize lead_size, isize size) { - gbVirtualMemory new_vm = {0}; - void *ptr; - GB_ASSERT(vm.size >= lead_size + size); - - ptr = gb_pointer_add(vm.data, lead_size); - - gb_vm_free(vm); - new_vm = gb_vm_alloc(ptr, size); - if (new_vm.data == ptr) - return new_vm; - if (new_vm.data) - gb_vm_free(new_vm); - return new_vm; -} - -gb_inline b32 gb_vm_purge(gbVirtualMemory vm) { - VirtualAlloc(vm.data, vm.size, MEM_RESET, PAGE_READWRITE); - // NOTE(bill): Can this really fail? - return true; -} - -isize gb_virtual_memory_page_size(isize *alignment_out) { - SYSTEM_INFO info; - GetSystemInfo(&info); - if (alignment_out) *alignment_out = info.dwAllocationGranularity; - return info.dwPageSize; -} - -#else - -#ifndef MAP_ANONYMOUS -#define MAP_ANONYMOUS MAP_ANON -#endif - -gb_inline gbVirtualMemory gb_vm_alloc(void *addr, isize size) { - gbVirtualMemory vm; - GB_ASSERT(size > 0); - vm.data = mmap(addr, size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); - vm.size = size; - return vm; -} - -gb_inline b32 gb_vm_free(gbVirtualMemory vm) { - munmap(vm.data, vm.size); - return true; -} - -gb_inline gbVirtualMemory gb_vm_trim(gbVirtualMemory vm, isize lead_size, isize size) { - void *ptr; - isize trail_size; - GB_ASSERT(vm.size >= lead_size + size); - - ptr = gb_pointer_add(vm.data, lead_size); - trail_size = vm.size - lead_size - size; - - if (lead_size != 0) - gb_vm_free(gb_virtual_memory(vm.data, lead_size)); - if (trail_size != 0) - gb_vm_free(gb_virtual_memory(ptr, trail_size)); - return gb_virtual_memory(ptr, size); - -} - -gb_inline b32 gb_vm_purge(gbVirtualMemory vm) { - int err = madvise(vm.data, vm.size, MADV_DONTNEED); - return err != 0; -} - -isize gb_virtual_memory_page_size(isize *alignment_out) { - // TODO(bill): Is this always true? - isize result = cast(isize)sysconf(_SC_PAGE_SIZE); - if (alignment_out) *alignment_out = result; - return result; -} - -#endif - - - - -//////////////////////////////////////////////////////////////// -// -// Custom Allocation -// -// - - -// -// Arena Allocator -// - -gb_inline void gb_arena_init_from_memory(gbArena *arena, void *start, 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; -} - -gb_inline void gb_arena_init_from_allocator(gbArena *arena, gbAllocator backing, isize size) { - arena->backing = backing; - arena->physical_start = gb_alloc(backing, size); // NOTE(bill): Uses default alignment - arena->total_size = size; - arena->total_allocated = 0; - arena->temp_count = 0; -} - -gb_inline void gb_arena_init_sub(gbArena *arena, gbArena *parent_arena, isize size) { gb_arena_init_from_allocator(arena, gb_arena_allocator(parent_arena), size); } - - -gb_inline void gb_arena_free(gbArena *arena) { - if (arena->backing.proc) { - gb_free(arena->backing, arena->physical_start); - arena->physical_start = NULL; - } -} - - -gb_inline isize gb_arena_alignment_of(gbArena *arena, isize alignment) { - isize alignment_offset, result_pointer, mask; - GB_ASSERT(gb_is_power_of_two(alignment)); - - alignment_offset = 0; - result_pointer = cast(isize)arena->physical_start + arena->total_allocated; - mask = alignment - 1; - if (result_pointer & mask) - alignment_offset = alignment - (result_pointer & mask); - - return alignment_offset; -} - -gb_inline isize gb_arena_size_remaining(gbArena *arena, isize alignment) { - isize result = arena->total_size - (arena->total_allocated + gb_arena_alignment_of(arena, alignment)); - return result; -} - -gb_inline void gb_arena_check(gbArena *arena) { GB_ASSERT(arena->temp_count == 0); } - - - - - - -gb_inline gbAllocator gb_arena_allocator(gbArena *arena) { - gbAllocator allocator; - allocator.proc = gb_arena_allocator_proc; - allocator.data = arena; - return allocator; -} - -GB_ALLOCATOR_PROC(gb_arena_allocator_proc) { - gbArena *arena = cast(gbArena *)allocator_data; - void *ptr = NULL; - - gb_unused(old_size); - - switch (type) { - case gbAllocation_Alloc: { - void *end = gb_pointer_add(arena->physical_start, arena->total_allocated); - isize total_size = size + alignment; - - // NOTE(bill): Out of memory - if (arena->total_allocated + total_size > cast(isize)arena->total_size) { - gb_printf_err("Arena out of memory\n"); - return NULL; - } - - ptr = gb_align_forward(end, alignment); - arena->total_allocated += total_size; - if (flags & gbAllocatorFlag_ClearToZero) - gb_zero_size(ptr, size); - } break; - - case gbAllocation_Free: - // NOTE(bill): Free all at once - // Use Temp_Arena_Memory if you want to free a block - break; - - case gbAllocation_FreeAll: - arena->total_allocated = 0; - break; - - case gbAllocation_Resize: { - // TODO(bill): Check if ptr is on top of stack and just extend - gbAllocator a = gb_arena_allocator(arena); - ptr = gb_default_resize_align(a, old_memory, old_size, size, alignment); - } break; - } - return ptr; -} - - -gb_inline gbTempArenaMemory gb_temp_arena_memory_begin(gbArena *arena) { - gbTempArenaMemory tmp; - tmp.arena = arena; - tmp.original_count = arena->total_allocated; - arena->temp_count++; - return tmp; -} - -gb_inline void gb_temp_arena_memory_end(gbTempArenaMemory tmp) { - GB_ASSERT_MSG(tmp.arena->total_allocated >= tmp.original_count, - "%td >= %td", tmp.arena->total_allocated, tmp.original_count); - GB_ASSERT(tmp.arena->temp_count > 0); - tmp.arena->total_allocated = tmp.original_count; - tmp.arena->temp_count--; -} - - - - -// -// Pool Allocator -// - - -gb_inline void gb_pool_init(gbPool *pool, gbAllocator backing, isize num_blocks, isize block_size) { - gb_pool_init_align(pool, backing, num_blocks, block_size, GB_DEFAULT_MEMORY_ALIGNMENT); -} - -void gb_pool_init_align(gbPool *pool, gbAllocator backing, isize num_blocks, isize block_size, isize block_align) { - isize actual_block_size, pool_size, block_index; - void *data, *curr; - uintptr *end; - - gb_zero_item(pool); - - pool->backing = backing; - pool->block_size = block_size; - pool->block_align = block_align; - - actual_block_size = block_size + block_align; - pool_size = num_blocks * actual_block_size; - - data = gb_alloc_align(backing, pool_size, block_align); - - // NOTE(bill): Init intrusive freelist - curr = data; - for (block_index = 0; block_index < num_blocks-1; block_index++) { - uintptr *next = cast(uintptr *)curr; - *next = cast(uintptr)curr + actual_block_size; - curr = gb_pointer_add(curr, actual_block_size); - } - - end = cast(uintptr *)curr; - *end = cast(uintptr)NULL; - - pool->physical_start = data; - pool->free_list = data; -} - -gb_inline void gb_pool_free(gbPool *pool) { - if (pool->backing.proc) { - gb_free(pool->backing, pool->physical_start); - } -} - - -gb_inline gbAllocator gb_pool_allocator(gbPool *pool) { - gbAllocator allocator; - allocator.proc = gb_pool_allocator_proc; - allocator.data = pool; - return allocator; -} -GB_ALLOCATOR_PROC(gb_pool_allocator_proc) { - gbPool *pool = cast(gbPool *)allocator_data; - void *ptr = NULL; - - gb_unused(old_size); - - switch (type) { - case gbAllocation_Alloc: { - uintptr next_free; - GB_ASSERT(size == pool->block_size); - GB_ASSERT(alignment == pool->block_align); - GB_ASSERT(pool->free_list != NULL); - - next_free = *cast(uintptr *)pool->free_list; - ptr = pool->free_list; - pool->free_list = cast(void *)next_free; - pool->total_size += pool->block_size; - if (flags & gbAllocatorFlag_ClearToZero) - gb_zero_size(ptr, size); - } break; - - case gbAllocation_Free: { - uintptr *next; - if (old_memory == NULL) return NULL; - - next = cast(uintptr *)old_memory; - *next = cast(uintptr)pool->free_list; - pool->free_list = old_memory; - pool->total_size -= pool->block_size; - } break; - - case gbAllocation_FreeAll: - // TODO(bill): - break; - - case gbAllocation_Resize: - // NOTE(bill): Cannot resize - GB_PANIC("You cannot resize something allocated by with a pool."); - break; - } - - return ptr; -} - - - - - -gb_inline gbAllocationHeader *gb_allocation_header(void *data) { - isize *p = cast(isize *)data; - while (p[-1] == cast(isize)(-1)) { - p--; - } - return cast(gbAllocationHeader *)p - 1; -} - -gb_inline void gb_allocation_header_fill(gbAllocationHeader *header, void *data, isize size) { - isize *ptr; - header->size = size; - ptr = cast(isize *)(header + 1); - while (cast(void *)ptr < data) { - *ptr++ = cast(isize)(-1); - } -} - - - -// -// Free List Allocator -// - -gb_inline void gb_free_list_init(gbFreeList *fl, void *start, isize size) { - GB_ASSERT(size > gb_size_of(gbFreeListBlock)); - - fl->physical_start = start; - fl->total_size = size; - fl->curr_block = cast(gbFreeListBlock *)start; - fl->curr_block->size = size; - fl->curr_block->next = NULL; -} - - -gb_inline void gb_free_list_init_from_allocator(gbFreeList *fl, gbAllocator backing, isize size) { - void *start = gb_alloc(backing, size); - gb_free_list_init(fl, start, size); -} - - - -gb_inline gbAllocator gb_free_list_allocator(gbFreeList *fl) { - gbAllocator a; - a.proc = gb_free_list_allocator_proc; - a.data = fl; - return a; -} - -GB_ALLOCATOR_PROC(gb_free_list_allocator_proc) { - gbFreeList *fl = cast(gbFreeList *)allocator_data; - void *ptr = NULL; - - GB_ASSERT_NOT_NULL(fl); - - switch (type) { - case gbAllocation_Alloc: { - gbFreeListBlock *prev_block = NULL; - gbFreeListBlock *curr_block = fl->curr_block; - - while (curr_block) { - isize total_size; - gbAllocationHeader *header; - - total_size = size + alignment + gb_size_of(gbAllocationHeader); - - if (curr_block->size < total_size) { - prev_block = curr_block; - curr_block = curr_block->next; - continue; - } - - if (curr_block->size - total_size <= gb_size_of(gbAllocationHeader)) { - total_size = curr_block->size; - - if (prev_block) - prev_block->next = curr_block->next; - else - fl->curr_block = curr_block->next; - } else { - // NOTE(bill): Create a new block for the remaining memory - gbFreeListBlock *next_block; - next_block = cast(gbFreeListBlock *)gb_pointer_add(curr_block, total_size); - - GB_ASSERT(cast(void *)next_block < gb_pointer_add(fl->physical_start, fl->total_size)); - - next_block->size = curr_block->size - total_size; - next_block->next = curr_block->next; - - if (prev_block) - prev_block->next = next_block; - else - fl->curr_block = next_block; - } - - - // TODO(bill): Set Header Info - header = cast(gbAllocationHeader *)curr_block; - ptr = gb_align_forward(header+1, alignment); - gb_allocation_header_fill(header, ptr, size); - - fl->total_allocated += total_size; - fl->allocation_count++; - - - if (flags & gbAllocatorFlag_ClearToZero) - gb_zero_size(ptr, size); - return ptr; - } - // NOTE(bill): if ptr == NULL, ran out of free list memory! FUCK! - return NULL; - } break; - - case gbAllocation_Free: { - gbAllocationHeader *header = gb_allocation_header(old_memory); - isize block_size = header->size; - uintptr block_start, block_end; - gbFreeListBlock *prev_block = NULL; - gbFreeListBlock *curr_block = fl->curr_block; - - block_start = cast(uintptr)header; - block_end = cast(uintptr)block_start + block_size; - - while (curr_block) { - if (cast(uintptr)curr_block >= block_end) - break; - prev_block = curr_block; - curr_block = curr_block->next; - } - - if (prev_block == NULL) { - prev_block = cast(gbFreeListBlock *)block_start; - prev_block->size = block_size; - prev_block->next = fl->curr_block; - - fl->curr_block = prev_block; - } else if ((cast(uintptr)prev_block + prev_block->size) == block_start) { - prev_block->size += block_size; - } else { - gbFreeListBlock *tmp = cast(gbFreeListBlock *)block_start; - tmp->size = block_size; - tmp->next = prev_block->next; - prev_block->next = tmp; - - prev_block = tmp; - } - - if (curr_block && (cast(uintptr)curr_block == block_end)) { - prev_block->size += curr_block->size; - prev_block->next = curr_block->next; - } - - fl->allocation_count--; - fl->total_allocated -= block_size; - } break; - - case gbAllocation_FreeAll: - gb_free_list_init(fl, fl->physical_start, fl->total_size); - break; - - case gbAllocation_Resize: - ptr = gb_default_resize_align(gb_free_list_allocator(fl), old_memory, old_size, size, alignment); - break; - } - - return ptr; -} - - - -void gb_scratch_memory_init(gbScratchMemory *s, void *start, isize size) { - s->physical_start = start; - s->total_size = size; - s->alloc_point = start; - s->free_point = start; -} - - -b32 gb_scratch_memory_is_in_use(gbScratchMemory *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; -} - - -gbAllocator gb_scratch_allocator(gbScratchMemory *s) { - gbAllocator a; - a.proc = gb_scratch_allocator_proc; - a.data = s; - return a; -} - -GB_ALLOCATOR_PROC(gb_scratch_allocator_proc) { - gbScratchMemory *s = cast(gbScratchMemory *)allocator_data; - void *ptr = NULL; - GB_ASSERT_NOT_NULL(s); - - switch (type) { - case gbAllocation_Alloc: { - void *pt = s->alloc_point; - gbAllocationHeader *header = cast(gbAllocationHeader *)pt; - void *data = gb_align_forward(header+1, alignment); - void *end = gb_pointer_add(s->physical_start, s->total_size); - - GB_ASSERT(alignment % 4 == 0); - size = ((size + 3)/4)*4; - pt = gb_pointer_add(pt, size); - - // NOTE(bill): Wrap around - if (pt > end) { - header->size = gb_pointer_diff(header, end) | GB_ISIZE_HIGH_BIT; - pt = s->physical_start; - header = cast(gbAllocationHeader *)pt; - data = gb_align_forward(header+1, alignment); - pt = gb_pointer_add(pt, size); - } - - if (!gb_scratch_memory_is_in_use(s, pt)) { - gb_allocation_header_fill(header, pt, gb_pointer_diff(header, pt)); - s->alloc_point = cast(u8 *)pt; - ptr = data; - } - - if (flags & gbAllocatorFlag_ClearToZero) - gb_zero_size(ptr, size); - } break; - - case gbAllocation_Free: { - if (old_memory) { - void *end = gb_pointer_add(s->physical_start, s->total_size); - if (old_memory < s->physical_start || old_memory >= end) { - GB_ASSERT(false); - } else { - // NOTE(bill): Mark as free - gbAllocationHeader *h = gb_allocation_header(old_memory); - GB_ASSERT((h->size & GB_ISIZE_HIGH_BIT) == 0); - h->size = h->size | GB_ISIZE_HIGH_BIT; - - while (s->free_point != s->alloc_point) { - gbAllocationHeader *header = cast(gbAllocationHeader *)s->free_point; - if ((header->size & GB_ISIZE_HIGH_BIT) == 0) - break; - - s->free_point = gb_pointer_add(s->free_point, h->size & (~GB_ISIZE_HIGH_BIT)); - if (s->free_point == end) - s->free_point = s->physical_start; - } - } - } - } break; - - case gbAllocation_FreeAll: - s->alloc_point = s->physical_start; - s->free_point = s->physical_start; - break; - - case gbAllocation_Resize: - ptr = gb_default_resize_align(gb_scratch_allocator(s), old_memory, old_size, size, alignment); - break; - } - - return ptr; -} - - - - - - -//////////////////////////////////////////////////////////////// -// -// Sorting -// -// - -// TODO(bill): Should I make all the macros local? - -#define GB__COMPARE_PROC(Type) \ -gb_global isize gb__##Type##_cmp_offset; GB_COMPARE_PROC(gb__##Type##_cmp) { \ - Type const p = *cast(Type const *)gb_pointer_add_const(a, gb__##Type##_cmp_offset); \ - Type const q = *cast(Type const *)gb_pointer_add_const(b, gb__##Type##_cmp_offset); \ - return p < q ? -1 : p > q; \ -} \ -GB_COMPARE_PROC_PTR(gb_##Type##_cmp(isize offset)) { \ - gb__##Type##_cmp_offset = offset; \ - return &gb__##Type##_cmp; \ -} - - -GB__COMPARE_PROC(i16); -GB__COMPARE_PROC(i32); -GB__COMPARE_PROC(i64); -GB__COMPARE_PROC(isize); -GB__COMPARE_PROC(f32); -GB__COMPARE_PROC(f64); -GB__COMPARE_PROC(char); - -// NOTE(bill): str_cmp is special as it requires a funny type and funny comparison -gb_global isize gb__str_cmp_offset; GB_COMPARE_PROC(gb__str_cmp) { - char const *p = *cast(char const **)gb_pointer_add_const(a, gb__str_cmp_offset); - char const *q = *cast(char const **)gb_pointer_add_const(b, gb__str_cmp_offset); - return gb_strcmp(p, q); -} -GB_COMPARE_PROC_PTR(gb_str_cmp(isize offset)) { - gb__str_cmp_offset = offset; - return &gb__str_cmp; -} - -#undef GB__COMPARE_PROC - - - - -// TODO(bill): Make user definable? -#define GB__SORT_STACK_SIZE 64 -#define GB__SORT_INSERT_SORT_THRESHOLD 8 - -#define GB__SORT_PUSH(_base, _limit) do { \ - stack_ptr[0] = (_base); \ - stack_ptr[1] = (_limit); \ - stack_ptr += 2; \ -} while (0) - - -#define GB__SORT_POP(_base, _limit) do { \ - stack_ptr -= 2; \ - (_base) = stack_ptr[0]; \ - (_limit) = stack_ptr[1]; \ -} while (0) - - - -void gb_sort(void *base_, isize count, isize size, gbCompareProc cmp) { - u8 *i, *j; - u8 *base = cast(u8 *)base_; - u8 *limit = base + count*size; - isize threshold = GB__SORT_INSERT_SORT_THRESHOLD * size; - - // NOTE(bill): Prepare the stack - u8 *stack[GB__SORT_STACK_SIZE] = {0}; - u8 **stack_ptr = stack; - - for (;;) { - if ((limit-base) > threshold) { - // NOTE(bill): Quick sort - i = base + size; - j = limit - size; - - gb_memswap(((limit-base)/size/2) * size + base, base, size); - if (cmp(i, j) > 0) gb_memswap(i, j, size); - if (cmp(base, j) > 0) gb_memswap(base, j, size); - if (cmp(i, base) > 0) gb_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; - gb_memswap(i, j, size); - } - - gb_memswap(base, j, size); - - if (j - base > limit - i) { - GB__SORT_PUSH(base, j); - base = i; - } else { - GB__SORT_PUSH(i, limit); - limit = j; - } - } else { - // NOTE(bill): Insertion sort - for (j = base, i = j+size; - i < limit; - j = i, i += size) { - for (; cmp(j, j+size) > 0; j -= size) { - gb_memswap(j, j+size, size); - if (j == base) break; - } - } - - if (stack_ptr == stack) break; // NOTE(bill): Sorting is done! - GB__SORT_POP(base, limit); - } - } -} - -#undef GB__SORT_PUSH -#undef GB__SORT_POP - - -#define GB_RADIX_SORT_PROC_GEN(Type) GB_RADIX_SORT_PROC(Type) { \ - Type *source = items; \ - Type *dest = temp; \ - isize byte_index, i, byte_max = 8*gb_size_of(Type); \ - for (byte_index = 0; byte_index < byte_max; byte_index += 8) { \ - isize offsets[256] = {0}; \ - isize total = 0; \ - /* NOTE(bill): First pass - count how many of each key */ \ - for (i = 0; i < count; i++) { \ - Type radix_value = source[i]; \ - Type radix_piece = (radix_value >> byte_index) & 0xff; \ - offsets[radix_piece]++; \ - } \ - /* NOTE(bill): Change counts to offsets */ \ - for (i = 0; i < gb_count_of(offsets); i++) { \ - isize skcount = offsets[i]; \ - offsets[i] = total; \ - total += skcount; \ - } \ - /* NOTE(bill): Second pass - place elements into the right location */ \ - for (i = 0; i < count; i++) { \ - Type radix_value = source[i]; \ - Type radix_piece = (radix_value >> byte_index) & 0xff; \ - dest[offsets[radix_piece]++] = source[i]; \ - } \ - gb_swap(Type *, source, dest); \ - } \ -} - -GB_RADIX_SORT_PROC_GEN(u8); -GB_RADIX_SORT_PROC_GEN(u16); -GB_RADIX_SORT_PROC_GEN(u32); -GB_RADIX_SORT_PROC_GEN(u64); - -gb_inline isize gb_binary_search(void const *base, isize count, isize size, void const *key, gbCompareProc compare_proc) { - isize start = 0; - isize end = count; - - while (start < end) { - isize mid = start + (end-start)/2; - isize result = compare_proc(key, cast(u8 *)base + mid*size); - if (result < 0) - end = mid; - else if (result > 0) - start = mid+1; - else - return mid; - } - - return -1; -} - -void gb_shuffle(void *base, isize count, isize size) { - u8 *a; - isize i, j; - gbRandom random; gb_random_init(&random); - - a = cast(u8 *)base + (count-1) * size; - for (i = count; i > 1; i--) { - j = gb_random_gen_isize(&random) % i; - gb_memswap(a, cast(u8 *)base + j*size, size); - a -= size; - } -} - -void gb_reverse(void *base, isize count, isize size) { - isize i, j = count-1; - for (i = 0; i < j; i++, j++) { - gb_memswap(cast(u8 *)base + i*size, cast(u8 *)base + j*size, size); - } -} - - - -//////////////////////////////////////////////////////////////// -// -// Char things -// -// - - - - -gb_inline char gb_char_to_lower(char c) { - if (c >= 'A' && c <= 'Z') - return 'a' + (c - 'A'); - return c; -} - -gb_inline char gb_char_to_upper(char c) { - if (c >= 'a' && c <= 'z') - return 'A' + (c - 'a'); - return c; -} - -gb_inline b32 gb_char_is_space(char c) { - if (c == ' ' || - c == '\t' || - c == '\n' || - c == '\r' || - c == '\f' || - c == '\v') - return true; - return false; -} - -gb_inline b32 gb_char_is_digit(char c) { - if (c >= '0' && c <= '9') - return true; - return false; -} - -gb_inline b32 gb_char_is_hex_digit(char c) { - if (gb_char_is_digit(c) || - (c >= 'a' && c <= 'f') || - (c >= 'A' && c <= 'F')) - return true; - return false; -} - -gb_inline b32 gb_char_is_alpha(char c) { - if ((c >= 'A' && c <= 'Z') || - (c >= 'a' && c <= 'z')) - return true; - return false; -} - -gb_inline b32 gb_char_is_alphanumeric(char c) { - return gb_char_is_alpha(c) || gb_char_is_digit(c); -} - -gb_inline i32 gb_digit_to_int(char c) { - return gb_char_is_digit(c) ? c - '0' : c - 'W'; -} - -gb_inline i32 gb_hex_digit_to_int(char c) { - if (gb_char_is_digit(c)) - return gb_digit_to_int(c); - else if (gb_is_between(c, 'a', 'f')) - return c - 'a' + 10; - else if (gb_is_between(c, 'A', 'F')) - return c - 'A' + 10; - return -1; -} - - - - -gb_inline void gb_str_to_lower(char *str) { - if (!str) return; - while (*str) { - *str = gb_char_to_lower(*str); - str++; - } -} - -gb_inline void gb_str_to_upper(char *str) { - if (!str) return; - while (*str) { - *str = gb_char_to_upper(*str); - str++; - } -} - - -gb_inline isize gb_strlen(char const *str) { - char const *begin = str; - isize const *w; - if (str == NULL) { - return 0; - } - while (cast(uintptr)str % sizeof(usize)) { - if (!*str) - return str - begin; - str++; - } - w = cast(isize const *)str; - while (!GB__HAS_ZERO(*w)) { - w++; - } - str = cast(char const *)w; - while (*str) { - str++; - } - return str - begin; -} - -gb_inline isize gb_strnlen(char const *str, isize max_len) { - char const *end = cast(char const *)gb_memchr(str, 0, max_len); - if (end) { - return end - str; - } - return max_len; -} - -gb_inline isize gb_utf8_strlen(u8 const *str) { - isize count = 0; - for (; *str; count++) { - u8 c = *str; - 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; -} - -gb_inline isize gb_utf8_strnlen(u8 const *str, isize max_len) { - isize count = 0; - for (; *str && max_len > 0; count++) { - u8 c = *str; - 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; -} - - -gb_inline i32 gb_strcmp(char const *s1, char const *s2) { - while (*s1 && (*s1 == *s2)) { - s1++, s2++; - } - return *(u8 *)s1 - *(u8 *)s2; -} - -gb_inline char *gb_strcpy(char *dest, char const *source) { - GB_ASSERT_NOT_NULL(dest); - if (source) { - char *str = dest; - while (*source) *str++ = *source++; - } - return dest; -} - - -gb_inline char *gb_strncpy(char *dest, char const *source, isize len) { - GB_ASSERT_NOT_NULL(dest); - if (source) { - char *str = dest; - while (len > 0 && *source) { - *str++ = *source++; - len--; - } - while (len > 0) { - *str++ = '\0'; - len--; - } - } - return dest; -} - -gb_inline isize gb_strlcpy(char *dest, char const *source, isize len) { - isize result = 0; - GB_ASSERT_NOT_NULL(dest); - if (source) { - char const *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; -} - -gb_inline char *gb_strrev(char *str) { - isize len = gb_strlen(str); - char *a = str + 0; - char *b = str + len-1; - len /= 2; - while (len--) { - gb_swap(char, *a, *b); - a++, b--; - } - return str; -} - - - - -gb_inline i32 gb_strncmp(char const *s1, char const *s2, isize len) { - for (; len > 0; - s1++, s2++, len--) { - if (*s1 != *s2) { - return ((s1 < s2) ? -1 : +1); - } else if (*s1 == '\0') { - return 0; - } - } - return 0; -} - - -gb_inline char const *gb_strtok(char *output, char const *src, char const *delimit) { - while (*src && gb_char_first_occurence(delimit, *src) != NULL) { - *output++ = *src++; - } - - *output = 0; - return *src ? src+1 : src; -} - -gb_inline b32 gb_str_has_prefix(char const *str, char const *prefix) { - while (*prefix) { - if (*str++ != *prefix++) { - return false; - } - } - return true; -} - -gb_inline b32 gb_str_has_suffix(char const *str, char const *suffix) { - isize i = gb_strlen(str); - isize j = gb_strlen(suffix); - if (j <= i) { - return gb_strcmp(str+i-j, suffix) == 0; - } - return false; -} - - - - -gb_inline char const *gb_char_first_occurence(char const *s, char c) { - char ch = c; - for (; *s != ch; s++) { - if (*s == '\0') { - return NULL; - } - } - return s; -} - - -gb_inline char const *gb_char_last_occurence(char const *s, char c) { - char const *result = NULL; - do { - if (*s == c) { - result = s; - } - } while (*s++); - - return result; -} - - - -gb_inline void gb_str_concat(char *dest, isize dest_len, - char const *src_a, isize src_a_len, - char const *src_b, isize src_b_len) { - GB_ASSERT(dest_len >= src_a_len+src_b_len+1); - if (dest) { - gb_memcopy(dest, src_a, src_a_len); - gb_memcopy(dest+src_a_len, src_b, src_b_len); - dest[src_a_len+src_b_len] = '\0'; - } -} - - -gb_internal isize gb__scan_i64(char const *text, i32 base, i64 *value) { - char const *text_begin = text; - i64 result = 0; - b32 negative = false; - - if (*text == '-') { - negative = true; - text++; - } - - if (base == 16 && gb_strncmp(text, "0x", 2) == 0) { - text += 2; - } - - for (;;) { - i64 v; - if (gb_char_is_digit(*text)) { - v = *text - '0'; - } else if (base == 16 && gb_char_is_hex_digit(*text)) { - v = gb_hex_digit_to_int(*text); - } else { - break; - } - - result *= base; - result += v; - text++; - } - - if (value) { - if (negative) result = -result; - *value = result; - } - - return (text - text_begin); -} - -gb_internal isize gb__scan_u64(char const *text, i32 base, u64 *value) { - char const *text_begin = text; - u64 result = 0; - - if (base == 16 && gb_strncmp(text, "0x", 2) == 0) { - text += 2; - } - - for (;;) { - u64 v; - if (gb_char_is_digit(*text)) { - v = *text - '0'; - } else if (base == 16 && gb_char_is_hex_digit(*text)) { - v = gb_hex_digit_to_int(*text); - } else { - break; - } - - result *= base; - result += v; - text++; - } - - if (value) *value = result; - return (text - text_begin); -} - - -// TODO(bill): Make better -u64 gb_str_to_u64(char const *str, char **end_ptr, i32 base) { - isize len; - u64 value = 0; - - if (!base) { - if ((gb_strlen(str) > 2) && (gb_strncmp(str, "0x", 2) == 0)) { - base = 16; - } else { - base = 10; - } - } - - len = gb__scan_u64(str, base, &value); - if (end_ptr) *end_ptr = (char *)str + len; - return value; -} - -i64 gb_str_to_i64(char const *str, char **end_ptr, i32 base) { - isize len; - i64 value; - - if (!base) { - if ((gb_strlen(str) > 2) && (gb_strncmp(str, "0x", 2) == 0)) { - base = 16; - } else { - base = 10; - } - } - - len = gb__scan_i64(str, base, &value); - if (end_ptr) *end_ptr = (char *)str + len; - return value; -} - -// TODO(bill): Are these good enough for characters? -gb_global char const gb__num_to_char_table[] = - "0123456789" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "@$"; - -gb_inline void gb_i64_to_str(i64 value, char *string, i32 base) { - char *buf = string; - b32 negative = false; - u64 v; - if (value < 0) { - negative = true; - value = -value; - } - v = cast(u64)value; - if (v != 0) { - while (v > 0) { - *buf++ = gb__num_to_char_table[v % base]; - v /= base; - } - } else { - *buf++ = '0'; - } - if (negative) { - *buf++ = '-'; - } - *buf = '\0'; - gb_strrev(string); -} - - - -gb_inline void gb_u64_to_str(u64 value, char *string, i32 base) { - char *buf = string; - - if (value) { - while (value > 0) { - *buf++ = gb__num_to_char_table[value % base]; - value /= base; - } - } else { - *buf++ = '0'; - } - *buf = '\0'; - - gb_strrev(string); -} - -gb_inline f32 gb_str_to_f32(char const *str, char **end_ptr) { - f64 f = gb_str_to_f64(str, end_ptr); - f32 r = cast(f32)f; - return r; -} - -gb_inline f64 gb_str_to_f64(char const *str, char **end_ptr) { - f64 result, value, sign, scale; - i32 frac; - - while (gb_char_is_space(*str)) { - str++; - } - - sign = 1.0; - if (*str == '-') { - sign = -1.0; - str++; - } else if (*str == '+') { - str++; - } - - for (value = 0.0; gb_char_is_digit(*str); str++) { - value = value * 10.0 + (*str-'0'); - } - - if (*str == '.') { - f64 pow10 = 10.0; - str++; - while (gb_char_is_digit(*str)) { - value += (*str-'0') / pow10; - pow10 *= 10.0; - str++; - } - } - - frac = 0; - scale = 1.0; - if ((*str == 'e') || (*str == 'E')) { - u32 exp; - - str++; - if (*str == '-') { - frac = 1; - str++; - } else if (*str == '+') { - str++; - } - - for (exp = 0; gb_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; -} - - - - - - - -gb_inline void gb__set_string_length (gbString str, isize len) { GB_STRING_HEADER(str)->length = len; } -gb_inline void gb__set_string_capacity(gbString str, isize cap) { GB_STRING_HEADER(str)->capacity = cap; } - - -gbString gb_string_make_reserve(gbAllocator a, isize capacity) { - isize header_size = gb_size_of(gbStringHeader); - void *ptr = gb_alloc(a, header_size + capacity + 1); - - gbString str; - gbStringHeader *header; - - if (ptr == NULL) return NULL; - gb_zero_size(ptr, header_size + capacity + 1); - - str = cast(char *)ptr + header_size; - header = GB_STRING_HEADER(str); - header->allocator = a; - header->length = 0; - header->capacity = capacity; - str[capacity] = '\0'; - - return str; -} - - -gb_inline gbString gb_string_make(gbAllocator a, char const *str) { - isize len = str ? gb_strlen(str) : 0; - return gb_string_make_length(a, str, len); -} - -gbString gb_string_make_length(gbAllocator a, void const *init_str, isize num_bytes) { - isize header_size = gb_size_of(gbStringHeader); - void *ptr = gb_alloc(a, header_size + num_bytes + 1); - - gbString str; - gbStringHeader *header; - - if (ptr == NULL) return NULL; - if (!init_str) gb_zero_size(ptr, header_size + num_bytes + 1); - - str = cast(char *)ptr + header_size; - header = GB_STRING_HEADER(str); - header->allocator = a; - header->length = num_bytes; - header->capacity = num_bytes; - if (num_bytes && init_str) { - gb_memcopy(str, init_str, num_bytes); - } - str[num_bytes] = '\0'; - - return str; -} - -gb_inline void gb_string_free(gbString str) { - if (str) { - gbStringHeader *header = GB_STRING_HEADER(str); - gb_free(header->allocator, header); - } - -} - -gb_inline gbString gb_string_duplicate(gbAllocator a, gbString const str) { return gb_string_make_length(a, str, gb_string_length(str)); } - -gb_inline isize gb_string_length (gbString const str) { return GB_STRING_HEADER(str)->length; } -gb_inline isize gb_string_capacity(gbString const str) { return GB_STRING_HEADER(str)->capacity; } - -gb_inline isize gb_string_available_space(gbString const str) { - gbStringHeader *h = GB_STRING_HEADER(str); - if (h->capacity > h->length) { - return h->capacity - h->length; - } - return 0; -} - - -gb_inline void gb_string_clear(gbString str) { gb__set_string_length(str, 0); str[0] = '\0'; } - -gb_inline gbString gb_string_append(gbString str, gbString const other) { return gb_string_append_length(str, other, gb_string_length(other)); } - -gbString gb_string_append_length(gbString str, void const *other, isize other_len) { - if (other_len > 0) { - isize curr_len = gb_string_length(str); - - str = gb_string_make_space_for(str, other_len); - if (str == NULL) { - return NULL; - } - - gb_memcopy(str + curr_len, other, other_len); - str[curr_len + other_len] = '\0'; - gb__set_string_length(str, curr_len + other_len); - } - return str; -} - -gb_inline gbString gb_string_appendc(gbString str, char const *other) { - return gb_string_append_length(str, other, gb_strlen(other)); -} - -gbString gb_string_append_rune(gbString str, Rune r) { - if (r >= 0) { - u8 buf[8] = {0}; - isize len = gb_utf8_encode_rune(buf, r); - return gb_string_append_length(str, buf, len); - } - return str; -} - -gbString gb_string_append_fmt(gbString str, char const *fmt, ...) { - isize res; - char buf[4096] = {0}; - va_list va; - va_start(va, fmt); - res = gb_snprintf_va(buf, gb_count_of(buf)-1, fmt, va)-1; - va_end(va); - return gb_string_append_length(str, buf, res); -} - - - -gbString gb_string_set(gbString str, char const *cstr) { - isize len = gb_strlen(cstr); - if (gb_string_capacity(str) < len) { - str = gb_string_make_space_for(str, len - gb_string_length(str)); - if (str == NULL) { - return NULL; - } - } - - gb_memcopy(str, cstr, len); - str[len] = '\0'; - gb__set_string_length(str, len); - - return str; -} - - - -gbString gb_string_make_space_for(gbString str, isize add_len) { - isize available = gb_string_available_space(str); - - // NOTE(bill): Return if there is enough space left - if (available >= add_len) { - return str; - } else { - isize new_len, old_size, new_size; - void *ptr, *new_ptr; - gbAllocator a = GB_STRING_HEADER(str)->allocator; - gbStringHeader *header; - - new_len = gb_string_length(str) + add_len; - ptr = GB_STRING_HEADER(str); - old_size = gb_size_of(gbStringHeader) + gb_string_length(str) + 1; - new_size = gb_size_of(gbStringHeader) + new_len + 1; - - new_ptr = gb_resize(a, ptr, old_size, new_size); - if (new_ptr == NULL) return NULL; - - header = cast(gbStringHeader *)new_ptr; - header->allocator = a; - - str = cast(gbString)(header+1); - gb__set_string_capacity(str, new_len); - - return str; - } -} - -gb_inline isize gb_string_allocation_size(gbString const str) { - isize cap = gb_string_capacity(str); - return gb_size_of(gbStringHeader) + cap; -} - - -gb_inline b32 gb_string_are_equal(gbString const lhs, gbString const rhs) { - isize lhs_len, rhs_len, i; - lhs_len = gb_string_length(lhs); - rhs_len = gb_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; -} - - -gbString gb_string_trim(gbString str, char const *cut_set) { - char *start, *end, *start_pos, *end_pos; - isize len; - - start_pos = start = str; - end_pos = end = str + gb_string_length(str) - 1; - - while (start_pos <= end && gb_char_first_occurence(cut_set, *start_pos)) { - start_pos++; - } - while (end_pos > start_pos && gb_char_first_occurence(cut_set, *end_pos)) { - end_pos--; - } - - len = cast(isize)((start_pos > end_pos) ? 0 : ((end_pos - start_pos)+1)); - - if (str != start_pos) - gb_memmove(str, start_pos, len); - str[len] = '\0'; - - gb__set_string_length(str, len); - - return str; -} - -gb_inline gbString gb_string_trim_space(gbString str) { return gb_string_trim(str, " \t\r\n\v\f"); } - - - - -//////////////////////////////////////////////////////////////// -// -// Windows UTF-8 Handling -// -// - - -u16 *gb_utf8_to_ucs2(u16 *buffer, isize len, u8 const *str) { - Rune c; - 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(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(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; -} - -u8 *gb_ucs2_to_utf8(u8 *buffer, isize len, u16 const *str) { - 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) { - 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; -} - -u16 *gb_utf8_to_ucs2_buf(u8 const *str) { // NOTE(bill): Uses locally persisting buffer - gb_local_persist u16 buf[4096]; - return gb_utf8_to_ucs2(buf, gb_count_of(buf), str); -} - -u8 *gb_ucs2_to_utf8_buf(u16 const *str) { // NOTE(bill): Uses locally persisting buffer - gb_local_persist u8 buf[4096]; - return gb_ucs2_to_utf8(buf, gb_count_of(buf), str); -} - - - -gb_global u8 const gb__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 gbUtf8AcceptRange { - u8 lo, hi; -} gbUtf8AcceptRange; - -gb_global gbUtf8AcceptRange const gb__utf8_accept_ranges[] = { - {0x80, 0xbf}, - {0xa0, 0xbf}, - {0x80, 0x9f}, - {0x90, 0xbf}, - {0x80, 0x8f}, -}; - - -isize gb_utf8_decode(u8 const *str, isize str_len, Rune *codepoint_out) { - isize width = 0; - Rune codepoint = GB_RUNE_INVALID; - - if (str_len > 0) { - u8 s0 = str[0]; - u8 x = gb__utf8_first[s0], sz; - u8 b1, b2, b3; - gbUtf8AcceptRange accept; - if (x >= 0xf0) { - Rune mask = (cast(Rune)x << 31) >> 31; - codepoint = (cast(Rune)s0 & (~mask)) | (GB_RUNE_INVALID & mask); - width = 1; - goto end; - } - if (s0 < 0x80) { - codepoint = s0; - width = 1; - goto end; - } - - sz = x&7; - accept = gb__utf8_accept_ranges[x>>4]; - if (str_len < gb_size_of(sz)) - goto invalid_codepoint; - - b1 = str[1]; - if (b1 < accept.lo || accept.hi < b1) - goto invalid_codepoint; - - if (sz == 2) { - codepoint = (cast(Rune)s0&0x1f)<<6 | (cast(Rune)b1&0x3f); - width = 2; - goto end; - } - - b2 = str[2]; - if (!gb_is_between(b2, 0x80, 0xbf)) - goto invalid_codepoint; - - if (sz == 3) { - codepoint = (cast(Rune)s0&0x1f)<<12 | (cast(Rune)b1&0x3f)<<6 | (cast(Rune)b2&0x3f); - width = 3; - goto end; - } - - b3 = str[3]; - if (!gb_is_between(b3, 0x80, 0xbf)) - goto invalid_codepoint; - - codepoint = (cast(Rune)s0&0x07)<<18 | (cast(Rune)b1&0x3f)<<12 | (cast(Rune)b2&0x3f)<<6 | (cast(Rune)b3&0x3f); - width = 4; - goto end; - - invalid_codepoint: - codepoint = GB_RUNE_INVALID; - width = 1; - } - -end: - if (codepoint_out) *codepoint_out = codepoint; - return width; -} - -isize gb_utf8_codepoint_size(u8 const *str, isize str_len) { - isize i = 0; - for (; i < str_len && str[i]; i++) { - if ((str[i] & 0xc0) != 0x80) - break; - } - return i+1; -} - -isize gb_utf8_encode_rune(u8 buf[4], Rune r) { - u32 i = cast(u32)r; - u8 mask = 0x3f; - if (i <= (1<<7)-1) { - buf[0] = cast(u8)r; - return 1; - } - if (i <= (1<<11)-1) { - buf[0] = 0xc0 | cast(u8)(r>>6); - buf[1] = 0x80 | (cast(u8)(r)&mask); - return 2; - } - - // Invalid or Surrogate range - if (i > GB_RUNE_MAX || - gb_is_between(i, 0xd800, 0xdfff)) { - r = GB_RUNE_INVALID; - - buf[0] = 0xe0 | cast(u8)(r>>12); - buf[1] = 0x80 | (cast(u8)(r>>6)&mask); - buf[2] = 0x80 | (cast(u8)(r)&mask); - return 3; - } - - if (i <= (1<<16)-1) { - buf[0] = 0xe0 | cast(u8)(r>>12); - buf[1] = 0x80 | (cast(u8)(r>>6)&mask); - buf[2] = 0x80 | (cast(u8)(r)&mask); - return 3; - } - - buf[0] = 0xf0 | cast(u8)(r>>18); - buf[1] = 0x80 | (cast(u8)(r>>12)&mask); - buf[2] = 0x80 | (cast(u8)(r>>6)&mask); - buf[3] = 0x80 | (cast(u8)(r)&mask); - return 4; -} - - - - -//////////////////////////////////////////////////////////////// -// -// gbArray -// -// - - -gb_no_inline void *gb__array_set_capacity(void *array, isize capacity, isize element_size) { - gbArrayHeader *h = GB_ARRAY_HEADER(array); - - GB_ASSERT(element_size > 0); - - if (capacity == h->capacity) - return array; - - if (capacity < h->count) { - if (h->capacity < capacity) { - isize new_capacity = GB_ARRAY_GROW_FORMULA(h->capacity); - if (new_capacity < capacity) - new_capacity = capacity; - gb__array_set_capacity(array, new_capacity, element_size); - } - h->count = capacity; - } - - { - isize size = gb_size_of(gbArrayHeader) + element_size*capacity; - gbArrayHeader *nh = cast(gbArrayHeader *)gb_alloc(h->allocator, size); - gb_memmove(nh, h, gb_size_of(gbArrayHeader) + element_size*h->count); - nh->allocator = h->allocator; - nh->count = h->count; - nh->capacity = capacity; - gb_free(h->allocator, h); - return nh+1; - } -} - - -//////////////////////////////////////////////////////////////// -// -// Hashing functions -// -// - -u32 gb_adler32(void const *data, isize len) { - u32 const MOD_ALDER = 65521; - u32 a = 1, b = 0; - isize i, block_len; - u8 const *bytes = cast(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; -} - - -gb_global u32 const GB__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, -}; - -gb_global u64 const GB__CRC64_TABLE[256] = { - 0x0000000000000000ull, 0x42f0e1eba9ea3693ull, 0x85e1c3d753d46d26ull, 0xc711223cfa3e5bb5ull, - 0x493366450e42ecdfull, 0x0bc387aea7a8da4cull, 0xccd2a5925d9681f9ull, 0x8e224479f47cb76aull, - 0x9266cc8a1c85d9beull, 0xd0962d61b56fef2dull, 0x17870f5d4f51b498ull, 0x5577eeb6e6bb820bull, - 0xdb55aacf12c73561ull, 0x99a54b24bb2d03f2ull, 0x5eb4691841135847ull, 0x1c4488f3e8f96ed4ull, - 0x663d78ff90e185efull, 0x24cd9914390bb37cull, 0xe3dcbb28c335e8c9ull, 0xa12c5ac36adfde5aull, - 0x2f0e1eba9ea36930ull, 0x6dfeff5137495fa3ull, 0xaaefdd6dcd770416ull, 0xe81f3c86649d3285ull, - 0xf45bb4758c645c51ull, 0xb6ab559e258e6ac2ull, 0x71ba77a2dfb03177ull, 0x334a9649765a07e4ull, - 0xbd68d2308226b08eull, 0xff9833db2bcc861dull, 0x388911e7d1f2dda8ull, 0x7a79f00c7818eb3bull, - 0xcc7af1ff21c30bdeull, 0x8e8a101488293d4dull, 0x499b3228721766f8ull, 0x0b6bd3c3dbfd506bull, - 0x854997ba2f81e701ull, 0xc7b97651866bd192ull, 0x00a8546d7c558a27ull, 0x4258b586d5bfbcb4ull, - 0x5e1c3d753d46d260ull, 0x1cecdc9e94ace4f3ull, 0xdbfdfea26e92bf46ull, 0x990d1f49c77889d5ull, - 0x172f5b3033043ebfull, 0x55dfbadb9aee082cull, 0x92ce98e760d05399ull, 0xd03e790cc93a650aull, - 0xaa478900b1228e31ull, 0xe8b768eb18c8b8a2ull, 0x2fa64ad7e2f6e317ull, 0x6d56ab3c4b1cd584ull, - 0xe374ef45bf6062eeull, 0xa1840eae168a547dull, 0x66952c92ecb40fc8ull, 0x2465cd79455e395bull, - 0x3821458aada7578full, 0x7ad1a461044d611cull, 0xbdc0865dfe733aa9ull, 0xff3067b657990c3aull, - 0x711223cfa3e5bb50ull, 0x33e2c2240a0f8dc3ull, 0xf4f3e018f031d676ull, 0xb60301f359dbe0e5ull, - 0xda050215ea6c212full, 0x98f5e3fe438617bcull, 0x5fe4c1c2b9b84c09ull, 0x1d14202910527a9aull, - 0x93366450e42ecdf0ull, 0xd1c685bb4dc4fb63ull, 0x16d7a787b7faa0d6ull, 0x5427466c1e109645ull, - 0x4863ce9ff6e9f891ull, 0x0a932f745f03ce02ull, 0xcd820d48a53d95b7ull, 0x8f72eca30cd7a324ull, - 0x0150a8daf8ab144eull, 0x43a04931514122ddull, 0x84b16b0dab7f7968ull, 0xc6418ae602954ffbull, - 0xbc387aea7a8da4c0ull, 0xfec89b01d3679253ull, 0x39d9b93d2959c9e6ull, 0x7b2958d680b3ff75ull, - 0xf50b1caf74cf481full, 0xb7fbfd44dd257e8cull, 0x70eadf78271b2539ull, 0x321a3e938ef113aaull, - 0x2e5eb66066087d7eull, 0x6cae578bcfe24bedull, 0xabbf75b735dc1058ull, 0xe94f945c9c3626cbull, - 0x676dd025684a91a1ull, 0x259d31cec1a0a732ull, 0xe28c13f23b9efc87ull, 0xa07cf2199274ca14ull, - 0x167ff3eacbaf2af1ull, 0x548f120162451c62ull, 0x939e303d987b47d7ull, 0xd16ed1d631917144ull, - 0x5f4c95afc5edc62eull, 0x1dbc74446c07f0bdull, 0xdaad56789639ab08ull, 0x985db7933fd39d9bull, - 0x84193f60d72af34full, 0xc6e9de8b7ec0c5dcull, 0x01f8fcb784fe9e69ull, 0x43081d5c2d14a8faull, - 0xcd2a5925d9681f90ull, 0x8fdab8ce70822903ull, 0x48cb9af28abc72b6ull, 0x0a3b7b1923564425ull, - 0x70428b155b4eaf1eull, 0x32b26afef2a4998dull, 0xf5a348c2089ac238ull, 0xb753a929a170f4abull, - 0x3971ed50550c43c1ull, 0x7b810cbbfce67552ull, 0xbc902e8706d82ee7ull, 0xfe60cf6caf321874ull, - 0xe224479f47cb76a0ull, 0xa0d4a674ee214033ull, 0x67c58448141f1b86ull, 0x253565a3bdf52d15ull, - 0xab1721da49899a7full, 0xe9e7c031e063acecull, 0x2ef6e20d1a5df759ull, 0x6c0603e6b3b7c1caull, - 0xf6fae5c07d3274cdull, 0xb40a042bd4d8425eull, 0x731b26172ee619ebull, 0x31ebc7fc870c2f78ull, - 0xbfc9838573709812ull, 0xfd39626eda9aae81ull, 0x3a28405220a4f534ull, 0x78d8a1b9894ec3a7ull, - 0x649c294a61b7ad73ull, 0x266cc8a1c85d9be0ull, 0xe17dea9d3263c055ull, 0xa38d0b769b89f6c6ull, - 0x2daf4f0f6ff541acull, 0x6f5faee4c61f773full, 0xa84e8cd83c212c8aull, 0xeabe6d3395cb1a19ull, - 0x90c79d3fedd3f122ull, 0xd2377cd44439c7b1ull, 0x15265ee8be079c04ull, 0x57d6bf0317edaa97ull, - 0xd9f4fb7ae3911dfdull, 0x9b041a914a7b2b6eull, 0x5c1538adb04570dbull, 0x1ee5d94619af4648ull, - 0x02a151b5f156289cull, 0x4051b05e58bc1e0full, 0x87409262a28245baull, 0xc5b073890b687329ull, - 0x4b9237f0ff14c443ull, 0x0962d61b56fef2d0ull, 0xce73f427acc0a965ull, 0x8c8315cc052a9ff6ull, - 0x3a80143f5cf17f13ull, 0x7870f5d4f51b4980ull, 0xbf61d7e80f251235ull, 0xfd913603a6cf24a6ull, - 0x73b3727a52b393ccull, 0x31439391fb59a55full, 0xf652b1ad0167feeaull, 0xb4a25046a88dc879ull, - 0xa8e6d8b54074a6adull, 0xea16395ee99e903eull, 0x2d071b6213a0cb8bull, 0x6ff7fa89ba4afd18ull, - 0xe1d5bef04e364a72ull, 0xa3255f1be7dc7ce1ull, 0x64347d271de22754ull, 0x26c49cccb40811c7ull, - 0x5cbd6cc0cc10fafcull, 0x1e4d8d2b65facc6full, 0xd95caf179fc497daull, 0x9bac4efc362ea149ull, - 0x158e0a85c2521623ull, 0x577eeb6e6bb820b0ull, 0x906fc95291867b05ull, 0xd29f28b9386c4d96ull, - 0xcedba04ad0952342ull, 0x8c2b41a1797f15d1ull, 0x4b3a639d83414e64ull, 0x09ca82762aab78f7ull, - 0x87e8c60fded7cf9dull, 0xc51827e4773df90eull, 0x020905d88d03a2bbull, 0x40f9e43324e99428ull, - 0x2cffe7d5975e55e2ull, 0x6e0f063e3eb46371ull, 0xa91e2402c48a38c4ull, 0xebeec5e96d600e57ull, - 0x65cc8190991cb93dull, 0x273c607b30f68faeull, 0xe02d4247cac8d41bull, 0xa2dda3ac6322e288ull, - 0xbe992b5f8bdb8c5cull, 0xfc69cab42231bacfull, 0x3b78e888d80fe17aull, 0x7988096371e5d7e9ull, - 0xf7aa4d1a85996083ull, 0xb55aacf12c735610ull, 0x724b8ecdd64d0da5ull, 0x30bb6f267fa73b36ull, - 0x4ac29f2a07bfd00dull, 0x08327ec1ae55e69eull, 0xcf235cfd546bbd2bull, 0x8dd3bd16fd818bb8ull, - 0x03f1f96f09fd3cd2ull, 0x41011884a0170a41ull, 0x86103ab85a2951f4ull, 0xc4e0db53f3c36767ull, - 0xd8a453a01b3a09b3ull, 0x9a54b24bb2d03f20ull, 0x5d45907748ee6495ull, 0x1fb5719ce1045206ull, - 0x919735e51578e56cull, 0xd367d40ebc92d3ffull, 0x1476f63246ac884aull, 0x568617d9ef46bed9ull, - 0xe085162ab69d5e3cull, 0xa275f7c11f7768afull, 0x6564d5fde549331aull, 0x279434164ca30589ull, - 0xa9b6706fb8dfb2e3ull, 0xeb46918411358470ull, 0x2c57b3b8eb0bdfc5ull, 0x6ea7525342e1e956ull, - 0x72e3daa0aa188782ull, 0x30133b4b03f2b111ull, 0xf7021977f9cceaa4ull, 0xb5f2f89c5026dc37ull, - 0x3bd0bce5a45a6b5dull, 0x79205d0e0db05dceull, 0xbe317f32f78e067bull, 0xfcc19ed95e6430e8ull, - 0x86b86ed5267cdbd3ull, 0xc4488f3e8f96ed40ull, 0x0359ad0275a8b6f5ull, 0x41a94ce9dc428066ull, - 0xcf8b0890283e370cull, 0x8d7be97b81d4019full, 0x4a6acb477bea5a2aull, 0x089a2aacd2006cb9ull, - 0x14dea25f3af9026dull, 0x562e43b4931334feull, 0x913f6188692d6f4bull, 0xd3cf8063c0c759d8ull, - 0x5dedc41a34bbeeb2ull, 0x1f1d25f19d51d821ull, 0xd80c07cd676f8394ull, 0x9afce626ce85b507ull, -}; - -u32 gb_crc32(void const *data, isize len) { - isize remaining; - u32 result = ~(cast(u32)0); - u8 const *c = cast(u8 const *)data; - for (remaining = len; remaining--; c++) { - result = (result >> 8) ^ (GB__CRC32_TABLE[(result ^ *c) & 0xff]); - } - return ~result; -} - -u64 gb_crc64(void const *data, isize len) { - isize remaining; - u64 result = ~(cast(u64)0); - u8 const *c = cast(u8 const *)data; - for (remaining = len; remaining--; c++) { - result = (result >> 8) ^ (GB__CRC64_TABLE[(result ^ *c) & 0xff]); - } - return ~result; -} - -u32 gb_fnv32(void const *data, isize len) { - isize i; - u32 h = 0x811c9dc5; - u8 const *c = cast(u8 const *)data; - - for (i = 0; i < len; i++) { - h = (h * 0x01000193) ^ c[i]; - } - - return h; -} - -u64 gb_fnv64(void const *data, isize len) { - isize i; - u64 h = 0xcbf29ce484222325ull; - u8 const *c = cast(u8 const *)data; - - for (i = 0; i < len; i++) { - h = (h * 0x100000001b3ll) ^ c[i]; - } - - return h; -} - -u32 gb_fnv32a(void const *data, isize len) { - isize i; - u32 h = 0x811c9dc5; - u8 const *c = cast(u8 const *)data; - - for (i = 0; i < len; i++) { - h = (h ^ c[i]) * 0x01000193; - } - - return h; -} - -u64 gb_fnv64a(void const *data, isize len) { - isize i; - u64 h = 0xcbf29ce484222325ull; - u8 const *c = cast(u8 const *)data; - - for (i = 0; i < len; i++) { - h = (h ^ c[i]) * 0x100000001b3ll; - } - - return h; -} - -gb_inline u32 gb_murmur32(void const *data, isize len) { return gb_murmur32_seed(data, len, 0x9747b28c); } -gb_inline u64 gb_murmur64(void const *data, isize len) { return gb_murmur64_seed(data, len, 0x9747b28c); } - -u32 gb_murmur32_seed(void const *data, isize len, u32 seed) { - u32 const c1 = 0xcc9e2d51; - u32 const c2 = 0x1b873593; - u32 const r1 = 15; - u32 const r2 = 13; - u32 const m = 5; - u32 const n = 0xe6546b64; - - isize i, nblocks = len / 4; - u32 hash = seed, k1 = 0; - u32 const *blocks = cast(u32 const*)data; - u8 const *tail = cast(u8 const *)(data) + nblocks*4; - - for (i = 0; i < nblocks; i++) { - 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; -} - -u64 gb_murmur64_seed(void const *data_, isize len, u64 seed) { -#if defined(GB_ARCH_64_BIT) - u64 const m = 0xc6a4a7935bd1e995ULL; - i32 const r = 47; - - u64 h = seed ^ (len * m); - - u64 const *data = cast(u64 const *)data_; - u8 const *data2 = cast(u8 const *)data_; - u64 const* end = data + (len / 8); - - while (data != end) { - u64 k = *data++; - - k *= m; - k ^= k >> r; - k *= m; - - h ^= k; - h *= m; - } - - switch (len & 7) { - case 7: h ^= cast(u64)(data2[6]) << 48; - case 6: h ^= cast(u64)(data2[5]) << 40; - case 5: h ^= cast(u64)(data2[4]) << 32; - case 4: h ^= cast(u64)(data2[3]) << 24; - case 3: h ^= cast(u64)(data2[2]) << 16; - case 2: h ^= cast(u64)(data2[1]) << 8; - case 1: h ^= cast(u64)(data2[0]); - h *= m; - }; - - h ^= h >> r; - h *= m; - h ^= h >> r; - - return h; -#else - u64 h; - u32 const m = 0x5bd1e995; - i32 const r = 24; - - u32 h1 = cast(u32)(seed) ^ cast(u32)(len); - u32 h2 = cast(u32)(seed >> 32); - - u32 const *data = cast(u32 const *)data_; - - while (len >= 8) { - u32 k1, k2; - k1 = *data++; - k1 *= m; - k1 ^= k1 >> r; - k1 *= m; - h1 *= m; - h1 ^= k1; - len -= 4; - - k2 = *data++; - k2 *= m; - k2 ^= k2 >> r; - k2 *= m; - h2 *= m; - h2 ^= k2; - len -= 4; - } - - if (len >= 4) { - u32 k1 = *data++; - k1 *= m; - k1 ^= k1 >> r; - k1 *= m; - h1 *= m; - h1 ^= k1; - len -= 4; - } - - switch (len) { - case 3: h2 ^= (cast(u8 const *)data)[2] << 16; - case 2: h2 ^= (cast(u8 const *)data)[1] << 8; - case 1: h2 ^= (cast(u8 const *)data)[0] << 0; - h2 *= m; - }; - - h1 ^= h2 >> 18; - h1 *= m; - h2 ^= h1 >> 22; - h2 *= m; - h1 ^= h2 >> 17; - h1 *= m; - h2 ^= h1 >> 19; - h2 *= m; - - h = h1; - h = (h << 32) | h2; - - return h; -#endif -} - - - - - - - -//////////////////////////////////////////////////////////////// -// -// File Handling -// -// - -#if defined(GB_SYSTEM_WINDOWS) - - gb_internal wchar_t *gb__alloc_utf8_to_ucs2(gbAllocator a, char const *text, isize *w_len_) { - wchar_t *w_text = NULL; - isize len = 0, w_len = 0, w_len1 = 0; - if (text == NULL) { - if (w_len_) *w_len_ = w_len; - return NULL; - } - len = gb_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 = gb_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) { - gb_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; - } - - gb_internal GB_FILE_SEEK_PROC(gb__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; - } - - gb_internal GB_FILE_READ_AT_PROC(gb__win32_file_read) { - b32 result = false; - DWORD size_ = cast(DWORD)(size > I32_MAX ? I32_MAX : size); - DWORD bytes_read_; - gb__win32_file_seek(fd, offset, gbSeekWhence_Begin, NULL); - if (ReadFile(fd.p, buffer, size_, &bytes_read_, NULL)) { - if (bytes_read) *bytes_read = bytes_read_; - result = true; - } - - return result; - } - - gb_internal GB_FILE_WRITE_AT_PROC(gb__win32_file_write) { - DWORD size_ = cast(DWORD)(size > I32_MAX ? I32_MAX : size); - DWORD bytes_written_; - gb__win32_file_seek(fd, offset, gbSeekWhence_Begin, NULL); - if (WriteFile(fd.p, buffer, size_, &bytes_written_, NULL)) { - if (bytes_written) *bytes_written = bytes_written_; - return true; - } - return false; - } - - gb_internal GB_FILE_CLOSE_PROC(gb__win32_file_close) { - CloseHandle(fd.p); - } - - gbFileOperations const gbDefaultFileOperations = { - gb__win32_file_read, - gb__win32_file_write, - gb__win32_file_seek, - gb__win32_file_close - }; - - gb_no_inline GB_FILE_OPEN_PROC(gb__win32_file_open) { - DWORD desired_access; - DWORD creation_disposition; - void *handle; - wchar_t *w_text; - - switch (mode & gbFileMode_Modes) { - case gbFileMode_Read: - desired_access = GENERIC_READ; - creation_disposition = OPEN_EXISTING; - break; - case gbFileMode_Write: - desired_access = GENERIC_WRITE; - creation_disposition = CREATE_ALWAYS; - break; - case gbFileMode_Append: - desired_access = GENERIC_WRITE; - creation_disposition = OPEN_ALWAYS; - break; - case gbFileMode_Read | gbFileMode_Rw: - desired_access = GENERIC_READ | GENERIC_WRITE; - creation_disposition = OPEN_EXISTING; - break; - case gbFileMode_Write | gbFileMode_Rw: - desired_access = GENERIC_READ | GENERIC_WRITE; - creation_disposition = CREATE_ALWAYS; - break; - case gbFileMode_Append | gbFileMode_Rw: - desired_access = GENERIC_READ | GENERIC_WRITE; - creation_disposition = OPEN_ALWAYS; - break; - default: - GB_PANIC("Invalid file mode"); - return gbFileError_Invalid; - } - - w_text = gb__alloc_utf8_to_ucs2(gb_heap_allocator(), filename, NULL); - if (w_text == NULL) { - return gbFileError_InvalidFilename; - } - handle = CreateFileW(w_text, - desired_access, - FILE_SHARE_READ|FILE_SHARE_DELETE, NULL, - creation_disposition, FILE_ATTRIBUTE_NORMAL, NULL); - - gb_free(gb_heap_allocator(), w_text); - - if (handle == INVALID_HANDLE_VALUE) { - DWORD err = GetLastError(); - switch (err) { - case ERROR_FILE_NOT_FOUND: return gbFileError_NotExists; - case ERROR_FILE_EXISTS: return gbFileError_Exists; - case ERROR_ALREADY_EXISTS: return gbFileError_Exists; - case ERROR_ACCESS_DENIED: return gbFileError_Permission; - } - return gbFileError_Invalid; - } - - if (mode & gbFileMode_Append) { - LARGE_INTEGER offset = {0}; - if (!SetFilePointerEx(handle, offset, NULL, gbSeekWhence_End)) { - CloseHandle(handle); - return gbFileError_Invalid; - } - } - - fd->p = handle; - *ops = gbDefaultFileOperations; - return gbFileError_None; - } - -#else // POSIX - gb_internal GB_FILE_SEEK_PROC(gb__posix_file_seek) { - #if defined(GB_SYSTEM_OSX) - i64 res = lseek(fd.i, offset, whence); - #else - i64 res = lseek64(fd.i, offset, whence); - #endif - if (res < 0) return false; - if (new_offset) *new_offset = res; - return true; - } - - gb_internal GB_FILE_READ_AT_PROC(gb__posix_file_read) { - isize res = pread(fd.i, buffer, size, offset); - if (res < 0) return false; - if (bytes_read) *bytes_read = res; - return true; - } - - gb_internal GB_FILE_WRITE_AT_PROC(gb__posix_file_write) { - isize res; - i64 curr_offset = 0; - gb__posix_file_seek(fd, 0, gbSeekWhence_Current, &curr_offset); - if (curr_offset == offset) { - // NOTE(bill): 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; - } - - - gb_internal GB_FILE_CLOSE_PROC(gb__posix_file_close) { - close(fd.i); - } - - gbFileOperations const gbDefaultFileOperations = { - gb__posix_file_read, - gb__posix_file_write, - gb__posix_file_seek, - gb__posix_file_close - }; - - gb_no_inline GB_FILE_OPEN_PROC(gb__posix_file_open) { - i32 os_mode; - switch (mode & gbFileMode_Modes) { - case gbFileMode_Read: - os_mode = O_RDONLY; - break; - case gbFileMode_Write: - os_mode = O_WRONLY | O_CREAT | O_TRUNC; - break; - case gbFileMode_Append: - os_mode = O_WRONLY | O_APPEND | O_CREAT; - break; - case gbFileMode_Read | gbFileMode_Rw: - os_mode = O_RDWR; - break; - case gbFileMode_Write | gbFileMode_Rw: - os_mode = O_RDWR | O_CREAT | O_TRUNC; - break; - case gbFileMode_Append | gbFileMode_Rw: - os_mode = O_RDWR | O_APPEND | O_CREAT; - break; - default: - GB_PANIC("Invalid file mode"); - return gbFileError_Invalid; - } - - fd->i = open(filename, os_mode, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); - if (fd->i < 0) { - // TODO(bill): More file errors - return gbFileError_Invalid; - } - - *ops = gbDefaultFileOperations; - return gbFileError_None; - } - -#endif - - - -gbFileError gb_file_new(gbFile *f, gbFileDescriptor fd, gbFileOperations ops, char const *filename) { - gbFileError err = gbFileError_None; - isize len = gb_strlen(filename); - - // gb_printf_err("gb_file_new: %s\n", filename); - - f->ops = ops; - f->fd = fd; - f->filename = gb_alloc_array(gb_heap_allocator(), char, len+1); - gb_memcopy(cast(char *)f->filename, cast(char *)filename, len+1); - f->last_write_time = gb_file_last_write_time(f->filename); - - return err; -} - - - -gbFileError gb_file_open_mode(gbFile *f, gbFileMode mode, char const *filename) { - gbFileError err; -#if defined(GB_SYSTEM_WINDOWS) - err = gb__win32_file_open(&f->fd, &f->ops, mode, filename); -#else - err = gb__posix_file_open(&f->fd, &f->ops, mode, filename); -#endif - if (err == gbFileError_None) { - return gb_file_new(f, f->fd, f->ops, filename); - } - return err; -} - -gbFileError gb_file_close(gbFile *f) { - if (f == NULL) { - return gbFileError_Invalid; - } - -#if defined(GB_COMPILER_MSVC) - if (f->filename != NULL) { - gb_free(gb_heap_allocator(), cast(char *)f->filename); - } -#else - // TODO HACK(bill): Memory Leak!!! -#endif - -#if defined(GB_SYSTEM_WINDOWS) - if (f->fd.p == INVALID_HANDLE_VALUE) { - return gbFileError_Invalid; - } -#else - if (f->fd.i < 0) { - return gbFileError_Invalid; - } -#endif - - if (!f->ops.read_at) f->ops = gbDefaultFileOperations; - f->ops.close(f->fd); - - return gbFileError_None; -} - -gb_inline b32 gb_file_read_at_check(gbFile *f, void *buffer, isize size, i64 offset, isize *bytes_read) { - if (!f->ops.read_at) f->ops = gbDefaultFileOperations; - return f->ops.read_at(f->fd, buffer, size, offset, bytes_read); -} - -gb_inline b32 gb_file_write_at_check(gbFile *f, void const *buffer, isize size, i64 offset, isize *bytes_written) { - if (!f->ops.read_at) f->ops = gbDefaultFileOperations; - return f->ops.write_at(f->fd, buffer, size, offset, bytes_written); -} - - -gb_inline b32 gb_file_read_at(gbFile *f, void *buffer, isize size, i64 offset) { - return gb_file_read_at_check(f, buffer, size, offset, NULL); -} - -gb_inline b32 gb_file_write_at(gbFile *f, void const *buffer, isize size, i64 offset) { - return gb_file_write_at_check(f, buffer, size, offset, NULL); -} - -gb_inline i64 gb_file_seek(gbFile *f, i64 offset) { - i64 new_offset = 0; - if (!f->ops.read_at) f->ops = gbDefaultFileOperations; - f->ops.seek(f->fd, offset, gbSeekWhence_Begin, &new_offset); - return new_offset; -} - -gb_inline i64 gb_file_seek_to_end(gbFile *f) { - i64 new_offset = 0; - if (!f->ops.read_at) f->ops = gbDefaultFileOperations; - f->ops.seek(f->fd, 0, gbSeekWhence_End, &new_offset); - return new_offset; -} - -// NOTE(bill): Skips a certain amount of bytes -gb_inline i64 gb_file_skip(gbFile *f, i64 bytes) { - i64 new_offset = 0; - if (!f->ops.read_at) f->ops = gbDefaultFileOperations; - f->ops.seek(f->fd, bytes, gbSeekWhence_Current, &new_offset); - return new_offset; -} - -gb_inline i64 gb_file_tell(gbFile *f) { - i64 new_offset = 0; - if (!f->ops.read_at) f->ops = gbDefaultFileOperations; - f->ops.seek(f->fd, 0, gbSeekWhence_Current, &new_offset); - return new_offset; -} -gb_inline b32 gb_file_read (gbFile *f, void *buffer, isize size) { return gb_file_read_at(f, buffer, size, gb_file_tell(f)); } -gb_inline b32 gb_file_write(gbFile *f, void const *buffer, isize size) { return gb_file_write_at(f, buffer, size, gb_file_tell(f)); } - - -gbFileError gb_file_create(gbFile *f, char const *filename) { - return gb_file_open_mode(f, gbFileMode_Write|gbFileMode_Rw, filename); -} - - -gbFileError gb_file_open(gbFile *f, char const *filename) { - return gb_file_open_mode(f, gbFileMode_Read, filename); -} - - -char const *gb_file_name(gbFile *f) { return f->filename ? f->filename : ""; } - -gb_inline b32 gb_file_has_changed(gbFile *f) { - b32 result = false; - gbFileTime last_write_time = gb_file_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(bill): Is this a bad idea? -gb_global b32 gb__std_file_set = false; -gb_global gbFile gb__std_files[gbFileStandard_Count] = {{0}}; - - -#if defined(GB_SYSTEM_WINDOWS) - -gb_inline gbFile *const gb_file_get_standard(gbFileStandardType std) { - if (!gb__std_file_set) { - #define GB__SET_STD_FILE(type, v) gb__std_files[type].fd.p = v; gb__std_files[type].ops = gbDefaultFileOperations - GB__SET_STD_FILE(gbFileStandard_Input, GetStdHandle(STD_INPUT_HANDLE)); - GB__SET_STD_FILE(gbFileStandard_Output, GetStdHandle(STD_OUTPUT_HANDLE)); - GB__SET_STD_FILE(gbFileStandard_Error, GetStdHandle(STD_ERROR_HANDLE)); - #undef GB__SET_STD_FILE - gb__std_file_set = true; - } - return &gb__std_files[std]; -} - -gb_inline i64 gb_file_size(gbFile *f) { - LARGE_INTEGER size; - GetFileSizeEx(f->fd.p, &size); - return size.QuadPart; -} - -gbFileError gb_file_truncate(gbFile *f, i64 size) { - gbFileError err = gbFileError_None; - i64 prev_offset = gb_file_tell(f); - gb_file_seek(f, size); - if (!SetEndOfFile(f)) { - err = gbFileError_TruncationFailure; - } - gb_file_seek(f, prev_offset); - return err; -} - - -b32 gb_file_exists(char const *name) { - WIN32_FIND_DATAW data; - wchar_t *w_text; - void *handle; - b32 found = false; - gbAllocator a = gb_heap_allocator(); - - w_text = gb__alloc_utf8_to_ucs2(a, name, NULL); - if (w_text == NULL) { - return false; - } - handle = FindFirstFileW(w_text, &data); - gb_free(a, w_text); - found = handle != INVALID_HANDLE_VALUE; - if (found) FindClose(handle); - return found; -} - -#else // POSIX - -gb_inline gbFile *const gb_file_get_standard(gbFileStandardType std) { - if (!gb__std_file_set) { - #define GB__SET_STD_FILE(type, v) gb__std_files[type].fd.i = v; gb__std_files[type].ops = gbDefaultFileOperations - GB__SET_STD_FILE(gbFileStandard_Input, 0); - GB__SET_STD_FILE(gbFileStandard_Output, 1); - GB__SET_STD_FILE(gbFileStandard_Error, 2); - #undef GB__SET_STD_FILE - gb__std_file_set = true; - } - return &gb__std_files[std]; -} - -gb_inline i64 gb_file_size(gbFile *f) { - i64 size = 0; - i64 prev_offset = gb_file_tell(f); - gb_file_seek_to_end(f); - size = gb_file_tell(f); - gb_file_seek(f, prev_offset); - return size; -} - -gb_inline gbFileError gb_file_truncate(gbFile *f, i64 size) { - gbFileError err = gbFileError_None; - int i = ftruncate(f->fd.i, size); - if (i != 0) err = gbFileError_TruncationFailure; - return err; -} - -gb_inline b32 gb_file_exists(char const *name) { - return access(name, F_OK) != -1; -} -#endif - - - -#if defined(GB_SYSTEM_WINDOWS) -gbFileTime gb_file_last_write_time(char const *filepath) { - ULARGE_INTEGER li = {0}; - FILETIME last_write_time = {0}; - WIN32_FILE_ATTRIBUTE_DATA data = {0}; - gbAllocator a = gb_heap_allocator(); - - wchar_t *w_text = gb__alloc_utf8_to_ucs2(a, filepath, NULL); - if (w_text == NULL) { - return 0; - } - - if (GetFileAttributesExW(w_text, GetFileExInfoStandard, &data)) { - last_write_time = data.ftLastWriteTime; - } - gb_free(a, w_text); - - li.LowPart = last_write_time.dwLowDateTime; - li.HighPart = last_write_time.dwHighDateTime; - return cast(gbFileTime)li.QuadPart; -} - - -gb_inline b32 gb_file_copy(char const *existing_filename, char const *new_filename, b32 fail_if_exists) { - wchar_t *w_old = NULL; - wchar_t *w_new = NULL; - gbAllocator a = gb_heap_allocator(); - b32 result = false; - - w_old = gb__alloc_utf8_to_ucs2(a, existing_filename, NULL); - if (w_old == NULL) { - return false; - } - w_new = gb__alloc_utf8_to_ucs2(a, new_filename, NULL); - if (w_new != NULL) { - result = CopyFileW(w_old, w_new, fail_if_exists); - } - gb_free(a, w_new); - gb_free(a, w_old); - return result; -} - -gb_inline b32 gb_file_move(char const *existing_filename, char const *new_filename) { - wchar_t *w_old = NULL; - wchar_t *w_new = NULL; - gbAllocator a = gb_heap_allocator(); - b32 result = false; - - w_old = gb__alloc_utf8_to_ucs2(a, existing_filename, NULL); - if (w_old == NULL) { - return false; - } - w_new = gb__alloc_utf8_to_ucs2(a, new_filename, NULL); - if (w_new != NULL) { - result = MoveFileW(w_old, w_new); - } - gb_free(a, w_new); - gb_free(a, w_old); - return result; -} - -b32 gb_file_remove(char const *filename) { - wchar_t *w_filename = NULL; - gbAllocator a = gb_heap_allocator(); - b32 result = false; - w_filename = gb__alloc_utf8_to_ucs2(a, filename, NULL); - if (w_filename == NULL) { - return false; - } - result = DeleteFileW(w_filename); - gb_free(a, w_filename); - return result; -} - - - -#else - -gbFileTime gb_file_last_write_time(char const *filepath) { - time_t result = 0; - struct stat file_stat; - - if (stat(filepath, &file_stat) == 0) { - result = file_stat.st_mtime; - } - - return cast(gbFileTime)result; -} - - -gb_inline b32 gb_file_copy(char const *existing_filename, char const *new_filename, b32 fail_if_exists) { -#if defined(GB_SYSTEM_OSX) - return copyfile(existing_filename, new_filename, NULL, COPYFILE_DATA) == 0; -#else - isize size; - int existing_fd = open(existing_filename, O_RDONLY, 0); - int new_fd = open(new_filename, O_WRONLY|O_CREAT, 0666); - - struct stat stat_existing; - fstat(existing_fd, &stat_existing); - - size = sendfile(new_fd, existing_fd, 0, stat_existing.st_size); - - close(new_fd); - close(existing_fd); - - return size == stat_existing.st_size; -#endif -} - -gb_inline b32 gb_file_move(char const *existing_filename, char const *new_filename) { - if (link(existing_filename, new_filename) == 0) { - return unlink(existing_filename) != -1; - } - return false; -} - -b32 gb_file_remove(char const *filename) { -#if defined(GB_SYSTEM_OSX) - return unlink(filename) != -1; -#else - return remove(filename) == 0; -#endif -} - - -#endif - - - - - -gbFileContents gb_file_read_contents(gbAllocator a, b32 zero_terminate, char const *filepath) { - gbFileContents result = {0}; - gbFile file = {0}; - - result.allocator = a; - - if (gb_file_open(&file, filepath) == gbFileError_None) { - isize file_size = cast(isize)gb_file_size(&file); - if (file_size > 0) { - result.data = gb_alloc(a, zero_terminate ? file_size+1 : file_size); - result.size = file_size; - gb_file_read_at(&file, result.data, result.size, 0); - if (zero_terminate) { - u8 *str = cast(u8 *)result.data; - str[file_size] = '\0'; - } - } - gb_file_close(&file); - } - - return result; -} - -void gb_file_free_contents(gbFileContents *fc) { - GB_ASSERT_NOT_NULL(fc->data); - gb_free(fc->allocator, fc->data); - fc->data = NULL; - fc->size = 0; -} - - - - - -gb_inline b32 gb_path_is_absolute(char const *path) { - b32 result = false; - GB_ASSERT_NOT_NULL(path); -#if defined(GB_SYSTEM_WINDOWS) - result == (gb_strlen(path) > 2) && - gb_char_is_alpha(path[0]) && - (path[1] == ':' && path[2] == GB_PATH_SEPARATOR); -#else - result = (gb_strlen(path) > 0 && path[0] == GB_PATH_SEPARATOR); -#endif - return result; -} - -gb_inline b32 gb_path_is_relative(char const *path) { return !gb_path_is_absolute(path); } - -gb_inline b32 gb_path_is_root(char const *path) { - b32 result = false; - GB_ASSERT_NOT_NULL(path); -#if defined(GB_SYSTEM_WINDOWS) - result = gb_path_is_absolute(path) && (gb_strlen(path) == 3); -#else - result = gb_path_is_absolute(path) && (gb_strlen(path) == 1); -#endif - return result; -} - -gb_inline char const *gb_path_base_name(char const *path) { - char const *ls; - GB_ASSERT_NOT_NULL(path); - ls = gb_char_last_occurence(path, '/'); - return (ls == NULL) ? path : ls+1; -} - -gb_inline char const *gb_path_extension(char const *path) { - char const *ld; - GB_ASSERT_NOT_NULL(path); - ld = gb_char_last_occurence(path, '.'); - return (ld == NULL) ? NULL : ld+1; -} - - -#if !defined(_WINDOWS_) && defined(GB_SYSTEM_WINDOWS) -GB_DLL_IMPORT DWORD WINAPI GetFullPathNameA(char const *lpFileName, DWORD nBufferLength, char *lpBuffer, char **lpFilePart); -GB_DLL_IMPORT DWORD WINAPI GetFullPathNameW(wchar_t const *lpFileName, DWORD nBufferLength, wchar_t *lpBuffer, wchar_t **lpFilePart); -#endif - -char *gb_path_get_full_name(gbAllocator a, char const *path) { -#if defined(GB_SYSTEM_WINDOWS) -// TODO(bill): Make UTF-8 - wchar_t *w_path = NULL; - wchar_t *w_fullpath = NULL; - isize w_len = 0; - isize new_len = 0; - isize new_len1 = 0; - char *new_path = 0; - w_path = gb__alloc_utf8_to_ucs2(gb_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 = gb_alloc_array(gb_heap_allocator(), wchar_t, w_len+1); - GetFullPathNameW(w_path, cast(int)w_len, w_fullpath, NULL); - w_fullpath[w_len] = 0; - gb_free(gb_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) { - gb_free(gb_heap_allocator(), w_fullpath); - return NULL; - } - new_path = gb_alloc_array(a, char, new_len+1); - 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) { - gb_free(gb_heap_allocator(), w_fullpath); - gb_free(a, new_path); - return NULL; - } - new_path[new_len] = 0; - return new_path; -#else - char *p, *result, *fullpath = NULL; - isize len; - p = realpath(path, NULL); - fullpath = p; - if (p == NULL) { - // NOTE(bill): File does not exist - fullpath = cast(char *)path; - } - - len = gb_strlen(fullpath); - - result = gb_alloc_array(a, char, len + 1); - gb_memmove(result, fullpath, len); - result[len] = 0; - free(p); - - return result; -#endif -} - - - - - -//////////////////////////////////////////////////////////////// -// -// Printing -// -// - - -isize gb_printf(char const *fmt, ...) { - isize res; - va_list va; - va_start(va, fmt); - res = gb_printf_va(fmt, va); - va_end(va); - return res; -} - - -isize gb_printf_err(char const *fmt, ...) { - isize res; - va_list va; - va_start(va, fmt); - res = gb_printf_err_va(fmt, va); - va_end(va); - return res; -} - -isize gb_fprintf(struct gbFile *f, char const *fmt, ...) { - isize res; - va_list va; - va_start(va, fmt); - res = gb_fprintf_va(f, fmt, va); - va_end(va); - return res; -} - -char *gb_bprintf(char const *fmt, ...) { - va_list va; - char *str; - va_start(va, fmt); - str = gb_bprintf_va(fmt, va); - va_end(va); - return str; -} - -isize gb_snprintf(char *str, isize n, char const *fmt, ...) { - isize res; - va_list va; - va_start(va, fmt); - res = gb_snprintf_va(str, n, fmt, va); - va_end(va); - return res; -} - - - -gb_inline isize gb_printf_va(char const *fmt, va_list va) { - return gb_fprintf_va(gb_file_get_standard(gbFileStandard_Output), fmt, va); -} - -gb_inline isize gb_printf_err_va(char const *fmt, va_list va) { - return gb_fprintf_va(gb_file_get_standard(gbFileStandard_Error), fmt, va); -} - -gb_inline isize gb_fprintf_va(struct gbFile *f, char const *fmt, va_list va) { - gb_local_persist char buf[4096]; - isize len = gb_snprintf_va(buf, gb_size_of(buf), fmt, va); - gb_file_write(f, buf, len-1); // NOTE(bill): prevent extra whitespace - return len; -} - - -gb_inline char *gb_bprintf_va(char const *fmt, va_list va) { - gb_local_persist char buffer[4096]; - gb_snprintf_va(buffer, gb_size_of(buffer), fmt, va); - return buffer; -} - - -enum { - gbFmt_Minus = GB_BIT(0), - gbFmt_Plus = GB_BIT(1), - gbFmt_Alt = GB_BIT(2), - gbFmt_Space = GB_BIT(3), - gbFmt_Zero = GB_BIT(4), - - gbFmt_Char = GB_BIT(5), - gbFmt_Short = GB_BIT(6), - gbFmt_Int = GB_BIT(7), - gbFmt_Long = GB_BIT(8), - gbFmt_Llong = GB_BIT(9), - gbFmt_Size = GB_BIT(10), - gbFmt_Intptr = GB_BIT(11), - - gbFmt_Unsigned = GB_BIT(12), - gbFmt_Lower = GB_BIT(13), - gbFmt_Upper = GB_BIT(14), - - - gbFmt_Done = GB_BIT(30), - - gbFmt_Ints = gbFmt_Char|gbFmt_Short|gbFmt_Int|gbFmt_Long|gbFmt_Llong|gbFmt_Size|gbFmt_Intptr -}; - -typedef struct { - i32 base; - i32 flags; - i32 width; - i32 precision; -} gbprivFmtInfo; - - -gb_internal isize gb__print_string(char *text, isize max_len, gbprivFmtInfo *info, char const *str) { - // TODO(bill): Get precision and width to work correctly. How does it actually work?! - // TODO(bill): This looks very buggy indeed. - isize res = 0, len; - isize remaining = max_len; - - if (info && info->precision >= 0) { - len = gb_strnlen(str, info->precision); - } else { - len = gb_strlen(str); - } - - if (info && (info->width == 0 || info->flags & gbFmt_Minus)) { - if (info->precision > 0) { - len = info->precision < len ? info->precision : len; - } - - res += gb_strlcpy(text, str, len); - - if (info->width > res) { - isize padding = info->width - len; - char pad = (info->flags & gbFmt_Zero) ? '0' : ' '; - while (padding --> 0 && remaining --> 0) { - *text++ = pad, res++; - } - } - } else { - if (info && (info->width > res)) { - isize padding = info->width - len; - char pad = (info->flags & gbFmt_Zero) ? '0' : ' '; - while (padding --> 0 && remaining --> 0) { - *text++ = pad, res++; - } - } - - res += gb_strlcpy(text, str, len); - } - - - if (info) { - if (info->flags & gbFmt_Upper) { - gb_str_to_upper(text); - } else if (info->flags & gbFmt_Lower) { - gb_str_to_lower(text); - } - } - - return res; -} - -gb_internal isize gb__print_char(char *text, isize max_len, gbprivFmtInfo *info, char arg) { - char str[2] = ""; - str[0] = arg; - return gb__print_string(text, max_len, info, str); -} - - -gb_internal isize gb__print_i64(char *text, isize max_len, gbprivFmtInfo *info, i64 value) { - char num[130]; - gb_i64_to_str(value, num, info ? info->base : 10); - return gb__print_string(text, max_len, info, num); -} - -gb_internal isize gb__print_u64(char *text, isize max_len, gbprivFmtInfo *info, u64 value) { - char num[130]; - gb_u64_to_str(value, num, info ? info->base : 10); - return gb__print_string(text, max_len, info, num); -} - - -gb_internal isize gb__print_f64(char *text, isize max_len, gbprivFmtInfo *info, f64 arg) { - // TODO(bill): Handle exponent notation - isize width, len, remaining = max_len; - char *text_begin = text; - - if (arg) { - u64 value; - if (arg < 0) { - if (remaining > 1) { - *text = '-', remaining--; - } - text++; - arg = -arg; - } else if (info->flags & gbFmt_Minus) { - if (remaining > 1) { - *text = '+', remaining--; - } - text++; - } - - value = cast(u64)arg; - len = gb__print_u64(text, remaining, NULL, value); - text += len; - - if (len >= remaining) { - remaining = gb_min(remaining, 1); - } else { - remaining -= len; - } - arg -= value; - - if (info->precision < 0) { - info->precision = 6; - } - - if ((info->flags & gbFmt_Alt) || info->precision > 0) { - i64 mult = 10; - if (remaining > 1) { - *text = '.', remaining--; - } - text++; - while (info->precision-- > 0) { - value = cast(u64)(arg * mult); - len = gb__print_u64(text, remaining, NULL, value); - text += len; - if (len >= remaining) { - remaining = gb_min(remaining, 1); - } else { - remaining -= len; - } - arg -= cast(f64)value / mult; - mult *= 10; - } - } - } else { - if (remaining > 1) { - *text = '0', remaining--; - } - text++; - if (info->flags & gbFmt_Alt) { - if (remaining > 1) { - *text = '.', remaining--; - } - text++; - } - } - - width = info->width - (text - text_begin); - if (width > 0) { - char fill = (info->flags & gbFmt_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 = gb_min(remaining, 1); - } else { - remaining -= len; - } - - while (len--) { - if (text_begin+len < end) { - text_begin[len] = fill; - } - } - } - - return (text - text_begin); -} - - - -gb_no_inline isize gb_snprintf_va(char *text, isize max_len, char const *fmt, va_list va) { - char const *text_begin = text; - isize remaining = max_len, res; - - while (*fmt) { - gbprivFmtInfo info = {0}; - isize len = 0; - info.precision = -1; - - while (*fmt && *fmt != '%' && remaining) { - *text++ = *fmt++; - } - - if (*fmt == '%') { - do { - switch (*++fmt) { - case '-': info.flags |= gbFmt_Minus; break; - case '+': info.flags |= gbFmt_Plus; break; - case '#': info.flags |= gbFmt_Alt; break; - case ' ': info.flags |= gbFmt_Space; break; - case '0': info.flags |= gbFmt_Zero; break; - default: info.flags |= gbFmt_Done; break; - } - } while (!(info.flags & gbFmt_Done)); - } - - // NOTE(bill): Optional Width - if (*fmt == '*') { - int width = va_arg(va, int); - if (width < 0) { - info.flags |= gbFmt_Minus; - info.width = -width; - } else { - info.width = width; - } - fmt++; - } else { - info.width = cast(i32)gb_str_to_i64(fmt, cast(char **)&fmt, 10); - } - - // NOTE(bill): Optional Precision - if (*fmt == '.') { - fmt++; - if (*fmt == '*') { - info.precision = va_arg(va, int); - fmt++; - } else { - info.precision = cast(i32)gb_str_to_i64(fmt, cast(char **)&fmt, 10); - } - info.flags &= ~gbFmt_Zero; - } - - - switch (*fmt++) { - case 'h': - if (*fmt == 'h') { // hh => char - info.flags |= gbFmt_Char; - fmt++; - } else { // h => short - info.flags |= gbFmt_Short; - } - break; - - case 'l': - if (*fmt == 'l') { // ll => long long - info.flags |= gbFmt_Llong; - fmt++; - } else { // l => long - info.flags |= gbFmt_Long; - } - break; - - break; - - case 'z': // NOTE(bill): usize - info.flags |= gbFmt_Unsigned; - // fallthrough - case 't': // NOTE(bill): isize - info.flags |= gbFmt_Size; - break; - - default: fmt--; break; - } - - - switch (*fmt) { - case 'u': - info.flags |= gbFmt_Unsigned; - // fallthrough - case 'd': - case 'i': - info.base = 10; - break; - - case 'o': - info.base = 8; - break; - - case 'x': - info.base = 16; - info.flags |= (gbFmt_Unsigned | gbFmt_Lower); - break; - - case 'X': - info.base = 16; - info.flags |= (gbFmt_Unsigned | gbFmt_Upper); - break; - - case 'f': - case 'F': - case 'g': - case 'G': - len = gb__print_f64(text, remaining, &info, va_arg(va, f64)); - break; - - case 'a': - case 'A': - // TODO(bill): - break; - - case 'c': - len = gb__print_char(text, remaining, &info, cast(char)va_arg(va, int)); - break; - - case 's': - len = gb__print_string(text, remaining, &info, va_arg(va, char *)); - break; - - case 'p': - info.base = 16; - info.flags |= (gbFmt_Lower|gbFmt_Unsigned|gbFmt_Alt|gbFmt_Intptr); - break; - - case '%': - len = gb__print_char(text, remaining, &info, '%'); - break; - - default: fmt--; break; - } - - fmt++; - - if (info.base != 0) { - if (info.flags & gbFmt_Unsigned) { - u64 value = 0; - switch (info.flags & gbFmt_Ints) { - case gbFmt_Char: value = cast(u64)cast(u8) va_arg(va, int); break; - case gbFmt_Short: value = cast(u64)cast(u16)va_arg(va, int); break; - case gbFmt_Long: value = cast(u64)va_arg(va, unsigned long); break; - case gbFmt_Llong: value = cast(u64)va_arg(va, unsigned long long); break; - case gbFmt_Size: value = cast(u64)va_arg(va, usize); break; - case gbFmt_Intptr: value = cast(u64)va_arg(va, uintptr); break; - default: value = cast(u64)va_arg(va, unsigned int); break; - } - - len = gb__print_u64(text, remaining, &info, value); - - } else { - i64 value = 0; - switch (info.flags & gbFmt_Ints) { - case gbFmt_Char: value = cast(i64)cast(i8) va_arg(va, int); break; - case gbFmt_Short: value = cast(i64)cast(i16)va_arg(va, int); break; - case gbFmt_Long: value = cast(i64)va_arg(va, long); break; - case gbFmt_Llong: value = cast(i64)va_arg(va, long long); break; - case gbFmt_Size: value = cast(i64)va_arg(va, usize); break; - case gbFmt_Intptr: value = cast(i64)va_arg(va, uintptr); break; - default: value = cast(i64)va_arg(va, int); break; - } - - len = gb__print_i64(text, remaining, &info, value); - } - } - - - text += len; - if (len >= remaining) { - remaining = gb_min(remaining, 1); - } else { - remaining -= len; - } - } - - *text++ = '\0'; - res = (text - text_begin); - return (res >= max_len || res < 0) ? -1 : res; -} - - -//////////////////////////////////////////////////////////////// -// -// DLL Handling -// -// - -#if defined(GB_SYSTEM_WINDOWS) - -gbDllHandle gb_dll_load(char const *filepath) { - return cast(gbDllHandle)LoadLibraryA(filepath); -} -gb_inline void gb_dll_unload (gbDllHandle dll) { FreeLibrary(cast(HMODULE)dll); } -gb_inline gbDllProc gb_dll_proc_address(gbDllHandle dll, char const *proc_name) { return cast(gbDllProc)GetProcAddress(cast(HMODULE)dll, proc_name); } - -#else // POSIX - -gbDllHandle gb_dll_load(char const *filepath) { - // TODO(bill): Should this be RTLD_LOCAL? - return cast(gbDllHandle)dlopen(filepath, RTLD_LAZY|RTLD_GLOBAL); -} - -gb_inline void gb_dll_unload (gbDllHandle dll) { dlclose(dll); } -gb_inline gbDllProc gb_dll_proc_address(gbDllHandle dll, char const *proc_name) { return cast(gbDllProc)dlsym(dll, proc_name); } - -#endif - - -//////////////////////////////////////////////////////////////// -// -// Time -// -// - -#if defined(GB_COMPILER_MSVC) && !defined(__clang__) - gb_inline u64 gb_rdtsc(void) { return __rdtsc(); } -#elif defined(__i386__) - gb_inline u64 gb_rdtsc(void) { - u64 x; - __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x)); - return x; - } -#elif defined(__x86_64__) - gb_inline u64 gb_rdtsc(void) { - u32 hi, lo; - __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi)); - return (cast(u64)lo) | ((cast(u64)hi)<<32); - } -#elif defined(__powerpc__) - gb_inline u64 gb_rdtsc(void) { - u64 result = 0; - 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; - } -#endif - -#if defined(GB_SYSTEM_WINDOWS) - - gb_inline f64 gb_time_now(void) { - gb_local_persist LARGE_INTEGER win32_perf_count_freq = {0}; - f64 result; - LARGE_INTEGER counter; - if (!win32_perf_count_freq.QuadPart) { - QueryPerformanceFrequency(&win32_perf_count_freq); - GB_ASSERT(win32_perf_count_freq.QuadPart != 0); - } - - QueryPerformanceCounter(&counter); - - result = counter.QuadPart / cast(f64)(win32_perf_count_freq.QuadPart); - return result; - } - - gb_inline u64 gb_utc_time_now(void) { - FILETIME ft; - ULARGE_INTEGER li; - - GetSystemTimeAsFileTime(&ft); - li.LowPart = ft.dwLowDateTime; - li.HighPart = ft.dwHighDateTime; - - return li.QuadPart/10; - } - - gb_inline void gb_sleep_ms(u32 ms) { Sleep(ms); } - -#else - - gb_global f64 gb__timebase = 0.0; - gb_global u64 gb__timestart = 0; - - gb_inline f64 gb_time_now(void) { -#if defined(GB_SYSTEM_OSX) - f64 result; - - if (!gb__timestart) { - mach_timebase_info_data_t tb = {0}; - mach_timebase_info(&tb); - gb__timebase = tb.numer; - gb__timebase /= tb.denom; - gb__timestart = mach_absolute_time(); - } - - // NOTE(bill): mach_absolute_time() returns things in nanoseconds - result = 1.0e-9 * (mach_absolute_time() - gb__timestart) * gb__timebase; - return result; -#else - struct timespec t; - f64 result; - - // IMPORTANT TODO(bill): THIS IS A HACK - clock_gettime(1 /*CLOCK_MONOTONIC*/, &t); - result = t.tv_sec + 1.0e-9 * t.tv_nsec; - return result; -#endif - } - - gb_inline u64 gb_utc_time_now(void) { - struct timespec t; -#if defined(GB_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 - // IMPORTANT TODO(bill): THIS IS A HACK - clock_gettime(0 /*CLOCK_REALTIME*/, &t); -#endif - return cast(u64)t.tv_sec * 1000000ull + t.tv_nsec/1000 + 11644473600000000ull; - } - - gb_inline void gb_sleep_ms(u32 ms) { - struct timespec req = {cast(time_t)ms/1000, cast(long)((ms%1000)*1000000)}; - struct timespec rem = {0, 0}; - nanosleep(&req, &rem); - } - -#endif - - - -//////////////////////////////////////////////////////////////// -// -// Miscellany -// -// - -gb_global gbAtomic32 gb__random_shared_counter = {0}; - -gb_internal u32 gb__get_noise_from_time(void) { - u32 accum = 0; - f64 start, remaining, end, curr = 0; - u64 interval = 100000ll; - - start = gb_time_now(); - remaining = (interval - cast(u64)(interval*start)%interval) / cast(f64)interval; - end = start + remaining; - - do { - curr = gb_time_now(); - accum += cast(u32)curr; - } while (curr >= end); - return accum; -} - -// NOTE(bill): Partly from http://preshing.com/20121224/how-to-generate-a-sequence-of-unique-random-integers/ -// But the generation is even more random-er-est - -gb_internal gb_inline u32 gb__permute_qpr(u32 x) { - gb_local_persist u32 const prime = 4294967291; // 2^32 - 5 - if (x >= prime) { - return x; - } else { - u32 residue = cast(u32)(cast(u64) x * x) % prime; - if (x <= prime / 2) { - return residue; - } else { - return prime - residue; - } - } -} - -gb_internal gb_inline u32 gb__permute_with_offset(u32 x, u32 offset) { - return (gb__permute_qpr(x) + offset) ^ 0x5bf03635; -} - - -void gb_random_init(gbRandom *r) { - u64 time, tick; - isize i, j; - u32 x = 0; - r->value = 0; - - r->offsets[0] = gb__get_noise_from_time(); - r->offsets[1] = gb_atomic32_fetch_add(&gb__random_shared_counter, 1); - r->offsets[2] = gb_thread_current_id(); - r->offsets[3] = gb_thread_current_id() * 3 + 1; - time = gb_utc_time_now(); - r->offsets[4] = cast(u32)(time >> 32); - r->offsets[5] = cast(u32)time; - r->offsets[6] = gb__get_noise_from_time(); - tick = gb_rdtsc(); - r->offsets[7] = cast(u32)(tick ^ (tick >> 32)); - - for (j = 0; j < 4; j++) { - for (i = 0; i < gb_count_of(r->offsets); i++) { - r->offsets[i] = x = gb__permute_with_offset(x, r->offsets[i]); - } - } -} - -u32 gb_random_gen_u32(gbRandom *r) { - u32 x = r->value; - u32 carry = 1; - isize i; - for (i = 0; i < gb_count_of(r->offsets); i++) { - x = gb__permute_with_offset(x, r->offsets[i]); - if (carry > 0) { - carry = ++r->offsets[i] ? 0 : 1; - } - } - - r->value = x; - return x; -} - -u32 gb_random_gen_u32_unique(gbRandom *r) { - u32 x = r->value; - isize i; - r->value++; - for (i = 0; i < gb_count_of(r->offsets); i++) { - x = gb__permute_with_offset(x, r->offsets[i]); - } - - return x; -} - -u64 gb_random_gen_u64(gbRandom *r) { - return ((cast(u64)gb_random_gen_u32(r)) << 32) | gb_random_gen_u32(r); -} - - -isize gb_random_gen_isize(gbRandom *r) { - u64 u = gb_random_gen_u64(r); - return *cast(isize *)&u; -} - - - - -i64 gb_random_range_i64(gbRandom *r, i64 lower_inc, i64 higher_inc) { - u64 u = gb_random_gen_u64(r); - i64 i = *cast(i64 *)&u; - i64 diff = higher_inc-lower_inc+1; - i %= diff; - i += lower_inc; - return i; -} - -isize gb_random_range_isize(gbRandom *r, isize lower_inc, isize higher_inc) { - u64 u = gb_random_gen_u64(r); - isize i = *cast(isize *)&u; - isize diff = higher_inc-lower_inc+1; - i %= diff; - i += lower_inc; - return i; -} - -// NOTE(bill): Semi-cc'ed from gb_math to remove need for fmod and math.h -f64 gb__copy_sign64(f64 x, f64 y) { - i64 ix, iy; - ix = *(i64 *)&x; - iy = *(i64 *)&y; - - ix &= 0x7fffffffffffffff; - ix |= iy & 0x8000000000000000; - return *cast(f64 *)&ix; -} - -f64 gb__floor64 (f64 x) { return cast(f64)((x >= 0.0) ? cast(i64)x : cast(i64)(x-0.9999999999999999)); } -f64 gb__ceil64 (f64 x) { return cast(f64)((x < 0) ? cast(i64)x : (cast(i64)x)+1); } -f64 gb__round64 (f64 x) { return cast(f64)((x >= 0.0) ? gb__floor64(x + 0.5) : gb__ceil64(x - 0.5)); } -f64 gb__remainder64(f64 x, f64 y) { return x - (gb__round64(x/y)*y); } -f64 gb__abs64 (f64 x) { return x < 0 ? -x : x; } -f64 gb__sign64 (f64 x) { return x < 0 ? -1.0 : +1.0; } - -f64 gb__mod64(f64 x, f64 y) { - f64 result; - y = gb__abs64(y); - result = gb__remainder64(gb__abs64(x), y); - if (gb__sign64(result)) result += y; - return gb__copy_sign64(result, x); -} - - -f64 gb_random_range_f64(gbRandom *r, f64 lower_inc, f64 higher_inc) { - u64 u = gb_random_gen_u64(r); - f64 f = *cast(f64 *)&u; - f64 diff = higher_inc-lower_inc+1.0; - f = gb__mod64(f, diff); - f += lower_inc; - return f; -} - - - -#if defined(GB_SYSTEM_WINDOWS) -gb_inline void gb_exit(u32 code) { ExitProcess(code); } -#else -gb_inline void gb_exit(u32 code) { exit(code); } -#endif - -gb_inline void gb_yield(void) { -#if defined(GB_SYSTEM_WINDOWS) - Sleep(0); -#else - sched_yield(); -#endif -} - -gb_inline void gb_set_env(char const *name, char const *value) { -#if defined(GB_SYSTEM_WINDOWS) - // TODO(bill): Should this be a Wide version? - SetEnvironmentVariableA(name, value); -#else - setenv(name, value, 1); -#endif -} - -gb_inline void gb_unset_env(char const *name) { -#if defined(GB_SYSTEM_WINDOWS) - // TODO(bill): Should this be a Wide version? - SetEnvironmentVariableA(name, NULL); -#else - unsetenv(name); -#endif -} - - -gb_inline u16 gb_endian_swap16(u16 i) { - return (i>>8) | (i<<8); -} - -gb_inline u32 gb_endian_swap32(u32 i) { - return (i>>24) |(i<<24) | - ((i&0x00ff0000u)>>8) | ((i&0x0000ff00u)<<8); -} - -gb_inline u64 gb_endian_swap64(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); -} - - -gb_inline isize gb_count_set_bits(u64 mask) { - isize count = 0; - while (mask) { - count += (mask & 1); - mask >>= 1; - } - return count; -} - - - - - - -//////////////////////////////////////////////////////////////// -// -// Platform -// -// - -#if defined(GB_PLATFORM) - -gb_inline void gb_key_state_update(gbKeyState *s, b32 is_down) { - b32 was_down = (*s & gbKeyState_Down) != 0; - is_down = is_down != 0; // NOTE(bill): Make sure it's a boolean - GB_MASK_SET(*s, is_down, gbKeyState_Down); - GB_MASK_SET(*s, !was_down && is_down, gbKeyState_Pressed); - GB_MASK_SET(*s, was_down && !is_down, gbKeyState_Released); -} - -#if defined(GB_SYSTEM_WINDOWS) - -#ifndef ERROR_DEVICE_NOT_CONNECTED -#define ERROR_DEVICE_NOT_CONNECTED 1167 -#endif - -GB_XINPUT_GET_STATE(gbXInputGetState_Stub) { - gb_unused(dwUserIndex); gb_unused(pState); - return ERROR_DEVICE_NOT_CONNECTED; -} -GB_XINPUT_SET_STATE(gbXInputSetState_Stub) { - gb_unused(dwUserIndex); gb_unused(pVibration); - return ERROR_DEVICE_NOT_CONNECTED; -} - - -gb_internal gb_inline f32 gb__process_xinput_stick_value(i16 value, i16 dead_zone_threshold) { - f32 result = 0; - - if (value < -dead_zone_threshold) { - result = cast(f32) (value + dead_zone_threshold) / (32768.0f - dead_zone_threshold); - } else if (value > dead_zone_threshold) { - result = cast(f32) (value - dead_zone_threshold) / (32767.0f - dead_zone_threshold); - } - - return result; -} - -gb_internal void gb__platform_resize_dib_section(gbPlatform *p, i32 width, i32 height) { - if ((p->renderer_type == gbRenderer_Software) && - !(p->window_width == width && p->window_height == height)) { - BITMAPINFO bmi = {0}; - - if (width == 0 || height == 0) { - return; - } - - p->window_width = width; - p->window_height = height; - - // TODO(bill): Is this slow to get the desktop mode everytime? - p->sw_framebuffer.bits_per_pixel = gb_video_mode_get_desktop().bits_per_pixel; - p->sw_framebuffer.pitch = (p->sw_framebuffer.bits_per_pixel * width / 8); - - bmi.bmiHeader.biSize = gb_size_of(bmi.bmiHeader); - bmi.bmiHeader.biWidth = width; - bmi.bmiHeader.biHeight = height; // NOTE(bill): -ve is top-down, +ve is bottom-up - bmi.bmiHeader.biPlanes = 1; - bmi.bmiHeader.biBitCount = cast(u16)p->sw_framebuffer.bits_per_pixel; - bmi.bmiHeader.biCompression = 0 /*BI_RGB*/; - - p->sw_framebuffer.win32_bmi = bmi; - - - if (p->sw_framebuffer.memory) { - gb_vm_free(gb_virtual_memory(p->sw_framebuffer.memory, p->sw_framebuffer.memory_size)); - } - - { - isize memory_size = p->sw_framebuffer.pitch * height; - gbVirtualMemory vm = gb_vm_alloc(0, memory_size); - p->sw_framebuffer.memory = vm.data; - p->sw_framebuffer.memory_size = vm.size; - } - } -} - - -gb_internal gbKeyType gb__win32_from_vk(unsigned int key) { - // NOTE(bill): Letters and numbers are defined the same for VK_* and GB_* - if (key >= 'A' && key < 'Z') return cast(gbKeyType)key; - if (key >= '0' && key < '9') return cast(gbKeyType)key; - switch (key) { - case VK_ESCAPE: return gbKey_Escape; - - case VK_LCONTROL: return gbKey_Lcontrol; - case VK_LSHIFT: return gbKey_Lshift; - case VK_LMENU: return gbKey_Lalt; - case VK_LWIN: return gbKey_Lsystem; - case VK_RCONTROL: return gbKey_Rcontrol; - case VK_RSHIFT: return gbKey_Rshift; - case VK_RMENU: return gbKey_Ralt; - case VK_RWIN: return gbKey_Rsystem; - case VK_MENU: return gbKey_Menu; - - case VK_OEM_4: return gbKey_Lbracket; - case VK_OEM_6: return gbKey_Rbracket; - case VK_OEM_1: return gbKey_Semicolon; - case VK_OEM_COMMA: return gbKey_Comma; - case VK_OEM_PERIOD: return gbKey_Period; - case VK_OEM_7: return gbKey_Quote; - case VK_OEM_2: return gbKey_Slash; - case VK_OEM_5: return gbKey_Backslash; - case VK_OEM_3: return gbKey_Grave; - case VK_OEM_PLUS: return gbKey_Equals; - case VK_OEM_MINUS: return gbKey_Minus; - - case VK_SPACE: return gbKey_Space; - case VK_RETURN: return gbKey_Return; - case VK_BACK: return gbKey_Backspace; - case VK_TAB: return gbKey_Tab; - - case VK_PRIOR: return gbKey_Pageup; - case VK_NEXT: return gbKey_Pagedown; - case VK_END: return gbKey_End; - case VK_HOME: return gbKey_Home; - case VK_INSERT: return gbKey_Insert; - case VK_DELETE: return gbKey_Delete; - - case VK_ADD: return gbKey_Plus; - case VK_SUBTRACT: return gbKey_Subtract; - case VK_MULTIPLY: return gbKey_Multiply; - case VK_DIVIDE: return gbKey_Divide; - - case VK_LEFT: return gbKey_Left; - case VK_RIGHT: return gbKey_Right; - case VK_UP: return gbKey_Up; - case VK_DOWN: return gbKey_Down; - - case VK_NUMPAD0: return gbKey_Numpad0; - case VK_NUMPAD1: return gbKey_Numpad1; - case VK_NUMPAD2: return gbKey_Numpad2; - case VK_NUMPAD3: return gbKey_Numpad3; - case VK_NUMPAD4: return gbKey_Numpad4; - case VK_NUMPAD5: return gbKey_Numpad5; - case VK_NUMPAD6: return gbKey_Numpad6; - case VK_NUMPAD7: return gbKey_Numpad7; - case VK_NUMPAD8: return gbKey_Numpad8; - case VK_NUMPAD9: return gbKey_Numpad9; - case VK_SEPARATOR: return gbKey_NumpadEnter; - case VK_DECIMAL: return gbKey_NumpadDot; - - case VK_F1: return gbKey_F1; - case VK_F2: return gbKey_F2; - case VK_F3: return gbKey_F3; - case VK_F4: return gbKey_F4; - case VK_F5: return gbKey_F5; - case VK_F6: return gbKey_F6; - case VK_F7: return gbKey_F7; - case VK_F8: return gbKey_F8; - case VK_F9: return gbKey_F9; - case VK_F10: return gbKey_F10; - case VK_F11: return gbKey_F11; - case VK_F12: return gbKey_F12; - case VK_F13: return gbKey_F13; - case VK_F14: return gbKey_F14; - case VK_F15: return gbKey_F15; - - case VK_PAUSE: return gbKey_Pause; - } - return gbKey_Unknown; -} -LRESULT CALLBACK gb__win32_window_callback(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { - // NOTE(bill): Silly callbacks - gbPlatform *platform = cast(gbPlatform *)GetWindowLongPtrW(hWnd, GWLP_USERDATA); - b32 window_has_focus = (platform != NULL) && platform->window_has_focus; - - if (msg == WM_CREATE) { // NOTE(bill): Doesn't need the platform - // NOTE(bill): https://msdn.microsoft.com/en-us/library/windows/desktop/ms645536(v=vs.85).aspx - RAWINPUTDEVICE rid[2] = {0}; - - // NOTE(bill): Keyboard - rid[0].usUsagePage = 0x01; - rid[0].usUsage = 0x06; - rid[0].dwFlags = 0x00000030/*RIDEV_NOLEGACY*/; // NOTE(bill): Do not generate legacy messages such as WM_KEYDOWN - rid[0].hwndTarget = hWnd; - - // NOTE(bill): Mouse - rid[1].usUsagePage = 0x01; - rid[1].usUsage = 0x02; - rid[1].dwFlags = 0; // NOTE(bill): adds HID mouse and also allows legacy mouse messages to allow for window movement etc. - rid[1].hwndTarget = hWnd; - - if (RegisterRawInputDevices(rid, gb_count_of(rid), gb_size_of(rid[0])) == false) { - DWORD err = GetLastError(); - GB_PANIC("Failed to initialize raw input device for win32." - "Err: %u", err); - } - } - - if (!platform) { - return DefWindowProcW(hWnd, msg, wParam, lParam); - } - - switch (msg) { - case WM_CLOSE: - case WM_DESTROY: - platform->window_is_closed = true; - return 0; - - case WM_QUIT: { - platform->quit_requested = true; - } break; - - case WM_UNICHAR: { - if (window_has_focus) { - if (wParam == '\r') { - wParam = '\n'; - } - // TODO(bill): Does this need to be thread-safe? - platform->char_buffer[platform->char_buffer_count++] = cast(Rune)wParam; - } - } break; - - - case WM_INPUT: { - RAWINPUT raw = {0}; - unsigned int size = gb_size_of(RAWINPUT); - - if (!GetRawInputData(cast(HRAWINPUT)lParam, RID_INPUT, &raw, &size, gb_size_of(RAWINPUTHEADER))) { - return 0; - } - switch (raw.header.dwType) { - case RIM_TYPEKEYBOARD: { - // NOTE(bill): Many thanks to https://blog.molecular-matters.com/2011/09/05/properly-handling-keyboard-input/ - // for the - RAWKEYBOARD *raw_kb = &raw.data.keyboard; - unsigned int vk = raw_kb->VKey; - unsigned int scan_code = raw_kb->MakeCode; - unsigned int flags = raw_kb->Flags; - // NOTE(bill): e0 and e1 are escape sequences used for certain special keys, such as PRINT and PAUSE/BREAK. - // NOTE(bill): http://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.html - b32 is_e0 = (flags & RI_KEY_E0) != 0; - b32 is_e1 = (flags & RI_KEY_E1) != 0; - b32 is_up = (flags & RI_KEY_BREAK) != 0; - b32 is_down = !is_up; - - // TODO(bill): Should I handle scan codes? - - if (vk == 255) { - // NOTE(bill): Discard "fake keys" - return 0; - } else if (vk == VK_SHIFT) { - // NOTE(bill): Correct left/right shift - vk = MapVirtualKeyW(scan_code, MAPVK_VSC_TO_VK_EX); - } else if (vk == VK_NUMLOCK) { - // NOTE(bill): Correct PAUSE/BREAK and NUM LOCK and set the extended bit - scan_code = MapVirtualKeyW(vk, MAPVK_VK_TO_VSC) | 0x100; - } - - if (is_e1) { - // NOTE(bill): Escaped sequences, turn vk into the correct scan code - // except for VK_PAUSE (it's a bug) - if (vk == VK_PAUSE) { - scan_code = 0x45; - } else { - scan_code = MapVirtualKeyW(vk, MAPVK_VK_TO_VSC); - } - } - - switch (vk) { - case VK_CONTROL: vk = (is_e0) ? VK_RCONTROL : VK_LCONTROL; break; - case VK_MENU: vk = (is_e0) ? VK_RMENU : VK_LMENU; break; - - case VK_RETURN: if (is_e0) vk = VK_SEPARATOR; break; // NOTE(bill): Numpad return - case VK_DELETE: if (!is_e0) vk = VK_DECIMAL; break; // NOTE(bill): Numpad dot - case VK_INSERT: if (!is_e0) vk = VK_NUMPAD0; break; - case VK_HOME: if (!is_e0) vk = VK_NUMPAD7; break; - case VK_END: if (!is_e0) vk = VK_NUMPAD1; break; - case VK_PRIOR: if (!is_e0) vk = VK_NUMPAD9; break; - case VK_NEXT: if (!is_e0) vk = VK_NUMPAD3; break; - - // NOTE(bill): The standard arrow keys will always have their e0 bit set, but the - // corresponding keys on the NUMPAD will not. - case VK_LEFT: if (!is_e0) vk = VK_NUMPAD4; break; - case VK_RIGHT: if (!is_e0) vk = VK_NUMPAD6; break; - case VK_UP: if (!is_e0) vk = VK_NUMPAD8; break; - case VK_DOWN: if (!is_e0) vk = VK_NUMPAD2; break; - - // NUMPAD 5 doesn't have its e0 bit set - case VK_CLEAR: if (!is_e0) vk = VK_NUMPAD5; break; - } - - // NOTE(bill): Set appropriate key state flags - gb_key_state_update(&platform->keys[gb__win32_from_vk(vk)], is_down); - - } break; - case RIM_TYPEMOUSE: { - RAWMOUSE *raw_mouse = &raw.data.mouse; - u16 flags = raw_mouse->usButtonFlags; - long dx = +raw_mouse->lLastX; - long dy = -raw_mouse->lLastY; - - if (flags & RI_MOUSE_WHEEL) { - platform->mouse_wheel_delta = cast(i16)raw_mouse->usButtonData; - } - - platform->mouse_raw_dx = dx; - platform->mouse_raw_dy = dy; - } break; - } - } break; - - default: break; - } - - return DefWindowProcW(hWnd, msg, wParam, lParam); -} - - -typedef void *wglCreateContextAttribsARB_Proc(void *hDC, void *hshareContext, int const *attribList); - - -b32 gb__platform_init(gbPlatform *p, char const *window_title, gbVideoMode mode, gbRendererType type, u32 window_flags) { - WNDCLASSEXW wc = {gb_size_of(WNDCLASSEXW)}; - DWORD ex_style = 0, style = 0; - RECT wr; - u16 title_buffer[256] = {0}; // TODO(bill): gb_local_persist this? - - wc.style = CS_HREDRAW | CS_VREDRAW; // | CS_OWNDC - wc.lpfnWndProc = gb__win32_window_callback; - wc.hbrBackground = cast(HBRUSH)GetStockObject(0/*WHITE_BRUSH*/); - wc.lpszMenuName = NULL; - wc.lpszClassName = L"gb-win32-wndclass"; // TODO(bill): Is this enough? - wc.hInstance = GetModuleHandleW(NULL); - - if (RegisterClassExW(&wc) == 0) { - MessageBoxW(NULL, L"Failed to register the window class", L"ERROR", MB_OK | MB_ICONEXCLAMATION); - return false; - } - - if ((window_flags & gbWindow_Fullscreen) && !(window_flags & gbWindow_Borderless)) { - DEVMODEW screen_settings = {gb_size_of(DEVMODEW)}; - screen_settings.dmPelsWidth = mode.width; - screen_settings.dmPelsHeight = mode.height; - screen_settings.dmBitsPerPel = mode.bits_per_pixel; - screen_settings.dmFields = DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT; - - if (ChangeDisplaySettingsW(&screen_settings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) { - if (MessageBoxW(NULL, L"The requested fullscreen mode is not supported by\n" - L"your video card. Use windowed mode instead?", - L"", - MB_YESNO|MB_ICONEXCLAMATION) == IDYES) { - window_flags &= ~gbWindow_Fullscreen; - } else { - mode = gb_video_mode_get_desktop(); - screen_settings.dmPelsWidth = mode.width; - screen_settings.dmPelsHeight = mode.height; - screen_settings.dmBitsPerPel = mode.bits_per_pixel; - ChangeDisplaySettingsW(&screen_settings, CDS_FULLSCREEN); - } - } - } - - - // ex_style = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; - // style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE | WS_THICKFRAME | WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX; - - style |= WS_VISIBLE; - - if (window_flags & gbWindow_Hidden) style &= ~WS_VISIBLE; - if (window_flags & gbWindow_Resizable) style |= WS_THICKFRAME | WS_MAXIMIZEBOX; - if (window_flags & gbWindow_Maximized) style |= WS_MAXIMIZE; - if (window_flags & gbWindow_Minimized) style |= WS_MINIMIZE; - - // NOTE(bill): Completely ignore the given mode and just change it - if (window_flags & gbWindow_FullscreenDesktop) { - mode = gb_video_mode_get_desktop(); - } - - if ((window_flags & gbWindow_Fullscreen) || (window_flags & gbWindow_Borderless)) { - style |= WS_POPUP; - } else { - style |= WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX; - } - - - wr.left = 0; - wr.top = 0; - wr.right = mode.width; - wr.bottom = mode.height; - AdjustWindowRect(&wr, style, false); - - p->window_flags = window_flags; - p->window_handle = CreateWindowExW(ex_style, - wc.lpszClassName, - cast(wchar_t const *)gb_utf8_to_ucs2(title_buffer, gb_size_of(title_buffer), window_title), - style, - CW_USEDEFAULT, CW_USEDEFAULT, - wr.right - wr.left, wr.bottom - wr.top, - 0, 0, - GetModuleHandleW(NULL), - NULL); - - if (!p->window_handle) { - MessageBoxW(NULL, L"Window creation failed", L"Error", MB_OK|MB_ICONEXCLAMATION); - return false; - } - - p->win32_dc = GetDC(cast(HWND)p->window_handle); - - p->renderer_type = type; - switch (p->renderer_type) { - case gbRenderer_Opengl: { - wglCreateContextAttribsARB_Proc *wglCreateContextAttribsARB; - i32 attribs[8] = {0}; - isize c = 0; - - PIXELFORMATDESCRIPTOR pfd = {gb_size_of(PIXELFORMATDESCRIPTOR)}; - pfd.nVersion = 1; - pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; - pfd.iPixelType = PFD_TYPE_RGBA; - pfd.cColorBits = 32; - pfd.cAlphaBits = 8; - pfd.cDepthBits = 24; - pfd.cStencilBits = 8; - pfd.iLayerType = PFD_MAIN_PLANE; - - SetPixelFormat(cast(HDC)p->win32_dc, ChoosePixelFormat(cast(HDC)p->win32_dc, &pfd), NULL); - p->opengl.context = cast(void *)wglCreateContext(cast(HDC)p->win32_dc); - wglMakeCurrent(cast(HDC)p->win32_dc, cast(HGLRC)p->opengl.context); - - if (p->opengl.major > 0) { - attribs[c++] = 0x2091; // WGL_CONTEXT_MAJOR_VERSION_ARB - attribs[c++] = gb_max(p->opengl.major, 1); - } - if (p->opengl.major > 0 && p->opengl.minor >= 0) { - attribs[c++] = 0x2092; // WGL_CONTEXT_MINOR_VERSION_ARB - attribs[c++] = gb_max(p->opengl.minor, 0); - } - - if (p->opengl.core) { - attribs[c++] = 0x9126; // WGL_CONTEXT_PROFILE_MASK_ARB - attribs[c++] = 0x0001; // WGL_CONTEXT_CORE_PROFILE_BIT_ARB - } else if (p->opengl.compatible) { - attribs[c++] = 0x9126; // WGL_CONTEXT_PROFILE_MASK_ARB - attribs[c++] = 0x0002; // WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB - } - attribs[c++] = 0; // NOTE(bill): tells the proc that this is the end of attribs - - wglCreateContextAttribsARB = cast(wglCreateContextAttribsARB_Proc *)wglGetProcAddress("wglCreateContextAttribsARB"); - if (wglCreateContextAttribsARB) { - HGLRC rc = cast(HGLRC)wglCreateContextAttribsARB(p->win32_dc, 0, attribs); - if (rc && wglMakeCurrent(cast(HDC)p->win32_dc, rc)) { - p->opengl.context = rc; - } else { - // TODO(bill): Handle errors from GetLastError - // ERROR_INVALID_VERSION_ARB 0x2095 - // ERROR_INVALID_PROFILE_ARB 0x2096 - } - } - - } break; - - case gbRenderer_Software: - gb__platform_resize_dib_section(p, mode.width, mode.height); - break; - - default: - GB_PANIC("Unknown window type"); - break; - } - - SetForegroundWindow(cast(HWND)p->window_handle); - SetFocus(cast(HWND)p->window_handle); - SetWindowLongPtrW(cast(HWND)p->window_handle, GWLP_USERDATA, cast(LONG_PTR)p); - - p->window_width = mode.width; - p->window_height = mode.height; - - if (p->renderer_type == gbRenderer_Opengl) { - p->opengl.dll_handle = gb_dll_load("opengl32.dll"); - } - - { // Load XInput - // TODO(bill): What other dlls should I look for? - gbDllHandle xinput_library = gb_dll_load("xinput1_4.dll"); - p->xinput.get_state = gbXInputGetState_Stub; - p->xinput.set_state = gbXInputSetState_Stub; - - if (!xinput_library) xinput_library = gb_dll_load("xinput9_1_0.dll"); - if (!xinput_library) xinput_library = gb_dll_load("xinput1_3.dll"); - if (!xinput_library) { - // TODO(bill): Proper Diagnostic - gb_printf_err("XInput could not be loaded. Controllers will not work!\n"); - } else { - p->xinput.get_state = cast(gbXInputGetStateProc *)gb_dll_proc_address(xinput_library, "XInputGetState"); - p->xinput.set_state = cast(gbXInputSetStateProc *)gb_dll_proc_address(xinput_library, "XInputSetState"); - } - } - - // Init keys - gb_zero_array(p->keys, gb_count_of(p->keys)); - - p->is_initialized = true; - return true; -} - -gb_inline b32 gb_platform_init_with_software(gbPlatform *p, char const *window_title, - i32 width, i32 height, u32 window_flags) { - gbVideoMode mode; - mode.width = width; - mode.height = height; - mode.bits_per_pixel = 32; - return gb__platform_init(p, window_title, mode, gbRenderer_Software, window_flags); -} - -gb_inline b32 gb_platform_init_with_opengl(gbPlatform *p, char const *window_title, - i32 width, i32 height, u32 window_flags, i32 major, i32 minor, b32 core, b32 compatible) { - gbVideoMode mode; - mode.width = width; - mode.height = height; - mode.bits_per_pixel = 32; - p->opengl.major = major; - p->opengl.minor = minor; - p->opengl.core = cast(b16)core; - p->opengl.compatible = cast(b16)compatible; - return gb__platform_init(p, window_title, mode, gbRenderer_Opengl, window_flags); -} - -#ifndef _XINPUT_H_ -typedef struct _XINPUT_GAMEPAD { - u16 wButtons; - u8 bLeftTrigger; - u8 bRightTrigger; - u16 sThumbLX; - u16 sThumbLY; - u16 sThumbRX; - u16 sThumbRY; -} XINPUT_GAMEPAD; - -typedef struct _XINPUT_STATE { - DWORD dwPacketNumber; - XINPUT_GAMEPAD Gamepad; -} XINPUT_STATE; - -typedef struct _XINPUT_VIBRATION { - u16 wLeftMotorSpeed; - u16 wRightMotorSpeed; -} XINPUT_VIBRATION; - -#define XINPUT_GAMEPAD_DPAD_UP 0x00000001 -#define XINPUT_GAMEPAD_DPAD_DOWN 0x00000002 -#define XINPUT_GAMEPAD_DPAD_LEFT 0x00000004 -#define XINPUT_GAMEPAD_DPAD_RIGHT 0x00000008 -#define XINPUT_GAMEPAD_START 0x00000010 -#define XINPUT_GAMEPAD_BACK 0x00000020 -#define XINPUT_GAMEPAD_LEFT_THUMB 0x00000040 -#define XINPUT_GAMEPAD_RIGHT_THUMB 0x00000080 -#define XINPUT_GAMEPAD_LEFT_SHOULDER 0x0100 -#define XINPUT_GAMEPAD_RIGHT_SHOULDER 0x0200 -#define XINPUT_GAMEPAD_A 0x1000 -#define XINPUT_GAMEPAD_B 0x2000 -#define XINPUT_GAMEPAD_X 0x4000 -#define XINPUT_GAMEPAD_Y 0x8000 -#define XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE 7849 -#define XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE 8689 -#define XINPUT_GAMEPAD_TRIGGER_THRESHOLD 30 -#endif - -#ifndef XUSER_MAX_COUNT -#define XUSER_MAX_COUNT 4 -#endif - -void gb_platform_update(gbPlatform *p) { - isize i; - - { // NOTE(bill): Set window state - // TODO(bill): Should this be moved to gb__win32_window_callback ? - RECT window_rect; - i32 x, y, w, h; - - GetClientRect(cast(HWND)p->window_handle, &window_rect); - x = window_rect.left; - y = window_rect.top; - w = window_rect.right - window_rect.left; - h = window_rect.bottom - window_rect.top; - - if ((p->window_width != w) || (p->window_height != h)) { - if (p->renderer_type == gbRenderer_Software) { - gb__platform_resize_dib_section(p, w, h); - } - } - - - p->window_x = x; - p->window_y = y; - p->window_width = w; - p->window_height = h; - GB_MASK_SET(p->window_flags, IsIconic(cast(HWND)p->window_handle) != 0, gbWindow_Minimized); - - p->window_has_focus = GetFocus() == cast(HWND)p->window_handle; - } - - { // NOTE(bill): Set mouse position - POINT mouse_pos; - DWORD win_button_id[gbMouseButton_Count] = { - VK_LBUTTON, - VK_MBUTTON, - VK_RBUTTON, - VK_XBUTTON1, - VK_XBUTTON2, - }; - - // NOTE(bill): This needs to be GetAsyncKeyState as RAWMOUSE doesn't aways work for some odd reason - // TODO(bill): Try and get RAWMOUSE to work for key presses - for (i = 0; i < gbMouseButton_Count; i++) { - gb_key_state_update(p->mouse_buttons+i, GetAsyncKeyState(win_button_id[i]) < 0); - } - - GetCursorPos(&mouse_pos); - ScreenToClient(cast(HWND)p->window_handle, &mouse_pos); - { - i32 x = mouse_pos.x; - i32 y = p->window_height-1 - mouse_pos.y; - p->mouse_dx = x - p->mouse_x; - p->mouse_dy = y - p->mouse_y; - p->mouse_x = x; - p->mouse_y = y; - } - - if (p->mouse_clip) { - b32 update = false; - i32 x = p->mouse_x; - i32 y = p->mouse_y; - if (p->mouse_x < 0) { - x = 0; - update = true; - } else if (p->mouse_y > p->window_height-1) { - y = p->window_height-1; - update = true; - } - - if (p->mouse_y < 0) { - y = 0; - update = true; - } else if (p->mouse_x > p->window_width-1) { - x = p->window_width-1; - update = true; - } - - if (update) { - gb_platform_set_mouse_position(p, x, y); - } - } - - - } - - - // NOTE(bill): Set Key/Button states - if (p->window_has_focus) { - p->char_buffer_count = 0; // TODO(bill): Reset buffer count here or else where? - - // NOTE(bill): Need to update as the keys only get updates on events - for (i = 0; i < gbKey_Count; i++) { - b32 is_down = (p->keys[i] & gbKeyState_Down) != 0; - gb_key_state_update(&p->keys[i], is_down); - } - - p->key_modifiers.control = p->keys[gbKey_Lcontrol] | p->keys[gbKey_Rcontrol]; - p->key_modifiers.alt = p->keys[gbKey_Lalt] | p->keys[gbKey_Ralt]; - p->key_modifiers.shift = p->keys[gbKey_Lshift] | p->keys[gbKey_Rshift]; - - } - - { // NOTE(bill): Set Controller states - isize max_controller_count = XUSER_MAX_COUNT; - if (max_controller_count > gb_count_of(p->game_controllers)) { - max_controller_count = gb_count_of(p->game_controllers); - } - - for (i = 0; i < max_controller_count; i++) { - gbGameController *controller = &p->game_controllers[i]; - XINPUT_STATE controller_state = {0}; - if (p->xinput.get_state(cast(DWORD)i, &controller_state) != 0) { - // NOTE(bill): The controller is not available - controller->is_connected = false; - } else { - // NOTE(bill): This controller is plugged in - // TODO(bill): See if ControllerState.dwPacketNumber increments too rapidly - XINPUT_GAMEPAD *pad = &controller_state.Gamepad; - - controller->is_connected = true; - - // TODO(bill): This is a square deadzone, check XInput to verify that the deadzone is "round" and do round deadzone processing. - controller->axes[gbControllerAxis_LeftX] = gb__process_xinput_stick_value(pad->sThumbLX, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE); - controller->axes[gbControllerAxis_LeftY] = gb__process_xinput_stick_value(pad->sThumbLY, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE); - controller->axes[gbControllerAxis_RightX] = gb__process_xinput_stick_value(pad->sThumbRX, XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE); - controller->axes[gbControllerAxis_RightY] = gb__process_xinput_stick_value(pad->sThumbRY, XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE); - - controller->axes[gbControllerAxis_LeftTrigger] = cast(f32)pad->bLeftTrigger / 255.0f; - controller->axes[gbControllerAxis_RightTrigger] = cast(f32)pad->bRightTrigger / 255.0f; - - - if ((controller->axes[gbControllerAxis_LeftX] != 0.0f) || - (controller->axes[gbControllerAxis_LeftY] != 0.0f)) { - controller->is_analog = true; - } - - #define GB__PROCESS_DIGITAL_BUTTON(button_type, xinput_button) \ - gb_key_state_update(&controller->buttons[button_type], (pad->wButtons & xinput_button) == xinput_button) - - GB__PROCESS_DIGITAL_BUTTON(gbControllerButton_A, XINPUT_GAMEPAD_A); - GB__PROCESS_DIGITAL_BUTTON(gbControllerButton_B, XINPUT_GAMEPAD_B); - GB__PROCESS_DIGITAL_BUTTON(gbControllerButton_X, XINPUT_GAMEPAD_X); - GB__PROCESS_DIGITAL_BUTTON(gbControllerButton_Y, XINPUT_GAMEPAD_Y); - GB__PROCESS_DIGITAL_BUTTON(gbControllerButton_LeftShoulder, XINPUT_GAMEPAD_LEFT_SHOULDER); - GB__PROCESS_DIGITAL_BUTTON(gbControllerButton_RightShoulder, XINPUT_GAMEPAD_RIGHT_SHOULDER); - GB__PROCESS_DIGITAL_BUTTON(gbControllerButton_Start, XINPUT_GAMEPAD_START); - GB__PROCESS_DIGITAL_BUTTON(gbControllerButton_Back, XINPUT_GAMEPAD_BACK); - GB__PROCESS_DIGITAL_BUTTON(gbControllerButton_Left, XINPUT_GAMEPAD_DPAD_LEFT); - GB__PROCESS_DIGITAL_BUTTON(gbControllerButton_Right, XINPUT_GAMEPAD_DPAD_RIGHT); - GB__PROCESS_DIGITAL_BUTTON(gbControllerButton_Down, XINPUT_GAMEPAD_DPAD_DOWN); - GB__PROCESS_DIGITAL_BUTTON(gbControllerButton_Up, XINPUT_GAMEPAD_DPAD_UP); - GB__PROCESS_DIGITAL_BUTTON(gbControllerButton_LeftThumb, XINPUT_GAMEPAD_LEFT_THUMB); - GB__PROCESS_DIGITAL_BUTTON(gbControllerButton_RightThumb, XINPUT_GAMEPAD_RIGHT_THUMB); - #undef GB__PROCESS_DIGITAL_BUTTON - } - } - } - - { // NOTE(bill): Process pending messages - MSG message; - for (;;) { - BOOL is_okay = PeekMessageW(&message, 0, 0, 0, PM_REMOVE); - if (!is_okay) break; - - switch (message.message) { - case WM_QUIT: - p->quit_requested = true; - break; - - default: - TranslateMessage(&message); - DispatchMessageW(&message); - break; - } - } - } -} - -void gb_platform_display(gbPlatform *p) { - if (p->renderer_type == gbRenderer_Opengl) { - SwapBuffers(cast(HDC)p->win32_dc); - } else if (p->renderer_type == gbRenderer_Software) { - StretchDIBits(cast(HDC)p->win32_dc, - 0, 0, p->window_width, p->window_height, - 0, 0, p->window_width, p->window_height, - p->sw_framebuffer.memory, - &p->sw_framebuffer.win32_bmi, - DIB_RGB_COLORS, SRCCOPY); - } else { - GB_PANIC("Invalid window rendering type"); - } - - { - f64 prev_time = p->curr_time; - f64 curr_time = gb_time_now(); - p->dt_for_frame = curr_time - prev_time; - p->curr_time = curr_time; - } -} - - -void gb_platform_destroy(gbPlatform *p) { - if (p->renderer_type == gbRenderer_Opengl) { - wglDeleteContext(cast(HGLRC)p->opengl.context); - } else if (p->renderer_type == gbRenderer_Software) { - gb_vm_free(gb_virtual_memory(p->sw_framebuffer.memory, p->sw_framebuffer.memory_size)); - } - - DestroyWindow(cast(HWND)p->window_handle); -} - -void gb_platform_show_cursor(gbPlatform *p, b32 show) { - gb_unused(p); - ShowCursor(show); -} - -void gb_platform_set_mouse_position(gbPlatform *p, i32 x, i32 y) { - POINT point; - point.x = cast(LONG)x; - point.y = cast(LONG)(p->window_height-1 - y); - ClientToScreen(cast(HWND)p->window_handle, &point); - SetCursorPos(point.x, point.y); - - p->mouse_x = point.x; - p->mouse_y = p->window_height-1 - point.y; -} - - - -void gb_platform_set_controller_vibration(gbPlatform *p, isize index, f32 left_motor, f32 right_motor) { - if (gb_is_between(index, 0, GB_MAX_GAME_CONTROLLER_COUNT-1)) { - XINPUT_VIBRATION vibration = {0}; - left_motor = gb_clamp01(left_motor); - right_motor = gb_clamp01(right_motor); - vibration.wLeftMotorSpeed = cast(WORD)(65535 * left_motor); - vibration.wRightMotorSpeed = cast(WORD)(65535 * right_motor); - - p->xinput.set_state(cast(DWORD)index, &vibration); - } -} - - -void gb_platform_set_window_position(gbPlatform *p, i32 x, i32 y) { - RECT rect; - i32 width, height; - - GetClientRect(cast(HWND)p->window_handle, &rect); - width = rect.right - rect.left; - height = rect.bottom - rect.top; - MoveWindow(cast(HWND)p->window_handle, x, y, width, height, false); -} - -void gb_platform_set_window_title(gbPlatform *p, char const *title, ...) { - u16 buffer[256] = {0}; - char str[512] = {0}; - va_list va; - va_start(va, title); - gb_snprintf_va(str, gb_size_of(str), title, va); - va_end(va); - - if (str[0] != '\0') { - SetWindowTextW(cast(HWND)p->window_handle, cast(wchar_t const *)gb_utf8_to_ucs2(buffer, gb_size_of(buffer), str)); - } -} - -void gb_platform_toggle_fullscreen(gbPlatform *p, b32 fullscreen_desktop) { - // NOTE(bill): From the man himself, Raymond Chen! (Modified for my need.) - HWND handle = cast(HWND)p->window_handle; - DWORD style = cast(DWORD)GetWindowLongW(handle, GWL_STYLE); - WINDOWPLACEMENT placement; - - if (style & WS_OVERLAPPEDWINDOW) { - MONITORINFO monitor_info = {gb_size_of(monitor_info)}; - if (GetWindowPlacement(handle, &placement) && - GetMonitorInfoW(MonitorFromWindow(handle, 1), &monitor_info)) { - style &= ~WS_OVERLAPPEDWINDOW; - if (fullscreen_desktop) { - style &= ~WS_CAPTION; - style |= WS_POPUP; - } - SetWindowLongW(handle, GWL_STYLE, style); - SetWindowPos(handle, HWND_TOP, - monitor_info.rcMonitor.left, monitor_info.rcMonitor.top, - monitor_info.rcMonitor.right - monitor_info.rcMonitor.left, - monitor_info.rcMonitor.bottom - monitor_info.rcMonitor.top, - SWP_NOOWNERZORDER | SWP_FRAMECHANGED); - - if (fullscreen_desktop) { - p->window_flags |= gbWindow_FullscreenDesktop; - } else { - p->window_flags |= gbWindow_Fullscreen; - } - } - } else { - style &= ~WS_POPUP; - style |= WS_OVERLAPPEDWINDOW | WS_CAPTION; - SetWindowLongW(handle, GWL_STYLE, style); - SetWindowPlacement(handle, &placement); - SetWindowPos(handle, 0, 0, 0, 0, 0, - SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | - SWP_NOOWNERZORDER | SWP_FRAMECHANGED); - - p->window_flags &= ~gbWindow_Fullscreen; - } -} - -void gb_platform_toggle_borderless(gbPlatform *p) { - HWND handle = cast(HWND)p->window_handle; - DWORD style = GetWindowLongW(handle, GWL_STYLE); - b32 is_borderless = (style & WS_POPUP) != 0; - - GB_MASK_SET(style, is_borderless, WS_OVERLAPPEDWINDOW | WS_CAPTION); - GB_MASK_SET(style, !is_borderless, WS_POPUP); - - SetWindowLongW(handle, GWL_STYLE, style); - - GB_MASK_SET(p->window_flags, !is_borderless, gbWindow_Borderless); -} - - - -gb_inline void gb_platform_make_opengl_context_current(gbPlatform *p) { - if (p->renderer_type == gbRenderer_Opengl) { - wglMakeCurrent(cast(HDC)p->win32_dc, cast(HGLRC)p->opengl.context); - } -} - -gb_inline void gb_platform_show_window(gbPlatform *p) { - ShowWindow(cast(HWND)p->window_handle, SW_SHOW); - p->window_flags &= ~gbWindow_Hidden; -} - -gb_inline void gb_platform_hide_window(gbPlatform *p) { - ShowWindow(cast(HWND)p->window_handle, SW_HIDE); - p->window_flags |= gbWindow_Hidden; -} - -gb_inline gbVideoMode gb_video_mode_get_desktop(void) { - DEVMODEW win32_mode = {gb_size_of(win32_mode)}; - EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &win32_mode); - return gb_video_mode(win32_mode.dmPelsWidth, win32_mode.dmPelsHeight, win32_mode.dmBitsPerPel); -} - -isize gb_video_mode_get_fullscreen_modes(gbVideoMode *modes, isize max_mode_count) { - DEVMODEW win32_mode = {gb_size_of(win32_mode)}; - i32 count; - for (count = 0; - count < max_mode_count && EnumDisplaySettingsW(NULL, count, &win32_mode); - count++) { - modes[count] = gb_video_mode(win32_mode.dmPelsWidth, win32_mode.dmPelsHeight, win32_mode.dmBitsPerPel); - } - - gb_sort_array(modes, count, gb_video_mode_dsc_cmp); - return count; -} - - - -b32 gb_platform_has_clipboard_text(gbPlatform *p) { - b32 result = false; - - if (IsClipboardFormatAvailable(1/*CF_TEXT*/) && - OpenClipboard(cast(HWND)p->window_handle)) { - HANDLE mem = GetClipboardData(1/*CF_TEXT*/); - if (mem) { - char *str = cast(char *)GlobalLock(mem); - if (str && str[0] != '\0') { - result = true; - } - GlobalUnlock(mem); - } else { - return false; - } - - CloseClipboard(); - } - - return result; -} - -// TODO(bill): Handle UTF-8 -void gb_platform_set_clipboard_text(gbPlatform *p, char const *str) { - if (OpenClipboard(cast(HWND)p->window_handle)) { - isize i, len = gb_strlen(str)+1; - - HANDLE mem = cast(HANDLE)GlobalAlloc(0x0002/*GMEM_MOVEABLE*/, len); - if (mem) { - char *dst = cast(char *)GlobalLock(mem); - if (dst) { - for (i = 0; str[i]; i++) { - // TODO(bill): Does this cause a buffer overflow? - // NOTE(bill): Change \n to \r\n 'cause windows - if (str[i] == '\n' && (i == 0 || str[i-1] != '\r')) { - *dst++ = '\r'; - } - *dst++ = str[i]; - } - *dst = 0; - } - GlobalUnlock(mem); - } - - EmptyClipboard(); - if (!SetClipboardData(1/*CF_TEXT*/, mem)) { - return; - } - CloseClipboard(); - } -} - -// TODO(bill): Handle UTF-8 -char *gb_platform_get_clipboard_text(gbPlatform *p, gbAllocator a) { - char *text = NULL; - - if (IsClipboardFormatAvailable(1/*CF_TEXT*/) && - OpenClipboard(cast(HWND)p->window_handle)) { - HANDLE mem = GetClipboardData(1/*CF_TEXT*/); - if (mem) { - char *str = cast(char *)GlobalLock(mem); - text = gb_alloc_str(a, str); - GlobalUnlock(mem); - } else { - return NULL; - } - - CloseClipboard(); - } - - return text; -} - -#elif defined(GB_SYSTEM_OSX) - -#include -#include -#include -#include - -#if __LP64__ || (TARGET_OS_EMBEDDED && !TARGET_OS_IPHONE) || TARGET_OS_WIN32 || NS_BUILD_32_LIKE_64 - #define NSIntegerEncoding "q" - #define NSUIntegerEncoding "L" -#else - #define NSIntegerEncoding "i" - #define NSUIntegerEncoding "I" -#endif - -#ifdef __OBJC__ - #import -#else - typedef CGPoint NSPoint; - typedef CGSize NSSize; - typedef CGRect NSRect; - - extern id NSApp; - extern id const NSDefaultRunLoopMode; -#endif - -#if defined(__OBJC__) && __has_feature(objc_arc) -#error TODO(bill): Cannot compile as objective-c code just yet! -#endif - -// ABI is a bit different between platforms -#ifdef __arm64__ -#define abi_objc_msgSend_stret objc_msgSend -#else -#define abi_objc_msgSend_stret objc_msgSend_stret -#endif -#ifdef __i386__ -#define abi_objc_msgSend_fpret objc_msgSend_fpret -#else -#define abi_objc_msgSend_fpret objc_msgSend -#endif - -#define objc_msgSend_id ((id (*)(id, SEL))objc_msgSend) -#define objc_msgSend_void ((void (*)(id, SEL))objc_msgSend) -#define objc_msgSend_void_id ((void (*)(id, SEL, id))objc_msgSend) -#define objc_msgSend_void_bool ((void (*)(id, SEL, BOOL))objc_msgSend) -#define objc_msgSend_id_char_const ((id (*)(id, SEL, char const *))objc_msgSend) - -gb_internal NSUInteger gb__osx_application_should_terminate(id self, SEL _sel, id sender) { - // NOTE(bill): Do nothing - return 0; -} - -gb_internal void gb__osx_window_will_close(id self, SEL _sel, id notification) { - NSUInteger value = true; - object_setInstanceVariable(self, "closed", cast(void *)value); -} - -gb_internal void gb__osx_window_did_become_key(id self, SEL _sel, id notification) { - gbPlatform *p = NULL; - object_getInstanceVariable(self, "gbPlatform", cast(void **)&p); - if (p) { - // TODO(bill): - } -} - -b32 gb__platform_init(gbPlatform *p, char const *window_title, gbVideoMode mode, gbRendererType type, u32 window_flags) { - if (p->is_initialized) { - return true; - } - // Init Platform - { // Initial OSX State - Class appDelegateClass; - b32 resultAddProtoc, resultAddMethod; - id dgAlloc, dg, menubarAlloc, menubar; - id appMenuItemAlloc, appMenuItem; - id appMenuAlloc, appMenu; - - #if defined(ARC_AVAILABLE) - #error TODO(bill): This code should be compiled as C for now - #else - id poolAlloc = objc_msgSend_id(cast(id)objc_getClass("NSAutoreleasePool"), sel_registerName("alloc")); - p->osx_autorelease_pool = objc_msgSend_id(poolAlloc, sel_registerName("init")); - #endif - - objc_msgSend_id(cast(id)objc_getClass("NSApplication"), sel_registerName("sharedApplication")); - ((void (*)(id, SEL, NSInteger))objc_msgSend)(NSApp, sel_registerName("setActivationPolicy:"), 0); - - appDelegateClass = objc_allocateClassPair((Class)objc_getClass("NSObject"), "AppDelegate", 0); - resultAddProtoc = class_addProtocol(appDelegateClass, objc_getProtocol("NSApplicationDelegate")); - assert(resultAddProtoc); - resultAddMethod = class_addMethod(appDelegateClass, sel_registerName("applicationShouldTerminate:"), cast(IMP)gb__osx_application_should_terminate, NSUIntegerEncoding "@:@"); - assert(resultAddMethod); - dgAlloc = objc_msgSend_id(cast(id)appDelegateClass, sel_registerName("alloc")); - dg = objc_msgSend_id(dgAlloc, sel_registerName("init")); - #ifndef ARC_AVAILABLE - objc_msgSend_void(dg, sel_registerName("autorelease")); - #endif - - objc_msgSend_void_id(NSApp, sel_registerName("setDelegate:"), dg); - objc_msgSend_void(NSApp, sel_registerName("finishLaunching")); - - menubarAlloc = objc_msgSend_id(cast(id)objc_getClass("NSMenu"), sel_registerName("alloc")); - menubar = objc_msgSend_id(menubarAlloc, sel_registerName("init")); - #ifndef ARC_AVAILABLE - objc_msgSend_void(menubar, sel_registerName("autorelease")); - #endif - - appMenuItemAlloc = objc_msgSend_id(cast(id)objc_getClass("NSMenuItem"), sel_registerName("alloc")); - appMenuItem = objc_msgSend_id(appMenuItemAlloc, sel_registerName("init")); - #ifndef ARC_AVAILABLE - objc_msgSend_void(appMenuItem, sel_registerName("autorelease")); - #endif - - objc_msgSend_void_id(menubar, sel_registerName("addItem:"), appMenuItem); - ((id (*)(id, SEL, id))objc_msgSend)(NSApp, sel_registerName("setMainMenu:"), menubar); - - appMenuAlloc = objc_msgSend_id(cast(id)objc_getClass("NSMenu"), sel_registerName("alloc")); - appMenu = objc_msgSend_id(appMenuAlloc, sel_registerName("init")); - #ifndef ARC_AVAILABLE - objc_msgSend_void(appMenu, sel_registerName("autorelease")); - #endif - - { - id processInfo = objc_msgSend_id(cast(id)objc_getClass("NSProcessInfo"), sel_registerName("processInfo")); - id appName = objc_msgSend_id(processInfo, sel_registerName("processName")); - - id quitTitlePrefixString = objc_msgSend_id_char_const(cast(id)objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), "Quit "); - id quitTitle = ((id (*)(id, SEL, id))objc_msgSend)(quitTitlePrefixString, sel_registerName("stringByAppendingString:"), appName); - - id quitMenuItemKey = objc_msgSend_id_char_const(cast(id)objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), "q"); - id quitMenuItemAlloc = objc_msgSend_id(cast(id)objc_getClass("NSMenuItem"), sel_registerName("alloc")); - id quitMenuItem = ((id (*)(id, SEL, id, SEL, id))objc_msgSend)(quitMenuItemAlloc, sel_registerName("initWithTitle:action:keyEquivalent:"), quitTitle, sel_registerName("terminate:"), quitMenuItemKey); - #ifndef ARC_AVAILABLE - objc_msgSend_void(quitMenuItem, sel_registerName("autorelease")); - #endif - - objc_msgSend_void_id(appMenu, sel_registerName("addItem:"), quitMenuItem); - objc_msgSend_void_id(appMenuItem, sel_registerName("setSubmenu:"), appMenu); - } - } - - { // Init Window - NSRect rect = {{0, 0}, {cast(CGFloat)mode.width, cast(CGFloat)mode.height}}; - id windowAlloc, window, wdgAlloc, wdg, contentView, titleString; - Class WindowDelegateClass; - b32 resultAddProtoc, resultAddIvar, resultAddMethod; - - windowAlloc = objc_msgSend_id(cast(id)objc_getClass("NSWindow"), sel_registerName("alloc")); - window = ((id (*)(id, SEL, NSRect, NSUInteger, NSUInteger, BOOL))objc_msgSend)(windowAlloc, sel_registerName("initWithContentRect:styleMask:backing:defer:"), rect, 15, 2, NO); - #ifndef ARC_AVAILABLE - objc_msgSend_void(window, sel_registerName("autorelease")); - #endif - - // when we are not using ARC, than window will be added to autorelease pool - // so if we close it by hand (pressing red button), we don't want it to be released for us - // so it will be released by autorelease pool later - objc_msgSend_void_bool(window, sel_registerName("setReleasedWhenClosed:"), NO); - - WindowDelegateClass = objc_allocateClassPair((Class)objc_getClass("NSObject"), "WindowDelegate", 0); - resultAddProtoc = class_addProtocol(WindowDelegateClass, objc_getProtocol("NSWindowDelegate")); - GB_ASSERT(resultAddProtoc); - resultAddIvar = class_addIvar(WindowDelegateClass, "closed", gb_size_of(NSUInteger), rint(log2(gb_size_of(NSUInteger))), NSUIntegerEncoding); - GB_ASSERT(resultAddIvar); - resultAddIvar = class_addIvar(WindowDelegateClass, "gbPlatform", gb_size_of(void *), rint(log2(gb_size_of(void *))), "ˆv"); - GB_ASSERT(resultAddIvar); - resultAddMethod = class_addMethod(WindowDelegateClass, sel_registerName("windowWillClose:"), cast(IMP)gb__osx_window_will_close, "v@:@"); - GB_ASSERT(resultAddMethod); - resultAddMethod = class_addMethod(WindowDelegateClass, sel_registerName("windowDidBecomeKey:"), cast(IMP)gb__osx_window_did_become_key, "v@:@"); - GB_ASSERT(resultAddMethod); - wdgAlloc = objc_msgSend_id(cast(id)WindowDelegateClass, sel_registerName("alloc")); - wdg = objc_msgSend_id(wdgAlloc, sel_registerName("init")); - #ifndef ARC_AVAILABLE - objc_msgSend_void(wdg, sel_registerName("autorelease")); - #endif - - objc_msgSend_void_id(window, sel_registerName("setDelegate:"), wdg); - - contentView = objc_msgSend_id(window, sel_registerName("contentView")); - - { - NSPoint point = {20, 20}; - ((void (*)(id, SEL, NSPoint))objc_msgSend)(window, sel_registerName("cascadeTopLeftFromPoint:"), point); - } - - titleString = objc_msgSend_id_char_const(cast(id)objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), window_title); - objc_msgSend_void_id(window, sel_registerName("setTitle:"), titleString); - - if (type == gbRenderer_Opengl) { - // TODO(bill): Make sure this works correctly - u32 opengl_hex_version = (p->opengl.major << 12) | (p->opengl.minor << 8); - u32 gl_attribs[] = { - 8, 24, // NSOpenGLPFAColorSize, 24, - 11, 8, // NSOpenGLPFAAlphaSize, 8, - 5, // NSOpenGLPFADoubleBuffer, - 73, // NSOpenGLPFAAccelerated, - //72, // NSOpenGLPFANoRecovery, - //55, 1, // NSOpenGLPFASampleBuffers, 1, - //56, 4, // NSOpenGLPFASamples, 4, - 99, opengl_hex_version, // NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core, - 0 - }; - - id pixel_format_alloc, pixel_format; - id opengl_context_alloc, opengl_context; - - pixel_format_alloc = objc_msgSend_id(cast(id)objc_getClass("NSOpenGLPixelFormat"), sel_registerName("alloc")); - pixel_format = ((id (*)(id, SEL, const uint32_t*))objc_msgSend)(pixel_format_alloc, sel_registerName("initWithAttributes:"), gl_attribs); - #ifndef ARC_AVAILABLE - objc_msgSend_void(pixel_format, sel_registerName("autorelease")); - #endif - - opengl_context_alloc = objc_msgSend_id(cast(id)objc_getClass("NSOpenGLContext"), sel_registerName("alloc")); - opengl_context = ((id (*)(id, SEL, id, id))objc_msgSend)(opengl_context_alloc, sel_registerName("initWithFormat:shareContext:"), pixel_format, nil); - #ifndef ARC_AVAILABLE - objc_msgSend_void(opengl_context, sel_registerName("autorelease")); - #endif - - objc_msgSend_void_id(opengl_context, sel_registerName("setView:"), contentView); - objc_msgSend_void_id(window, sel_registerName("makeKeyAndOrderFront:"), window); - objc_msgSend_void_bool(window, sel_registerName("setAcceptsMouseMovedEvents:"), YES); - - - p->window_handle = cast(void *)window; - p->opengl.context = cast(void *)opengl_context; - } else { - GB_PANIC("TODO(bill): Software rendering"); - } - - { - id blackColor = objc_msgSend_id(cast(id)objc_getClass("NSColor"), sel_registerName("blackColor")); - objc_msgSend_void_id(window, sel_registerName("setBackgroundColor:"), blackColor); - objc_msgSend_void_bool(NSApp, sel_registerName("activateIgnoringOtherApps:"), YES); - } - object_setInstanceVariable(wdg, "gbPlatform", cast(void *)p); - - p->is_initialized = true; - } - - return true; -} - -// NOTE(bill): Software rendering -b32 gb_platform_init_with_software(gbPlatform *p, char const *window_title, i32 width, i32 height, u32 window_flags) { - GB_PANIC("TODO(bill): Software rendering in not yet implemented on OS X\n"); - return gb__platform_init(p, window_title, gb_video_mode(width, height, 32), gbRenderer_Software, window_flags); -} -// NOTE(bill): OpenGL Rendering -b32 gb_platform_init_with_opengl(gbPlatform *p, char const *window_title, i32 width, i32 height, u32 window_flags, - i32 major, i32 minor, b32 core, b32 compatible) { - - p->opengl.major = major; - p->opengl.minor = minor; - p->opengl.core = core; - p->opengl.compatible = compatible; - return gb__platform_init(p, window_title, gb_video_mode(width, height, 32), gbRenderer_Opengl, window_flags); -} - -// NOTE(bill): Reverse engineering can be fun!!! -gb_internal gbKeyType gb__osx_from_key_code(u16 key_code) { - switch (key_code) { - default: return gbKey_Unknown; - // NOTE(bill): WHO THE FUCK DESIGNED THIS VIRTUAL KEY CODE SYSTEM?! - // THEY ARE FUCKING IDIOTS! - case 0x1d: return gbKey_0; - case 0x12: return gbKey_1; - case 0x13: return gbKey_2; - case 0x14: return gbKey_3; - case 0x15: return gbKey_4; - case 0x17: return gbKey_5; - case 0x16: return gbKey_6; - case 0x1a: return gbKey_7; - case 0x1c: return gbKey_8; - case 0x19: return gbKey_9; - - case 0x00: return gbKey_A; - case 0x0b: return gbKey_B; - case 0x08: return gbKey_C; - case 0x02: return gbKey_D; - case 0x0e: return gbKey_E; - case 0x03: return gbKey_F; - case 0x05: return gbKey_G; - case 0x04: return gbKey_H; - case 0x22: return gbKey_I; - case 0x26: return gbKey_J; - case 0x28: return gbKey_K; - case 0x25: return gbKey_L; - case 0x2e: return gbKey_M; - case 0x2d: return gbKey_N; - case 0x1f: return gbKey_O; - case 0x23: return gbKey_P; - case 0x0c: return gbKey_Q; - case 0x0f: return gbKey_R; - case 0x01: return gbKey_S; - case 0x11: return gbKey_T; - case 0x20: return gbKey_U; - case 0x09: return gbKey_V; - case 0x0d: return gbKey_W; - case 0x07: return gbKey_X; - case 0x10: return gbKey_Y; - case 0x06: return gbKey_Z; - - case 0x21: return gbKey_Lbracket; - case 0x1e: return gbKey_Rbracket; - case 0x29: return gbKey_Semicolon; - case 0x2b: return gbKey_Comma; - case 0x2f: return gbKey_Period; - case 0x27: return gbKey_Quote; - case 0x2c: return gbKey_Slash; - case 0x2a: return gbKey_Backslash; - case 0x32: return gbKey_Grave; - case 0x18: return gbKey_Equals; - case 0x1b: return gbKey_Minus; - case 0x31: return gbKey_Space; - - case 0x35: return gbKey_Escape; // Escape - case 0x3b: return gbKey_Lcontrol; // Left Control - case 0x38: return gbKey_Lshift; // Left Shift - case 0x3a: return gbKey_Lalt; // Left Alt - case 0x37: return gbKey_Lsystem; // Left OS specific: window (Windows and Linux), apple/cmd (MacOS X), ... - case 0x3e: return gbKey_Rcontrol; // Right Control - case 0x3c: return gbKey_Rshift; // Right Shift - case 0x3d: return gbKey_Ralt; // Right Alt - // case 0x37: return gbKey_Rsystem; // Right OS specific: window (Windows and Linux), apple/cmd (MacOS X), ... - case 0x6e: return gbKey_Menu; // Menu - case 0x24: return gbKey_Return; // Return - case 0x33: return gbKey_Backspace; // Backspace - case 0x30: return gbKey_Tab; // Tabulation - case 0x74: return gbKey_Pageup; // Page up - case 0x79: return gbKey_Pagedown; // Page down - case 0x77: return gbKey_End; // End - case 0x73: return gbKey_Home; // Home - case 0x72: return gbKey_Insert; // Insert - case 0x75: return gbKey_Delete; // Delete - case 0x45: return gbKey_Plus; // + - case 0x4e: return gbKey_Subtract; // - - case 0x43: return gbKey_Multiply; // * - case 0x4b: return gbKey_Divide; // / - case 0x7b: return gbKey_Left; // Left arrow - case 0x7c: return gbKey_Right; // Right arrow - case 0x7e: return gbKey_Up; // Up arrow - case 0x7d: return gbKey_Down; // Down arrow - case 0x52: return gbKey_Numpad0; // Numpad 0 - case 0x53: return gbKey_Numpad1; // Numpad 1 - case 0x54: return gbKey_Numpad2; // Numpad 2 - case 0x55: return gbKey_Numpad3; // Numpad 3 - case 0x56: return gbKey_Numpad4; // Numpad 4 - case 0x57: return gbKey_Numpad5; // Numpad 5 - case 0x58: return gbKey_Numpad6; // Numpad 6 - case 0x59: return gbKey_Numpad7; // Numpad 7 - case 0x5b: return gbKey_Numpad8; // Numpad 8 - case 0x5c: return gbKey_Numpad9; // Numpad 9 - case 0x41: return gbKey_NumpadDot; // Numpad . - case 0x4c: return gbKey_NumpadEnter; // Numpad Enter - case 0x7a: return gbKey_F1; // F1 - case 0x78: return gbKey_F2; // F2 - case 0x63: return gbKey_F3; // F3 - case 0x76: return gbKey_F4; // F4 - case 0x60: return gbKey_F5; // F5 - case 0x61: return gbKey_F6; // F6 - case 0x62: return gbKey_F7; // F7 - case 0x64: return gbKey_F8; // F8 - case 0x65: return gbKey_F9; // F8 - case 0x6d: return gbKey_F10; // F10 - case 0x67: return gbKey_F11; // F11 - case 0x6f: return gbKey_F12; // F12 - case 0x69: return gbKey_F13; // F13 - case 0x6b: return gbKey_F14; // F14 - case 0x71: return gbKey_F15; // F15 - // case : return gbKey_Pause; // Pause // NOTE(bill): Not possible on OS X - } -} - -gb_internal void gb__osx_on_cocoa_event(gbPlatform *p, id event, id window) { - if (!event) { - return; - } else if (objc_msgSend_id(window, sel_registerName("delegate"))) { - NSUInteger event_type = ((NSUInteger (*)(id, SEL))objc_msgSend)(event, sel_registerName("type")); - switch (event_type) { - case 1: gb_key_state_update(&p->mouse_buttons[gbMouseButton_Left], true); break; // NSLeftMouseDown - case 2: gb_key_state_update(&p->mouse_buttons[gbMouseButton_Left], false); break; // NSLeftMouseUp - case 3: gb_key_state_update(&p->mouse_buttons[gbMouseButton_Right], true); break; // NSRightMouseDown - case 4: gb_key_state_update(&p->mouse_buttons[gbMouseButton_Right], false); break; // NSRightMouseUp - case 25: { // NSOtherMouseDown - // TODO(bill): Test thoroughly - NSInteger number = ((NSInteger (*)(id, SEL))objc_msgSend)(event, sel_registerName("buttonNumber")); - if (number == 2) gb_key_state_update(&p->mouse_buttons[gbMouseButton_Middle], true); - if (number == 3) gb_key_state_update(&p->mouse_buttons[gbMouseButton_X1], true); - if (number == 4) gb_key_state_update(&p->mouse_buttons[gbMouseButton_X2], true); - } break; - case 26: { // NSOtherMouseUp - NSInteger number = ((NSInteger (*)(id, SEL))objc_msgSend)(event, sel_registerName("buttonNumber")); - if (number == 2) gb_key_state_update(&p->mouse_buttons[gbMouseButton_Middle], false); - if (number == 3) gb_key_state_update(&p->mouse_buttons[gbMouseButton_X1], false); - if (number == 4) gb_key_state_update(&p->mouse_buttons[gbMouseButton_X2], false); - - } break; - - // TODO(bill): Scroll wheel - case 22: { // NSScrollWheel - CGFloat dx = ((CGFloat (*)(id, SEL))abi_objc_msgSend_fpret)(event, sel_registerName("scrollingDeltaX")); - CGFloat dy = ((CGFloat (*)(id, SEL))abi_objc_msgSend_fpret)(event, sel_registerName("scrollingDeltaY")); - BOOL precision_scrolling = ((BOOL (*)(id, SEL))objc_msgSend)(event, sel_registerName("hasPreciseScrollingDeltas")); - if (precision_scrolling) { - dx *= 0.1f; - dy *= 0.1f; - } - // TODO(bill): Handle sideways - p->mouse_wheel_delta = dy; - // p->mouse_wheel_dy = dy; - // gb_printf("%f %f\n", dx, dy); - } break; - - case 12: { // NSFlagsChanged - #if 0 - // TODO(bill): Reverse engineer this properly - NSUInteger modifiers = ((NSUInteger (*)(id, SEL))objc_msgSend)(event, sel_registerName("modifierFlags")); - u32 upper_mask = (modifiers & 0xffff0000ul) >> 16; - b32 shift = (upper_mask & 0x02) != 0; - b32 control = (upper_mask & 0x04) != 0; - b32 alt = (upper_mask & 0x08) != 0; - b32 command = (upper_mask & 0x10) != 0; - #endif - - // gb_printf("%u\n", keys.mask); - // gb_printf("%x\n", cast(u32)modifiers); - } break; - - case 10: { // NSKeyDown - u16 key_code; - - id input_text = objc_msgSend_id(event, sel_registerName("characters")); - char const *input_text_utf8 = ((char const *(*)(id, SEL))objc_msgSend)(input_text, sel_registerName("UTF8String")); - p->char_buffer_count = gb_strnlen(input_text_utf8, gb_size_of(p->char_buffer)); - gb_memcopy(p->char_buffer, input_text_utf8, p->char_buffer_count); - - key_code = ((unsigned short (*)(id, SEL))objc_msgSend)(event, sel_registerName("keyCode")); - gb_key_state_update(&p->keys[gb__osx_from_key_code(key_code)], true); - } break; - - case 11: { // NSKeyUp - u16 key_code = ((unsigned short (*)(id, SEL))objc_msgSend)(event, sel_registerName("keyCode")); - gb_key_state_update(&p->keys[gb__osx_from_key_code(key_code)], false); - } break; - - default: break; - } - - objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), event); - } -} - - -void gb_platform_update(gbPlatform *p) { - id window, key_window, content_view; - NSRect original_frame; - - window = cast(id)p->window_handle; - key_window = objc_msgSend_id(NSApp, sel_registerName("keyWindow")); - p->window_has_focus = key_window == window; // TODO(bill): Is this right - - - if (p->window_has_focus) { - isize i; - p->char_buffer_count = 0; // TODO(bill): Reset buffer count here or else where? - - // NOTE(bill): Need to update as the keys only get updates on events - for (i = 0; i < gbKey_Count; i++) { - b32 is_down = (p->keys[i] & gbKeyState_Down) != 0; - gb_key_state_update(&p->keys[i], is_down); - } - - for (i = 0; i < gbMouseButton_Count; i++) { - b32 is_down = (p->mouse_buttons[i] & gbKeyState_Down) != 0; - gb_key_state_update(&p->mouse_buttons[i], is_down); - } - - } - - { // Handle Events - id distant_past = objc_msgSend_id(cast(id)objc_getClass("NSDate"), sel_registerName("distantPast")); - id event = ((id (*)(id, SEL, NSUInteger, id, id, BOOL))objc_msgSend)(NSApp, sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:"), NSUIntegerMax, distant_past, NSDefaultRunLoopMode, YES); - gb__osx_on_cocoa_event(p, event, window); - } - - if (p->window_has_focus) { - p->key_modifiers.control = p->keys[gbKey_Lcontrol] | p->keys[gbKey_Rcontrol]; - p->key_modifiers.alt = p->keys[gbKey_Lalt] | p->keys[gbKey_Ralt]; - p->key_modifiers.shift = p->keys[gbKey_Lshift] | p->keys[gbKey_Rshift]; - } - - { // Check if window is closed - id wdg = objc_msgSend_id(window, sel_registerName("delegate")); - if (!wdg) { - p->window_is_closed = false; - } else { - NSUInteger value = 0; - object_getInstanceVariable(wdg, "closed", cast(void **)&value); - p->window_is_closed = (value != 0); - } - } - - - - content_view = objc_msgSend_id(window, sel_registerName("contentView")); - original_frame = ((NSRect (*)(id, SEL))abi_objc_msgSend_stret)(content_view, sel_registerName("frame")); - - { // Window - NSRect frame = original_frame; - frame = ((NSRect (*)(id, SEL, NSRect))abi_objc_msgSend_stret)(content_view, sel_registerName("convertRectToBacking:"), frame); - p->window_width = frame.size.width; - p->window_height = frame.size.height; - frame = ((NSRect (*)(id, SEL, NSRect))abi_objc_msgSend_stret)(window, sel_registerName("convertRectToScreen:"), frame); - p->window_x = frame.origin.x; - p->window_y = frame.origin.y; - } - - { // Mouse - NSRect frame = original_frame; - NSPoint mouse_pos = ((NSPoint (*)(id, SEL))objc_msgSend)(window, sel_registerName("mouseLocationOutsideOfEventStream")); - mouse_pos.x = gb_clamp(mouse_pos.x, 0, frame.size.width-1); - mouse_pos.y = gb_clamp(mouse_pos.y, 0, frame.size.height-1); - - { - i32 x = mouse_pos.x; - i32 y = mouse_pos.y; - p->mouse_dx = x - p->mouse_x; - p->mouse_dy = y - p->mouse_y; - p->mouse_x = x; - p->mouse_y = y; - } - - if (p->mouse_clip) { - b32 update = false; - i32 x = p->mouse_x; - i32 y = p->mouse_y; - if (p->mouse_x < 0) { - x = 0; - update = true; - } else if (p->mouse_y > p->window_height-1) { - y = p->window_height-1; - update = true; - } - - if (p->mouse_y < 0) { - y = 0; - update = true; - } else if (p->mouse_x > p->window_width-1) { - x = p->window_width-1; - update = true; - } - - if (update) { - gb_platform_set_mouse_position(p, x, y); - } - } - } - - { // TODO(bill): Controllers - - } - - // TODO(bill): Is this in the correct place? - objc_msgSend_void(NSApp, sel_registerName("updateWindows")); - if (p->renderer_type == gbRenderer_Opengl) { - objc_msgSend_void(cast(id)p->opengl.context, sel_registerName("update")); - gb_platform_make_opengl_context_current(p); - } -} - -void gb_platform_display(gbPlatform *p) { - // TODO(bill): Do more - if (p->renderer_type == gbRenderer_Opengl) { - gb_platform_make_opengl_context_current(p); - objc_msgSend_void(cast(id)p->opengl.context, sel_registerName("flushBuffer")); - } else if (p->renderer_type == gbRenderer_Software) { - // TODO(bill): - } else { - GB_PANIC("Invalid window rendering type"); - } - - { - f64 prev_time = p->curr_time; - f64 curr_time = gb_time_now(); - p->dt_for_frame = curr_time - prev_time; - p->curr_time = curr_time; - } -} - -void gb_platform_destroy(gbPlatform *p) { - gb_platform_make_opengl_context_current(p); - - objc_msgSend_void(cast(id)p->window_handle, sel_registerName("close")); - - #if defined(ARC_AVAILABLE) - // TODO(bill): autorelease pool - #else - objc_msgSend_void(cast(id)p->osx_autorelease_pool, sel_registerName("drain")); - #endif -} - -void gb_platform_show_cursor(gbPlatform *p, b32 show) { - if (show ) { - // objc_msgSend_void(class_registerName("NSCursor"), sel_registerName("unhide")); - } else { - // objc_msgSend_void(class_registerName("NSCursor"), sel_registerName("hide")); - } -} - -void gb_platform_set_mouse_position(gbPlatform *p, i32 x, i32 y) { - // TODO(bill): - CGPoint pos = {cast(CGFloat)x, cast(CGFloat)y}; - pos.x += p->window_x; - pos.y += p->window_y; - CGWarpMouseCursorPosition(pos); -} - -void gb_platform_set_controller_vibration(gbPlatform *p, isize index, f32 left_motor, f32 right_motor) { - // TODO(bill): -} - -b32 gb_platform_has_clipboard_text(gbPlatform *p) { - // TODO(bill): - return false; -} - -void gb_platform_set_clipboard_text(gbPlatform *p, char const *str) { - // TODO(bill): -} - -char *gb_platform_get_clipboard_text(gbPlatform *p, gbAllocator a) { - // TODO(bill): - return NULL; -} - -void gb_platform_set_window_position(gbPlatform *p, i32 x, i32 y) { - // TODO(bill): -} - -void gb_platform_set_window_title(gbPlatform *p, char const *title, ...) { - id title_string; - char buf[256] = {0}; - va_list va; - va_start(va, title); - gb_snprintf_va(buf, gb_count_of(buf), title, va); - va_end(va); - - title_string = objc_msgSend_id_char_const(cast(id)objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), buf); - objc_msgSend_void_id(cast(id)p->window_handle, sel_registerName("setTitle:"), title_string); -} - -void gb_platform_toggle_fullscreen(gbPlatform *p, b32 fullscreen_desktop) { - // TODO(bill): -} - -void gb_platform_toggle_borderless(gbPlatform *p) { - // TODO(bill): -} - -void gb_platform_make_opengl_context_current(gbPlatform *p) { - objc_msgSend_void(cast(id)p->opengl.context, sel_registerName("makeCurrentContext")); -} - -void gb_platform_show_window(gbPlatform *p) { - // TODO(bill): -} - -void gb_platform_hide_window(gbPlatform *p) { - // TODO(bill): -} - -i32 gb__osx_mode_bits_per_pixel(CGDisplayModeRef mode) { - i32 bits_per_pixel = 0; - CFStringRef pixel_encoding = CGDisplayModeCopyPixelEncoding(mode); - if(CFStringCompare(pixel_encoding, CFSTR(IO32BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo) { - bits_per_pixel = 32; - } else if(CFStringCompare(pixel_encoding, CFSTR(IO16BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo) { - bits_per_pixel = 16; - } else if(CFStringCompare(pixel_encoding, CFSTR(IO8BitIndexedPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo) { - bits_per_pixel = 8; - } - CFRelease(pixel_encoding); - - return bits_per_pixel; -} - -i32 gb__osx_display_bits_per_pixel(CGDirectDisplayID display) { - CGDisplayModeRef mode = CGDisplayCopyDisplayMode(display); - i32 bits_per_pixel = gb__osx_mode_bits_per_pixel(mode); - CGDisplayModeRelease(mode); - return bits_per_pixel; -} - -gbVideoMode gb_video_mode_get_desktop(void) { - CGDirectDisplayID display = CGMainDisplayID(); - return gb_video_mode(CGDisplayPixelsWide(display), - CGDisplayPixelsHigh(display), - gb__osx_display_bits_per_pixel(display)); -} - - -isize gb_video_mode_get_fullscreen_modes(gbVideoMode *modes, isize max_mode_count) { - CFArrayRef cg_modes = CGDisplayCopyAllDisplayModes(CGMainDisplayID(), NULL); - CFIndex i, count; - if (cg_modes == NULL) { - return 0; - } - - count = gb_min(CFArrayGetCount(cg_modes), max_mode_count); - for (i = 0; i < count; i++) { - CGDisplayModeRef cg_mode = cast(CGDisplayModeRef)CFArrayGetValueAtIndex(cg_modes, i); - modes[i] = gb_video_mode(CGDisplayModeGetWidth(cg_mode), - CGDisplayModeGetHeight(cg_mode), - gb__osx_mode_bits_per_pixel(cg_mode)); - } - - CFRelease(cg_modes); - - gb_sort_array(modes, count, gb_video_mode_dsc_cmp); - return cast(isize)count; -} - -#endif - - -// TODO(bill): OSX Platform Layer -// NOTE(bill): Use this as a guide so there is no need for Obj-C https://github.com/jimon/osx_app_in_plain_c - -gb_inline gbVideoMode gb_video_mode(i32 width, i32 height, i32 bits_per_pixel) { - gbVideoMode m; - m.width = width; - m.height = height; - m.bits_per_pixel = bits_per_pixel; - return m; -} - -gb_inline b32 gb_video_mode_is_valid(gbVideoMode mode) { - gb_local_persist gbVideoMode modes[256] = {0}; - gb_local_persist isize mode_count = 0; - gb_local_persist b32 is_set = false; - isize i; - - if (!is_set) { - mode_count = gb_video_mode_get_fullscreen_modes(modes, gb_count_of(modes)); - is_set = true; - } - - for (i = 0; i < mode_count; i++) { - gb_printf("%d %d\n", modes[i].width, modes[i].height); - } - - return gb_binary_search_array(modes, mode_count, &mode, gb_video_mode_cmp) >= 0; -} - -GB_COMPARE_PROC(gb_video_mode_cmp) { - gbVideoMode const *x = cast(gbVideoMode const *)a; - gbVideoMode const *y = cast(gbVideoMode const *)b; - - if (x->bits_per_pixel == y->bits_per_pixel) { - if (x->width == y->width) { - return x->height < y->height ? -1 : x->height > y->height; - } - return x->width < y->width ? -1 : x->width > y->width; - } - return x->bits_per_pixel < y->bits_per_pixel ? -1 : +1; -} - -GB_COMPARE_PROC(gb_video_mode_dsc_cmp) { - return gb_video_mode_cmp(b, a); -} - -#endif // defined(GB_PLATFORM) - - - - -#if defined(GB_COMPILER_MSVC) -#pragma warning(pop) -#endif - -#if defined(__GCC__) || defined(__GNUC__) -#pragma GCC diagnostic pop -#endif - - -#if defined(__cplusplus) -} -#endif - -#endif // GB_IMPLEMENTATION diff --git a/thirdparty/stb/src/stb_image.c b/thirdparty/stb/src/stb_image.c deleted file mode 100644 index badb3ef..0000000 --- a/thirdparty/stb/src/stb_image.c +++ /dev/null @@ -1,2 +0,0 @@ -#define STB_IMAGE_IMPLEMENTATION -#include "stb_image.h" \ No newline at end of file diff --git a/thirdparty/stb/src/stb_image.h b/thirdparty/stb/src/stb_image.h deleted file mode 100644 index 39acae6..0000000 --- a/thirdparty/stb/src/stb_image.h +++ /dev/null @@ -1,7897 +0,0 @@ -/* stb_image - v2.27 - public domain image loader - http://nothings.org/stb - no warranty implied; use at your own risk - - Do this: - #define STB_IMAGE_IMPLEMENTATION - before you include this file in *one* C or C++ file to create the implementation. - - // i.e. it should look like this: - #include ... - #include ... - #include ... - #define STB_IMAGE_IMPLEMENTATION - #include "stb_image.h" - - You can #define STBI_ASSERT(x) before the #include to avoid using assert.h. - And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free - - - QUICK NOTES: - Primarily of interest to game developers and other people who can - avoid problematic images and only need the trivial interface - - JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib) - PNG 1/2/4/8/16-bit-per-channel - - TGA (not sure what subset, if a subset) - BMP non-1bpp, non-RLE - PSD (composited view only, no extra channels, 8/16 bit-per-channel) - - GIF (*comp always reports as 4-channel) - HDR (radiance rgbE format) - PIC (Softimage PIC) - PNM (PPM and PGM binary only) - - Animated GIF still needs a proper API, but here's one way to do it: - http://gist.github.com/urraka/685d9a6340b26b830d49 - - - decode from memory or through FILE (define STBI_NO_STDIO to remove code) - - decode from arbitrary I/O callbacks - - SIMD acceleration on x86/x64 (SSE2) and ARM (NEON) - - Full documentation under "DOCUMENTATION" below. - - -LICENSE - - See end of file for license information. - -RECENT REVISION HISTORY: - - 2.27 (2021-07-11) document stbi_info better, 16-bit PNM support, bug fixes - 2.26 (2020-07-13) many minor fixes - 2.25 (2020-02-02) fix warnings - 2.24 (2020-02-02) fix warnings; thread-local failure_reason and flip_vertically - 2.23 (2019-08-11) fix clang static analysis warning - 2.22 (2019-03-04) gif fixes, fix warnings - 2.21 (2019-02-25) fix typo in comment - 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs - 2.19 (2018-02-11) fix warning - 2.18 (2018-01-30) fix warnings - 2.17 (2018-01-29) bugfix, 1-bit BMP, 16-bitness query, fix warnings - 2.16 (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes - 2.15 (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC - 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs - 2.13 (2016-12-04) experimental 16-bit API, only for PNG so far; fixes - 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes - 2.11 (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64 - RGB-format JPEG; remove white matting in PSD; - allocate large structures on the stack; - correct channel count for PNG & BMP - 2.10 (2016-01-22) avoid warning introduced in 2.09 - 2.09 (2016-01-16) 16-bit TGA; comments in PNM files; STBI_REALLOC_SIZED - - See end of file for full revision history. - - - ============================ Contributors ========================= - - Image formats Extensions, features - Sean Barrett (jpeg, png, bmp) Jetro Lauha (stbi_info) - Nicolas Schulz (hdr, psd) Martin "SpartanJ" Golini (stbi_info) - Jonathan Dummer (tga) James "moose2000" Brown (iPhone PNG) - Jean-Marc Lienher (gif) Ben "Disch" Wenger (io callbacks) - Tom Seddon (pic) Omar Cornut (1/2/4-bit PNG) - Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip) - Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD) - github:urraka (animated gif) Junggon Kim (PNM comments) - Christopher Forseth (animated gif) Daniel Gibson (16-bit TGA) - socks-the-fox (16-bit PNG) - Jeremy Sawicki (handle all ImageNet JPGs) - Optimizations & bugfixes Mikhail Morozov (1-bit BMP) - Fabian "ryg" Giesen Anael Seghezzi (is-16-bit query) - Arseny Kapoulkine Simon Breuss (16-bit PNM) - John-Mark Allen - Carmelo J Fdez-Aguera - - Bug & warning fixes - Marc LeBlanc David Woo Guillaume George Martins Mozeiko - Christpher Lloyd Jerry Jansson Joseph Thomson Blazej Dariusz Roszkowski - Phil Jordan Dave Moore Roy Eltham - Hayaki Saito Nathan Reed Won Chun - Luke Graham Johan Duparc Nick Verigakis the Horde3D community - Thomas Ruf Ronny Chevalier github:rlyeh - Janez Zemva John Bartholomew Michal Cichon github:romigrou - Jonathan Blow Ken Hamada Tero Hanninen github:svdijk - Eugene Golushkov Laurent Gomila Cort Stratton github:snagar - Aruelien Pocheville Sergio Gonzalez Thibault Reuille github:Zelex - Cass Everitt Ryamond Barbiero github:grim210 - Paul Du Bois Engin Manap Aldo Culquicondor github:sammyhw - Philipp Wiesemann Dale Weiler Oriol Ferrer Mesia github:phprus - Josh Tobin Matthew Gregan github:poppolopoppo - Julian Raschke Gregory Mullen Christian Floisand github:darealshinji - Baldur Karlsson Kevin Schmidt JR Smith github:Michaelangel007 - Brad Weinberger Matvey Cherevko github:mosra - Luca Sas Alexander Veselov Zack Middleton [reserved] - Ryan C. Gordon [reserved] [reserved] - DO NOT ADD YOUR NAME HERE - - Jacko Dirks - - To add your name to the credits, pick a random blank space in the middle and fill it. - 80% of merge conflicts on stb PRs are due to people adding their name at the end - of the credits. -*/ - -#ifndef STBI_INCLUDE_STB_IMAGE_H -#define STBI_INCLUDE_STB_IMAGE_H - -// DOCUMENTATION -// -// Limitations: -// - no 12-bit-per-channel JPEG -// - no JPEGs with arithmetic coding -// - GIF always returns *comp=4 -// -// Basic usage (see HDR discussion below for HDR usage): -// int x,y,n; -// unsigned char *data = stbi_load(filename, &x, &y, &n, 0); -// // ... process data if not NULL ... -// // ... x = width, y = height, n = # 8-bit components per pixel ... -// // ... replace '0' with '1'..'4' to force that many components per pixel -// // ... but 'n' will always be the number that it would have been if you said 0 -// stbi_image_free(data) -// -// Standard parameters: -// int *x -- outputs image width in pixels -// int *y -- outputs image height in pixels -// int *channels_in_file -- outputs # of image components in image file -// int desired_channels -- if non-zero, # of image components requested in result -// -// The return value from an image loader is an 'unsigned char *' which points -// to the pixel data, or NULL on an allocation failure or if the image is -// corrupt or invalid. The pixel data consists of *y scanlines of *x pixels, -// with each pixel consisting of N interleaved 8-bit components; the first -// pixel pointed to is top-left-most in the image. There is no padding between -// image scanlines or between pixels, regardless of format. The number of -// components N is 'desired_channels' if desired_channels is non-zero, or -// *channels_in_file otherwise. If desired_channels is non-zero, -// *channels_in_file has the number of components that _would_ have been -// output otherwise. E.g. if you set desired_channels to 4, you will always -// get RGBA output, but you can check *channels_in_file to see if it's trivially -// opaque because e.g. there were only 3 channels in the source image. -// -// An output image with N components has the following components interleaved -// in this order in each pixel: -// -// N=#comp components -// 1 grey -// 2 grey, alpha -// 3 red, green, blue -// 4 red, green, blue, alpha -// -// If image loading fails for any reason, the return value will be NULL, -// and *x, *y, *channels_in_file will be unchanged. The function -// stbi_failure_reason() can be queried for an extremely brief, end-user -// unfriendly explanation of why the load failed. Define STBI_NO_FAILURE_STRINGS -// to avoid compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly -// more user-friendly ones. -// -// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized. -// -// To query the width, height and component count of an image without having to -// decode the full file, you can use the stbi_info family of functions: -// -// int x,y,n,ok; -// ok = stbi_info(filename, &x, &y, &n); -// // returns ok=1 and sets x, y, n if image is a supported format, -// // 0 otherwise. -// -// Note that stb_image pervasively uses ints in its public API for sizes, -// including sizes of memory buffers. This is now part of the API and thus -// hard to change without causing breakage. As a result, the various image -// loaders all have certain limits on image size; these differ somewhat -// by format but generally boil down to either just under 2GB or just under -// 1GB. When the decoded image would be larger than this, stb_image decoding -// will fail. -// -// Additionally, stb_image will reject image files that have any of their -// dimensions set to a larger value than the configurable STBI_MAX_DIMENSIONS, -// which defaults to 2**24 = 16777216 pixels. Due to the above memory limit, -// the only way to have an image with such dimensions load correctly -// is for it to have a rather extreme aspect ratio. Either way, the -// assumption here is that such larger images are likely to be malformed -// or malicious. If you do need to load an image with individual dimensions -// larger than that, and it still fits in the overall size limit, you can -// #define STBI_MAX_DIMENSIONS on your own to be something larger. -// -// =========================================================================== -// -// UNICODE: -// -// If compiling for Windows and you wish to use Unicode filenames, compile -// with -// #define STBI_WINDOWS_UTF8 -// and pass utf8-encoded filenames. Call stbi_convert_wchar_to_utf8 to convert -// Windows wchar_t filenames to utf8. -// -// =========================================================================== -// -// Philosophy -// -// stb libraries are designed with the following priorities: -// -// 1. easy to use -// 2. easy to maintain -// 3. good performance -// -// Sometimes I let "good performance" creep up in priority over "easy to maintain", -// and for best performance I may provide less-easy-to-use APIs that give higher -// performance, in addition to the easy-to-use ones. Nevertheless, it's important -// to keep in mind that from the standpoint of you, a client of this library, -// all you care about is #1 and #3, and stb libraries DO NOT emphasize #3 above all. -// -// Some secondary priorities arise directly from the first two, some of which -// provide more explicit reasons why performance can't be emphasized. -// -// - Portable ("ease of use") -// - Small source code footprint ("easy to maintain") -// - No dependencies ("ease of use") -// -// =========================================================================== -// -// I/O callbacks -// -// I/O callbacks allow you to read from arbitrary sources, like packaged -// files or some other source. Data read from callbacks are processed -// through a small internal buffer (currently 128 bytes) to try to reduce -// overhead. -// -// The three functions you must define are "read" (reads some bytes of data), -// "skip" (skips some bytes of data), "eof" (reports if the stream is at the end). -// -// =========================================================================== -// -// SIMD support -// -// The JPEG decoder will try to automatically use SIMD kernels on x86 when -// supported by the compiler. For ARM Neon support, you must explicitly -// request it. -// -// (The old do-it-yourself SIMD API is no longer supported in the current -// code.) -// -// On x86, SSE2 will automatically be used when available based on a run-time -// test; if not, the generic C versions are used as a fall-back. On ARM targets, -// the typical path is to have separate builds for NEON and non-NEON devices -// (at least this is true for iOS and Android). Therefore, the NEON support is -// toggled by a build flag: define STBI_NEON to get NEON loops. -// -// If for some reason you do not want to use any of SIMD code, or if -// you have issues compiling it, you can disable it entirely by -// defining STBI_NO_SIMD. -// -// =========================================================================== -// -// HDR image support (disable by defining STBI_NO_HDR) -// -// stb_image supports loading HDR images in general, and currently the Radiance -// .HDR file format specifically. You can still load any file through the existing -// interface; if you attempt to load an HDR file, it will be automatically remapped -// to LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1; -// both of these constants can be reconfigured through this interface: -// -// stbi_hdr_to_ldr_gamma(2.2f); -// stbi_hdr_to_ldr_scale(1.0f); -// -// (note, do not use _inverse_ constants; stbi_image will invert them -// appropriately). -// -// Additionally, there is a new, parallel interface for loading files as -// (linear) floats to preserve the full dynamic range: -// -// float *data = stbi_loadf(filename, &x, &y, &n, 0); -// -// If you load LDR images through this interface, those images will -// be promoted to floating point values, run through the inverse of -// constants corresponding to the above: -// -// stbi_ldr_to_hdr_scale(1.0f); -// stbi_ldr_to_hdr_gamma(2.2f); -// -// Finally, given a filename (or an open file or memory block--see header -// file for details) containing image data, you can query for the "most -// appropriate" interface to use (that is, whether the image is HDR or -// not), using: -// -// stbi_is_hdr(char *filename); -// -// =========================================================================== -// -// iPhone PNG support: -// -// We optionally support converting iPhone-formatted PNGs (which store -// premultiplied BGRA) back to RGB, even though they're internally encoded -// differently. To enable this conversion, call -// stbi_convert_iphone_png_to_rgb(1). -// -// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per -// pixel to remove any premultiplied alpha *only* if the image file explicitly -// says there's premultiplied data (currently only happens in iPhone images, -// and only if iPhone convert-to-rgb processing is on). -// -// =========================================================================== -// -// ADDITIONAL CONFIGURATION -// -// - You can suppress implementation of any of the decoders to reduce -// your code footprint by #defining one or more of the following -// symbols before creating the implementation. -// -// STBI_NO_JPEG -// STBI_NO_PNG -// STBI_NO_BMP -// STBI_NO_PSD -// STBI_NO_TGA -// STBI_NO_GIF -// STBI_NO_HDR -// STBI_NO_PIC -// STBI_NO_PNM (.ppm and .pgm) -// -// - You can request *only* certain decoders and suppress all other ones -// (this will be more forward-compatible, as addition of new decoders -// doesn't require you to disable them explicitly): -// -// STBI_ONLY_JPEG -// STBI_ONLY_PNG -// STBI_ONLY_BMP -// STBI_ONLY_PSD -// STBI_ONLY_TGA -// STBI_ONLY_GIF -// STBI_ONLY_HDR -// STBI_ONLY_PIC -// STBI_ONLY_PNM (.ppm and .pgm) -// -// - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still -// want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB -// -// - If you define STBI_MAX_DIMENSIONS, stb_image will reject images greater -// than that size (in either width or height) without further processing. -// This is to let programs in the wild set an upper bound to prevent -// denial-of-service attacks on untrusted data, as one could generate a -// valid image of gigantic dimensions and force stb_image to allocate a -// huge block of memory and spend disproportionate time decoding it. By -// default this is set to (1 << 24), which is 16777216, but that's still -// very big. - -#ifndef STBI_NO_STDIO -#include -#endif // STBI_NO_STDIO - -#define STBI_VERSION 1 - -enum -{ - STBI_default = 0, // only used for desired_channels - - STBI_grey = 1, - STBI_grey_alpha = 2, - STBI_rgb = 3, - STBI_rgb_alpha = 4 -}; - -#include -typedef unsigned char stbi_uc; -typedef unsigned short stbi_us; - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef STBIDEF -#ifdef STB_IMAGE_STATIC -#define STBIDEF static -#else -#define STBIDEF extern -#endif -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// PRIMARY API - works on images of any type -// - -// -// load image by filename, open file, or memory buffer -// - -typedef struct -{ - int (*read) (void *user,char *data,int size); // fill 'data' with 'size' bytes. return number of bytes actually read - void (*skip) (void *user,int n); // skip the next 'n' bytes, or 'unget' the last -n bytes if negative - int (*eof) (void *user); // returns nonzero if we are at end of file/data -} stbi_io_callbacks; - -//////////////////////////////////// -// -// 8-bits-per-channel interface -// - -STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *channels_in_file, int desired_channels); -STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *channels_in_file, int desired_channels); - -#ifndef STBI_NO_STDIO -STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); -STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); -// for stbi_load_from_file, file pointer is left pointing immediately after image -#endif - -#ifndef STBI_NO_GIF -STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp); -#endif - -#ifdef STBI_WINDOWS_UTF8 -STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input); -#endif - -//////////////////////////////////// -// -// 16-bits-per-channel interface -// - -STBIDEF stbi_us *stbi_load_16_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); -STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); - -#ifndef STBI_NO_STDIO -STBIDEF stbi_us *stbi_load_16 (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); -STBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); -#endif - -//////////////////////////////////// -// -// float-per-channel interface -// -#ifndef STBI_NO_LINEAR - STBIDEF float *stbi_loadf_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); - STBIDEF float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); - - #ifndef STBI_NO_STDIO - STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); - STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); - #endif -#endif - -#ifndef STBI_NO_HDR - STBIDEF void stbi_hdr_to_ldr_gamma(float gamma); - STBIDEF void stbi_hdr_to_ldr_scale(float scale); -#endif // STBI_NO_HDR - -#ifndef STBI_NO_LINEAR - STBIDEF void stbi_ldr_to_hdr_gamma(float gamma); - STBIDEF void stbi_ldr_to_hdr_scale(float scale); -#endif // STBI_NO_LINEAR - -// stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR -STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user); -STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len); -#ifndef STBI_NO_STDIO -STBIDEF int stbi_is_hdr (char const *filename); -STBIDEF int stbi_is_hdr_from_file(FILE *f); -#endif // STBI_NO_STDIO - - -// get a VERY brief reason for failure -// on most compilers (and ALL modern mainstream compilers) this is threadsafe -STBIDEF const char *stbi_failure_reason (void); - -// free the loaded image -- this is just free() -STBIDEF void stbi_image_free (void *retval_from_stbi_load); - -// get image dimensions & components without fully decoding -STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); -STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp); -STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len); -STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *clbk, void *user); - -#ifndef STBI_NO_STDIO -STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp); -STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp); -STBIDEF int stbi_is_16_bit (char const *filename); -STBIDEF int stbi_is_16_bit_from_file(FILE *f); -#endif - - - -// for image formats that explicitly notate that they have premultiplied alpha, -// we just return the colors as stored in the file. set this flag to force -// unpremultiplication. results are undefined if the unpremultiply overflow. -STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply); - -// indicate whether we should process iphone images back to canonical format, -// or just pass them through "as-is" -STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert); - -// flip the image vertically, so the first pixel in the output array is the bottom left -STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip); - -// as above, but only applies to images loaded on the thread that calls the function -// this function is only available if your compiler supports thread-local variables; -// calling it will fail to link if your compiler doesn't -STBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply); -STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert); -STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip); - -// ZLIB client - used by PNG, available for other purposes - -STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen); -STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header); -STBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen); -STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); - -STBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen); -STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); - - -#ifdef __cplusplus -} -#endif - -// -// -//// end header file ///////////////////////////////////////////////////// -#endif // STBI_INCLUDE_STB_IMAGE_H - -#ifdef STB_IMAGE_IMPLEMENTATION - -#if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || defined(STBI_ONLY_BMP) \ - || defined(STBI_ONLY_TGA) || defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) \ - || defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || defined(STBI_ONLY_PNM) \ - || defined(STBI_ONLY_ZLIB) - #ifndef STBI_ONLY_JPEG - #define STBI_NO_JPEG - #endif - #ifndef STBI_ONLY_PNG - #define STBI_NO_PNG - #endif - #ifndef STBI_ONLY_BMP - #define STBI_NO_BMP - #endif - #ifndef STBI_ONLY_PSD - #define STBI_NO_PSD - #endif - #ifndef STBI_ONLY_TGA - #define STBI_NO_TGA - #endif - #ifndef STBI_ONLY_GIF - #define STBI_NO_GIF - #endif - #ifndef STBI_ONLY_HDR - #define STBI_NO_HDR - #endif - #ifndef STBI_ONLY_PIC - #define STBI_NO_PIC - #endif - #ifndef STBI_ONLY_PNM - #define STBI_NO_PNM - #endif -#endif - -#if defined(STBI_NO_PNG) && !defined(STBI_SUPPORT_ZLIB) && !defined(STBI_NO_ZLIB) -#define STBI_NO_ZLIB -#endif - - -#include -#include // ptrdiff_t on osx -#include -#include -#include - -#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) -#include // ldexp, pow -#endif - -#ifndef STBI_NO_STDIO -#include -#endif - -#ifndef STBI_ASSERT -#include -#define STBI_ASSERT(x) assert(x) -#endif - -#ifdef __cplusplus -#define STBI_EXTERN extern "C" -#else -#define STBI_EXTERN extern -#endif - - -#ifndef _MSC_VER - #ifdef __cplusplus - #define stbi_inline inline - #else - #define stbi_inline - #endif -#else - #define stbi_inline __forceinline -#endif - -#ifndef STBI_NO_THREAD_LOCALS - #if defined(__cplusplus) && __cplusplus >= 201103L - #define STBI_THREAD_LOCAL thread_local - #elif defined(__GNUC__) && __GNUC__ < 5 - #define STBI_THREAD_LOCAL __thread - #elif defined(_MSC_VER) - #define STBI_THREAD_LOCAL __declspec(thread) - #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_THREADS__) - #define STBI_THREAD_LOCAL _Thread_local - #endif - - #ifndef STBI_THREAD_LOCAL - #if defined(__GNUC__) - #define STBI_THREAD_LOCAL __thread - #endif - #endif -#endif - -#ifdef _MSC_VER -typedef unsigned short stbi__uint16; -typedef signed short stbi__int16; -typedef unsigned int stbi__uint32; -typedef signed int stbi__int32; -#else -#include -typedef uint16_t stbi__uint16; -typedef int16_t stbi__int16; -typedef uint32_t stbi__uint32; -typedef int32_t stbi__int32; -#endif - -// should produce compiler error if size is wrong -typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; - -#ifdef _MSC_VER -#define STBI_NOTUSED(v) (void)(v) -#else -#define STBI_NOTUSED(v) (void)sizeof(v) -#endif - -#ifdef _MSC_VER -#define STBI_HAS_LROTL -#endif - -#ifdef STBI_HAS_LROTL - #define stbi_lrot(x,y) _lrotl(x,y) -#else - #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (-(y) & 31))) -#endif - -#if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED)) -// ok -#elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC) && !defined(STBI_REALLOC_SIZED) -// ok -#else -#error "Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC (or STBI_REALLOC_SIZED)." -#endif - -#ifndef STBI_MALLOC -#define STBI_MALLOC(sz) malloc(sz) -#define STBI_REALLOC(p,newsz) realloc(p,newsz) -#define STBI_FREE(p) free(p) -#endif - -#ifndef STBI_REALLOC_SIZED -#define STBI_REALLOC_SIZED(p,oldsz,newsz) STBI_REALLOC(p,newsz) -#endif - -// x86/x64 detection -#if defined(__x86_64__) || defined(_M_X64) -#define STBI__X64_TARGET -#elif defined(__i386) || defined(_M_IX86) -#define STBI__X86_TARGET -#endif - -#if defined(__GNUC__) && defined(STBI__X86_TARGET) && !defined(__SSE2__) && !defined(STBI_NO_SIMD) -// gcc doesn't support sse2 intrinsics unless you compile with -msse2, -// which in turn means it gets to use SSE2 everywhere. This is unfortunate, -// but previous attempts to provide the SSE2 functions with runtime -// detection caused numerous issues. The way architecture extensions are -// exposed in GCC/Clang is, sadly, not really suited for one-file libs. -// New behavior: if compiled with -msse2, we use SSE2 without any -// detection; if not, we don't use it at all. -#define STBI_NO_SIMD -#endif - -#if defined(__MINGW32__) && defined(STBI__X86_TARGET) && !defined(STBI_MINGW_ENABLE_SSE2) && !defined(STBI_NO_SIMD) -// Note that __MINGW32__ doesn't actually mean 32-bit, so we have to avoid STBI__X64_TARGET -// -// 32-bit MinGW wants ESP to be 16-byte aligned, but this is not in the -// Windows ABI and VC++ as well as Windows DLLs don't maintain that invariant. -// As a result, enabling SSE2 on 32-bit MinGW is dangerous when not -// simultaneously enabling "-mstackrealign". -// -// See https://github.com/nothings/stb/issues/81 for more information. -// -// So default to no SSE2 on 32-bit MinGW. If you've read this far and added -// -mstackrealign to your build settings, feel free to #define STBI_MINGW_ENABLE_SSE2. -#define STBI_NO_SIMD -#endif - -#if !defined(STBI_NO_SIMD) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET)) -#define STBI_SSE2 -#include - -#ifdef _MSC_VER - -#if _MSC_VER >= 1400 // not VC6 -#include // __cpuid -static int stbi__cpuid3(void) -{ - int info[4]; - __cpuid(info,1); - return info[3]; -} -#else -static int stbi__cpuid3(void) -{ - int res; - __asm { - mov eax,1 - cpuid - mov res,edx - } - return res; -} -#endif - -#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name - -#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2) -static int stbi__sse2_available(void) -{ - int info3 = stbi__cpuid3(); - return ((info3 >> 26) & 1) != 0; -} -#endif - -#else // assume GCC-style if not VC++ -#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) - -#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2) -static int stbi__sse2_available(void) -{ - // If we're even attempting to compile this on GCC/Clang, that means - // -msse2 is on, which means the compiler is allowed to use SSE2 - // instructions at will, and so are we. - return 1; -} -#endif - -#endif -#endif - -// ARM NEON -#if defined(STBI_NO_SIMD) && defined(STBI_NEON) -#undef STBI_NEON -#endif - -#ifdef STBI_NEON -#include -#ifdef _MSC_VER -#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name -#else -#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) -#endif -#endif - -#ifndef STBI_SIMD_ALIGN -#define STBI_SIMD_ALIGN(type, name) type name -#endif - -#ifndef STBI_MAX_DIMENSIONS -#define STBI_MAX_DIMENSIONS (1 << 24) -#endif - -/////////////////////////////////////////////// -// -// stbi__context struct and start_xxx functions - -// stbi__context structure is our basic context used by all images, so it -// contains all the IO context, plus some basic image information -typedef struct -{ - stbi__uint32 img_x, img_y; - int img_n, img_out_n; - - stbi_io_callbacks io; - void *io_user_data; - - int read_from_callbacks; - int buflen; - stbi_uc buffer_start[128]; - int callback_already_read; - - stbi_uc *img_buffer, *img_buffer_end; - stbi_uc *img_buffer_original, *img_buffer_original_end; -} stbi__context; - - -static void stbi__refill_buffer(stbi__context *s); - -// initialize a memory-decode context -static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len) -{ - s->io.read = NULL; - s->read_from_callbacks = 0; - s->callback_already_read = 0; - s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer; - s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *) buffer+len; -} - -// initialize a callback-based context -static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user) -{ - s->io = *c; - s->io_user_data = user; - s->buflen = sizeof(s->buffer_start); - s->read_from_callbacks = 1; - s->callback_already_read = 0; - s->img_buffer = s->img_buffer_original = s->buffer_start; - stbi__refill_buffer(s); - s->img_buffer_original_end = s->img_buffer_end; -} - -#ifndef STBI_NO_STDIO - -static int stbi__stdio_read(void *user, char *data, int size) -{ - return (int) fread(data,1,size,(FILE*) user); -} - -static void stbi__stdio_skip(void *user, int n) -{ - int ch; - fseek((FILE*) user, n, SEEK_CUR); - ch = fgetc((FILE*) user); /* have to read a byte to reset feof()'s flag */ - if (ch != EOF) { - ungetc(ch, (FILE *) user); /* push byte back onto stream if valid. */ - } -} - -static int stbi__stdio_eof(void *user) -{ - return feof((FILE*) user) || ferror((FILE *) user); -} - -static stbi_io_callbacks stbi__stdio_callbacks = -{ - stbi__stdio_read, - stbi__stdio_skip, - stbi__stdio_eof, -}; - -static void stbi__start_file(stbi__context *s, FILE *f) -{ - stbi__start_callbacks(s, &stbi__stdio_callbacks, (void *) f); -} - -//static void stop_file(stbi__context *s) { } - -#endif // !STBI_NO_STDIO - -static void stbi__rewind(stbi__context *s) -{ - // conceptually rewind SHOULD rewind to the beginning of the stream, - // but we just rewind to the beginning of the initial buffer, because - // we only use it after doing 'test', which only ever looks at at most 92 bytes - s->img_buffer = s->img_buffer_original; - s->img_buffer_end = s->img_buffer_original_end; -} - -enum -{ - STBI_ORDER_RGB, - STBI_ORDER_BGR -}; - -typedef struct -{ - int bits_per_channel; - int num_channels; - int channel_order; -} stbi__result_info; - -#ifndef STBI_NO_JPEG -static int stbi__jpeg_test(stbi__context *s); -static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); -static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp); -#endif - -#ifndef STBI_NO_PNG -static int stbi__png_test(stbi__context *s); -static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); -static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp); -static int stbi__png_is16(stbi__context *s); -#endif - -#ifndef STBI_NO_BMP -static int stbi__bmp_test(stbi__context *s); -static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); -static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp); -#endif - -#ifndef STBI_NO_TGA -static int stbi__tga_test(stbi__context *s); -static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); -static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp); -#endif - -#ifndef STBI_NO_PSD -static int stbi__psd_test(stbi__context *s); -static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc); -static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp); -static int stbi__psd_is16(stbi__context *s); -#endif - -#ifndef STBI_NO_HDR -static int stbi__hdr_test(stbi__context *s); -static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); -static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp); -#endif - -#ifndef STBI_NO_PIC -static int stbi__pic_test(stbi__context *s); -static void *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); -static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp); -#endif - -#ifndef STBI_NO_GIF -static int stbi__gif_test(stbi__context *s); -static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); -static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp); -static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp); -#endif - -#ifndef STBI_NO_PNM -static int stbi__pnm_test(stbi__context *s); -static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); -static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp); -static int stbi__pnm_is16(stbi__context *s); -#endif - -static -#ifdef STBI_THREAD_LOCAL -STBI_THREAD_LOCAL -#endif -const char *stbi__g_failure_reason; - -STBIDEF const char *stbi_failure_reason(void) -{ - return stbi__g_failure_reason; -} - -#ifndef STBI_NO_FAILURE_STRINGS -static int stbi__err(const char *str) -{ - stbi__g_failure_reason = str; - return 0; -} -#endif - -static void *stbi__malloc(size_t size) -{ - return STBI_MALLOC(size); -} - -// stb_image uses ints pervasively, including for offset calculations. -// therefore the largest decoded image size we can support with the -// current code, even on 64-bit targets, is INT_MAX. this is not a -// significant limitation for the intended use case. -// -// we do, however, need to make sure our size calculations don't -// overflow. hence a few helper functions for size calculations that -// multiply integers together, making sure that they're non-negative -// and no overflow occurs. - -// return 1 if the sum is valid, 0 on overflow. -// negative terms are considered invalid. -static int stbi__addsizes_valid(int a, int b) -{ - if (b < 0) return 0; - // now 0 <= b <= INT_MAX, hence also - // 0 <= INT_MAX - b <= INTMAX. - // And "a + b <= INT_MAX" (which might overflow) is the - // same as a <= INT_MAX - b (no overflow) - return a <= INT_MAX - b; -} - -// returns 1 if the product is valid, 0 on overflow. -// negative factors are considered invalid. -static int stbi__mul2sizes_valid(int a, int b) -{ - if (a < 0 || b < 0) return 0; - if (b == 0) return 1; // mul-by-0 is always safe - // portable way to check for no overflows in a*b - return a <= INT_MAX/b; -} - -#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR) -// returns 1 if "a*b + add" has no negative terms/factors and doesn't overflow -static int stbi__mad2sizes_valid(int a, int b, int add) -{ - return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, add); -} -#endif - -// returns 1 if "a*b*c + add" has no negative terms/factors and doesn't overflow -static int stbi__mad3sizes_valid(int a, int b, int c, int add) -{ - return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && - stbi__addsizes_valid(a*b*c, add); -} - -// returns 1 if "a*b*c*d + add" has no negative terms/factors and doesn't overflow -#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM) -static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add) -{ - return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && - stbi__mul2sizes_valid(a*b*c, d) && stbi__addsizes_valid(a*b*c*d, add); -} -#endif - -#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR) -// mallocs with size overflow checking -static void *stbi__malloc_mad2(int a, int b, int add) -{ - if (!stbi__mad2sizes_valid(a, b, add)) return NULL; - return stbi__malloc(a*b + add); -} -#endif - -static void *stbi__malloc_mad3(int a, int b, int c, int add) -{ - if (!stbi__mad3sizes_valid(a, b, c, add)) return NULL; - return stbi__malloc(a*b*c + add); -} - -#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM) -static void *stbi__malloc_mad4(int a, int b, int c, int d, int add) -{ - if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL; - return stbi__malloc(a*b*c*d + add); -} -#endif - -// stbi__err - error -// stbi__errpf - error returning pointer to float -// stbi__errpuc - error returning pointer to unsigned char - -#ifdef STBI_NO_FAILURE_STRINGS - #define stbi__err(x,y) 0 -#elif defined(STBI_FAILURE_USERMSG) - #define stbi__err(x,y) stbi__err(y) -#else - #define stbi__err(x,y) stbi__err(x) -#endif - -#define stbi__errpf(x,y) ((float *)(size_t) (stbi__err(x,y)?NULL:NULL)) -#define stbi__errpuc(x,y) ((unsigned char *)(size_t) (stbi__err(x,y)?NULL:NULL)) - -STBIDEF void stbi_image_free(void *retval_from_stbi_load) -{ - STBI_FREE(retval_from_stbi_load); -} - -#ifndef STBI_NO_LINEAR -static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp); -#endif - -#ifndef STBI_NO_HDR -static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp); -#endif - -static int stbi__vertically_flip_on_load_global = 0; - -STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip) -{ - stbi__vertically_flip_on_load_global = flag_true_if_should_flip; -} - -#ifndef STBI_THREAD_LOCAL -#define stbi__vertically_flip_on_load stbi__vertically_flip_on_load_global -#else -static STBI_THREAD_LOCAL int stbi__vertically_flip_on_load_local, stbi__vertically_flip_on_load_set; - -STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip) -{ - stbi__vertically_flip_on_load_local = flag_true_if_should_flip; - stbi__vertically_flip_on_load_set = 1; -} - -#define stbi__vertically_flip_on_load (stbi__vertically_flip_on_load_set \ - ? stbi__vertically_flip_on_load_local \ - : stbi__vertically_flip_on_load_global) -#endif // STBI_THREAD_LOCAL - -static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) -{ - memset(ri, 0, sizeof(*ri)); // make sure it's initialized if we add new fields - ri->bits_per_channel = 8; // default is 8 so most paths don't have to be changed - ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order - ri->num_channels = 0; - - // test the formats with a very explicit header first (at least a FOURCC - // or distinctive magic number first) - #ifndef STBI_NO_PNG - if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp, ri); - #endif - #ifndef STBI_NO_BMP - if (stbi__bmp_test(s)) return stbi__bmp_load(s,x,y,comp,req_comp, ri); - #endif - #ifndef STBI_NO_GIF - if (stbi__gif_test(s)) return stbi__gif_load(s,x,y,comp,req_comp, ri); - #endif - #ifndef STBI_NO_PSD - if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp, ri, bpc); - #else - STBI_NOTUSED(bpc); - #endif - #ifndef STBI_NO_PIC - if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp, ri); - #endif - - // then the formats that can end up attempting to load with just 1 or 2 - // bytes matching expectations; these are prone to false positives, so - // try them later - #ifndef STBI_NO_JPEG - if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri); - #endif - #ifndef STBI_NO_PNM - if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp, ri); - #endif - - #ifndef STBI_NO_HDR - if (stbi__hdr_test(s)) { - float *hdr = stbi__hdr_load(s, x,y,comp,req_comp, ri); - return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp); - } - #endif - - #ifndef STBI_NO_TGA - // test tga last because it's a crappy test! - if (stbi__tga_test(s)) - return stbi__tga_load(s,x,y,comp,req_comp, ri); - #endif - - return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt"); -} - -static stbi_uc *stbi__convert_16_to_8(stbi__uint16 *orig, int w, int h, int channels) -{ - int i; - int img_len = w * h * channels; - stbi_uc *reduced; - - reduced = (stbi_uc *) stbi__malloc(img_len); - if (reduced == NULL) return stbi__errpuc("outofmem", "Out of memory"); - - for (i = 0; i < img_len; ++i) - reduced[i] = (stbi_uc)((orig[i] >> 8) & 0xFF); // top half of each byte is sufficient approx of 16->8 bit scaling - - STBI_FREE(orig); - return reduced; -} - -static stbi__uint16 *stbi__convert_8_to_16(stbi_uc *orig, int w, int h, int channels) -{ - int i; - int img_len = w * h * channels; - stbi__uint16 *enlarged; - - enlarged = (stbi__uint16 *) stbi__malloc(img_len*2); - if (enlarged == NULL) return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); - - for (i = 0; i < img_len; ++i) - enlarged[i] = (stbi__uint16)((orig[i] << 8) + orig[i]); // replicate to high and low byte, maps 0->0, 255->0xffff - - STBI_FREE(orig); - return enlarged; -} - -static void stbi__vertical_flip(void *image, int w, int h, int bytes_per_pixel) -{ - int row; - size_t bytes_per_row = (size_t)w * bytes_per_pixel; - stbi_uc temp[2048]; - stbi_uc *bytes = (stbi_uc *)image; - - for (row = 0; row < (h>>1); row++) { - stbi_uc *row0 = bytes + row*bytes_per_row; - stbi_uc *row1 = bytes + (h - row - 1)*bytes_per_row; - // swap row0 with row1 - size_t bytes_left = bytes_per_row; - while (bytes_left) { - size_t bytes_copy = (bytes_left < sizeof(temp)) ? bytes_left : sizeof(temp); - memcpy(temp, row0, bytes_copy); - memcpy(row0, row1, bytes_copy); - memcpy(row1, temp, bytes_copy); - row0 += bytes_copy; - row1 += bytes_copy; - bytes_left -= bytes_copy; - } - } -} - -#ifndef STBI_NO_GIF -static void stbi__vertical_flip_slices(void *image, int w, int h, int z, int bytes_per_pixel) -{ - int slice; - int slice_size = w * h * bytes_per_pixel; - - stbi_uc *bytes = (stbi_uc *)image; - for (slice = 0; slice < z; ++slice) { - stbi__vertical_flip(bytes, w, h, bytes_per_pixel); - bytes += slice_size; - } -} -#endif - -static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - stbi__result_info ri; - void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 8); - - if (result == NULL) - return NULL; - - // it is the responsibility of the loaders to make sure we get either 8 or 16 bit. - STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16); - - if (ri.bits_per_channel != 8) { - result = stbi__convert_16_to_8((stbi__uint16 *) result, *x, *y, req_comp == 0 ? *comp : req_comp); - ri.bits_per_channel = 8; - } - - // @TODO: move stbi__convert_format to here - - if (stbi__vertically_flip_on_load) { - int channels = req_comp ? req_comp : *comp; - stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi_uc)); - } - - return (unsigned char *) result; -} - -static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - stbi__result_info ri; - void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 16); - - if (result == NULL) - return NULL; - - // it is the responsibility of the loaders to make sure we get either 8 or 16 bit. - STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16); - - if (ri.bits_per_channel != 16) { - result = stbi__convert_8_to_16((stbi_uc *) result, *x, *y, req_comp == 0 ? *comp : req_comp); - ri.bits_per_channel = 16; - } - - // @TODO: move stbi__convert_format16 to here - // @TODO: special case RGB-to-Y (and RGBA-to-YA) for 8-bit-to-16-bit case to keep more precision - - if (stbi__vertically_flip_on_load) { - int channels = req_comp ? req_comp : *comp; - stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi__uint16)); - } - - return (stbi__uint16 *) result; -} - -#if !defined(STBI_NO_HDR) && !defined(STBI_NO_LINEAR) -static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp) -{ - if (stbi__vertically_flip_on_load && result != NULL) { - int channels = req_comp ? req_comp : *comp; - stbi__vertical_flip(result, *x, *y, channels * sizeof(float)); - } -} -#endif - -#ifndef STBI_NO_STDIO - -#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) -STBI_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide); -STBI_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default); -#endif - -#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) -STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input) -{ - return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); -} -#endif - -static FILE *stbi__fopen(char const *filename, char const *mode) -{ - FILE *f; -#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) - wchar_t wMode[64]; - wchar_t wFilename[1024]; - if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename))) - return 0; - - if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode))) - return 0; - -#if defined(_MSC_VER) && _MSC_VER >= 1400 - if (0 != _wfopen_s(&f, wFilename, wMode)) - f = 0; -#else - f = _wfopen(wFilename, wMode); -#endif - -#elif defined(_MSC_VER) && _MSC_VER >= 1400 - if (0 != fopen_s(&f, filename, mode)) - f=0; -#else - f = fopen(filename, mode); -#endif - return f; -} - - -STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp) -{ - FILE *f = stbi__fopen(filename, "rb"); - unsigned char *result; - if (!f) return stbi__errpuc("can't fopen", "Unable to open file"); - result = stbi_load_from_file(f,x,y,comp,req_comp); - fclose(f); - return result; -} - -STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) -{ - unsigned char *result; - stbi__context s; - stbi__start_file(&s,f); - result = stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); - if (result) { - // need to 'unget' all the characters in the IO buffer - fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); - } - return result; -} - -STBIDEF stbi__uint16 *stbi_load_from_file_16(FILE *f, int *x, int *y, int *comp, int req_comp) -{ - stbi__uint16 *result; - stbi__context s; - stbi__start_file(&s,f); - result = stbi__load_and_postprocess_16bit(&s,x,y,comp,req_comp); - if (result) { - // need to 'unget' all the characters in the IO buffer - fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); - } - return result; -} - -STBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *comp, int req_comp) -{ - FILE *f = stbi__fopen(filename, "rb"); - stbi__uint16 *result; - if (!f) return (stbi_us *) stbi__errpuc("can't fopen", "Unable to open file"); - result = stbi_load_from_file_16(f,x,y,comp,req_comp); - fclose(f); - return result; -} - - -#endif //!STBI_NO_STDIO - -STBIDEF stbi_us *stbi_load_16_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels) -{ - stbi__context s; - stbi__start_mem(&s,buffer,len); - return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); -} - -STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels) -{ - stbi__context s; - stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user); - return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); -} - -STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) -{ - stbi__context s; - stbi__start_mem(&s,buffer,len); - return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); -} - -STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) -{ - stbi__context s; - stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); - return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); -} - -#ifndef STBI_NO_GIF -STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp) -{ - unsigned char *result; - stbi__context s; - stbi__start_mem(&s,buffer,len); - - result = (unsigned char*) stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp); - if (stbi__vertically_flip_on_load) { - stbi__vertical_flip_slices( result, *x, *y, *z, *comp ); - } - - return result; -} -#endif - -#ifndef STBI_NO_LINEAR -static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - unsigned char *data; - #ifndef STBI_NO_HDR - if (stbi__hdr_test(s)) { - stbi__result_info ri; - float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp, &ri); - if (hdr_data) - stbi__float_postprocess(hdr_data,x,y,comp,req_comp); - return hdr_data; - } - #endif - data = stbi__load_and_postprocess_8bit(s, x, y, comp, req_comp); - if (data) - return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp); - return stbi__errpf("unknown image type", "Image not of any known type, or corrupt"); -} - -STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) -{ - stbi__context s; - stbi__start_mem(&s,buffer,len); - return stbi__loadf_main(&s,x,y,comp,req_comp); -} - -STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) -{ - stbi__context s; - stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); - return stbi__loadf_main(&s,x,y,comp,req_comp); -} - -#ifndef STBI_NO_STDIO -STBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp) -{ - float *result; - FILE *f = stbi__fopen(filename, "rb"); - if (!f) return stbi__errpf("can't fopen", "Unable to open file"); - result = stbi_loadf_from_file(f,x,y,comp,req_comp); - fclose(f); - return result; -} - -STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) -{ - stbi__context s; - stbi__start_file(&s,f); - return stbi__loadf_main(&s,x,y,comp,req_comp); -} -#endif // !STBI_NO_STDIO - -#endif // !STBI_NO_LINEAR - -// these is-hdr-or-not is defined independent of whether STBI_NO_LINEAR is -// defined, for API simplicity; if STBI_NO_LINEAR is defined, it always -// reports false! - -STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len) -{ - #ifndef STBI_NO_HDR - stbi__context s; - stbi__start_mem(&s,buffer,len); - return stbi__hdr_test(&s); - #else - STBI_NOTUSED(buffer); - STBI_NOTUSED(len); - return 0; - #endif -} - -#ifndef STBI_NO_STDIO -STBIDEF int stbi_is_hdr (char const *filename) -{ - FILE *f = stbi__fopen(filename, "rb"); - int result=0; - if (f) { - result = stbi_is_hdr_from_file(f); - fclose(f); - } - return result; -} - -STBIDEF int stbi_is_hdr_from_file(FILE *f) -{ - #ifndef STBI_NO_HDR - long pos = ftell(f); - int res; - stbi__context s; - stbi__start_file(&s,f); - res = stbi__hdr_test(&s); - fseek(f, pos, SEEK_SET); - return res; - #else - STBI_NOTUSED(f); - return 0; - #endif -} -#endif // !STBI_NO_STDIO - -STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user) -{ - #ifndef STBI_NO_HDR - stbi__context s; - stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); - return stbi__hdr_test(&s); - #else - STBI_NOTUSED(clbk); - STBI_NOTUSED(user); - return 0; - #endif -} - -#ifndef STBI_NO_LINEAR -static float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f; - -STBIDEF void stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; } -STBIDEF void stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; } -#endif - -static float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f; - -STBIDEF void stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; } -STBIDEF void stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; } - - -////////////////////////////////////////////////////////////////////////////// -// -// Common code used by all image loaders -// - -enum -{ - STBI__SCAN_load=0, - STBI__SCAN_type, - STBI__SCAN_header -}; - -static void stbi__refill_buffer(stbi__context *s) -{ - int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen); - s->callback_already_read += (int) (s->img_buffer - s->img_buffer_original); - if (n == 0) { - // at end of file, treat same as if from memory, but need to handle case - // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file - s->read_from_callbacks = 0; - s->img_buffer = s->buffer_start; - s->img_buffer_end = s->buffer_start+1; - *s->img_buffer = 0; - } else { - s->img_buffer = s->buffer_start; - s->img_buffer_end = s->buffer_start + n; - } -} - -stbi_inline static stbi_uc stbi__get8(stbi__context *s) -{ - if (s->img_buffer < s->img_buffer_end) - return *s->img_buffer++; - if (s->read_from_callbacks) { - stbi__refill_buffer(s); - return *s->img_buffer++; - } - return 0; -} - -#if defined(STBI_NO_JPEG) && defined(STBI_NO_HDR) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) -// nothing -#else -stbi_inline static int stbi__at_eof(stbi__context *s) -{ - if (s->io.read) { - if (!(s->io.eof)(s->io_user_data)) return 0; - // if feof() is true, check if buffer = end - // special case: we've only got the special 0 character at the end - if (s->read_from_callbacks == 0) return 1; - } - - return s->img_buffer >= s->img_buffer_end; -} -#endif - -#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) -// nothing -#else -static void stbi__skip(stbi__context *s, int n) -{ - if (n == 0) return; // already there! - if (n < 0) { - s->img_buffer = s->img_buffer_end; - return; - } - if (s->io.read) { - int blen = (int) (s->img_buffer_end - s->img_buffer); - if (blen < n) { - s->img_buffer = s->img_buffer_end; - (s->io.skip)(s->io_user_data, n - blen); - return; - } - } - s->img_buffer += n; -} -#endif - -#if defined(STBI_NO_PNG) && defined(STBI_NO_TGA) && defined(STBI_NO_HDR) && defined(STBI_NO_PNM) -// nothing -#else -static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n) -{ - if (s->io.read) { - int blen = (int) (s->img_buffer_end - s->img_buffer); - if (blen < n) { - int res, count; - - memcpy(buffer, s->img_buffer, blen); - - count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen); - res = (count == (n-blen)); - s->img_buffer = s->img_buffer_end; - return res; - } - } - - if (s->img_buffer+n <= s->img_buffer_end) { - memcpy(buffer, s->img_buffer, n); - s->img_buffer += n; - return 1; - } else - return 0; -} -#endif - -#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC) -// nothing -#else -static int stbi__get16be(stbi__context *s) -{ - int z = stbi__get8(s); - return (z << 8) + stbi__get8(s); -} -#endif - -#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC) -// nothing -#else -static stbi__uint32 stbi__get32be(stbi__context *s) -{ - stbi__uint32 z = stbi__get16be(s); - return (z << 16) + stbi__get16be(s); -} -#endif - -#if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) -// nothing -#else -static int stbi__get16le(stbi__context *s) -{ - int z = stbi__get8(s); - return z + (stbi__get8(s) << 8); -} -#endif - -#ifndef STBI_NO_BMP -static stbi__uint32 stbi__get32le(stbi__context *s) -{ - stbi__uint32 z = stbi__get16le(s); - z += (stbi__uint32)stbi__get16le(s) << 16; - return z; -} -#endif - -#define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255)) // truncate int to byte without warnings - -#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) -// nothing -#else -////////////////////////////////////////////////////////////////////////////// -// -// generic converter from built-in img_n to req_comp -// individual types do this automatically as much as possible (e.g. jpeg -// does all cases internally since it needs to colorspace convert anyway, -// and it never has alpha, so very few cases ). png can automatically -// interleave an alpha=255 channel, but falls back to this for other cases -// -// assume data buffer is malloced, so malloc a new one and free that one -// only failure mode is malloc failing - -static stbi_uc stbi__compute_y(int r, int g, int b) -{ - return (stbi_uc) (((r*77) + (g*150) + (29*b)) >> 8); -} -#endif - -#if defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) -// nothing -#else -static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y) -{ - int i,j; - unsigned char *good; - - if (req_comp == img_n) return data; - STBI_ASSERT(req_comp >= 1 && req_comp <= 4); - - good = (unsigned char *) stbi__malloc_mad3(req_comp, x, y, 0); - if (good == NULL) { - STBI_FREE(data); - return stbi__errpuc("outofmem", "Out of memory"); - } - - for (j=0; j < (int) y; ++j) { - unsigned char *src = data + j * x * img_n ; - unsigned char *dest = good + j * x * req_comp; - - #define STBI__COMBO(a,b) ((a)*8+(b)) - #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) - // convert source image with img_n components to one with req_comp components; - // avoid switch per pixel, so use switch per scanline and massive macros - switch (STBI__COMBO(img_n, req_comp)) { - STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=255; } break; - STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; - STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=255; } break; - STBI__CASE(2,1) { dest[0]=src[0]; } break; - STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; - STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1]; } break; - STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=255; } break; - STBI__CASE(3,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; - STBI__CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = 255; } break; - STBI__CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; - STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = src[3]; } break; - STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break; - default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return stbi__errpuc("unsupported", "Unsupported format conversion"); - } - #undef STBI__CASE - } - - STBI_FREE(data); - return good; -} -#endif - -#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) -// nothing -#else -static stbi__uint16 stbi__compute_y_16(int r, int g, int b) -{ - return (stbi__uint16) (((r*77) + (g*150) + (29*b)) >> 8); -} -#endif - -#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) -// nothing -#else -static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y) -{ - int i,j; - stbi__uint16 *good; - - if (req_comp == img_n) return data; - STBI_ASSERT(req_comp >= 1 && req_comp <= 4); - - good = (stbi__uint16 *) stbi__malloc(req_comp * x * y * 2); - if (good == NULL) { - STBI_FREE(data); - return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); - } - - for (j=0; j < (int) y; ++j) { - stbi__uint16 *src = data + j * x * img_n ; - stbi__uint16 *dest = good + j * x * req_comp; - - #define STBI__COMBO(a,b) ((a)*8+(b)) - #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) - // convert source image with img_n components to one with req_comp components; - // avoid switch per pixel, so use switch per scanline and massive macros - switch (STBI__COMBO(img_n, req_comp)) { - STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=0xffff; } break; - STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; - STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=0xffff; } break; - STBI__CASE(2,1) { dest[0]=src[0]; } break; - STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; - STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1]; } break; - STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=0xffff; } break; - STBI__CASE(3,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; - STBI__CASE(3,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = 0xffff; } break; - STBI__CASE(4,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; - STBI__CASE(4,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = src[3]; } break; - STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break; - default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return (stbi__uint16*) stbi__errpuc("unsupported", "Unsupported format conversion"); - } - #undef STBI__CASE - } - - STBI_FREE(data); - return good; -} -#endif - -#ifndef STBI_NO_LINEAR -static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp) -{ - int i,k,n; - float *output; - if (!data) return NULL; - output = (float *) stbi__malloc_mad4(x, y, comp, sizeof(float), 0); - if (output == NULL) { STBI_FREE(data); return stbi__errpf("outofmem", "Out of memory"); } - // compute number of non-alpha components - if (comp & 1) n = comp; else n = comp-1; - for (i=0; i < x*y; ++i) { - for (k=0; k < n; ++k) { - output[i*comp + k] = (float) (pow(data[i*comp+k]/255.0f, stbi__l2h_gamma) * stbi__l2h_scale); - } - } - if (n < comp) { - for (i=0; i < x*y; ++i) { - output[i*comp + n] = data[i*comp + n]/255.0f; - } - } - STBI_FREE(data); - return output; -} -#endif - -#ifndef STBI_NO_HDR -#define stbi__float2int(x) ((int) (x)) -static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp) -{ - int i,k,n; - stbi_uc *output; - if (!data) return NULL; - output = (stbi_uc *) stbi__malloc_mad3(x, y, comp, 0); - if (output == NULL) { STBI_FREE(data); return stbi__errpuc("outofmem", "Out of memory"); } - // compute number of non-alpha components - if (comp & 1) n = comp; else n = comp-1; - for (i=0; i < x*y; ++i) { - for (k=0; k < n; ++k) { - float z = (float) pow(data[i*comp+k]*stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 + 0.5f; - if (z < 0) z = 0; - if (z > 255) z = 255; - output[i*comp + k] = (stbi_uc) stbi__float2int(z); - } - if (k < comp) { - float z = data[i*comp+k] * 255 + 0.5f; - if (z < 0) z = 0; - if (z > 255) z = 255; - output[i*comp + k] = (stbi_uc) stbi__float2int(z); - } - } - STBI_FREE(data); - return output; -} -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// "baseline" JPEG/JFIF decoder -// -// simple implementation -// - doesn't support delayed output of y-dimension -// - simple interface (only one output format: 8-bit interleaved RGB) -// - doesn't try to recover corrupt jpegs -// - doesn't allow partial loading, loading multiple at once -// - still fast on x86 (copying globals into locals doesn't help x86) -// - allocates lots of intermediate memory (full size of all components) -// - non-interleaved case requires this anyway -// - allows good upsampling (see next) -// high-quality -// - upsampled channels are bilinearly interpolated, even across blocks -// - quality integer IDCT derived from IJG's 'slow' -// performance -// - fast huffman; reasonable integer IDCT -// - some SIMD kernels for common paths on targets with SSE2/NEON -// - uses a lot of intermediate memory, could cache poorly - -#ifndef STBI_NO_JPEG - -// huffman decoding acceleration -#define FAST_BITS 9 // larger handles more cases; smaller stomps less cache - -typedef struct -{ - stbi_uc fast[1 << FAST_BITS]; - // weirdly, repacking this into AoS is a 10% speed loss, instead of a win - stbi__uint16 code[256]; - stbi_uc values[256]; - stbi_uc size[257]; - unsigned int maxcode[18]; - int delta[17]; // old 'firstsymbol' - old 'firstcode' -} stbi__huffman; - -typedef struct -{ - stbi__context *s; - stbi__huffman huff_dc[4]; - stbi__huffman huff_ac[4]; - stbi__uint16 dequant[4][64]; - stbi__int16 fast_ac[4][1 << FAST_BITS]; - -// sizes for components, interleaved MCUs - int img_h_max, img_v_max; - int img_mcu_x, img_mcu_y; - int img_mcu_w, img_mcu_h; - -// definition of jpeg image component - struct - { - int id; - int h,v; - int tq; - int hd,ha; - int dc_pred; - - int x,y,w2,h2; - stbi_uc *data; - void *raw_data, *raw_coeff; - stbi_uc *linebuf; - short *coeff; // progressive only - int coeff_w, coeff_h; // number of 8x8 coefficient blocks - } img_comp[4]; - - stbi__uint32 code_buffer; // jpeg entropy-coded buffer - int code_bits; // number of valid bits - unsigned char marker; // marker seen while filling entropy buffer - int nomore; // flag if we saw a marker so must stop - - int progressive; - int spec_start; - int spec_end; - int succ_high; - int succ_low; - int eob_run; - int jfif; - int app14_color_transform; // Adobe APP14 tag - int rgb; - - int scan_n, order[4]; - int restart_interval, todo; - -// kernels - void (*idct_block_kernel)(stbi_uc *out, int out_stride, short data[64]); - void (*YCbCr_to_RGB_kernel)(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step); - stbi_uc *(*resample_row_hv_2_kernel)(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs); -} stbi__jpeg; - -static int stbi__build_huffman(stbi__huffman *h, int *count) -{ - int i,j,k=0; - unsigned int code; - // build size list for each symbol (from JPEG spec) - for (i=0; i < 16; ++i) - for (j=0; j < count[i]; ++j) - h->size[k++] = (stbi_uc) (i+1); - h->size[k] = 0; - - // compute actual symbols (from jpeg spec) - code = 0; - k = 0; - for(j=1; j <= 16; ++j) { - // compute delta to add to code to compute symbol id - h->delta[j] = k - code; - if (h->size[k] == j) { - while (h->size[k] == j) - h->code[k++] = (stbi__uint16) (code++); - if (code-1 >= (1u << j)) return stbi__err("bad code lengths","Corrupt JPEG"); - } - // compute largest code + 1 for this size, preshifted as needed later - h->maxcode[j] = code << (16-j); - code <<= 1; - } - h->maxcode[j] = 0xffffffff; - - // build non-spec acceleration table; 255 is flag for not-accelerated - memset(h->fast, 255, 1 << FAST_BITS); - for (i=0; i < k; ++i) { - int s = h->size[i]; - if (s <= FAST_BITS) { - int c = h->code[i] << (FAST_BITS-s); - int m = 1 << (FAST_BITS-s); - for (j=0; j < m; ++j) { - h->fast[c+j] = (stbi_uc) i; - } - } - } - return 1; -} - -// build a table that decodes both magnitude and value of small ACs in -// one go. -static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h) -{ - int i; - for (i=0; i < (1 << FAST_BITS); ++i) { - stbi_uc fast = h->fast[i]; - fast_ac[i] = 0; - if (fast < 255) { - int rs = h->values[fast]; - int run = (rs >> 4) & 15; - int magbits = rs & 15; - int len = h->size[fast]; - - if (magbits && len + magbits <= FAST_BITS) { - // magnitude code followed by receive_extend code - int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits); - int m = 1 << (magbits - 1); - if (k < m) k += (~0U << magbits) + 1; - // if the result is small enough, we can fit it in fast_ac table - if (k >= -128 && k <= 127) - fast_ac[i] = (stbi__int16) ((k * 256) + (run * 16) + (len + magbits)); - } - } - } -} - -static void stbi__grow_buffer_unsafe(stbi__jpeg *j) -{ - do { - unsigned int b = j->nomore ? 0 : stbi__get8(j->s); - if (b == 0xff) { - int c = stbi__get8(j->s); - while (c == 0xff) c = stbi__get8(j->s); // consume fill bytes - if (c != 0) { - j->marker = (unsigned char) c; - j->nomore = 1; - return; - } - } - j->code_buffer |= b << (24 - j->code_bits); - j->code_bits += 8; - } while (j->code_bits <= 24); -} - -// (1 << n) - 1 -static const stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535}; - -// decode a jpeg huffman value from the bitstream -stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h) -{ - unsigned int temp; - int c,k; - - if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); - - // look at the top FAST_BITS and determine what symbol ID it is, - // if the code is <= FAST_BITS - c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); - k = h->fast[c]; - if (k < 255) { - int s = h->size[k]; - if (s > j->code_bits) - return -1; - j->code_buffer <<= s; - j->code_bits -= s; - return h->values[k]; - } - - // naive test is to shift the code_buffer down so k bits are - // valid, then test against maxcode. To speed this up, we've - // preshifted maxcode left so that it has (16-k) 0s at the - // end; in other words, regardless of the number of bits, it - // wants to be compared against something shifted to have 16; - // that way we don't need to shift inside the loop. - temp = j->code_buffer >> 16; - for (k=FAST_BITS+1 ; ; ++k) - if (temp < h->maxcode[k]) - break; - if (k == 17) { - // error! code not found - j->code_bits -= 16; - return -1; - } - - if (k > j->code_bits) - return -1; - - // convert the huffman code to the symbol id - c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k]; - STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]); - - // convert the id to a symbol - j->code_bits -= k; - j->code_buffer <<= k; - return h->values[c]; -} - -// bias[n] = (-1<code_bits < n) stbi__grow_buffer_unsafe(j); - - sgn = j->code_buffer >> 31; // sign bit always in MSB; 0 if MSB clear (positive), 1 if MSB set (negative) - k = stbi_lrot(j->code_buffer, n); - j->code_buffer = k & ~stbi__bmask[n]; - k &= stbi__bmask[n]; - j->code_bits -= n; - return k + (stbi__jbias[n] & (sgn - 1)); -} - -// get some unsigned bits -stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n) -{ - unsigned int k; - if (j->code_bits < n) stbi__grow_buffer_unsafe(j); - k = stbi_lrot(j->code_buffer, n); - j->code_buffer = k & ~stbi__bmask[n]; - k &= stbi__bmask[n]; - j->code_bits -= n; - return k; -} - -stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j) -{ - unsigned int k; - if (j->code_bits < 1) stbi__grow_buffer_unsafe(j); - k = j->code_buffer; - j->code_buffer <<= 1; - --j->code_bits; - return k & 0x80000000; -} - -// given a value that's at position X in the zigzag stream, -// where does it appear in the 8x8 matrix coded as row-major? -static const stbi_uc stbi__jpeg_dezigzag[64+15] = -{ - 0, 1, 8, 16, 9, 2, 3, 10, - 17, 24, 32, 25, 18, 11, 4, 5, - 12, 19, 26, 33, 40, 48, 41, 34, - 27, 20, 13, 6, 7, 14, 21, 28, - 35, 42, 49, 56, 57, 50, 43, 36, - 29, 22, 15, 23, 30, 37, 44, 51, - 58, 59, 52, 45, 38, 31, 39, 46, - 53, 60, 61, 54, 47, 55, 62, 63, - // let corrupt input sample past end - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63 -}; - -// decode one 64-entry block-- -static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi__uint16 *dequant) -{ - int diff,dc,k; - int t; - - if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); - t = stbi__jpeg_huff_decode(j, hdc); - if (t < 0 || t > 15) return stbi__err("bad huffman code","Corrupt JPEG"); - - // 0 all the ac values now so we can do it 32-bits at a time - memset(data,0,64*sizeof(data[0])); - - diff = t ? stbi__extend_receive(j, t) : 0; - dc = j->img_comp[b].dc_pred + diff; - j->img_comp[b].dc_pred = dc; - data[0] = (short) (dc * dequant[0]); - - // decode AC components, see JPEG spec - k = 1; - do { - unsigned int zig; - int c,r,s; - if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); - c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); - r = fac[c]; - if (r) { // fast-AC path - k += (r >> 4) & 15; // run - s = r & 15; // combined length - j->code_buffer <<= s; - j->code_bits -= s; - // decode into unzigzag'd location - zig = stbi__jpeg_dezigzag[k++]; - data[zig] = (short) ((r >> 8) * dequant[zig]); - } else { - int rs = stbi__jpeg_huff_decode(j, hac); - if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); - s = rs & 15; - r = rs >> 4; - if (s == 0) { - if (rs != 0xf0) break; // end block - k += 16; - } else { - k += r; - // decode into unzigzag'd location - zig = stbi__jpeg_dezigzag[k++]; - data[zig] = (short) (stbi__extend_receive(j,s) * dequant[zig]); - } - } - } while (k < 64); - return 1; -} - -static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__huffman *hdc, int b) -{ - int diff,dc; - int t; - if (j->spec_end != 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); - - if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); - - if (j->succ_high == 0) { - // first scan for DC coefficient, must be first - memset(data,0,64*sizeof(data[0])); // 0 all the ac values now - t = stbi__jpeg_huff_decode(j, hdc); - if (t < 0 || t > 15) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); - diff = t ? stbi__extend_receive(j, t) : 0; - - dc = j->img_comp[b].dc_pred + diff; - j->img_comp[b].dc_pred = dc; - data[0] = (short) (dc * (1 << j->succ_low)); - } else { - // refinement scan for DC coefficient - if (stbi__jpeg_get_bit(j)) - data[0] += (short) (1 << j->succ_low); - } - return 1; -} - -// @OPTIMIZE: store non-zigzagged during the decode passes, -// and only de-zigzag when dequantizing -static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__huffman *hac, stbi__int16 *fac) -{ - int k; - if (j->spec_start == 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); - - if (j->succ_high == 0) { - int shift = j->succ_low; - - if (j->eob_run) { - --j->eob_run; - return 1; - } - - k = j->spec_start; - do { - unsigned int zig; - int c,r,s; - if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); - c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); - r = fac[c]; - if (r) { // fast-AC path - k += (r >> 4) & 15; // run - s = r & 15; // combined length - j->code_buffer <<= s; - j->code_bits -= s; - zig = stbi__jpeg_dezigzag[k++]; - data[zig] = (short) ((r >> 8) * (1 << shift)); - } else { - int rs = stbi__jpeg_huff_decode(j, hac); - if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); - s = rs & 15; - r = rs >> 4; - if (s == 0) { - if (r < 15) { - j->eob_run = (1 << r); - if (r) - j->eob_run += stbi__jpeg_get_bits(j, r); - --j->eob_run; - break; - } - k += 16; - } else { - k += r; - zig = stbi__jpeg_dezigzag[k++]; - data[zig] = (short) (stbi__extend_receive(j,s) * (1 << shift)); - } - } - } while (k <= j->spec_end); - } else { - // refinement scan for these AC coefficients - - short bit = (short) (1 << j->succ_low); - - if (j->eob_run) { - --j->eob_run; - for (k = j->spec_start; k <= j->spec_end; ++k) { - short *p = &data[stbi__jpeg_dezigzag[k]]; - if (*p != 0) - if (stbi__jpeg_get_bit(j)) - if ((*p & bit)==0) { - if (*p > 0) - *p += bit; - else - *p -= bit; - } - } - } else { - k = j->spec_start; - do { - int r,s; - int rs = stbi__jpeg_huff_decode(j, hac); // @OPTIMIZE see if we can use the fast path here, advance-by-r is so slow, eh - if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); - s = rs & 15; - r = rs >> 4; - if (s == 0) { - if (r < 15) { - j->eob_run = (1 << r) - 1; - if (r) - j->eob_run += stbi__jpeg_get_bits(j, r); - r = 64; // force end of block - } else { - // r=15 s=0 should write 16 0s, so we just do - // a run of 15 0s and then write s (which is 0), - // so we don't have to do anything special here - } - } else { - if (s != 1) return stbi__err("bad huffman code", "Corrupt JPEG"); - // sign bit - if (stbi__jpeg_get_bit(j)) - s = bit; - else - s = -bit; - } - - // advance by r - while (k <= j->spec_end) { - short *p = &data[stbi__jpeg_dezigzag[k++]]; - if (*p != 0) { - if (stbi__jpeg_get_bit(j)) - if ((*p & bit)==0) { - if (*p > 0) - *p += bit; - else - *p -= bit; - } - } else { - if (r == 0) { - *p = (short) s; - break; - } - --r; - } - } - } while (k <= j->spec_end); - } - } - return 1; -} - -// take a -128..127 value and stbi__clamp it and convert to 0..255 -stbi_inline static stbi_uc stbi__clamp(int x) -{ - // trick to use a single test to catch both cases - if ((unsigned int) x > 255) { - if (x < 0) return 0; - if (x > 255) return 255; - } - return (stbi_uc) x; -} - -#define stbi__f2f(x) ((int) (((x) * 4096 + 0.5))) -#define stbi__fsh(x) ((x) * 4096) - -// derived from jidctint -- DCT_ISLOW -#define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \ - int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \ - p2 = s2; \ - p3 = s6; \ - p1 = (p2+p3) * stbi__f2f(0.5411961f); \ - t2 = p1 + p3*stbi__f2f(-1.847759065f); \ - t3 = p1 + p2*stbi__f2f( 0.765366865f); \ - p2 = s0; \ - p3 = s4; \ - t0 = stbi__fsh(p2+p3); \ - t1 = stbi__fsh(p2-p3); \ - x0 = t0+t3; \ - x3 = t0-t3; \ - x1 = t1+t2; \ - x2 = t1-t2; \ - t0 = s7; \ - t1 = s5; \ - t2 = s3; \ - t3 = s1; \ - p3 = t0+t2; \ - p4 = t1+t3; \ - p1 = t0+t3; \ - p2 = t1+t2; \ - p5 = (p3+p4)*stbi__f2f( 1.175875602f); \ - t0 = t0*stbi__f2f( 0.298631336f); \ - t1 = t1*stbi__f2f( 2.053119869f); \ - t2 = t2*stbi__f2f( 3.072711026f); \ - t3 = t3*stbi__f2f( 1.501321110f); \ - p1 = p5 + p1*stbi__f2f(-0.899976223f); \ - p2 = p5 + p2*stbi__f2f(-2.562915447f); \ - p3 = p3*stbi__f2f(-1.961570560f); \ - p4 = p4*stbi__f2f(-0.390180644f); \ - t3 += p1+p4; \ - t2 += p2+p3; \ - t1 += p2+p4; \ - t0 += p1+p3; - -static void stbi__idct_block(stbi_uc *out, int out_stride, short data[64]) -{ - int i,val[64],*v=val; - stbi_uc *o; - short *d = data; - - // columns - for (i=0; i < 8; ++i,++d, ++v) { - // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing - if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0 - && d[40]==0 && d[48]==0 && d[56]==0) { - // no shortcut 0 seconds - // (1|2|3|4|5|6|7)==0 0 seconds - // all separate -0.047 seconds - // 1 && 2|3 && 4|5 && 6|7: -0.047 seconds - int dcterm = d[0]*4; - v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm; - } else { - STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56]) - // constants scaled things up by 1<<12; let's bring them back - // down, but keep 2 extra bits of precision - x0 += 512; x1 += 512; x2 += 512; x3 += 512; - v[ 0] = (x0+t3) >> 10; - v[56] = (x0-t3) >> 10; - v[ 8] = (x1+t2) >> 10; - v[48] = (x1-t2) >> 10; - v[16] = (x2+t1) >> 10; - v[40] = (x2-t1) >> 10; - v[24] = (x3+t0) >> 10; - v[32] = (x3-t0) >> 10; - } - } - - for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) { - // no fast case since the first 1D IDCT spread components out - STBI__IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]) - // constants scaled things up by 1<<12, plus we had 1<<2 from first - // loop, plus horizontal and vertical each scale by sqrt(8) so together - // we've got an extra 1<<3, so 1<<17 total we need to remove. - // so we want to round that, which means adding 0.5 * 1<<17, - // aka 65536. Also, we'll end up with -128 to 127 that we want - // to encode as 0..255 by adding 128, so we'll add that before the shift - x0 += 65536 + (128<<17); - x1 += 65536 + (128<<17); - x2 += 65536 + (128<<17); - x3 += 65536 + (128<<17); - // tried computing the shifts into temps, or'ing the temps to see - // if any were out of range, but that was slower - o[0] = stbi__clamp((x0+t3) >> 17); - o[7] = stbi__clamp((x0-t3) >> 17); - o[1] = stbi__clamp((x1+t2) >> 17); - o[6] = stbi__clamp((x1-t2) >> 17); - o[2] = stbi__clamp((x2+t1) >> 17); - o[5] = stbi__clamp((x2-t1) >> 17); - o[3] = stbi__clamp((x3+t0) >> 17); - o[4] = stbi__clamp((x3-t0) >> 17); - } -} - -#ifdef STBI_SSE2 -// sse2 integer IDCT. not the fastest possible implementation but it -// produces bit-identical results to the generic C version so it's -// fully "transparent". -static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) -{ - // This is constructed to match our regular (generic) integer IDCT exactly. - __m128i row0, row1, row2, row3, row4, row5, row6, row7; - __m128i tmp; - - // dot product constant: even elems=x, odd elems=y - #define dct_const(x,y) _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y)) - - // out(0) = c0[even]*x + c0[odd]*y (c0, x, y 16-bit, out 32-bit) - // out(1) = c1[even]*x + c1[odd]*y - #define dct_rot(out0,out1, x,y,c0,c1) \ - __m128i c0##lo = _mm_unpacklo_epi16((x),(y)); \ - __m128i c0##hi = _mm_unpackhi_epi16((x),(y)); \ - __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \ - __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \ - __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \ - __m128i out1##_h = _mm_madd_epi16(c0##hi, c1) - - // out = in << 12 (in 16-bit, out 32-bit) - #define dct_widen(out, in) \ - __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \ - __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4) - - // wide add - #define dct_wadd(out, a, b) \ - __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \ - __m128i out##_h = _mm_add_epi32(a##_h, b##_h) - - // wide sub - #define dct_wsub(out, a, b) \ - __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \ - __m128i out##_h = _mm_sub_epi32(a##_h, b##_h) - - // butterfly a/b, add bias, then shift by "s" and pack - #define dct_bfly32o(out0, out1, a,b,bias,s) \ - { \ - __m128i abiased_l = _mm_add_epi32(a##_l, bias); \ - __m128i abiased_h = _mm_add_epi32(a##_h, bias); \ - dct_wadd(sum, abiased, b); \ - dct_wsub(dif, abiased, b); \ - out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \ - out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \ - } - - // 8-bit interleave step (for transposes) - #define dct_interleave8(a, b) \ - tmp = a; \ - a = _mm_unpacklo_epi8(a, b); \ - b = _mm_unpackhi_epi8(tmp, b) - - // 16-bit interleave step (for transposes) - #define dct_interleave16(a, b) \ - tmp = a; \ - a = _mm_unpacklo_epi16(a, b); \ - b = _mm_unpackhi_epi16(tmp, b) - - #define dct_pass(bias,shift) \ - { \ - /* even part */ \ - dct_rot(t2e,t3e, row2,row6, rot0_0,rot0_1); \ - __m128i sum04 = _mm_add_epi16(row0, row4); \ - __m128i dif04 = _mm_sub_epi16(row0, row4); \ - dct_widen(t0e, sum04); \ - dct_widen(t1e, dif04); \ - dct_wadd(x0, t0e, t3e); \ - dct_wsub(x3, t0e, t3e); \ - dct_wadd(x1, t1e, t2e); \ - dct_wsub(x2, t1e, t2e); \ - /* odd part */ \ - dct_rot(y0o,y2o, row7,row3, rot2_0,rot2_1); \ - dct_rot(y1o,y3o, row5,row1, rot3_0,rot3_1); \ - __m128i sum17 = _mm_add_epi16(row1, row7); \ - __m128i sum35 = _mm_add_epi16(row3, row5); \ - dct_rot(y4o,y5o, sum17,sum35, rot1_0,rot1_1); \ - dct_wadd(x4, y0o, y4o); \ - dct_wadd(x5, y1o, y5o); \ - dct_wadd(x6, y2o, y5o); \ - dct_wadd(x7, y3o, y4o); \ - dct_bfly32o(row0,row7, x0,x7,bias,shift); \ - dct_bfly32o(row1,row6, x1,x6,bias,shift); \ - dct_bfly32o(row2,row5, x2,x5,bias,shift); \ - dct_bfly32o(row3,row4, x3,x4,bias,shift); \ - } - - __m128i rot0_0 = dct_const(stbi__f2f(0.5411961f), stbi__f2f(0.5411961f) + stbi__f2f(-1.847759065f)); - __m128i rot0_1 = dct_const(stbi__f2f(0.5411961f) + stbi__f2f( 0.765366865f), stbi__f2f(0.5411961f)); - __m128i rot1_0 = dct_const(stbi__f2f(1.175875602f) + stbi__f2f(-0.899976223f), stbi__f2f(1.175875602f)); - __m128i rot1_1 = dct_const(stbi__f2f(1.175875602f), stbi__f2f(1.175875602f) + stbi__f2f(-2.562915447f)); - __m128i rot2_0 = dct_const(stbi__f2f(-1.961570560f) + stbi__f2f( 0.298631336f), stbi__f2f(-1.961570560f)); - __m128i rot2_1 = dct_const(stbi__f2f(-1.961570560f), stbi__f2f(-1.961570560f) + stbi__f2f( 3.072711026f)); - __m128i rot3_0 = dct_const(stbi__f2f(-0.390180644f) + stbi__f2f( 2.053119869f), stbi__f2f(-0.390180644f)); - __m128i rot3_1 = dct_const(stbi__f2f(-0.390180644f), stbi__f2f(-0.390180644f) + stbi__f2f( 1.501321110f)); - - // rounding biases in column/row passes, see stbi__idct_block for explanation. - __m128i bias_0 = _mm_set1_epi32(512); - __m128i bias_1 = _mm_set1_epi32(65536 + (128<<17)); - - // load - row0 = _mm_load_si128((const __m128i *) (data + 0*8)); - row1 = _mm_load_si128((const __m128i *) (data + 1*8)); - row2 = _mm_load_si128((const __m128i *) (data + 2*8)); - row3 = _mm_load_si128((const __m128i *) (data + 3*8)); - row4 = _mm_load_si128((const __m128i *) (data + 4*8)); - row5 = _mm_load_si128((const __m128i *) (data + 5*8)); - row6 = _mm_load_si128((const __m128i *) (data + 6*8)); - row7 = _mm_load_si128((const __m128i *) (data + 7*8)); - - // column pass - dct_pass(bias_0, 10); - - { - // 16bit 8x8 transpose pass 1 - dct_interleave16(row0, row4); - dct_interleave16(row1, row5); - dct_interleave16(row2, row6); - dct_interleave16(row3, row7); - - // transpose pass 2 - dct_interleave16(row0, row2); - dct_interleave16(row1, row3); - dct_interleave16(row4, row6); - dct_interleave16(row5, row7); - - // transpose pass 3 - dct_interleave16(row0, row1); - dct_interleave16(row2, row3); - dct_interleave16(row4, row5); - dct_interleave16(row6, row7); - } - - // row pass - dct_pass(bias_1, 17); - - { - // pack - __m128i p0 = _mm_packus_epi16(row0, row1); // a0a1a2a3...a7b0b1b2b3...b7 - __m128i p1 = _mm_packus_epi16(row2, row3); - __m128i p2 = _mm_packus_epi16(row4, row5); - __m128i p3 = _mm_packus_epi16(row6, row7); - - // 8bit 8x8 transpose pass 1 - dct_interleave8(p0, p2); // a0e0a1e1... - dct_interleave8(p1, p3); // c0g0c1g1... - - // transpose pass 2 - dct_interleave8(p0, p1); // a0c0e0g0... - dct_interleave8(p2, p3); // b0d0f0h0... - - // transpose pass 3 - dct_interleave8(p0, p2); // a0b0c0d0... - dct_interleave8(p1, p3); // a4b4c4d4... - - // store - _mm_storel_epi64((__m128i *) out, p0); out += out_stride; - _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p0, 0x4e)); out += out_stride; - _mm_storel_epi64((__m128i *) out, p2); out += out_stride; - _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p2, 0x4e)); out += out_stride; - _mm_storel_epi64((__m128i *) out, p1); out += out_stride; - _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p1, 0x4e)); out += out_stride; - _mm_storel_epi64((__m128i *) out, p3); out += out_stride; - _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p3, 0x4e)); - } - -#undef dct_const -#undef dct_rot -#undef dct_widen -#undef dct_wadd -#undef dct_wsub -#undef dct_bfly32o -#undef dct_interleave8 -#undef dct_interleave16 -#undef dct_pass -} - -#endif // STBI_SSE2 - -#ifdef STBI_NEON - -// NEON integer IDCT. should produce bit-identical -// results to the generic C version. -static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) -{ - int16x8_t row0, row1, row2, row3, row4, row5, row6, row7; - - int16x4_t rot0_0 = vdup_n_s16(stbi__f2f(0.5411961f)); - int16x4_t rot0_1 = vdup_n_s16(stbi__f2f(-1.847759065f)); - int16x4_t rot0_2 = vdup_n_s16(stbi__f2f( 0.765366865f)); - int16x4_t rot1_0 = vdup_n_s16(stbi__f2f( 1.175875602f)); - int16x4_t rot1_1 = vdup_n_s16(stbi__f2f(-0.899976223f)); - int16x4_t rot1_2 = vdup_n_s16(stbi__f2f(-2.562915447f)); - int16x4_t rot2_0 = vdup_n_s16(stbi__f2f(-1.961570560f)); - int16x4_t rot2_1 = vdup_n_s16(stbi__f2f(-0.390180644f)); - int16x4_t rot3_0 = vdup_n_s16(stbi__f2f( 0.298631336f)); - int16x4_t rot3_1 = vdup_n_s16(stbi__f2f( 2.053119869f)); - int16x4_t rot3_2 = vdup_n_s16(stbi__f2f( 3.072711026f)); - int16x4_t rot3_3 = vdup_n_s16(stbi__f2f( 1.501321110f)); - -#define dct_long_mul(out, inq, coeff) \ - int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \ - int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff) - -#define dct_long_mac(out, acc, inq, coeff) \ - int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \ - int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff) - -#define dct_widen(out, inq) \ - int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \ - int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12) - -// wide add -#define dct_wadd(out, a, b) \ - int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \ - int32x4_t out##_h = vaddq_s32(a##_h, b##_h) - -// wide sub -#define dct_wsub(out, a, b) \ - int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \ - int32x4_t out##_h = vsubq_s32(a##_h, b##_h) - -// butterfly a/b, then shift using "shiftop" by "s" and pack -#define dct_bfly32o(out0,out1, a,b,shiftop,s) \ - { \ - dct_wadd(sum, a, b); \ - dct_wsub(dif, a, b); \ - out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \ - out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \ - } - -#define dct_pass(shiftop, shift) \ - { \ - /* even part */ \ - int16x8_t sum26 = vaddq_s16(row2, row6); \ - dct_long_mul(p1e, sum26, rot0_0); \ - dct_long_mac(t2e, p1e, row6, rot0_1); \ - dct_long_mac(t3e, p1e, row2, rot0_2); \ - int16x8_t sum04 = vaddq_s16(row0, row4); \ - int16x8_t dif04 = vsubq_s16(row0, row4); \ - dct_widen(t0e, sum04); \ - dct_widen(t1e, dif04); \ - dct_wadd(x0, t0e, t3e); \ - dct_wsub(x3, t0e, t3e); \ - dct_wadd(x1, t1e, t2e); \ - dct_wsub(x2, t1e, t2e); \ - /* odd part */ \ - int16x8_t sum15 = vaddq_s16(row1, row5); \ - int16x8_t sum17 = vaddq_s16(row1, row7); \ - int16x8_t sum35 = vaddq_s16(row3, row5); \ - int16x8_t sum37 = vaddq_s16(row3, row7); \ - int16x8_t sumodd = vaddq_s16(sum17, sum35); \ - dct_long_mul(p5o, sumodd, rot1_0); \ - dct_long_mac(p1o, p5o, sum17, rot1_1); \ - dct_long_mac(p2o, p5o, sum35, rot1_2); \ - dct_long_mul(p3o, sum37, rot2_0); \ - dct_long_mul(p4o, sum15, rot2_1); \ - dct_wadd(sump13o, p1o, p3o); \ - dct_wadd(sump24o, p2o, p4o); \ - dct_wadd(sump23o, p2o, p3o); \ - dct_wadd(sump14o, p1o, p4o); \ - dct_long_mac(x4, sump13o, row7, rot3_0); \ - dct_long_mac(x5, sump24o, row5, rot3_1); \ - dct_long_mac(x6, sump23o, row3, rot3_2); \ - dct_long_mac(x7, sump14o, row1, rot3_3); \ - dct_bfly32o(row0,row7, x0,x7,shiftop,shift); \ - dct_bfly32o(row1,row6, x1,x6,shiftop,shift); \ - dct_bfly32o(row2,row5, x2,x5,shiftop,shift); \ - dct_bfly32o(row3,row4, x3,x4,shiftop,shift); \ - } - - // load - row0 = vld1q_s16(data + 0*8); - row1 = vld1q_s16(data + 1*8); - row2 = vld1q_s16(data + 2*8); - row3 = vld1q_s16(data + 3*8); - row4 = vld1q_s16(data + 4*8); - row5 = vld1q_s16(data + 5*8); - row6 = vld1q_s16(data + 6*8); - row7 = vld1q_s16(data + 7*8); - - // add DC bias - row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0)); - - // column pass - dct_pass(vrshrn_n_s32, 10); - - // 16bit 8x8 transpose - { -// these three map to a single VTRN.16, VTRN.32, and VSWP, respectively. -// whether compilers actually get this is another story, sadly. -#define dct_trn16(x, y) { int16x8x2_t t = vtrnq_s16(x, y); x = t.val[0]; y = t.val[1]; } -#define dct_trn32(x, y) { int32x4x2_t t = vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); x = vreinterpretq_s16_s32(t.val[0]); y = vreinterpretq_s16_s32(t.val[1]); } -#define dct_trn64(x, y) { int16x8_t x0 = x; int16x8_t y0 = y; x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); } - - // pass 1 - dct_trn16(row0, row1); // a0b0a2b2a4b4a6b6 - dct_trn16(row2, row3); - dct_trn16(row4, row5); - dct_trn16(row6, row7); - - // pass 2 - dct_trn32(row0, row2); // a0b0c0d0a4b4c4d4 - dct_trn32(row1, row3); - dct_trn32(row4, row6); - dct_trn32(row5, row7); - - // pass 3 - dct_trn64(row0, row4); // a0b0c0d0e0f0g0h0 - dct_trn64(row1, row5); - dct_trn64(row2, row6); - dct_trn64(row3, row7); - -#undef dct_trn16 -#undef dct_trn32 -#undef dct_trn64 - } - - // row pass - // vrshrn_n_s32 only supports shifts up to 16, we need - // 17. so do a non-rounding shift of 16 first then follow - // up with a rounding shift by 1. - dct_pass(vshrn_n_s32, 16); - - { - // pack and round - uint8x8_t p0 = vqrshrun_n_s16(row0, 1); - uint8x8_t p1 = vqrshrun_n_s16(row1, 1); - uint8x8_t p2 = vqrshrun_n_s16(row2, 1); - uint8x8_t p3 = vqrshrun_n_s16(row3, 1); - uint8x8_t p4 = vqrshrun_n_s16(row4, 1); - uint8x8_t p5 = vqrshrun_n_s16(row5, 1); - uint8x8_t p6 = vqrshrun_n_s16(row6, 1); - uint8x8_t p7 = vqrshrun_n_s16(row7, 1); - - // again, these can translate into one instruction, but often don't. -#define dct_trn8_8(x, y) { uint8x8x2_t t = vtrn_u8(x, y); x = t.val[0]; y = t.val[1]; } -#define dct_trn8_16(x, y) { uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); x = vreinterpret_u8_u16(t.val[0]); y = vreinterpret_u8_u16(t.val[1]); } -#define dct_trn8_32(x, y) { uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); x = vreinterpret_u8_u32(t.val[0]); y = vreinterpret_u8_u32(t.val[1]); } - - // sadly can't use interleaved stores here since we only write - // 8 bytes to each scan line! - - // 8x8 8-bit transpose pass 1 - dct_trn8_8(p0, p1); - dct_trn8_8(p2, p3); - dct_trn8_8(p4, p5); - dct_trn8_8(p6, p7); - - // pass 2 - dct_trn8_16(p0, p2); - dct_trn8_16(p1, p3); - dct_trn8_16(p4, p6); - dct_trn8_16(p5, p7); - - // pass 3 - dct_trn8_32(p0, p4); - dct_trn8_32(p1, p5); - dct_trn8_32(p2, p6); - dct_trn8_32(p3, p7); - - // store - vst1_u8(out, p0); out += out_stride; - vst1_u8(out, p1); out += out_stride; - vst1_u8(out, p2); out += out_stride; - vst1_u8(out, p3); out += out_stride; - vst1_u8(out, p4); out += out_stride; - vst1_u8(out, p5); out += out_stride; - vst1_u8(out, p6); out += out_stride; - vst1_u8(out, p7); - -#undef dct_trn8_8 -#undef dct_trn8_16 -#undef dct_trn8_32 - } - -#undef dct_long_mul -#undef dct_long_mac -#undef dct_widen -#undef dct_wadd -#undef dct_wsub -#undef dct_bfly32o -#undef dct_pass -} - -#endif // STBI_NEON - -#define STBI__MARKER_none 0xff -// if there's a pending marker from the entropy stream, return that -// otherwise, fetch from the stream and get a marker. if there's no -// marker, return 0xff, which is never a valid marker value -static stbi_uc stbi__get_marker(stbi__jpeg *j) -{ - stbi_uc x; - if (j->marker != STBI__MARKER_none) { x = j->marker; j->marker = STBI__MARKER_none; return x; } - x = stbi__get8(j->s); - if (x != 0xff) return STBI__MARKER_none; - while (x == 0xff) - x = stbi__get8(j->s); // consume repeated 0xff fill bytes - return x; -} - -// in each scan, we'll have scan_n components, and the order -// of the components is specified by order[] -#define STBI__RESTART(x) ((x) >= 0xd0 && (x) <= 0xd7) - -// after a restart interval, stbi__jpeg_reset the entropy decoder and -// the dc prediction -static void stbi__jpeg_reset(stbi__jpeg *j) -{ - j->code_bits = 0; - j->code_buffer = 0; - j->nomore = 0; - j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = j->img_comp[3].dc_pred = 0; - j->marker = STBI__MARKER_none; - j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff; - j->eob_run = 0; - // no more than 1<<31 MCUs if no restart_interal? that's plenty safe, - // since we don't even allow 1<<30 pixels -} - -static int stbi__parse_entropy_coded_data(stbi__jpeg *z) -{ - stbi__jpeg_reset(z); - if (!z->progressive) { - if (z->scan_n == 1) { - int i,j; - STBI_SIMD_ALIGN(short, data[64]); - int n = z->order[0]; - // non-interleaved data, we just need to process one block at a time, - // in trivial scanline order - // number of blocks to do just depends on how many actual "pixels" this - // component has, independent of interleaved MCU blocking and such - int w = (z->img_comp[n].x+7) >> 3; - int h = (z->img_comp[n].y+7) >> 3; - for (j=0; j < h; ++j) { - for (i=0; i < w; ++i) { - int ha = z->img_comp[n].ha; - if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; - z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); - // every data block is an MCU, so countdown the restart interval - if (--z->todo <= 0) { - if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); - // if it's NOT a restart, then just bail, so we get corrupt data - // rather than no data - if (!STBI__RESTART(z->marker)) return 1; - stbi__jpeg_reset(z); - } - } - } - return 1; - } else { // interleaved - int i,j,k,x,y; - STBI_SIMD_ALIGN(short, data[64]); - for (j=0; j < z->img_mcu_y; ++j) { - for (i=0; i < z->img_mcu_x; ++i) { - // scan an interleaved mcu... process scan_n components in order - for (k=0; k < z->scan_n; ++k) { - int n = z->order[k]; - // scan out an mcu's worth of this component; that's just determined - // by the basic H and V specified for the component - for (y=0; y < z->img_comp[n].v; ++y) { - for (x=0; x < z->img_comp[n].h; ++x) { - int x2 = (i*z->img_comp[n].h + x)*8; - int y2 = (j*z->img_comp[n].v + y)*8; - int ha = z->img_comp[n].ha; - if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; - z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data); - } - } - } - // after all interleaved components, that's an interleaved MCU, - // so now count down the restart interval - if (--z->todo <= 0) { - if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); - if (!STBI__RESTART(z->marker)) return 1; - stbi__jpeg_reset(z); - } - } - } - return 1; - } - } else { - if (z->scan_n == 1) { - int i,j; - int n = z->order[0]; - // non-interleaved data, we just need to process one block at a time, - // in trivial scanline order - // number of blocks to do just depends on how many actual "pixels" this - // component has, independent of interleaved MCU blocking and such - int w = (z->img_comp[n].x+7) >> 3; - int h = (z->img_comp[n].y+7) >> 3; - for (j=0; j < h; ++j) { - for (i=0; i < w; ++i) { - short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); - if (z->spec_start == 0) { - if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) - return 0; - } else { - int ha = z->img_comp[n].ha; - if (!stbi__jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha])) - return 0; - } - // every data block is an MCU, so countdown the restart interval - if (--z->todo <= 0) { - if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); - if (!STBI__RESTART(z->marker)) return 1; - stbi__jpeg_reset(z); - } - } - } - return 1; - } else { // interleaved - int i,j,k,x,y; - for (j=0; j < z->img_mcu_y; ++j) { - for (i=0; i < z->img_mcu_x; ++i) { - // scan an interleaved mcu... process scan_n components in order - for (k=0; k < z->scan_n; ++k) { - int n = z->order[k]; - // scan out an mcu's worth of this component; that's just determined - // by the basic H and V specified for the component - for (y=0; y < z->img_comp[n].v; ++y) { - for (x=0; x < z->img_comp[n].h; ++x) { - int x2 = (i*z->img_comp[n].h + x); - int y2 = (j*z->img_comp[n].v + y); - short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w); - if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) - return 0; - } - } - } - // after all interleaved components, that's an interleaved MCU, - // so now count down the restart interval - if (--z->todo <= 0) { - if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); - if (!STBI__RESTART(z->marker)) return 1; - stbi__jpeg_reset(z); - } - } - } - return 1; - } - } -} - -static void stbi__jpeg_dequantize(short *data, stbi__uint16 *dequant) -{ - int i; - for (i=0; i < 64; ++i) - data[i] *= dequant[i]; -} - -static void stbi__jpeg_finish(stbi__jpeg *z) -{ - if (z->progressive) { - // dequantize and idct the data - int i,j,n; - for (n=0; n < z->s->img_n; ++n) { - int w = (z->img_comp[n].x+7) >> 3; - int h = (z->img_comp[n].y+7) >> 3; - for (j=0; j < h; ++j) { - for (i=0; i < w; ++i) { - short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); - stbi__jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]); - z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); - } - } - } - } -} - -static int stbi__process_marker(stbi__jpeg *z, int m) -{ - int L; - switch (m) { - case STBI__MARKER_none: // no marker found - return stbi__err("expected marker","Corrupt JPEG"); - - case 0xDD: // DRI - specify restart interval - if (stbi__get16be(z->s) != 4) return stbi__err("bad DRI len","Corrupt JPEG"); - z->restart_interval = stbi__get16be(z->s); - return 1; - - case 0xDB: // DQT - define quantization table - L = stbi__get16be(z->s)-2; - while (L > 0) { - int q = stbi__get8(z->s); - int p = q >> 4, sixteen = (p != 0); - int t = q & 15,i; - if (p != 0 && p != 1) return stbi__err("bad DQT type","Corrupt JPEG"); - if (t > 3) return stbi__err("bad DQT table","Corrupt JPEG"); - - for (i=0; i < 64; ++i) - z->dequant[t][stbi__jpeg_dezigzag[i]] = (stbi__uint16)(sixteen ? stbi__get16be(z->s) : stbi__get8(z->s)); - L -= (sixteen ? 129 : 65); - } - return L==0; - - case 0xC4: // DHT - define huffman table - L = stbi__get16be(z->s)-2; - while (L > 0) { - stbi_uc *v; - int sizes[16],i,n=0; - int q = stbi__get8(z->s); - int tc = q >> 4; - int th = q & 15; - if (tc > 1 || th > 3) return stbi__err("bad DHT header","Corrupt JPEG"); - for (i=0; i < 16; ++i) { - sizes[i] = stbi__get8(z->s); - n += sizes[i]; - } - L -= 17; - if (tc == 0) { - if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0; - v = z->huff_dc[th].values; - } else { - if (!stbi__build_huffman(z->huff_ac+th, sizes)) return 0; - v = z->huff_ac[th].values; - } - for (i=0; i < n; ++i) - v[i] = stbi__get8(z->s); - if (tc != 0) - stbi__build_fast_ac(z->fast_ac[th], z->huff_ac + th); - L -= n; - } - return L==0; - } - - // check for comment block or APP blocks - if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) { - L = stbi__get16be(z->s); - if (L < 2) { - if (m == 0xFE) - return stbi__err("bad COM len","Corrupt JPEG"); - else - return stbi__err("bad APP len","Corrupt JPEG"); - } - L -= 2; - - if (m == 0xE0 && L >= 5) { // JFIF APP0 segment - static const unsigned char tag[5] = {'J','F','I','F','\0'}; - int ok = 1; - int i; - for (i=0; i < 5; ++i) - if (stbi__get8(z->s) != tag[i]) - ok = 0; - L -= 5; - if (ok) - z->jfif = 1; - } else if (m == 0xEE && L >= 12) { // Adobe APP14 segment - static const unsigned char tag[6] = {'A','d','o','b','e','\0'}; - int ok = 1; - int i; - for (i=0; i < 6; ++i) - if (stbi__get8(z->s) != tag[i]) - ok = 0; - L -= 6; - if (ok) { - stbi__get8(z->s); // version - stbi__get16be(z->s); // flags0 - stbi__get16be(z->s); // flags1 - z->app14_color_transform = stbi__get8(z->s); // color transform - L -= 6; - } - } - - stbi__skip(z->s, L); - return 1; - } - - return stbi__err("unknown marker","Corrupt JPEG"); -} - -// after we see SOS -static int stbi__process_scan_header(stbi__jpeg *z) -{ - int i; - int Ls = stbi__get16be(z->s); - z->scan_n = stbi__get8(z->s); - if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return stbi__err("bad SOS component count","Corrupt JPEG"); - if (Ls != 6+2*z->scan_n) return stbi__err("bad SOS len","Corrupt JPEG"); - for (i=0; i < z->scan_n; ++i) { - int id = stbi__get8(z->s), which; - int q = stbi__get8(z->s); - for (which = 0; which < z->s->img_n; ++which) - if (z->img_comp[which].id == id) - break; - if (which == z->s->img_n) return 0; // no match - z->img_comp[which].hd = q >> 4; if (z->img_comp[which].hd > 3) return stbi__err("bad DC huff","Corrupt JPEG"); - z->img_comp[which].ha = q & 15; if (z->img_comp[which].ha > 3) return stbi__err("bad AC huff","Corrupt JPEG"); - z->order[i] = which; - } - - { - int aa; - z->spec_start = stbi__get8(z->s); - z->spec_end = stbi__get8(z->s); // should be 63, but might be 0 - aa = stbi__get8(z->s); - z->succ_high = (aa >> 4); - z->succ_low = (aa & 15); - if (z->progressive) { - if (z->spec_start > 63 || z->spec_end > 63 || z->spec_start > z->spec_end || z->succ_high > 13 || z->succ_low > 13) - return stbi__err("bad SOS", "Corrupt JPEG"); - } else { - if (z->spec_start != 0) return stbi__err("bad SOS","Corrupt JPEG"); - if (z->succ_high != 0 || z->succ_low != 0) return stbi__err("bad SOS","Corrupt JPEG"); - z->spec_end = 63; - } - } - - return 1; -} - -static int stbi__free_jpeg_components(stbi__jpeg *z, int ncomp, int why) -{ - int i; - for (i=0; i < ncomp; ++i) { - if (z->img_comp[i].raw_data) { - STBI_FREE(z->img_comp[i].raw_data); - z->img_comp[i].raw_data = NULL; - z->img_comp[i].data = NULL; - } - if (z->img_comp[i].raw_coeff) { - STBI_FREE(z->img_comp[i].raw_coeff); - z->img_comp[i].raw_coeff = 0; - z->img_comp[i].coeff = 0; - } - if (z->img_comp[i].linebuf) { - STBI_FREE(z->img_comp[i].linebuf); - z->img_comp[i].linebuf = NULL; - } - } - return why; -} - -static int stbi__process_frame_header(stbi__jpeg *z, int scan) -{ - stbi__context *s = z->s; - int Lf,p,i,q, h_max=1,v_max=1,c; - Lf = stbi__get16be(s); if (Lf < 11) return stbi__err("bad SOF len","Corrupt JPEG"); // JPEG - p = stbi__get8(s); if (p != 8) return stbi__err("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline - s->img_y = stbi__get16be(s); if (s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG - s->img_x = stbi__get16be(s); if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires - if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); - if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); - c = stbi__get8(s); - if (c != 3 && c != 1 && c != 4) return stbi__err("bad component count","Corrupt JPEG"); - s->img_n = c; - for (i=0; i < c; ++i) { - z->img_comp[i].data = NULL; - z->img_comp[i].linebuf = NULL; - } - - if (Lf != 8+3*s->img_n) return stbi__err("bad SOF len","Corrupt JPEG"); - - z->rgb = 0; - for (i=0; i < s->img_n; ++i) { - static const unsigned char rgb[3] = { 'R', 'G', 'B' }; - z->img_comp[i].id = stbi__get8(s); - if (s->img_n == 3 && z->img_comp[i].id == rgb[i]) - ++z->rgb; - q = stbi__get8(s); - z->img_comp[i].h = (q >> 4); if (!z->img_comp[i].h || z->img_comp[i].h > 4) return stbi__err("bad H","Corrupt JPEG"); - z->img_comp[i].v = q & 15; if (!z->img_comp[i].v || z->img_comp[i].v > 4) return stbi__err("bad V","Corrupt JPEG"); - z->img_comp[i].tq = stbi__get8(s); if (z->img_comp[i].tq > 3) return stbi__err("bad TQ","Corrupt JPEG"); - } - - if (scan != STBI__SCAN_load) return 1; - - if (!stbi__mad3sizes_valid(s->img_x, s->img_y, s->img_n, 0)) return stbi__err("too large", "Image too large to decode"); - - for (i=0; i < s->img_n; ++i) { - if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h; - if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v; - } - - // check that plane subsampling factors are integer ratios; our resamplers can't deal with fractional ratios - // and I've never seen a non-corrupted JPEG file actually use them - for (i=0; i < s->img_n; ++i) { - if (h_max % z->img_comp[i].h != 0) return stbi__err("bad H","Corrupt JPEG"); - if (v_max % z->img_comp[i].v != 0) return stbi__err("bad V","Corrupt JPEG"); - } - - // compute interleaved mcu info - z->img_h_max = h_max; - z->img_v_max = v_max; - z->img_mcu_w = h_max * 8; - z->img_mcu_h = v_max * 8; - // these sizes can't be more than 17 bits - z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w; - z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h; - - for (i=0; i < s->img_n; ++i) { - // number of effective pixels (e.g. for non-interleaved MCU) - z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max; - z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max; - // to simplify generation, we'll allocate enough memory to decode - // the bogus oversized data from using interleaved MCUs and their - // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't - // discard the extra data until colorspace conversion - // - // img_mcu_x, img_mcu_y: <=17 bits; comp[i].h and .v are <=4 (checked earlier) - // so these muls can't overflow with 32-bit ints (which we require) - z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8; - z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8; - z->img_comp[i].coeff = 0; - z->img_comp[i].raw_coeff = 0; - z->img_comp[i].linebuf = NULL; - z->img_comp[i].raw_data = stbi__malloc_mad2(z->img_comp[i].w2, z->img_comp[i].h2, 15); - if (z->img_comp[i].raw_data == NULL) - return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); - // align blocks for idct using mmx/sse - z->img_comp[i].data = (stbi_uc*) (((size_t) z->img_comp[i].raw_data + 15) & ~15); - if (z->progressive) { - // w2, h2 are multiples of 8 (see above) - z->img_comp[i].coeff_w = z->img_comp[i].w2 / 8; - z->img_comp[i].coeff_h = z->img_comp[i].h2 / 8; - z->img_comp[i].raw_coeff = stbi__malloc_mad3(z->img_comp[i].w2, z->img_comp[i].h2, sizeof(short), 15); - if (z->img_comp[i].raw_coeff == NULL) - return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); - z->img_comp[i].coeff = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15); - } - } - - return 1; -} - -// use comparisons since in some cases we handle more than one case (e.g. SOF) -#define stbi__DNL(x) ((x) == 0xdc) -#define stbi__SOI(x) ((x) == 0xd8) -#define stbi__EOI(x) ((x) == 0xd9) -#define stbi__SOF(x) ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2) -#define stbi__SOS(x) ((x) == 0xda) - -#define stbi__SOF_progressive(x) ((x) == 0xc2) - -static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan) -{ - int m; - z->jfif = 0; - z->app14_color_transform = -1; // valid values are 0,1,2 - z->marker = STBI__MARKER_none; // initialize cached marker to empty - m = stbi__get_marker(z); - if (!stbi__SOI(m)) return stbi__err("no SOI","Corrupt JPEG"); - if (scan == STBI__SCAN_type) return 1; - m = stbi__get_marker(z); - while (!stbi__SOF(m)) { - if (!stbi__process_marker(z,m)) return 0; - m = stbi__get_marker(z); - while (m == STBI__MARKER_none) { - // some files have extra padding after their blocks, so ok, we'll scan - if (stbi__at_eof(z->s)) return stbi__err("no SOF", "Corrupt JPEG"); - m = stbi__get_marker(z); - } - } - z->progressive = stbi__SOF_progressive(m); - if (!stbi__process_frame_header(z, scan)) return 0; - return 1; -} - -// decode image to YCbCr format -static int stbi__decode_jpeg_image(stbi__jpeg *j) -{ - int m; - for (m = 0; m < 4; m++) { - j->img_comp[m].raw_data = NULL; - j->img_comp[m].raw_coeff = NULL; - } - j->restart_interval = 0; - if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) return 0; - m = stbi__get_marker(j); - while (!stbi__EOI(m)) { - if (stbi__SOS(m)) { - if (!stbi__process_scan_header(j)) return 0; - if (!stbi__parse_entropy_coded_data(j)) return 0; - if (j->marker == STBI__MARKER_none ) { - // handle 0s at the end of image data from IP Kamera 9060 - while (!stbi__at_eof(j->s)) { - int x = stbi__get8(j->s); - if (x == 255) { - j->marker = stbi__get8(j->s); - break; - } - } - // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0 - } - } else if (stbi__DNL(m)) { - int Ld = stbi__get16be(j->s); - stbi__uint32 NL = stbi__get16be(j->s); - if (Ld != 4) return stbi__err("bad DNL len", "Corrupt JPEG"); - if (NL != j->s->img_y) return stbi__err("bad DNL height", "Corrupt JPEG"); - } else { - if (!stbi__process_marker(j, m)) return 0; - } - m = stbi__get_marker(j); - } - if (j->progressive) - stbi__jpeg_finish(j); - return 1; -} - -// static jfif-centered resampling (across block boundaries) - -typedef stbi_uc *(*resample_row_func)(stbi_uc *out, stbi_uc *in0, stbi_uc *in1, - int w, int hs); - -#define stbi__div4(x) ((stbi_uc) ((x) >> 2)) - -static stbi_uc *resample_row_1(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - STBI_NOTUSED(out); - STBI_NOTUSED(in_far); - STBI_NOTUSED(w); - STBI_NOTUSED(hs); - return in_near; -} - -static stbi_uc* stbi__resample_row_v_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - // need to generate two samples vertically for every one in input - int i; - STBI_NOTUSED(hs); - for (i=0; i < w; ++i) - out[i] = stbi__div4(3*in_near[i] + in_far[i] + 2); - return out; -} - -static stbi_uc* stbi__resample_row_h_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - // need to generate two samples horizontally for every one in input - int i; - stbi_uc *input = in_near; - - if (w == 1) { - // if only one sample, can't do any interpolation - out[0] = out[1] = input[0]; - return out; - } - - out[0] = input[0]; - out[1] = stbi__div4(input[0]*3 + input[1] + 2); - for (i=1; i < w-1; ++i) { - int n = 3*input[i]+2; - out[i*2+0] = stbi__div4(n+input[i-1]); - out[i*2+1] = stbi__div4(n+input[i+1]); - } - out[i*2+0] = stbi__div4(input[w-2]*3 + input[w-1] + 2); - out[i*2+1] = input[w-1]; - - STBI_NOTUSED(in_far); - STBI_NOTUSED(hs); - - return out; -} - -#define stbi__div16(x) ((stbi_uc) ((x) >> 4)) - -static stbi_uc *stbi__resample_row_hv_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - // need to generate 2x2 samples for every one in input - int i,t0,t1; - if (w == 1) { - out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); - return out; - } - - t1 = 3*in_near[0] + in_far[0]; - out[0] = stbi__div4(t1+2); - for (i=1; i < w; ++i) { - t0 = t1; - t1 = 3*in_near[i]+in_far[i]; - out[i*2-1] = stbi__div16(3*t0 + t1 + 8); - out[i*2 ] = stbi__div16(3*t1 + t0 + 8); - } - out[w*2-1] = stbi__div4(t1+2); - - STBI_NOTUSED(hs); - - return out; -} - -#if defined(STBI_SSE2) || defined(STBI_NEON) -static stbi_uc *stbi__resample_row_hv_2_simd(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - // need to generate 2x2 samples for every one in input - int i=0,t0,t1; - - if (w == 1) { - out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); - return out; - } - - t1 = 3*in_near[0] + in_far[0]; - // process groups of 8 pixels for as long as we can. - // note we can't handle the last pixel in a row in this loop - // because we need to handle the filter boundary conditions. - for (; i < ((w-1) & ~7); i += 8) { -#if defined(STBI_SSE2) - // load and perform the vertical filtering pass - // this uses 3*x + y = 4*x + (y - x) - __m128i zero = _mm_setzero_si128(); - __m128i farb = _mm_loadl_epi64((__m128i *) (in_far + i)); - __m128i nearb = _mm_loadl_epi64((__m128i *) (in_near + i)); - __m128i farw = _mm_unpacklo_epi8(farb, zero); - __m128i nearw = _mm_unpacklo_epi8(nearb, zero); - __m128i diff = _mm_sub_epi16(farw, nearw); - __m128i nears = _mm_slli_epi16(nearw, 2); - __m128i curr = _mm_add_epi16(nears, diff); // current row - - // horizontal filter works the same based on shifted vers of current - // row. "prev" is current row shifted right by 1 pixel; we need to - // insert the previous pixel value (from t1). - // "next" is current row shifted left by 1 pixel, with first pixel - // of next block of 8 pixels added in. - __m128i prv0 = _mm_slli_si128(curr, 2); - __m128i nxt0 = _mm_srli_si128(curr, 2); - __m128i prev = _mm_insert_epi16(prv0, t1, 0); - __m128i next = _mm_insert_epi16(nxt0, 3*in_near[i+8] + in_far[i+8], 7); - - // horizontal filter, polyphase implementation since it's convenient: - // even pixels = 3*cur + prev = cur*4 + (prev - cur) - // odd pixels = 3*cur + next = cur*4 + (next - cur) - // note the shared term. - __m128i bias = _mm_set1_epi16(8); - __m128i curs = _mm_slli_epi16(curr, 2); - __m128i prvd = _mm_sub_epi16(prev, curr); - __m128i nxtd = _mm_sub_epi16(next, curr); - __m128i curb = _mm_add_epi16(curs, bias); - __m128i even = _mm_add_epi16(prvd, curb); - __m128i odd = _mm_add_epi16(nxtd, curb); - - // interleave even and odd pixels, then undo scaling. - __m128i int0 = _mm_unpacklo_epi16(even, odd); - __m128i int1 = _mm_unpackhi_epi16(even, odd); - __m128i de0 = _mm_srli_epi16(int0, 4); - __m128i de1 = _mm_srli_epi16(int1, 4); - - // pack and write output - __m128i outv = _mm_packus_epi16(de0, de1); - _mm_storeu_si128((__m128i *) (out + i*2), outv); -#elif defined(STBI_NEON) - // load and perform the vertical filtering pass - // this uses 3*x + y = 4*x + (y - x) - uint8x8_t farb = vld1_u8(in_far + i); - uint8x8_t nearb = vld1_u8(in_near + i); - int16x8_t diff = vreinterpretq_s16_u16(vsubl_u8(farb, nearb)); - int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2)); - int16x8_t curr = vaddq_s16(nears, diff); // current row - - // horizontal filter works the same based on shifted vers of current - // row. "prev" is current row shifted right by 1 pixel; we need to - // insert the previous pixel value (from t1). - // "next" is current row shifted left by 1 pixel, with first pixel - // of next block of 8 pixels added in. - int16x8_t prv0 = vextq_s16(curr, curr, 7); - int16x8_t nxt0 = vextq_s16(curr, curr, 1); - int16x8_t prev = vsetq_lane_s16(t1, prv0, 0); - int16x8_t next = vsetq_lane_s16(3*in_near[i+8] + in_far[i+8], nxt0, 7); - - // horizontal filter, polyphase implementation since it's convenient: - // even pixels = 3*cur + prev = cur*4 + (prev - cur) - // odd pixels = 3*cur + next = cur*4 + (next - cur) - // note the shared term. - int16x8_t curs = vshlq_n_s16(curr, 2); - int16x8_t prvd = vsubq_s16(prev, curr); - int16x8_t nxtd = vsubq_s16(next, curr); - int16x8_t even = vaddq_s16(curs, prvd); - int16x8_t odd = vaddq_s16(curs, nxtd); - - // undo scaling and round, then store with even/odd phases interleaved - uint8x8x2_t o; - o.val[0] = vqrshrun_n_s16(even, 4); - o.val[1] = vqrshrun_n_s16(odd, 4); - vst2_u8(out + i*2, o); -#endif - - // "previous" value for next iter - t1 = 3*in_near[i+7] + in_far[i+7]; - } - - t0 = t1; - t1 = 3*in_near[i] + in_far[i]; - out[i*2] = stbi__div16(3*t1 + t0 + 8); - - for (++i; i < w; ++i) { - t0 = t1; - t1 = 3*in_near[i]+in_far[i]; - out[i*2-1] = stbi__div16(3*t0 + t1 + 8); - out[i*2 ] = stbi__div16(3*t1 + t0 + 8); - } - out[w*2-1] = stbi__div4(t1+2); - - STBI_NOTUSED(hs); - - return out; -} -#endif - -static stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - // resample with nearest-neighbor - int i,j; - STBI_NOTUSED(in_far); - for (i=0; i < w; ++i) - for (j=0; j < hs; ++j) - out[i*hs+j] = in_near[i]; - return out; -} - -// this is a reduced-precision calculation of YCbCr-to-RGB introduced -// to make sure the code produces the same results in both SIMD and scalar -#define stbi__float2fixed(x) (((int) ((x) * 4096.0f + 0.5f)) << 8) -static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step) -{ - int i; - for (i=0; i < count; ++i) { - int y_fixed = (y[i] << 20) + (1<<19); // rounding - int r,g,b; - int cr = pcr[i] - 128; - int cb = pcb[i] - 128; - r = y_fixed + cr* stbi__float2fixed(1.40200f); - g = y_fixed + (cr*-stbi__float2fixed(0.71414f)) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); - b = y_fixed + cb* stbi__float2fixed(1.77200f); - r >>= 20; - g >>= 20; - b >>= 20; - if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } - if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } - if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } - out[0] = (stbi_uc)r; - out[1] = (stbi_uc)g; - out[2] = (stbi_uc)b; - out[3] = 255; - out += step; - } -} - -#if defined(STBI_SSE2) || defined(STBI_NEON) -static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, int step) -{ - int i = 0; - -#ifdef STBI_SSE2 - // step == 3 is pretty ugly on the final interleave, and i'm not convinced - // it's useful in practice (you wouldn't use it for textures, for example). - // so just accelerate step == 4 case. - if (step == 4) { - // this is a fairly straightforward implementation and not super-optimized. - __m128i signflip = _mm_set1_epi8(-0x80); - __m128i cr_const0 = _mm_set1_epi16( (short) ( 1.40200f*4096.0f+0.5f)); - __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f)); - __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f)); - __m128i cb_const1 = _mm_set1_epi16( (short) ( 1.77200f*4096.0f+0.5f)); - __m128i y_bias = _mm_set1_epi8((char) (unsigned char) 128); - __m128i xw = _mm_set1_epi16(255); // alpha channel - - for (; i+7 < count; i += 8) { - // load - __m128i y_bytes = _mm_loadl_epi64((__m128i *) (y+i)); - __m128i cr_bytes = _mm_loadl_epi64((__m128i *) (pcr+i)); - __m128i cb_bytes = _mm_loadl_epi64((__m128i *) (pcb+i)); - __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); // -128 - __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); // -128 - - // unpack to short (and left-shift cr, cb by 8) - __m128i yw = _mm_unpacklo_epi8(y_bias, y_bytes); - __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased); - __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased); - - // color transform - __m128i yws = _mm_srli_epi16(yw, 4); - __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw); - __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw); - __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1); - __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1); - __m128i rws = _mm_add_epi16(cr0, yws); - __m128i gwt = _mm_add_epi16(cb0, yws); - __m128i bws = _mm_add_epi16(yws, cb1); - __m128i gws = _mm_add_epi16(gwt, cr1); - - // descale - __m128i rw = _mm_srai_epi16(rws, 4); - __m128i bw = _mm_srai_epi16(bws, 4); - __m128i gw = _mm_srai_epi16(gws, 4); - - // back to byte, set up for transpose - __m128i brb = _mm_packus_epi16(rw, bw); - __m128i gxb = _mm_packus_epi16(gw, xw); - - // transpose to interleave channels - __m128i t0 = _mm_unpacklo_epi8(brb, gxb); - __m128i t1 = _mm_unpackhi_epi8(brb, gxb); - __m128i o0 = _mm_unpacklo_epi16(t0, t1); - __m128i o1 = _mm_unpackhi_epi16(t0, t1); - - // store - _mm_storeu_si128((__m128i *) (out + 0), o0); - _mm_storeu_si128((__m128i *) (out + 16), o1); - out += 32; - } - } -#endif - -#ifdef STBI_NEON - // in this version, step=3 support would be easy to add. but is there demand? - if (step == 4) { - // this is a fairly straightforward implementation and not super-optimized. - uint8x8_t signflip = vdup_n_u8(0x80); - int16x8_t cr_const0 = vdupq_n_s16( (short) ( 1.40200f*4096.0f+0.5f)); - int16x8_t cr_const1 = vdupq_n_s16( - (short) ( 0.71414f*4096.0f+0.5f)); - int16x8_t cb_const0 = vdupq_n_s16( - (short) ( 0.34414f*4096.0f+0.5f)); - int16x8_t cb_const1 = vdupq_n_s16( (short) ( 1.77200f*4096.0f+0.5f)); - - for (; i+7 < count; i += 8) { - // load - uint8x8_t y_bytes = vld1_u8(y + i); - uint8x8_t cr_bytes = vld1_u8(pcr + i); - uint8x8_t cb_bytes = vld1_u8(pcb + i); - int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip)); - int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip)); - - // expand to s16 - int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4)); - int16x8_t crw = vshll_n_s8(cr_biased, 7); - int16x8_t cbw = vshll_n_s8(cb_biased, 7); - - // color transform - int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0); - int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0); - int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1); - int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1); - int16x8_t rws = vaddq_s16(yws, cr0); - int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1); - int16x8_t bws = vaddq_s16(yws, cb1); - - // undo scaling, round, convert to byte - uint8x8x4_t o; - o.val[0] = vqrshrun_n_s16(rws, 4); - o.val[1] = vqrshrun_n_s16(gws, 4); - o.val[2] = vqrshrun_n_s16(bws, 4); - o.val[3] = vdup_n_u8(255); - - // store, interleaving r/g/b/a - vst4_u8(out, o); - out += 8*4; - } - } -#endif - - for (; i < count; ++i) { - int y_fixed = (y[i] << 20) + (1<<19); // rounding - int r,g,b; - int cr = pcr[i] - 128; - int cb = pcb[i] - 128; - r = y_fixed + cr* stbi__float2fixed(1.40200f); - g = y_fixed + cr*-stbi__float2fixed(0.71414f) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); - b = y_fixed + cb* stbi__float2fixed(1.77200f); - r >>= 20; - g >>= 20; - b >>= 20; - if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } - if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } - if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } - out[0] = (stbi_uc)r; - out[1] = (stbi_uc)g; - out[2] = (stbi_uc)b; - out[3] = 255; - out += step; - } -} -#endif - -// set up the kernels -static void stbi__setup_jpeg(stbi__jpeg *j) -{ - j->idct_block_kernel = stbi__idct_block; - j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_row; - j->resample_row_hv_2_kernel = stbi__resample_row_hv_2; - -#ifdef STBI_SSE2 - if (stbi__sse2_available()) { - j->idct_block_kernel = stbi__idct_simd; - j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; - j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; - } -#endif - -#ifdef STBI_NEON - j->idct_block_kernel = stbi__idct_simd; - j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; - j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; -#endif -} - -// clean up the temporary component buffers -static void stbi__cleanup_jpeg(stbi__jpeg *j) -{ - stbi__free_jpeg_components(j, j->s->img_n, 0); -} - -typedef struct -{ - resample_row_func resample; - stbi_uc *line0,*line1; - int hs,vs; // expansion factor in each axis - int w_lores; // horizontal pixels pre-expansion - int ystep; // how far through vertical expansion we are - int ypos; // which pre-expansion row we're on -} stbi__resample; - -// fast 0..255 * 0..255 => 0..255 rounded multiplication -static stbi_uc stbi__blinn_8x8(stbi_uc x, stbi_uc y) -{ - unsigned int t = x*y + 128; - return (stbi_uc) ((t + (t >>8)) >> 8); -} - -static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp) -{ - int n, decode_n, is_rgb; - z->s->img_n = 0; // make stbi__cleanup_jpeg safe - - // validate req_comp - if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); - - // load a jpeg image from whichever source, but leave in YCbCr format - if (!stbi__decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; } - - // determine actual number of components to generate - n = req_comp ? req_comp : z->s->img_n >= 3 ? 3 : 1; - - is_rgb = z->s->img_n == 3 && (z->rgb == 3 || (z->app14_color_transform == 0 && !z->jfif)); - - if (z->s->img_n == 3 && n < 3 && !is_rgb) - decode_n = 1; - else - decode_n = z->s->img_n; - - // nothing to do if no components requested; check this now to avoid - // accessing uninitialized coutput[0] later - if (decode_n <= 0) { stbi__cleanup_jpeg(z); return NULL; } - - // resample and color-convert - { - int k; - unsigned int i,j; - stbi_uc *output; - stbi_uc *coutput[4] = { NULL, NULL, NULL, NULL }; - - stbi__resample res_comp[4]; - - for (k=0; k < decode_n; ++k) { - stbi__resample *r = &res_comp[k]; - - // allocate line buffer big enough for upsampling off the edges - // with upsample factor of 4 - z->img_comp[k].linebuf = (stbi_uc *) stbi__malloc(z->s->img_x + 3); - if (!z->img_comp[k].linebuf) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } - - r->hs = z->img_h_max / z->img_comp[k].h; - r->vs = z->img_v_max / z->img_comp[k].v; - r->ystep = r->vs >> 1; - r->w_lores = (z->s->img_x + r->hs-1) / r->hs; - r->ypos = 0; - r->line0 = r->line1 = z->img_comp[k].data; - - if (r->hs == 1 && r->vs == 1) r->resample = resample_row_1; - else if (r->hs == 1 && r->vs == 2) r->resample = stbi__resample_row_v_2; - else if (r->hs == 2 && r->vs == 1) r->resample = stbi__resample_row_h_2; - else if (r->hs == 2 && r->vs == 2) r->resample = z->resample_row_hv_2_kernel; - else r->resample = stbi__resample_row_generic; - } - - // can't error after this so, this is safe - output = (stbi_uc *) stbi__malloc_mad3(n, z->s->img_x, z->s->img_y, 1); - if (!output) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } - - // now go ahead and resample - for (j=0; j < z->s->img_y; ++j) { - stbi_uc *out = output + n * z->s->img_x * j; - for (k=0; k < decode_n; ++k) { - stbi__resample *r = &res_comp[k]; - int y_bot = r->ystep >= (r->vs >> 1); - coutput[k] = r->resample(z->img_comp[k].linebuf, - y_bot ? r->line1 : r->line0, - y_bot ? r->line0 : r->line1, - r->w_lores, r->hs); - if (++r->ystep >= r->vs) { - r->ystep = 0; - r->line0 = r->line1; - if (++r->ypos < z->img_comp[k].y) - r->line1 += z->img_comp[k].w2; - } - } - if (n >= 3) { - stbi_uc *y = coutput[0]; - if (z->s->img_n == 3) { - if (is_rgb) { - for (i=0; i < z->s->img_x; ++i) { - out[0] = y[i]; - out[1] = coutput[1][i]; - out[2] = coutput[2][i]; - out[3] = 255; - out += n; - } - } else { - z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); - } - } else if (z->s->img_n == 4) { - if (z->app14_color_transform == 0) { // CMYK - for (i=0; i < z->s->img_x; ++i) { - stbi_uc m = coutput[3][i]; - out[0] = stbi__blinn_8x8(coutput[0][i], m); - out[1] = stbi__blinn_8x8(coutput[1][i], m); - out[2] = stbi__blinn_8x8(coutput[2][i], m); - out[3] = 255; - out += n; - } - } else if (z->app14_color_transform == 2) { // YCCK - z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); - for (i=0; i < z->s->img_x; ++i) { - stbi_uc m = coutput[3][i]; - out[0] = stbi__blinn_8x8(255 - out[0], m); - out[1] = stbi__blinn_8x8(255 - out[1], m); - out[2] = stbi__blinn_8x8(255 - out[2], m); - out += n; - } - } else { // YCbCr + alpha? Ignore the fourth channel for now - z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); - } - } else - for (i=0; i < z->s->img_x; ++i) { - out[0] = out[1] = out[2] = y[i]; - out[3] = 255; // not used if n==3 - out += n; - } - } else { - if (is_rgb) { - if (n == 1) - for (i=0; i < z->s->img_x; ++i) - *out++ = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); - else { - for (i=0; i < z->s->img_x; ++i, out += 2) { - out[0] = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); - out[1] = 255; - } - } - } else if (z->s->img_n == 4 && z->app14_color_transform == 0) { - for (i=0; i < z->s->img_x; ++i) { - stbi_uc m = coutput[3][i]; - stbi_uc r = stbi__blinn_8x8(coutput[0][i], m); - stbi_uc g = stbi__blinn_8x8(coutput[1][i], m); - stbi_uc b = stbi__blinn_8x8(coutput[2][i], m); - out[0] = stbi__compute_y(r, g, b); - out[1] = 255; - out += n; - } - } else if (z->s->img_n == 4 && z->app14_color_transform == 2) { - for (i=0; i < z->s->img_x; ++i) { - out[0] = stbi__blinn_8x8(255 - coutput[0][i], coutput[3][i]); - out[1] = 255; - out += n; - } - } else { - stbi_uc *y = coutput[0]; - if (n == 1) - for (i=0; i < z->s->img_x; ++i) out[i] = y[i]; - else - for (i=0; i < z->s->img_x; ++i) { *out++ = y[i]; *out++ = 255; } - } - } - } - stbi__cleanup_jpeg(z); - *out_x = z->s->img_x; - *out_y = z->s->img_y; - if (comp) *comp = z->s->img_n >= 3 ? 3 : 1; // report original components, not output - return output; - } -} - -static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) -{ - unsigned char* result; - stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg)); - if (!j) return stbi__errpuc("outofmem", "Out of memory"); - STBI_NOTUSED(ri); - j->s = s; - stbi__setup_jpeg(j); - result = load_jpeg_image(j, x,y,comp,req_comp); - STBI_FREE(j); - return result; -} - -static int stbi__jpeg_test(stbi__context *s) -{ - int r; - stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg)); - if (!j) return stbi__err("outofmem", "Out of memory"); - j->s = s; - stbi__setup_jpeg(j); - r = stbi__decode_jpeg_header(j, STBI__SCAN_type); - stbi__rewind(s); - STBI_FREE(j); - return r; -} - -static int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp) -{ - if (!stbi__decode_jpeg_header(j, STBI__SCAN_header)) { - stbi__rewind( j->s ); - return 0; - } - if (x) *x = j->s->img_x; - if (y) *y = j->s->img_y; - if (comp) *comp = j->s->img_n >= 3 ? 3 : 1; - return 1; -} - -static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) -{ - int result; - stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg))); - if (!j) return stbi__err("outofmem", "Out of memory"); - j->s = s; - result = stbi__jpeg_info_raw(j, x, y, comp); - STBI_FREE(j); - return result; -} -#endif - -// public domain zlib decode v0.2 Sean Barrett 2006-11-18 -// simple implementation -// - all input must be provided in an upfront buffer -// - all output is written to a single output buffer (can malloc/realloc) -// performance -// - fast huffman - -#ifndef STBI_NO_ZLIB - -// fast-way is faster to check than jpeg huffman, but slow way is slower -#define STBI__ZFAST_BITS 9 // accelerate all cases in default tables -#define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1) -#define STBI__ZNSYMS 288 // number of symbols in literal/length alphabet - -// zlib-style huffman encoding -// (jpegs packs from left, zlib from right, so can't share code) -typedef struct -{ - stbi__uint16 fast[1 << STBI__ZFAST_BITS]; - stbi__uint16 firstcode[16]; - int maxcode[17]; - stbi__uint16 firstsymbol[16]; - stbi_uc size[STBI__ZNSYMS]; - stbi__uint16 value[STBI__ZNSYMS]; -} stbi__zhuffman; - -stbi_inline static int stbi__bitreverse16(int n) -{ - n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1); - n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2); - n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4); - n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8); - return n; -} - -stbi_inline static int stbi__bit_reverse(int v, int bits) -{ - STBI_ASSERT(bits <= 16); - // to bit reverse n bits, reverse 16 and shift - // e.g. 11 bits, bit reverse and shift away 5 - return stbi__bitreverse16(v) >> (16-bits); -} - -static int stbi__zbuild_huffman(stbi__zhuffman *z, const stbi_uc *sizelist, int num) -{ - int i,k=0; - int code, next_code[16], sizes[17]; - - // DEFLATE spec for generating codes - memset(sizes, 0, sizeof(sizes)); - memset(z->fast, 0, sizeof(z->fast)); - for (i=0; i < num; ++i) - ++sizes[sizelist[i]]; - sizes[0] = 0; - for (i=1; i < 16; ++i) - if (sizes[i] > (1 << i)) - return stbi__err("bad sizes", "Corrupt PNG"); - code = 0; - for (i=1; i < 16; ++i) { - next_code[i] = code; - z->firstcode[i] = (stbi__uint16) code; - z->firstsymbol[i] = (stbi__uint16) k; - code = (code + sizes[i]); - if (sizes[i]) - if (code-1 >= (1 << i)) return stbi__err("bad codelengths","Corrupt PNG"); - z->maxcode[i] = code << (16-i); // preshift for inner loop - code <<= 1; - k += sizes[i]; - } - z->maxcode[16] = 0x10000; // sentinel - for (i=0; i < num; ++i) { - int s = sizelist[i]; - if (s) { - int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s]; - stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i); - z->size [c] = (stbi_uc ) s; - z->value[c] = (stbi__uint16) i; - if (s <= STBI__ZFAST_BITS) { - int j = stbi__bit_reverse(next_code[s],s); - while (j < (1 << STBI__ZFAST_BITS)) { - z->fast[j] = fastv; - j += (1 << s); - } - } - ++next_code[s]; - } - } - return 1; -} - -// zlib-from-memory implementation for PNG reading -// because PNG allows splitting the zlib stream arbitrarily, -// and it's annoying structurally to have PNG call ZLIB call PNG, -// we require PNG read all the IDATs and combine them into a single -// memory buffer - -typedef struct -{ - stbi_uc *zbuffer, *zbuffer_end; - int num_bits; - stbi__uint32 code_buffer; - - char *zout; - char *zout_start; - char *zout_end; - int z_expandable; - - stbi__zhuffman z_length, z_distance; -} stbi__zbuf; - -stbi_inline static int stbi__zeof(stbi__zbuf *z) -{ - return (z->zbuffer >= z->zbuffer_end); -} - -stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z) -{ - return stbi__zeof(z) ? 0 : *z->zbuffer++; -} - -static void stbi__fill_bits(stbi__zbuf *z) -{ - do { - if (z->code_buffer >= (1U << z->num_bits)) { - z->zbuffer = z->zbuffer_end; /* treat this as EOF so we fail. */ - return; - } - z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits; - z->num_bits += 8; - } while (z->num_bits <= 24); -} - -stbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n) -{ - unsigned int k; - if (z->num_bits < n) stbi__fill_bits(z); - k = z->code_buffer & ((1 << n) - 1); - z->code_buffer >>= n; - z->num_bits -= n; - return k; -} - -static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) -{ - int b,s,k; - // not resolved by fast table, so compute it the slow way - // use jpeg approach, which requires MSbits at top - k = stbi__bit_reverse(a->code_buffer, 16); - for (s=STBI__ZFAST_BITS+1; ; ++s) - if (k < z->maxcode[s]) - break; - if (s >= 16) return -1; // invalid code! - // code size is s, so: - b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; - if (b >= STBI__ZNSYMS) return -1; // some data was corrupt somewhere! - if (z->size[b] != s) return -1; // was originally an assert, but report failure instead. - a->code_buffer >>= s; - a->num_bits -= s; - return z->value[b]; -} - -stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) -{ - int b,s; - if (a->num_bits < 16) { - if (stbi__zeof(a)) { - return -1; /* report error for unexpected end of data. */ - } - stbi__fill_bits(a); - } - b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; - if (b) { - s = b >> 9; - a->code_buffer >>= s; - a->num_bits -= s; - return b & 511; - } - return stbi__zhuffman_decode_slowpath(a, z); -} - -static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes -{ - char *q; - unsigned int cur, limit, old_limit; - z->zout = zout; - if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG"); - cur = (unsigned int) (z->zout - z->zout_start); - limit = old_limit = (unsigned) (z->zout_end - z->zout_start); - if (UINT_MAX - cur < (unsigned) n) return stbi__err("outofmem", "Out of memory"); - while (cur + n > limit) { - if(limit > UINT_MAX / 2) return stbi__err("outofmem", "Out of memory"); - limit *= 2; - } - q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit); - STBI_NOTUSED(old_limit); - if (q == NULL) return stbi__err("outofmem", "Out of memory"); - z->zout_start = q; - z->zout = q + cur; - z->zout_end = q + limit; - return 1; -} - -static const int stbi__zlength_base[31] = { - 3,4,5,6,7,8,9,10,11,13, - 15,17,19,23,27,31,35,43,51,59, - 67,83,99,115,131,163,195,227,258,0,0 }; - -static const int stbi__zlength_extra[31]= -{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; - -static const int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, -257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; - -static const int stbi__zdist_extra[32] = -{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; - -static int stbi__parse_huffman_block(stbi__zbuf *a) -{ - char *zout = a->zout; - for(;;) { - int z = stbi__zhuffman_decode(a, &a->z_length); - if (z < 256) { - if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); // error in huffman codes - if (zout >= a->zout_end) { - if (!stbi__zexpand(a, zout, 1)) return 0; - zout = a->zout; - } - *zout++ = (char) z; - } else { - stbi_uc *p; - int len,dist; - if (z == 256) { - a->zout = zout; - return 1; - } - z -= 257; - len = stbi__zlength_base[z]; - if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]); - z = stbi__zhuffman_decode(a, &a->z_distance); - if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); - dist = stbi__zdist_base[z]; - if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]); - if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG"); - if (zout + len > a->zout_end) { - if (!stbi__zexpand(a, zout, len)) return 0; - zout = a->zout; - } - p = (stbi_uc *) (zout - dist); - if (dist == 1) { // run of one byte; common in images. - stbi_uc v = *p; - if (len) { do *zout++ = v; while (--len); } - } else { - if (len) { do *zout++ = *p++; while (--len); } - } - } - } -} - -static int stbi__compute_huffman_codes(stbi__zbuf *a) -{ - static const stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; - stbi__zhuffman z_codelength; - stbi_uc lencodes[286+32+137];//padding for maximum single op - stbi_uc codelength_sizes[19]; - int i,n; - - int hlit = stbi__zreceive(a,5) + 257; - int hdist = stbi__zreceive(a,5) + 1; - int hclen = stbi__zreceive(a,4) + 4; - int ntot = hlit + hdist; - - memset(codelength_sizes, 0, sizeof(codelength_sizes)); - for (i=0; i < hclen; ++i) { - int s = stbi__zreceive(a,3); - codelength_sizes[length_dezigzag[i]] = (stbi_uc) s; - } - if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0; - - n = 0; - while (n < ntot) { - int c = stbi__zhuffman_decode(a, &z_codelength); - if (c < 0 || c >= 19) return stbi__err("bad codelengths", "Corrupt PNG"); - if (c < 16) - lencodes[n++] = (stbi_uc) c; - else { - stbi_uc fill = 0; - if (c == 16) { - c = stbi__zreceive(a,2)+3; - if (n == 0) return stbi__err("bad codelengths", "Corrupt PNG"); - fill = lencodes[n-1]; - } else if (c == 17) { - c = stbi__zreceive(a,3)+3; - } else if (c == 18) { - c = stbi__zreceive(a,7)+11; - } else { - return stbi__err("bad codelengths", "Corrupt PNG"); - } - if (ntot - n < c) return stbi__err("bad codelengths", "Corrupt PNG"); - memset(lencodes+n, fill, c); - n += c; - } - } - if (n != ntot) return stbi__err("bad codelengths","Corrupt PNG"); - if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0; - if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0; - return 1; -} - -static int stbi__parse_uncompressed_block(stbi__zbuf *a) -{ - stbi_uc header[4]; - int len,nlen,k; - if (a->num_bits & 7) - stbi__zreceive(a, a->num_bits & 7); // discard - // drain the bit-packed data into header - k = 0; - while (a->num_bits > 0) { - header[k++] = (stbi_uc) (a->code_buffer & 255); // suppress MSVC run-time check - a->code_buffer >>= 8; - a->num_bits -= 8; - } - if (a->num_bits < 0) return stbi__err("zlib corrupt","Corrupt PNG"); - // now fill header the normal way - while (k < 4) - header[k++] = stbi__zget8(a); - len = header[1] * 256 + header[0]; - nlen = header[3] * 256 + header[2]; - if (nlen != (len ^ 0xffff)) return stbi__err("zlib corrupt","Corrupt PNG"); - if (a->zbuffer + len > a->zbuffer_end) return stbi__err("read past buffer","Corrupt PNG"); - if (a->zout + len > a->zout_end) - if (!stbi__zexpand(a, a->zout, len)) return 0; - memcpy(a->zout, a->zbuffer, len); - a->zbuffer += len; - a->zout += len; - return 1; -} - -static int stbi__parse_zlib_header(stbi__zbuf *a) -{ - int cmf = stbi__zget8(a); - int cm = cmf & 15; - /* int cinfo = cmf >> 4; */ - int flg = stbi__zget8(a); - if (stbi__zeof(a)) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec - if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec - if (flg & 32) return stbi__err("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png - if (cm != 8) return stbi__err("bad compression","Corrupt PNG"); // DEFLATE required for png - // window = 1 << (8 + cinfo)... but who cares, we fully buffer output - return 1; -} - -static const stbi_uc stbi__zdefault_length[STBI__ZNSYMS] = -{ - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8 -}; -static const stbi_uc stbi__zdefault_distance[32] = -{ - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5 -}; -/* -Init algorithm: -{ - int i; // use <= to match clearly with spec - for (i=0; i <= 143; ++i) stbi__zdefault_length[i] = 8; - for ( ; i <= 255; ++i) stbi__zdefault_length[i] = 9; - for ( ; i <= 279; ++i) stbi__zdefault_length[i] = 7; - for ( ; i <= 287; ++i) stbi__zdefault_length[i] = 8; - - for (i=0; i <= 31; ++i) stbi__zdefault_distance[i] = 5; -} -*/ - -static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) -{ - int final, type; - if (parse_header) - if (!stbi__parse_zlib_header(a)) return 0; - a->num_bits = 0; - a->code_buffer = 0; - do { - final = stbi__zreceive(a,1); - type = stbi__zreceive(a,2); - if (type == 0) { - if (!stbi__parse_uncompressed_block(a)) return 0; - } else if (type == 3) { - return 0; - } else { - if (type == 1) { - // use fixed code lengths - if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , STBI__ZNSYMS)) return 0; - if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0; - } else { - if (!stbi__compute_huffman_codes(a)) return 0; - } - if (!stbi__parse_huffman_block(a)) return 0; - } - } while (!final); - return 1; -} - -static int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header) -{ - a->zout_start = obuf; - a->zout = obuf; - a->zout_end = obuf + olen; - a->z_expandable = exp; - - return stbi__parse_zlib(a, parse_header); -} - -STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen) -{ - stbi__zbuf a; - char *p = (char *) stbi__malloc(initial_size); - if (p == NULL) return NULL; - a.zbuffer = (stbi_uc *) buffer; - a.zbuffer_end = (stbi_uc *) buffer + len; - if (stbi__do_zlib(&a, p, initial_size, 1, 1)) { - if (outlen) *outlen = (int) (a.zout - a.zout_start); - return a.zout_start; - } else { - STBI_FREE(a.zout_start); - return NULL; - } -} - -STBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen) -{ - return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen); -} - -STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header) -{ - stbi__zbuf a; - char *p = (char *) stbi__malloc(initial_size); - if (p == NULL) return NULL; - a.zbuffer = (stbi_uc *) buffer; - a.zbuffer_end = (stbi_uc *) buffer + len; - if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) { - if (outlen) *outlen = (int) (a.zout - a.zout_start); - return a.zout_start; - } else { - STBI_FREE(a.zout_start); - return NULL; - } -} - -STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen) -{ - stbi__zbuf a; - a.zbuffer = (stbi_uc *) ibuffer; - a.zbuffer_end = (stbi_uc *) ibuffer + ilen; - if (stbi__do_zlib(&a, obuffer, olen, 0, 1)) - return (int) (a.zout - a.zout_start); - else - return -1; -} - -STBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen) -{ - stbi__zbuf a; - char *p = (char *) stbi__malloc(16384); - if (p == NULL) return NULL; - a.zbuffer = (stbi_uc *) buffer; - a.zbuffer_end = (stbi_uc *) buffer+len; - if (stbi__do_zlib(&a, p, 16384, 1, 0)) { - if (outlen) *outlen = (int) (a.zout - a.zout_start); - return a.zout_start; - } else { - STBI_FREE(a.zout_start); - return NULL; - } -} - -STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen) -{ - stbi__zbuf a; - a.zbuffer = (stbi_uc *) ibuffer; - a.zbuffer_end = (stbi_uc *) ibuffer + ilen; - if (stbi__do_zlib(&a, obuffer, olen, 0, 0)) - return (int) (a.zout - a.zout_start); - else - return -1; -} -#endif - -// public domain "baseline" PNG decoder v0.10 Sean Barrett 2006-11-18 -// simple implementation -// - only 8-bit samples -// - no CRC checking -// - allocates lots of intermediate memory -// - avoids problem of streaming data between subsystems -// - avoids explicit window management -// performance -// - uses stb_zlib, a PD zlib implementation with fast huffman decoding - -#ifndef STBI_NO_PNG -typedef struct -{ - stbi__uint32 length; - stbi__uint32 type; -} stbi__pngchunk; - -static stbi__pngchunk stbi__get_chunk_header(stbi__context *s) -{ - stbi__pngchunk c; - c.length = stbi__get32be(s); - c.type = stbi__get32be(s); - return c; -} - -static int stbi__check_png_header(stbi__context *s) -{ - static const stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 }; - int i; - for (i=0; i < 8; ++i) - if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG"); - return 1; -} - -typedef struct -{ - stbi__context *s; - stbi_uc *idata, *expanded, *out; - int depth; -} stbi__png; - - -enum { - STBI__F_none=0, - STBI__F_sub=1, - STBI__F_up=2, - STBI__F_avg=3, - STBI__F_paeth=4, - // synthetic filters used for first scanline to avoid needing a dummy row of 0s - STBI__F_avg_first, - STBI__F_paeth_first -}; - -static stbi_uc first_row_filter[5] = -{ - STBI__F_none, - STBI__F_sub, - STBI__F_none, - STBI__F_avg_first, - STBI__F_paeth_first -}; - -static int stbi__paeth(int a, int b, int c) -{ - int p = a + b - c; - int pa = abs(p-a); - int pb = abs(p-b); - int pc = abs(p-c); - if (pa <= pb && pa <= pc) return a; - if (pb <= pc) return b; - return c; -} - -static const stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 }; - -// create the png data from post-deflated data -static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color) -{ - int bytes = (depth == 16? 2 : 1); - stbi__context *s = a->s; - stbi__uint32 i,j,stride = x*out_n*bytes; - stbi__uint32 img_len, img_width_bytes; - int k; - int img_n = s->img_n; // copy it into a local for later - - int output_bytes = out_n*bytes; - int filter_bytes = img_n*bytes; - int width = x; - - STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1); - a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into - if (!a->out) return stbi__err("outofmem", "Out of memory"); - - if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) return stbi__err("too large", "Corrupt PNG"); - img_width_bytes = (((img_n * x * depth) + 7) >> 3); - img_len = (img_width_bytes + 1) * y; - - // we used to check for exact match between raw_len and img_len on non-interlaced PNGs, - // but issue #276 reported a PNG in the wild that had extra data at the end (all zeros), - // so just check for raw_len < img_len always. - if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG"); - - for (j=0; j < y; ++j) { - stbi_uc *cur = a->out + stride*j; - stbi_uc *prior; - int filter = *raw++; - - if (filter > 4) - return stbi__err("invalid filter","Corrupt PNG"); - - if (depth < 8) { - if (img_width_bytes > x) return stbi__err("invalid width","Corrupt PNG"); - cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place - filter_bytes = 1; - width = img_width_bytes; - } - prior = cur - stride; // bugfix: need to compute this after 'cur +=' computation above - - // if first row, use special filter that doesn't sample previous row - if (j == 0) filter = first_row_filter[filter]; - - // handle first byte explicitly - for (k=0; k < filter_bytes; ++k) { - switch (filter) { - case STBI__F_none : cur[k] = raw[k]; break; - case STBI__F_sub : cur[k] = raw[k]; break; - case STBI__F_up : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; - case STBI__F_avg : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break; - case STBI__F_paeth : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break; - case STBI__F_avg_first : cur[k] = raw[k]; break; - case STBI__F_paeth_first: cur[k] = raw[k]; break; - } - } - - if (depth == 8) { - if (img_n != out_n) - cur[img_n] = 255; // first pixel - raw += img_n; - cur += out_n; - prior += out_n; - } else if (depth == 16) { - if (img_n != out_n) { - cur[filter_bytes] = 255; // first pixel top byte - cur[filter_bytes+1] = 255; // first pixel bottom byte - } - raw += filter_bytes; - cur += output_bytes; - prior += output_bytes; - } else { - raw += 1; - cur += 1; - prior += 1; - } - - // this is a little gross, so that we don't switch per-pixel or per-component - if (depth < 8 || img_n == out_n) { - int nk = (width - 1)*filter_bytes; - #define STBI__CASE(f) \ - case f: \ - for (k=0; k < nk; ++k) - switch (filter) { - // "none" filter turns into a memcpy here; make that explicit. - case STBI__F_none: memcpy(cur, raw, nk); break; - STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); } break; - STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; - STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); } break; - STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); } break; - STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); } break; - STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); } break; - } - #undef STBI__CASE - raw += nk; - } else { - STBI_ASSERT(img_n+1 == out_n); - #define STBI__CASE(f) \ - case f: \ - for (i=x-1; i >= 1; --i, cur[filter_bytes]=255,raw+=filter_bytes,cur+=output_bytes,prior+=output_bytes) \ - for (k=0; k < filter_bytes; ++k) - switch (filter) { - STBI__CASE(STBI__F_none) { cur[k] = raw[k]; } break; - STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k- output_bytes]); } break; - STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; - STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k- output_bytes])>>1)); } break; - STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); } break; - STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k- output_bytes] >> 1)); } break; - STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],0,0)); } break; - } - #undef STBI__CASE - - // the loop above sets the high byte of the pixels' alpha, but for - // 16 bit png files we also need the low byte set. we'll do that here. - if (depth == 16) { - cur = a->out + stride*j; // start at the beginning of the row again - for (i=0; i < x; ++i,cur+=output_bytes) { - cur[filter_bytes+1] = 255; - } - } - } - } - - // we make a separate pass to expand bits to pixels; for performance, - // this could run two scanlines behind the above code, so it won't - // intefere with filtering but will still be in the cache. - if (depth < 8) { - for (j=0; j < y; ++j) { - stbi_uc *cur = a->out + stride*j; - stbi_uc *in = a->out + stride*j + x*out_n - img_width_bytes; - // unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common 8-bit path optimal at minimal cost for 1/2/4-bit - // png guarante byte alignment, if width is not multiple of 8/4/2 we'll decode dummy trailing data that will be skipped in the later loop - stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range - - // note that the final byte might overshoot and write more data than desired. - // we can allocate enough data that this never writes out of memory, but it - // could also overwrite the next scanline. can it overwrite non-empty data - // on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel. - // so we need to explicitly clamp the final ones - - if (depth == 4) { - for (k=x*img_n; k >= 2; k-=2, ++in) { - *cur++ = scale * ((*in >> 4) ); - *cur++ = scale * ((*in ) & 0x0f); - } - if (k > 0) *cur++ = scale * ((*in >> 4) ); - } else if (depth == 2) { - for (k=x*img_n; k >= 4; k-=4, ++in) { - *cur++ = scale * ((*in >> 6) ); - *cur++ = scale * ((*in >> 4) & 0x03); - *cur++ = scale * ((*in >> 2) & 0x03); - *cur++ = scale * ((*in ) & 0x03); - } - if (k > 0) *cur++ = scale * ((*in >> 6) ); - if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03); - if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03); - } else if (depth == 1) { - for (k=x*img_n; k >= 8; k-=8, ++in) { - *cur++ = scale * ((*in >> 7) ); - *cur++ = scale * ((*in >> 6) & 0x01); - *cur++ = scale * ((*in >> 5) & 0x01); - *cur++ = scale * ((*in >> 4) & 0x01); - *cur++ = scale * ((*in >> 3) & 0x01); - *cur++ = scale * ((*in >> 2) & 0x01); - *cur++ = scale * ((*in >> 1) & 0x01); - *cur++ = scale * ((*in ) & 0x01); - } - if (k > 0) *cur++ = scale * ((*in >> 7) ); - if (k > 1) *cur++ = scale * ((*in >> 6) & 0x01); - if (k > 2) *cur++ = scale * ((*in >> 5) & 0x01); - if (k > 3) *cur++ = scale * ((*in >> 4) & 0x01); - if (k > 4) *cur++ = scale * ((*in >> 3) & 0x01); - if (k > 5) *cur++ = scale * ((*in >> 2) & 0x01); - if (k > 6) *cur++ = scale * ((*in >> 1) & 0x01); - } - if (img_n != out_n) { - int q; - // insert alpha = 255 - cur = a->out + stride*j; - if (img_n == 1) { - for (q=x-1; q >= 0; --q) { - cur[q*2+1] = 255; - cur[q*2+0] = cur[q]; - } - } else { - STBI_ASSERT(img_n == 3); - for (q=x-1; q >= 0; --q) { - cur[q*4+3] = 255; - cur[q*4+2] = cur[q*3+2]; - cur[q*4+1] = cur[q*3+1]; - cur[q*4+0] = cur[q*3+0]; - } - } - } - } - } else if (depth == 16) { - // force the image data from big-endian to platform-native. - // this is done in a separate pass due to the decoding relying - // on the data being untouched, but could probably be done - // per-line during decode if care is taken. - stbi_uc *cur = a->out; - stbi__uint16 *cur16 = (stbi__uint16*)cur; - - for(i=0; i < x*y*out_n; ++i,cur16++,cur+=2) { - *cur16 = (cur[0] << 8) | cur[1]; - } - } - - return 1; -} - -static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced) -{ - int bytes = (depth == 16 ? 2 : 1); - int out_bytes = out_n * bytes; - stbi_uc *final; - int p; - if (!interlaced) - return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color); - - // de-interlacing - final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0); - if (!final) return stbi__err("outofmem", "Out of memory"); - for (p=0; p < 7; ++p) { - int xorig[] = { 0,4,0,2,0,1,0 }; - int yorig[] = { 0,0,4,0,2,0,1 }; - int xspc[] = { 8,8,4,4,2,2,1 }; - int yspc[] = { 8,8,8,4,4,2,2 }; - int i,j,x,y; - // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1 - x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p]; - y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p]; - if (x && y) { - stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y; - if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) { - STBI_FREE(final); - return 0; - } - for (j=0; j < y; ++j) { - for (i=0; i < x; ++i) { - int out_y = j*yspc[p]+yorig[p]; - int out_x = i*xspc[p]+xorig[p]; - memcpy(final + out_y*a->s->img_x*out_bytes + out_x*out_bytes, - a->out + (j*x+i)*out_bytes, out_bytes); - } - } - STBI_FREE(a->out); - image_data += img_len; - image_data_len -= img_len; - } - } - a->out = final; - - return 1; -} - -static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n) -{ - stbi__context *s = z->s; - stbi__uint32 i, pixel_count = s->img_x * s->img_y; - stbi_uc *p = z->out; - - // compute color-based transparency, assuming we've - // already got 255 as the alpha value in the output - STBI_ASSERT(out_n == 2 || out_n == 4); - - if (out_n == 2) { - for (i=0; i < pixel_count; ++i) { - p[1] = (p[0] == tc[0] ? 0 : 255); - p += 2; - } - } else { - for (i=0; i < pixel_count; ++i) { - if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) - p[3] = 0; - p += 4; - } - } - return 1; -} - -static int stbi__compute_transparency16(stbi__png *z, stbi__uint16 tc[3], int out_n) -{ - stbi__context *s = z->s; - stbi__uint32 i, pixel_count = s->img_x * s->img_y; - stbi__uint16 *p = (stbi__uint16*) z->out; - - // compute color-based transparency, assuming we've - // already got 65535 as the alpha value in the output - STBI_ASSERT(out_n == 2 || out_n == 4); - - if (out_n == 2) { - for (i = 0; i < pixel_count; ++i) { - p[1] = (p[0] == tc[0] ? 0 : 65535); - p += 2; - } - } else { - for (i = 0; i < pixel_count; ++i) { - if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) - p[3] = 0; - p += 4; - } - } - return 1; -} - -static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n) -{ - stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y; - stbi_uc *p, *temp_out, *orig = a->out; - - p = (stbi_uc *) stbi__malloc_mad2(pixel_count, pal_img_n, 0); - if (p == NULL) return stbi__err("outofmem", "Out of memory"); - - // between here and free(out) below, exitting would leak - temp_out = p; - - if (pal_img_n == 3) { - for (i=0; i < pixel_count; ++i) { - int n = orig[i]*4; - p[0] = palette[n ]; - p[1] = palette[n+1]; - p[2] = palette[n+2]; - p += 3; - } - } else { - for (i=0; i < pixel_count; ++i) { - int n = orig[i]*4; - p[0] = palette[n ]; - p[1] = palette[n+1]; - p[2] = palette[n+2]; - p[3] = palette[n+3]; - p += 4; - } - } - STBI_FREE(a->out); - a->out = temp_out; - - STBI_NOTUSED(len); - - return 1; -} - -static int stbi__unpremultiply_on_load_global = 0; -static int stbi__de_iphone_flag_global = 0; - -STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) -{ - stbi__unpremultiply_on_load_global = flag_true_if_should_unpremultiply; -} - -STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) -{ - stbi__de_iphone_flag_global = flag_true_if_should_convert; -} - -#ifndef STBI_THREAD_LOCAL -#define stbi__unpremultiply_on_load stbi__unpremultiply_on_load_global -#define stbi__de_iphone_flag stbi__de_iphone_flag_global -#else -static STBI_THREAD_LOCAL int stbi__unpremultiply_on_load_local, stbi__unpremultiply_on_load_set; -static STBI_THREAD_LOCAL int stbi__de_iphone_flag_local, stbi__de_iphone_flag_set; - -STBIDEF void stbi__unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply) -{ - stbi__unpremultiply_on_load_local = flag_true_if_should_unpremultiply; - stbi__unpremultiply_on_load_set = 1; -} - -STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert) -{ - stbi__de_iphone_flag_local = flag_true_if_should_convert; - stbi__de_iphone_flag_set = 1; -} - -#define stbi__unpremultiply_on_load (stbi__unpremultiply_on_load_set \ - ? stbi__unpremultiply_on_load_local \ - : stbi__unpremultiply_on_load_global) -#define stbi__de_iphone_flag (stbi__de_iphone_flag_set \ - ? stbi__de_iphone_flag_local \ - : stbi__de_iphone_flag_global) -#endif // STBI_THREAD_LOCAL - -static void stbi__de_iphone(stbi__png *z) -{ - stbi__context *s = z->s; - stbi__uint32 i, pixel_count = s->img_x * s->img_y; - stbi_uc *p = z->out; - - if (s->img_out_n == 3) { // convert bgr to rgb - for (i=0; i < pixel_count; ++i) { - stbi_uc t = p[0]; - p[0] = p[2]; - p[2] = t; - p += 3; - } - } else { - STBI_ASSERT(s->img_out_n == 4); - if (stbi__unpremultiply_on_load) { - // convert bgr to rgb and unpremultiply - for (i=0; i < pixel_count; ++i) { - stbi_uc a = p[3]; - stbi_uc t = p[0]; - if (a) { - stbi_uc half = a / 2; - p[0] = (p[2] * 255 + half) / a; - p[1] = (p[1] * 255 + half) / a; - p[2] = ( t * 255 + half) / a; - } else { - p[0] = p[2]; - p[2] = t; - } - p += 4; - } - } else { - // convert bgr to rgb - for (i=0; i < pixel_count; ++i) { - stbi_uc t = p[0]; - p[0] = p[2]; - p[2] = t; - p += 4; - } - } - } -} - -#define STBI__PNG_TYPE(a,b,c,d) (((unsigned) (a) << 24) + ((unsigned) (b) << 16) + ((unsigned) (c) << 8) + (unsigned) (d)) - -static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) -{ - stbi_uc palette[1024], pal_img_n=0; - stbi_uc has_trans=0, tc[3]={0}; - stbi__uint16 tc16[3]; - stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0; - int first=1,k,interlace=0, color=0, is_iphone=0; - stbi__context *s = z->s; - - z->expanded = NULL; - z->idata = NULL; - z->out = NULL; - - if (!stbi__check_png_header(s)) return 0; - - if (scan == STBI__SCAN_type) return 1; - - for (;;) { - stbi__pngchunk c = stbi__get_chunk_header(s); - switch (c.type) { - case STBI__PNG_TYPE('C','g','B','I'): - is_iphone = 1; - stbi__skip(s, c.length); - break; - case STBI__PNG_TYPE('I','H','D','R'): { - int comp,filter; - if (!first) return stbi__err("multiple IHDR","Corrupt PNG"); - first = 0; - if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG"); - s->img_x = stbi__get32be(s); - s->img_y = stbi__get32be(s); - if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); - if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); - z->depth = stbi__get8(s); if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) return stbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only"); - color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG"); - if (color == 3 && z->depth == 16) return stbi__err("bad ctype","Corrupt PNG"); - if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG"); - comp = stbi__get8(s); if (comp) return stbi__err("bad comp method","Corrupt PNG"); - filter= stbi__get8(s); if (filter) return stbi__err("bad filter method","Corrupt PNG"); - interlace = stbi__get8(s); if (interlace>1) return stbi__err("bad interlace method","Corrupt PNG"); - if (!s->img_x || !s->img_y) return stbi__err("0-pixel image","Corrupt PNG"); - if (!pal_img_n) { - s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); - if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); - if (scan == STBI__SCAN_header) return 1; - } else { - // if paletted, then pal_n is our final components, and - // img_n is # components to decompress/filter. - s->img_n = 1; - if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG"); - // if SCAN_header, have to scan to see if we have a tRNS - } - break; - } - - case STBI__PNG_TYPE('P','L','T','E'): { - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if (c.length > 256*3) return stbi__err("invalid PLTE","Corrupt PNG"); - pal_len = c.length / 3; - if (pal_len * 3 != c.length) return stbi__err("invalid PLTE","Corrupt PNG"); - for (i=0; i < pal_len; ++i) { - palette[i*4+0] = stbi__get8(s); - palette[i*4+1] = stbi__get8(s); - palette[i*4+2] = stbi__get8(s); - palette[i*4+3] = 255; - } - break; - } - - case STBI__PNG_TYPE('t','R','N','S'): { - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if (z->idata) return stbi__err("tRNS after IDAT","Corrupt PNG"); - if (pal_img_n) { - if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; } - if (pal_len == 0) return stbi__err("tRNS before PLTE","Corrupt PNG"); - if (c.length > pal_len) return stbi__err("bad tRNS len","Corrupt PNG"); - pal_img_n = 4; - for (i=0; i < c.length; ++i) - palette[i*4+3] = stbi__get8(s); - } else { - if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG"); - if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG"); - has_trans = 1; - if (z->depth == 16) { - for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is - } else { - for (k = 0; k < s->img_n; ++k) tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger - } - } - break; - } - - case STBI__PNG_TYPE('I','D','A','T'): { - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG"); - if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; } - if ((int)(ioff + c.length) < (int)ioff) return 0; - if (ioff + c.length > idata_limit) { - stbi__uint32 idata_limit_old = idata_limit; - stbi_uc *p; - if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096; - while (ioff + c.length > idata_limit) - idata_limit *= 2; - STBI_NOTUSED(idata_limit_old); - p = (stbi_uc *) STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory"); - z->idata = p; - } - if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG"); - ioff += c.length; - break; - } - - case STBI__PNG_TYPE('I','E','N','D'): { - stbi__uint32 raw_len, bpl; - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if (scan != STBI__SCAN_load) return 1; - if (z->idata == NULL) return stbi__err("no IDAT","Corrupt PNG"); - // initial guess for decoded data size to avoid unnecessary reallocs - bpl = (s->img_x * z->depth + 7) / 8; // bytes per line, per component - raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */; - z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone); - if (z->expanded == NULL) return 0; // zlib should set error - STBI_FREE(z->idata); z->idata = NULL; - if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans) - s->img_out_n = s->img_n+1; - else - s->img_out_n = s->img_n; - if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, z->depth, color, interlace)) return 0; - if (has_trans) { - if (z->depth == 16) { - if (!stbi__compute_transparency16(z, tc16, s->img_out_n)) return 0; - } else { - if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0; - } - } - if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2) - stbi__de_iphone(z); - if (pal_img_n) { - // pal_img_n == 3 or 4 - s->img_n = pal_img_n; // record the actual colors we had - s->img_out_n = pal_img_n; - if (req_comp >= 3) s->img_out_n = req_comp; - if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n)) - return 0; - } else if (has_trans) { - // non-paletted image with tRNS -> source image has (constant) alpha - ++s->img_n; - } - STBI_FREE(z->expanded); z->expanded = NULL; - // end of PNG chunk, read and skip CRC - stbi__get32be(s); - return 1; - } - - default: - // if critical, fail - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if ((c.type & (1 << 29)) == 0) { - #ifndef STBI_NO_FAILURE_STRINGS - // not threadsafe - static char invalid_chunk[] = "XXXX PNG chunk not known"; - invalid_chunk[0] = STBI__BYTECAST(c.type >> 24); - invalid_chunk[1] = STBI__BYTECAST(c.type >> 16); - invalid_chunk[2] = STBI__BYTECAST(c.type >> 8); - invalid_chunk[3] = STBI__BYTECAST(c.type >> 0); - #endif - return stbi__err(invalid_chunk, "PNG not supported: unknown PNG chunk type"); - } - stbi__skip(s, c.length); - break; - } - // end of PNG chunk, read and skip CRC - stbi__get32be(s); - } -} - -static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, stbi__result_info *ri) -{ - void *result=NULL; - if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); - if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) { - if (p->depth <= 8) - ri->bits_per_channel = 8; - else if (p->depth == 16) - ri->bits_per_channel = 16; - else - return stbi__errpuc("bad bits_per_channel", "PNG not supported: unsupported color depth"); - result = p->out; - p->out = NULL; - if (req_comp && req_comp != p->s->img_out_n) { - if (ri->bits_per_channel == 8) - result = stbi__convert_format((unsigned char *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); - else - result = stbi__convert_format16((stbi__uint16 *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); - p->s->img_out_n = req_comp; - if (result == NULL) return result; - } - *x = p->s->img_x; - *y = p->s->img_y; - if (n) *n = p->s->img_n; - } - STBI_FREE(p->out); p->out = NULL; - STBI_FREE(p->expanded); p->expanded = NULL; - STBI_FREE(p->idata); p->idata = NULL; - - return result; -} - -static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) -{ - stbi__png p; - p.s = s; - return stbi__do_png(&p, x,y,comp,req_comp, ri); -} - -static int stbi__png_test(stbi__context *s) -{ - int r; - r = stbi__check_png_header(s); - stbi__rewind(s); - return r; -} - -static int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp) -{ - if (!stbi__parse_png_file(p, STBI__SCAN_header, 0)) { - stbi__rewind( p->s ); - return 0; - } - if (x) *x = p->s->img_x; - if (y) *y = p->s->img_y; - if (comp) *comp = p->s->img_n; - return 1; -} - -static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp) -{ - stbi__png p; - p.s = s; - return stbi__png_info_raw(&p, x, y, comp); -} - -static int stbi__png_is16(stbi__context *s) -{ - stbi__png p; - p.s = s; - if (!stbi__png_info_raw(&p, NULL, NULL, NULL)) - return 0; - if (p.depth != 16) { - stbi__rewind(p.s); - return 0; - } - return 1; -} -#endif - -// Microsoft/Windows BMP image - -#ifndef STBI_NO_BMP -static int stbi__bmp_test_raw(stbi__context *s) -{ - int r; - int sz; - if (stbi__get8(s) != 'B') return 0; - if (stbi__get8(s) != 'M') return 0; - stbi__get32le(s); // discard filesize - stbi__get16le(s); // discard reserved - stbi__get16le(s); // discard reserved - stbi__get32le(s); // discard data offset - sz = stbi__get32le(s); - r = (sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124); - return r; -} - -static int stbi__bmp_test(stbi__context *s) -{ - int r = stbi__bmp_test_raw(s); - stbi__rewind(s); - return r; -} - - -// returns 0..31 for the highest set bit -static int stbi__high_bit(unsigned int z) -{ - int n=0; - if (z == 0) return -1; - if (z >= 0x10000) { n += 16; z >>= 16; } - if (z >= 0x00100) { n += 8; z >>= 8; } - if (z >= 0x00010) { n += 4; z >>= 4; } - if (z >= 0x00004) { n += 2; z >>= 2; } - if (z >= 0x00002) { n += 1;/* >>= 1;*/ } - return n; -} - -static int stbi__bitcount(unsigned int a) -{ - a = (a & 0x55555555) + ((a >> 1) & 0x55555555); // max 2 - a = (a & 0x33333333) + ((a >> 2) & 0x33333333); // max 4 - a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits - a = (a + (a >> 8)); // max 16 per 8 bits - a = (a + (a >> 16)); // max 32 per 8 bits - return a & 0xff; -} - -// extract an arbitrarily-aligned N-bit value (N=bits) -// from v, and then make it 8-bits long and fractionally -// extend it to full full range. -static int stbi__shiftsigned(unsigned int v, int shift, int bits) -{ - static unsigned int mul_table[9] = { - 0, - 0xff/*0b11111111*/, 0x55/*0b01010101*/, 0x49/*0b01001001*/, 0x11/*0b00010001*/, - 0x21/*0b00100001*/, 0x41/*0b01000001*/, 0x81/*0b10000001*/, 0x01/*0b00000001*/, - }; - static unsigned int shift_table[9] = { - 0, 0,0,1,0,2,4,6,0, - }; - if (shift < 0) - v <<= -shift; - else - v >>= shift; - STBI_ASSERT(v < 256); - v >>= (8-bits); - STBI_ASSERT(bits >= 0 && bits <= 8); - return (int) ((unsigned) v * mul_table[bits]) >> shift_table[bits]; -} - -typedef struct -{ - int bpp, offset, hsz; - unsigned int mr,mg,mb,ma, all_a; - int extra_read; -} stbi__bmp_data; - -static int stbi__bmp_set_mask_defaults(stbi__bmp_data *info, int compress) -{ - // BI_BITFIELDS specifies masks explicitly, don't override - if (compress == 3) - return 1; - - if (compress == 0) { - if (info->bpp == 16) { - info->mr = 31u << 10; - info->mg = 31u << 5; - info->mb = 31u << 0; - } else if (info->bpp == 32) { - info->mr = 0xffu << 16; - info->mg = 0xffu << 8; - info->mb = 0xffu << 0; - info->ma = 0xffu << 24; - info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0 - } else { - // otherwise, use defaults, which is all-0 - info->mr = info->mg = info->mb = info->ma = 0; - } - return 1; - } - return 0; // error -} - -static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) -{ - int hsz; - if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc("not BMP", "Corrupt BMP"); - stbi__get32le(s); // discard filesize - stbi__get16le(s); // discard reserved - stbi__get16le(s); // discard reserved - info->offset = stbi__get32le(s); - info->hsz = hsz = stbi__get32le(s); - info->mr = info->mg = info->mb = info->ma = 0; - info->extra_read = 14; - - if (info->offset < 0) return stbi__errpuc("bad BMP", "bad BMP"); - - if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown"); - if (hsz == 12) { - s->img_x = stbi__get16le(s); - s->img_y = stbi__get16le(s); - } else { - s->img_x = stbi__get32le(s); - s->img_y = stbi__get32le(s); - } - if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP"); - info->bpp = stbi__get16le(s); - if (hsz != 12) { - int compress = stbi__get32le(s); - if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); - if (compress >= 4) return stbi__errpuc("BMP JPEG/PNG", "BMP type not supported: unsupported compression"); // this includes PNG/JPEG modes - if (compress == 3 && info->bpp != 16 && info->bpp != 32) return stbi__errpuc("bad BMP", "bad BMP"); // bitfields requires 16 or 32 bits/pixel - stbi__get32le(s); // discard sizeof - stbi__get32le(s); // discard hres - stbi__get32le(s); // discard vres - stbi__get32le(s); // discard colorsused - stbi__get32le(s); // discard max important - if (hsz == 40 || hsz == 56) { - if (hsz == 56) { - stbi__get32le(s); - stbi__get32le(s); - stbi__get32le(s); - stbi__get32le(s); - } - if (info->bpp == 16 || info->bpp == 32) { - if (compress == 0) { - stbi__bmp_set_mask_defaults(info, compress); - } else if (compress == 3) { - info->mr = stbi__get32le(s); - info->mg = stbi__get32le(s); - info->mb = stbi__get32le(s); - info->extra_read += 12; - // not documented, but generated by photoshop and handled by mspaint - if (info->mr == info->mg && info->mg == info->mb) { - // ?!?!? - return stbi__errpuc("bad BMP", "bad BMP"); - } - } else - return stbi__errpuc("bad BMP", "bad BMP"); - } - } else { - // V4/V5 header - int i; - if (hsz != 108 && hsz != 124) - return stbi__errpuc("bad BMP", "bad BMP"); - info->mr = stbi__get32le(s); - info->mg = stbi__get32le(s); - info->mb = stbi__get32le(s); - info->ma = stbi__get32le(s); - if (compress != 3) // override mr/mg/mb unless in BI_BITFIELDS mode, as per docs - stbi__bmp_set_mask_defaults(info, compress); - stbi__get32le(s); // discard color space - for (i=0; i < 12; ++i) - stbi__get32le(s); // discard color space parameters - if (hsz == 124) { - stbi__get32le(s); // discard rendering intent - stbi__get32le(s); // discard offset of profile data - stbi__get32le(s); // discard size of profile data - stbi__get32le(s); // discard reserved - } - } - } - return (void *) 1; -} - - -static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) -{ - stbi_uc *out; - unsigned int mr=0,mg=0,mb=0,ma=0, all_a; - stbi_uc pal[256][4]; - int psize=0,i,j,width; - int flip_vertically, pad, target; - stbi__bmp_data info; - STBI_NOTUSED(ri); - - info.all_a = 255; - if (stbi__bmp_parse_header(s, &info) == NULL) - return NULL; // error code already set - - flip_vertically = ((int) s->img_y) > 0; - s->img_y = abs((int) s->img_y); - - if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); - if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); - - mr = info.mr; - mg = info.mg; - mb = info.mb; - ma = info.ma; - all_a = info.all_a; - - if (info.hsz == 12) { - if (info.bpp < 24) - psize = (info.offset - info.extra_read - 24) / 3; - } else { - if (info.bpp < 16) - psize = (info.offset - info.extra_read - info.hsz) >> 2; - } - if (psize == 0) { - if (info.offset != s->callback_already_read + (s->img_buffer - s->img_buffer_original)) { - return stbi__errpuc("bad offset", "Corrupt BMP"); - } - } - - if (info.bpp == 24 && ma == 0xff000000) - s->img_n = 3; - else - s->img_n = ma ? 4 : 3; - if (req_comp && req_comp >= 3) // we can directly decode 3 or 4 - target = req_comp; - else - target = s->img_n; // if they want monochrome, we'll post-convert - - // sanity-check size - if (!stbi__mad3sizes_valid(target, s->img_x, s->img_y, 0)) - return stbi__errpuc("too large", "Corrupt BMP"); - - out = (stbi_uc *) stbi__malloc_mad3(target, s->img_x, s->img_y, 0); - if (!out) return stbi__errpuc("outofmem", "Out of memory"); - if (info.bpp < 16) { - int z=0; - if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc("invalid", "Corrupt BMP"); } - for (i=0; i < psize; ++i) { - pal[i][2] = stbi__get8(s); - pal[i][1] = stbi__get8(s); - pal[i][0] = stbi__get8(s); - if (info.hsz != 12) stbi__get8(s); - pal[i][3] = 255; - } - stbi__skip(s, info.offset - info.extra_read - info.hsz - psize * (info.hsz == 12 ? 3 : 4)); - if (info.bpp == 1) width = (s->img_x + 7) >> 3; - else if (info.bpp == 4) width = (s->img_x + 1) >> 1; - else if (info.bpp == 8) width = s->img_x; - else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); } - pad = (-width)&3; - if (info.bpp == 1) { - for (j=0; j < (int) s->img_y; ++j) { - int bit_offset = 7, v = stbi__get8(s); - for (i=0; i < (int) s->img_x; ++i) { - int color = (v>>bit_offset)&0x1; - out[z++] = pal[color][0]; - out[z++] = pal[color][1]; - out[z++] = pal[color][2]; - if (target == 4) out[z++] = 255; - if (i+1 == (int) s->img_x) break; - if((--bit_offset) < 0) { - bit_offset = 7; - v = stbi__get8(s); - } - } - stbi__skip(s, pad); - } - } else { - for (j=0; j < (int) s->img_y; ++j) { - for (i=0; i < (int) s->img_x; i += 2) { - int v=stbi__get8(s),v2=0; - if (info.bpp == 4) { - v2 = v & 15; - v >>= 4; - } - out[z++] = pal[v][0]; - out[z++] = pal[v][1]; - out[z++] = pal[v][2]; - if (target == 4) out[z++] = 255; - if (i+1 == (int) s->img_x) break; - v = (info.bpp == 8) ? stbi__get8(s) : v2; - out[z++] = pal[v][0]; - out[z++] = pal[v][1]; - out[z++] = pal[v][2]; - if (target == 4) out[z++] = 255; - } - stbi__skip(s, pad); - } - } - } else { - int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0; - int z = 0; - int easy=0; - stbi__skip(s, info.offset - info.extra_read - info.hsz); - if (info.bpp == 24) width = 3 * s->img_x; - else if (info.bpp == 16) width = 2*s->img_x; - else /* bpp = 32 and pad = 0 */ width=0; - pad = (-width) & 3; - if (info.bpp == 24) { - easy = 1; - } else if (info.bpp == 32) { - if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000) - easy = 2; - } - if (!easy) { - if (!mr || !mg || !mb) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } - // right shift amt to put high bit in position #7 - rshift = stbi__high_bit(mr)-7; rcount = stbi__bitcount(mr); - gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg); - bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb); - ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma); - if (rcount > 8 || gcount > 8 || bcount > 8 || acount > 8) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } - } - for (j=0; j < (int) s->img_y; ++j) { - if (easy) { - for (i=0; i < (int) s->img_x; ++i) { - unsigned char a; - out[z+2] = stbi__get8(s); - out[z+1] = stbi__get8(s); - out[z+0] = stbi__get8(s); - z += 3; - a = (easy == 2 ? stbi__get8(s) : 255); - all_a |= a; - if (target == 4) out[z++] = a; - } - } else { - int bpp = info.bpp; - for (i=0; i < (int) s->img_x; ++i) { - stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s)); - unsigned int a; - out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount)); - out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount)); - out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount)); - a = (ma ? stbi__shiftsigned(v & ma, ashift, acount) : 255); - all_a |= a; - if (target == 4) out[z++] = STBI__BYTECAST(a); - } - } - stbi__skip(s, pad); - } - } - - // if alpha channel is all 0s, replace with all 255s - if (target == 4 && all_a == 0) - for (i=4*s->img_x*s->img_y-1; i >= 0; i -= 4) - out[i] = 255; - - if (flip_vertically) { - stbi_uc t; - for (j=0; j < (int) s->img_y>>1; ++j) { - stbi_uc *p1 = out + j *s->img_x*target; - stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target; - for (i=0; i < (int) s->img_x*target; ++i) { - t = p1[i]; p1[i] = p2[i]; p2[i] = t; - } - } - } - - if (req_comp && req_comp != target) { - out = stbi__convert_format(out, target, req_comp, s->img_x, s->img_y); - if (out == NULL) return out; // stbi__convert_format frees input on failure - } - - *x = s->img_x; - *y = s->img_y; - if (comp) *comp = s->img_n; - return out; -} -#endif - -// Targa Truevision - TGA -// by Jonathan Dummer -#ifndef STBI_NO_TGA -// returns STBI_rgb or whatever, 0 on error -static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16) -{ - // only RGB or RGBA (incl. 16bit) or grey allowed - if (is_rgb16) *is_rgb16 = 0; - switch(bits_per_pixel) { - case 8: return STBI_grey; - case 16: if(is_grey) return STBI_grey_alpha; - // fallthrough - case 15: if(is_rgb16) *is_rgb16 = 1; - return STBI_rgb; - case 24: // fallthrough - case 32: return bits_per_pixel/8; - default: return 0; - } -} - -static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp) -{ - int tga_w, tga_h, tga_comp, tga_image_type, tga_bits_per_pixel, tga_colormap_bpp; - int sz, tga_colormap_type; - stbi__get8(s); // discard Offset - tga_colormap_type = stbi__get8(s); // colormap type - if( tga_colormap_type > 1 ) { - stbi__rewind(s); - return 0; // only RGB or indexed allowed - } - tga_image_type = stbi__get8(s); // image type - if ( tga_colormap_type == 1 ) { // colormapped (paletted) image - if (tga_image_type != 1 && tga_image_type != 9) { - stbi__rewind(s); - return 0; - } - stbi__skip(s,4); // skip index of first colormap entry and number of entries - sz = stbi__get8(s); // check bits per palette color entry - if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) { - stbi__rewind(s); - return 0; - } - stbi__skip(s,4); // skip image x and y origin - tga_colormap_bpp = sz; - } else { // "normal" image w/o colormap - only RGB or grey allowed, +/- RLE - if ( (tga_image_type != 2) && (tga_image_type != 3) && (tga_image_type != 10) && (tga_image_type != 11) ) { - stbi__rewind(s); - return 0; // only RGB or grey allowed, +/- RLE - } - stbi__skip(s,9); // skip colormap specification and image x/y origin - tga_colormap_bpp = 0; - } - tga_w = stbi__get16le(s); - if( tga_w < 1 ) { - stbi__rewind(s); - return 0; // test width - } - tga_h = stbi__get16le(s); - if( tga_h < 1 ) { - stbi__rewind(s); - return 0; // test height - } - tga_bits_per_pixel = stbi__get8(s); // bits per pixel - stbi__get8(s); // ignore alpha bits - if (tga_colormap_bpp != 0) { - if((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16)) { - // when using a colormap, tga_bits_per_pixel is the size of the indexes - // I don't think anything but 8 or 16bit indexes makes sense - stbi__rewind(s); - return 0; - } - tga_comp = stbi__tga_get_comp(tga_colormap_bpp, 0, NULL); - } else { - tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3) || (tga_image_type == 11), NULL); - } - if(!tga_comp) { - stbi__rewind(s); - return 0; - } - if (x) *x = tga_w; - if (y) *y = tga_h; - if (comp) *comp = tga_comp; - return 1; // seems to have passed everything -} - -static int stbi__tga_test(stbi__context *s) -{ - int res = 0; - int sz, tga_color_type; - stbi__get8(s); // discard Offset - tga_color_type = stbi__get8(s); // color type - if ( tga_color_type > 1 ) goto errorEnd; // only RGB or indexed allowed - sz = stbi__get8(s); // image type - if ( tga_color_type == 1 ) { // colormapped (paletted) image - if (sz != 1 && sz != 9) goto errorEnd; // colortype 1 demands image type 1 or 9 - stbi__skip(s,4); // skip index of first colormap entry and number of entries - sz = stbi__get8(s); // check bits per palette color entry - if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; - stbi__skip(s,4); // skip image x and y origin - } else { // "normal" image w/o colormap - if ( (sz != 2) && (sz != 3) && (sz != 10) && (sz != 11) ) goto errorEnd; // only RGB or grey allowed, +/- RLE - stbi__skip(s,9); // skip colormap specification and image x/y origin - } - if ( stbi__get16le(s) < 1 ) goto errorEnd; // test width - if ( stbi__get16le(s) < 1 ) goto errorEnd; // test height - sz = stbi__get8(s); // bits per pixel - if ( (tga_color_type == 1) && (sz != 8) && (sz != 16) ) goto errorEnd; // for colormapped images, bpp is size of an index - if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; - - res = 1; // if we got this far, everything's good and we can return 1 instead of 0 - -errorEnd: - stbi__rewind(s); - return res; -} - -// read 16bit value and convert to 24bit RGB -static void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out) -{ - stbi__uint16 px = (stbi__uint16)stbi__get16le(s); - stbi__uint16 fiveBitMask = 31; - // we have 3 channels with 5bits each - int r = (px >> 10) & fiveBitMask; - int g = (px >> 5) & fiveBitMask; - int b = px & fiveBitMask; - // Note that this saves the data in RGB(A) order, so it doesn't need to be swapped later - out[0] = (stbi_uc)((r * 255)/31); - out[1] = (stbi_uc)((g * 255)/31); - out[2] = (stbi_uc)((b * 255)/31); - - // some people claim that the most significant bit might be used for alpha - // (possibly if an alpha-bit is set in the "image descriptor byte") - // but that only made 16bit test images completely translucent.. - // so let's treat all 15 and 16bit TGAs as RGB with no alpha. -} - -static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) -{ - // read in the TGA header stuff - int tga_offset = stbi__get8(s); - int tga_indexed = stbi__get8(s); - int tga_image_type = stbi__get8(s); - int tga_is_RLE = 0; - int tga_palette_start = stbi__get16le(s); - int tga_palette_len = stbi__get16le(s); - int tga_palette_bits = stbi__get8(s); - int tga_x_origin = stbi__get16le(s); - int tga_y_origin = stbi__get16le(s); - int tga_width = stbi__get16le(s); - int tga_height = stbi__get16le(s); - int tga_bits_per_pixel = stbi__get8(s); - int tga_comp, tga_rgb16=0; - int tga_inverted = stbi__get8(s); - // int tga_alpha_bits = tga_inverted & 15; // the 4 lowest bits - unused (useless?) - // image data - unsigned char *tga_data; - unsigned char *tga_palette = NULL; - int i, j; - unsigned char raw_data[4] = {0}; - int RLE_count = 0; - int RLE_repeating = 0; - int read_next_pixel = 1; - STBI_NOTUSED(ri); - STBI_NOTUSED(tga_x_origin); // @TODO - STBI_NOTUSED(tga_y_origin); // @TODO - - if (tga_height > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); - if (tga_width > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); - - // do a tiny bit of precessing - if ( tga_image_type >= 8 ) - { - tga_image_type -= 8; - tga_is_RLE = 1; - } - tga_inverted = 1 - ((tga_inverted >> 5) & 1); - - // If I'm paletted, then I'll use the number of bits from the palette - if ( tga_indexed ) tga_comp = stbi__tga_get_comp(tga_palette_bits, 0, &tga_rgb16); - else tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3), &tga_rgb16); - - if(!tga_comp) // shouldn't really happen, stbi__tga_test() should have ensured basic consistency - return stbi__errpuc("bad format", "Can't find out TGA pixelformat"); - - // tga info - *x = tga_width; - *y = tga_height; - if (comp) *comp = tga_comp; - - if (!stbi__mad3sizes_valid(tga_width, tga_height, tga_comp, 0)) - return stbi__errpuc("too large", "Corrupt TGA"); - - tga_data = (unsigned char*)stbi__malloc_mad3(tga_width, tga_height, tga_comp, 0); - if (!tga_data) return stbi__errpuc("outofmem", "Out of memory"); - - // skip to the data's starting position (offset usually = 0) - stbi__skip(s, tga_offset ); - - if ( !tga_indexed && !tga_is_RLE && !tga_rgb16 ) { - for (i=0; i < tga_height; ++i) { - int row = tga_inverted ? tga_height -i - 1 : i; - stbi_uc *tga_row = tga_data + row*tga_width*tga_comp; - stbi__getn(s, tga_row, tga_width * tga_comp); - } - } else { - // do I need to load a palette? - if ( tga_indexed) - { - if (tga_palette_len == 0) { /* you have to have at least one entry! */ - STBI_FREE(tga_data); - return stbi__errpuc("bad palette", "Corrupt TGA"); - } - - // any data to skip? (offset usually = 0) - stbi__skip(s, tga_palette_start ); - // load the palette - tga_palette = (unsigned char*)stbi__malloc_mad2(tga_palette_len, tga_comp, 0); - if (!tga_palette) { - STBI_FREE(tga_data); - return stbi__errpuc("outofmem", "Out of memory"); - } - if (tga_rgb16) { - stbi_uc *pal_entry = tga_palette; - STBI_ASSERT(tga_comp == STBI_rgb); - for (i=0; i < tga_palette_len; ++i) { - stbi__tga_read_rgb16(s, pal_entry); - pal_entry += tga_comp; - } - } else if (!stbi__getn(s, tga_palette, tga_palette_len * tga_comp)) { - STBI_FREE(tga_data); - STBI_FREE(tga_palette); - return stbi__errpuc("bad palette", "Corrupt TGA"); - } - } - // load the data - for (i=0; i < tga_width * tga_height; ++i) - { - // if I'm in RLE mode, do I need to get a RLE stbi__pngchunk? - if ( tga_is_RLE ) - { - if ( RLE_count == 0 ) - { - // yep, get the next byte as a RLE command - int RLE_cmd = stbi__get8(s); - RLE_count = 1 + (RLE_cmd & 127); - RLE_repeating = RLE_cmd >> 7; - read_next_pixel = 1; - } else if ( !RLE_repeating ) - { - read_next_pixel = 1; - } - } else - { - read_next_pixel = 1; - } - // OK, if I need to read a pixel, do it now - if ( read_next_pixel ) - { - // load however much data we did have - if ( tga_indexed ) - { - // read in index, then perform the lookup - int pal_idx = (tga_bits_per_pixel == 8) ? stbi__get8(s) : stbi__get16le(s); - if ( pal_idx >= tga_palette_len ) { - // invalid index - pal_idx = 0; - } - pal_idx *= tga_comp; - for (j = 0; j < tga_comp; ++j) { - raw_data[j] = tga_palette[pal_idx+j]; - } - } else if(tga_rgb16) { - STBI_ASSERT(tga_comp == STBI_rgb); - stbi__tga_read_rgb16(s, raw_data); - } else { - // read in the data raw - for (j = 0; j < tga_comp; ++j) { - raw_data[j] = stbi__get8(s); - } - } - // clear the reading flag for the next pixel - read_next_pixel = 0; - } // end of reading a pixel - - // copy data - for (j = 0; j < tga_comp; ++j) - tga_data[i*tga_comp+j] = raw_data[j]; - - // in case we're in RLE mode, keep counting down - --RLE_count; - } - // do I need to invert the image? - if ( tga_inverted ) - { - for (j = 0; j*2 < tga_height; ++j) - { - int index1 = j * tga_width * tga_comp; - int index2 = (tga_height - 1 - j) * tga_width * tga_comp; - for (i = tga_width * tga_comp; i > 0; --i) - { - unsigned char temp = tga_data[index1]; - tga_data[index1] = tga_data[index2]; - tga_data[index2] = temp; - ++index1; - ++index2; - } - } - } - // clear my palette, if I had one - if ( tga_palette != NULL ) - { - STBI_FREE( tga_palette ); - } - } - - // swap RGB - if the source data was RGB16, it already is in the right order - if (tga_comp >= 3 && !tga_rgb16) - { - unsigned char* tga_pixel = tga_data; - for (i=0; i < tga_width * tga_height; ++i) - { - unsigned char temp = tga_pixel[0]; - tga_pixel[0] = tga_pixel[2]; - tga_pixel[2] = temp; - tga_pixel += tga_comp; - } - } - - // convert to target component count - if (req_comp && req_comp != tga_comp) - tga_data = stbi__convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height); - - // the things I do to get rid of an error message, and yet keep - // Microsoft's C compilers happy... [8^( - tga_palette_start = tga_palette_len = tga_palette_bits = - tga_x_origin = tga_y_origin = 0; - STBI_NOTUSED(tga_palette_start); - // OK, done - return tga_data; -} -#endif - -// ************************************************************************************************* -// Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB - -#ifndef STBI_NO_PSD -static int stbi__psd_test(stbi__context *s) -{ - int r = (stbi__get32be(s) == 0x38425053); - stbi__rewind(s); - return r; -} - -static int stbi__psd_decode_rle(stbi__context *s, stbi_uc *p, int pixelCount) -{ - int count, nleft, len; - - count = 0; - while ((nleft = pixelCount - count) > 0) { - len = stbi__get8(s); - if (len == 128) { - // No-op. - } else if (len < 128) { - // Copy next len+1 bytes literally. - len++; - if (len > nleft) return 0; // corrupt data - count += len; - while (len) { - *p = stbi__get8(s); - p += 4; - len--; - } - } else if (len > 128) { - stbi_uc val; - // Next -len+1 bytes in the dest are replicated from next source byte. - // (Interpret len as a negative 8-bit int.) - len = 257 - len; - if (len > nleft) return 0; // corrupt data - val = stbi__get8(s); - count += len; - while (len) { - *p = val; - p += 4; - len--; - } - } - } - - return 1; -} - -static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) -{ - int pixelCount; - int channelCount, compression; - int channel, i; - int bitdepth; - int w,h; - stbi_uc *out; - STBI_NOTUSED(ri); - - // Check identifier - if (stbi__get32be(s) != 0x38425053) // "8BPS" - return stbi__errpuc("not PSD", "Corrupt PSD image"); - - // Check file type version. - if (stbi__get16be(s) != 1) - return stbi__errpuc("wrong version", "Unsupported version of PSD image"); - - // Skip 6 reserved bytes. - stbi__skip(s, 6 ); - - // Read the number of channels (R, G, B, A, etc). - channelCount = stbi__get16be(s); - if (channelCount < 0 || channelCount > 16) - return stbi__errpuc("wrong channel count", "Unsupported number of channels in PSD image"); - - // Read the rows and columns of the image. - h = stbi__get32be(s); - w = stbi__get32be(s); - - if (h > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); - if (w > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); - - // Make sure the depth is 8 bits. - bitdepth = stbi__get16be(s); - if (bitdepth != 8 && bitdepth != 16) - return stbi__errpuc("unsupported bit depth", "PSD bit depth is not 8 or 16 bit"); - - // Make sure the color mode is RGB. - // Valid options are: - // 0: Bitmap - // 1: Grayscale - // 2: Indexed color - // 3: RGB color - // 4: CMYK color - // 7: Multichannel - // 8: Duotone - // 9: Lab color - if (stbi__get16be(s) != 3) - return stbi__errpuc("wrong color format", "PSD is not in RGB color format"); - - // Skip the Mode Data. (It's the palette for indexed color; other info for other modes.) - stbi__skip(s,stbi__get32be(s) ); - - // Skip the image resources. (resolution, pen tool paths, etc) - stbi__skip(s, stbi__get32be(s) ); - - // Skip the reserved data. - stbi__skip(s, stbi__get32be(s) ); - - // Find out if the data is compressed. - // Known values: - // 0: no compression - // 1: RLE compressed - compression = stbi__get16be(s); - if (compression > 1) - return stbi__errpuc("bad compression", "PSD has an unknown compression format"); - - // Check size - if (!stbi__mad3sizes_valid(4, w, h, 0)) - return stbi__errpuc("too large", "Corrupt PSD"); - - // Create the destination image. - - if (!compression && bitdepth == 16 && bpc == 16) { - out = (stbi_uc *) stbi__malloc_mad3(8, w, h, 0); - ri->bits_per_channel = 16; - } else - out = (stbi_uc *) stbi__malloc(4 * w*h); - - if (!out) return stbi__errpuc("outofmem", "Out of memory"); - pixelCount = w*h; - - // Initialize the data to zero. - //memset( out, 0, pixelCount * 4 ); - - // Finally, the image data. - if (compression) { - // RLE as used by .PSD and .TIFF - // Loop until you get the number of unpacked bytes you are expecting: - // Read the next source byte into n. - // If n is between 0 and 127 inclusive, copy the next n+1 bytes literally. - // Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times. - // Else if n is 128, noop. - // Endloop - - // The RLE-compressed data is preceded by a 2-byte data count for each row in the data, - // which we're going to just skip. - stbi__skip(s, h * channelCount * 2 ); - - // Read the RLE data by channel. - for (channel = 0; channel < 4; channel++) { - stbi_uc *p; - - p = out+channel; - if (channel >= channelCount) { - // Fill this channel with default data. - for (i = 0; i < pixelCount; i++, p += 4) - *p = (channel == 3 ? 255 : 0); - } else { - // Read the RLE data. - if (!stbi__psd_decode_rle(s, p, pixelCount)) { - STBI_FREE(out); - return stbi__errpuc("corrupt", "bad RLE data"); - } - } - } - - } else { - // We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...) - // where each channel consists of an 8-bit (or 16-bit) value for each pixel in the image. - - // Read the data by channel. - for (channel = 0; channel < 4; channel++) { - if (channel >= channelCount) { - // Fill this channel with default data. - if (bitdepth == 16 && bpc == 16) { - stbi__uint16 *q = ((stbi__uint16 *) out) + channel; - stbi__uint16 val = channel == 3 ? 65535 : 0; - for (i = 0; i < pixelCount; i++, q += 4) - *q = val; - } else { - stbi_uc *p = out+channel; - stbi_uc val = channel == 3 ? 255 : 0; - for (i = 0; i < pixelCount; i++, p += 4) - *p = val; - } - } else { - if (ri->bits_per_channel == 16) { // output bpc - stbi__uint16 *q = ((stbi__uint16 *) out) + channel; - for (i = 0; i < pixelCount; i++, q += 4) - *q = (stbi__uint16) stbi__get16be(s); - } else { - stbi_uc *p = out+channel; - if (bitdepth == 16) { // input bpc - for (i = 0; i < pixelCount; i++, p += 4) - *p = (stbi_uc) (stbi__get16be(s) >> 8); - } else { - for (i = 0; i < pixelCount; i++, p += 4) - *p = stbi__get8(s); - } - } - } - } - } - - // remove weird white matte from PSD - if (channelCount >= 4) { - if (ri->bits_per_channel == 16) { - for (i=0; i < w*h; ++i) { - stbi__uint16 *pixel = (stbi__uint16 *) out + 4*i; - if (pixel[3] != 0 && pixel[3] != 65535) { - float a = pixel[3] / 65535.0f; - float ra = 1.0f / a; - float inv_a = 65535.0f * (1 - ra); - pixel[0] = (stbi__uint16) (pixel[0]*ra + inv_a); - pixel[1] = (stbi__uint16) (pixel[1]*ra + inv_a); - pixel[2] = (stbi__uint16) (pixel[2]*ra + inv_a); - } - } - } else { - for (i=0; i < w*h; ++i) { - unsigned char *pixel = out + 4*i; - if (pixel[3] != 0 && pixel[3] != 255) { - float a = pixel[3] / 255.0f; - float ra = 1.0f / a; - float inv_a = 255.0f * (1 - ra); - pixel[0] = (unsigned char) (pixel[0]*ra + inv_a); - pixel[1] = (unsigned char) (pixel[1]*ra + inv_a); - pixel[2] = (unsigned char) (pixel[2]*ra + inv_a); - } - } - } - } - - // convert to desired output format - if (req_comp && req_comp != 4) { - if (ri->bits_per_channel == 16) - out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, 4, req_comp, w, h); - else - out = stbi__convert_format(out, 4, req_comp, w, h); - if (out == NULL) return out; // stbi__convert_format frees input on failure - } - - if (comp) *comp = 4; - *y = h; - *x = w; - - return out; -} -#endif - -// ************************************************************************************************* -// Softimage PIC loader -// by Tom Seddon -// -// See http://softimage.wiki.softimage.com/index.php/INFO:_PIC_file_format -// See http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/ - -#ifndef STBI_NO_PIC -static int stbi__pic_is4(stbi__context *s,const char *str) -{ - int i; - for (i=0; i<4; ++i) - if (stbi__get8(s) != (stbi_uc)str[i]) - return 0; - - return 1; -} - -static int stbi__pic_test_core(stbi__context *s) -{ - int i; - - if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) - return 0; - - for(i=0;i<84;++i) - stbi__get8(s); - - if (!stbi__pic_is4(s,"PICT")) - return 0; - - return 1; -} - -typedef struct -{ - stbi_uc size,type,channel; -} stbi__pic_packet; - -static stbi_uc *stbi__readval(stbi__context *s, int channel, stbi_uc *dest) -{ - int mask=0x80, i; - - for (i=0; i<4; ++i, mask>>=1) { - if (channel & mask) { - if (stbi__at_eof(s)) return stbi__errpuc("bad file","PIC file too short"); - dest[i]=stbi__get8(s); - } - } - - return dest; -} - -static void stbi__copyval(int channel,stbi_uc *dest,const stbi_uc *src) -{ - int mask=0x80,i; - - for (i=0;i<4; ++i, mask>>=1) - if (channel&mask) - dest[i]=src[i]; -} - -static stbi_uc *stbi__pic_load_core(stbi__context *s,int width,int height,int *comp, stbi_uc *result) -{ - int act_comp=0,num_packets=0,y,chained; - stbi__pic_packet packets[10]; - - // this will (should...) cater for even some bizarre stuff like having data - // for the same channel in multiple packets. - do { - stbi__pic_packet *packet; - - if (num_packets==sizeof(packets)/sizeof(packets[0])) - return stbi__errpuc("bad format","too many packets"); - - packet = &packets[num_packets++]; - - chained = stbi__get8(s); - packet->size = stbi__get8(s); - packet->type = stbi__get8(s); - packet->channel = stbi__get8(s); - - act_comp |= packet->channel; - - if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (reading packets)"); - if (packet->size != 8) return stbi__errpuc("bad format","packet isn't 8bpp"); - } while (chained); - - *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel? - - for(y=0; ytype) { - default: - return stbi__errpuc("bad format","packet has bad compression type"); - - case 0: {//uncompressed - int x; - - for(x=0;xchannel,dest)) - return 0; - break; - } - - case 1://Pure RLE - { - int left=width, i; - - while (left>0) { - stbi_uc count,value[4]; - - count=stbi__get8(s); - if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pure read count)"); - - if (count > left) - count = (stbi_uc) left; - - if (!stbi__readval(s,packet->channel,value)) return 0; - - for(i=0; ichannel,dest,value); - left -= count; - } - } - break; - - case 2: {//Mixed RLE - int left=width; - while (left>0) { - int count = stbi__get8(s), i; - if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (mixed read count)"); - - if (count >= 128) { // Repeated - stbi_uc value[4]; - - if (count==128) - count = stbi__get16be(s); - else - count -= 127; - if (count > left) - return stbi__errpuc("bad file","scanline overrun"); - - if (!stbi__readval(s,packet->channel,value)) - return 0; - - for(i=0;ichannel,dest,value); - } else { // Raw - ++count; - if (count>left) return stbi__errpuc("bad file","scanline overrun"); - - for(i=0;ichannel,dest)) - return 0; - } - left-=count; - } - break; - } - } - } - } - - return result; -} - -static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp, stbi__result_info *ri) -{ - stbi_uc *result; - int i, x,y, internal_comp; - STBI_NOTUSED(ri); - - if (!comp) comp = &internal_comp; - - for (i=0; i<92; ++i) - stbi__get8(s); - - x = stbi__get16be(s); - y = stbi__get16be(s); - - if (y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); - if (x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); - - if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pic header)"); - if (!stbi__mad3sizes_valid(x, y, 4, 0)) return stbi__errpuc("too large", "PIC image too large to decode"); - - stbi__get32be(s); //skip `ratio' - stbi__get16be(s); //skip `fields' - stbi__get16be(s); //skip `pad' - - // intermediate buffer is RGBA - result = (stbi_uc *) stbi__malloc_mad3(x, y, 4, 0); - if (!result) return stbi__errpuc("outofmem", "Out of memory"); - memset(result, 0xff, x*y*4); - - if (!stbi__pic_load_core(s,x,y,comp, result)) { - STBI_FREE(result); - result=0; - } - *px = x; - *py = y; - if (req_comp == 0) req_comp = *comp; - result=stbi__convert_format(result,4,req_comp,x,y); - - return result; -} - -static int stbi__pic_test(stbi__context *s) -{ - int r = stbi__pic_test_core(s); - stbi__rewind(s); - return r; -} -#endif - -// ************************************************************************************************* -// GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb - -#ifndef STBI_NO_GIF -typedef struct -{ - stbi__int16 prefix; - stbi_uc first; - stbi_uc suffix; -} stbi__gif_lzw; - -typedef struct -{ - int w,h; - stbi_uc *out; // output buffer (always 4 components) - stbi_uc *background; // The current "background" as far as a gif is concerned - stbi_uc *history; - int flags, bgindex, ratio, transparent, eflags; - stbi_uc pal[256][4]; - stbi_uc lpal[256][4]; - stbi__gif_lzw codes[8192]; - stbi_uc *color_table; - int parse, step; - int lflags; - int start_x, start_y; - int max_x, max_y; - int cur_x, cur_y; - int line_size; - int delay; -} stbi__gif; - -static int stbi__gif_test_raw(stbi__context *s) -{ - int sz; - if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') return 0; - sz = stbi__get8(s); - if (sz != '9' && sz != '7') return 0; - if (stbi__get8(s) != 'a') return 0; - return 1; -} - -static int stbi__gif_test(stbi__context *s) -{ - int r = stbi__gif_test_raw(s); - stbi__rewind(s); - return r; -} - -static void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256][4], int num_entries, int transp) -{ - int i; - for (i=0; i < num_entries; ++i) { - pal[i][2] = stbi__get8(s); - pal[i][1] = stbi__get8(s); - pal[i][0] = stbi__get8(s); - pal[i][3] = transp == i ? 0 : 255; - } -} - -static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_info) -{ - stbi_uc version; - if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') - return stbi__err("not GIF", "Corrupt GIF"); - - version = stbi__get8(s); - if (version != '7' && version != '9') return stbi__err("not GIF", "Corrupt GIF"); - if (stbi__get8(s) != 'a') return stbi__err("not GIF", "Corrupt GIF"); - - stbi__g_failure_reason = ""; - g->w = stbi__get16le(s); - g->h = stbi__get16le(s); - g->flags = stbi__get8(s); - g->bgindex = stbi__get8(s); - g->ratio = stbi__get8(s); - g->transparent = -1; - - if (g->w > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); - if (g->h > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); - - if (comp != 0) *comp = 4; // can't actually tell whether it's 3 or 4 until we parse the comments - - if (is_info) return 1; - - if (g->flags & 0x80) - stbi__gif_parse_colortable(s,g->pal, 2 << (g->flags & 7), -1); - - return 1; -} - -static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp) -{ - stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif)); - if (!g) return stbi__err("outofmem", "Out of memory"); - if (!stbi__gif_header(s, g, comp, 1)) { - STBI_FREE(g); - stbi__rewind( s ); - return 0; - } - if (x) *x = g->w; - if (y) *y = g->h; - STBI_FREE(g); - return 1; -} - -static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) -{ - stbi_uc *p, *c; - int idx; - - // recurse to decode the prefixes, since the linked-list is backwards, - // and working backwards through an interleaved image would be nasty - if (g->codes[code].prefix >= 0) - stbi__out_gif_code(g, g->codes[code].prefix); - - if (g->cur_y >= g->max_y) return; - - idx = g->cur_x + g->cur_y; - p = &g->out[idx]; - g->history[idx / 4] = 1; - - c = &g->color_table[g->codes[code].suffix * 4]; - if (c[3] > 128) { // don't render transparent pixels; - p[0] = c[2]; - p[1] = c[1]; - p[2] = c[0]; - p[3] = c[3]; - } - g->cur_x += 4; - - if (g->cur_x >= g->max_x) { - g->cur_x = g->start_x; - g->cur_y += g->step; - - while (g->cur_y >= g->max_y && g->parse > 0) { - g->step = (1 << g->parse) * g->line_size; - g->cur_y = g->start_y + (g->step >> 1); - --g->parse; - } - } -} - -static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g) -{ - stbi_uc lzw_cs; - stbi__int32 len, init_code; - stbi__uint32 first; - stbi__int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear; - stbi__gif_lzw *p; - - lzw_cs = stbi__get8(s); - if (lzw_cs > 12) return NULL; - clear = 1 << lzw_cs; - first = 1; - codesize = lzw_cs + 1; - codemask = (1 << codesize) - 1; - bits = 0; - valid_bits = 0; - for (init_code = 0; init_code < clear; init_code++) { - g->codes[init_code].prefix = -1; - g->codes[init_code].first = (stbi_uc) init_code; - g->codes[init_code].suffix = (stbi_uc) init_code; - } - - // support no starting clear code - avail = clear+2; - oldcode = -1; - - len = 0; - for(;;) { - if (valid_bits < codesize) { - if (len == 0) { - len = stbi__get8(s); // start new block - if (len == 0) - return g->out; - } - --len; - bits |= (stbi__int32) stbi__get8(s) << valid_bits; - valid_bits += 8; - } else { - stbi__int32 code = bits & codemask; - bits >>= codesize; - valid_bits -= codesize; - // @OPTIMIZE: is there some way we can accelerate the non-clear path? - if (code == clear) { // clear code - codesize = lzw_cs + 1; - codemask = (1 << codesize) - 1; - avail = clear + 2; - oldcode = -1; - first = 0; - } else if (code == clear + 1) { // end of stream code - stbi__skip(s, len); - while ((len = stbi__get8(s)) > 0) - stbi__skip(s,len); - return g->out; - } else if (code <= avail) { - if (first) { - return stbi__errpuc("no clear code", "Corrupt GIF"); - } - - if (oldcode >= 0) { - p = &g->codes[avail++]; - if (avail > 8192) { - return stbi__errpuc("too many codes", "Corrupt GIF"); - } - - p->prefix = (stbi__int16) oldcode; - p->first = g->codes[oldcode].first; - p->suffix = (code == avail) ? p->first : g->codes[code].first; - } else if (code == avail) - return stbi__errpuc("illegal code in raster", "Corrupt GIF"); - - stbi__out_gif_code(g, (stbi__uint16) code); - - if ((avail & codemask) == 0 && avail <= 0x0FFF) { - codesize++; - codemask = (1 << codesize) - 1; - } - - oldcode = code; - } else { - return stbi__errpuc("illegal code in raster", "Corrupt GIF"); - } - } - } -} - -// this function is designed to support animated gifs, although stb_image doesn't support it -// two back is the image from two frames ago, used for a very specific disposal format -static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp, stbi_uc *two_back) -{ - int dispose; - int first_frame; - int pi; - int pcount; - STBI_NOTUSED(req_comp); - - // on first frame, any non-written pixels get the background colour (non-transparent) - first_frame = 0; - if (g->out == 0) { - if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header - if (!stbi__mad3sizes_valid(4, g->w, g->h, 0)) - return stbi__errpuc("too large", "GIF image is too large"); - pcount = g->w * g->h; - g->out = (stbi_uc *) stbi__malloc(4 * pcount); - g->background = (stbi_uc *) stbi__malloc(4 * pcount); - g->history = (stbi_uc *) stbi__malloc(pcount); - if (!g->out || !g->background || !g->history) - return stbi__errpuc("outofmem", "Out of memory"); - - // image is treated as "transparent" at the start - ie, nothing overwrites the current background; - // background colour is only used for pixels that are not rendered first frame, after that "background" - // color refers to the color that was there the previous frame. - memset(g->out, 0x00, 4 * pcount); - memset(g->background, 0x00, 4 * pcount); // state of the background (starts transparent) - memset(g->history, 0x00, pcount); // pixels that were affected previous frame - first_frame = 1; - } else { - // second frame - how do we dispose of the previous one? - dispose = (g->eflags & 0x1C) >> 2; - pcount = g->w * g->h; - - if ((dispose == 3) && (two_back == 0)) { - dispose = 2; // if I don't have an image to revert back to, default to the old background - } - - if (dispose == 3) { // use previous graphic - for (pi = 0; pi < pcount; ++pi) { - if (g->history[pi]) { - memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 ); - } - } - } else if (dispose == 2) { - // restore what was changed last frame to background before that frame; - for (pi = 0; pi < pcount; ++pi) { - if (g->history[pi]) { - memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 ); - } - } - } else { - // This is a non-disposal case eithe way, so just - // leave the pixels as is, and they will become the new background - // 1: do not dispose - // 0: not specified. - } - - // background is what out is after the undoing of the previou frame; - memcpy( g->background, g->out, 4 * g->w * g->h ); - } - - // clear my history; - memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame - - for (;;) { - int tag = stbi__get8(s); - switch (tag) { - case 0x2C: /* Image Descriptor */ - { - stbi__int32 x, y, w, h; - stbi_uc *o; - - x = stbi__get16le(s); - y = stbi__get16le(s); - w = stbi__get16le(s); - h = stbi__get16le(s); - if (((x + w) > (g->w)) || ((y + h) > (g->h))) - return stbi__errpuc("bad Image Descriptor", "Corrupt GIF"); - - g->line_size = g->w * 4; - g->start_x = x * 4; - g->start_y = y * g->line_size; - g->max_x = g->start_x + w * 4; - g->max_y = g->start_y + h * g->line_size; - g->cur_x = g->start_x; - g->cur_y = g->start_y; - - // if the width of the specified rectangle is 0, that means - // we may not see *any* pixels or the image is malformed; - // to make sure this is caught, move the current y down to - // max_y (which is what out_gif_code checks). - if (w == 0) - g->cur_y = g->max_y; - - g->lflags = stbi__get8(s); - - if (g->lflags & 0x40) { - g->step = 8 * g->line_size; // first interlaced spacing - g->parse = 3; - } else { - g->step = g->line_size; - g->parse = 0; - } - - if (g->lflags & 0x80) { - stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1); - g->color_table = (stbi_uc *) g->lpal; - } else if (g->flags & 0x80) { - g->color_table = (stbi_uc *) g->pal; - } else - return stbi__errpuc("missing color table", "Corrupt GIF"); - - o = stbi__process_gif_raster(s, g); - if (!o) return NULL; - - // if this was the first frame, - pcount = g->w * g->h; - if (first_frame && (g->bgindex > 0)) { - // if first frame, any pixel not drawn to gets the background color - for (pi = 0; pi < pcount; ++pi) { - if (g->history[pi] == 0) { - g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be reset next frame if need be; - memcpy( &g->out[pi * 4], &g->pal[g->bgindex], 4 ); - } - } - } - - return o; - } - - case 0x21: // Comment Extension. - { - int len; - int ext = stbi__get8(s); - if (ext == 0xF9) { // Graphic Control Extension. - len = stbi__get8(s); - if (len == 4) { - g->eflags = stbi__get8(s); - g->delay = 10 * stbi__get16le(s); // delay - 1/100th of a second, saving as 1/1000ths. - - // unset old transparent - if (g->transparent >= 0) { - g->pal[g->transparent][3] = 255; - } - if (g->eflags & 0x01) { - g->transparent = stbi__get8(s); - if (g->transparent >= 0) { - g->pal[g->transparent][3] = 0; - } - } else { - // don't need transparent - stbi__skip(s, 1); - g->transparent = -1; - } - } else { - stbi__skip(s, len); - break; - } - } - while ((len = stbi__get8(s)) != 0) { - stbi__skip(s, len); - } - break; - } - - case 0x3B: // gif stream termination code - return (stbi_uc *) s; // using '1' causes warning on some compilers - - default: - return stbi__errpuc("unknown code", "Corrupt GIF"); - } - } -} - -static void *stbi__load_gif_main_outofmem(stbi__gif *g, stbi_uc *out, int **delays) -{ - STBI_FREE(g->out); - STBI_FREE(g->history); - STBI_FREE(g->background); - - if (out) STBI_FREE(out); - if (delays && *delays) STBI_FREE(*delays); - return stbi__errpuc("outofmem", "Out of memory"); -} - -static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp) -{ - if (stbi__gif_test(s)) { - int layers = 0; - stbi_uc *u = 0; - stbi_uc *out = 0; - stbi_uc *two_back = 0; - stbi__gif g; - int stride; - int out_size = 0; - int delays_size = 0; - - STBI_NOTUSED(out_size); - STBI_NOTUSED(delays_size); - - memset(&g, 0, sizeof(g)); - if (delays) { - *delays = 0; - } - - do { - u = stbi__gif_load_next(s, &g, comp, req_comp, two_back); - if (u == (stbi_uc *) s) u = 0; // end of animated gif marker - - if (u) { - *x = g.w; - *y = g.h; - ++layers; - stride = g.w * g.h * 4; - - if (out) { - void *tmp = (stbi_uc*) STBI_REALLOC_SIZED( out, out_size, layers * stride ); - if (!tmp) - return stbi__load_gif_main_outofmem(&g, out, delays); - else { - out = (stbi_uc*) tmp; - out_size = layers * stride; - } - - if (delays) { - int *new_delays = (int*) STBI_REALLOC_SIZED( *delays, delays_size, sizeof(int) * layers ); - if (!new_delays) - return stbi__load_gif_main_outofmem(&g, out, delays); - *delays = new_delays; - delays_size = layers * sizeof(int); - } - } else { - out = (stbi_uc*)stbi__malloc( layers * stride ); - if (!out) - return stbi__load_gif_main_outofmem(&g, out, delays); - out_size = layers * stride; - if (delays) { - *delays = (int*) stbi__malloc( layers * sizeof(int) ); - if (!*delays) - return stbi__load_gif_main_outofmem(&g, out, delays); - delays_size = layers * sizeof(int); - } - } - memcpy( out + ((layers - 1) * stride), u, stride ); - if (layers >= 2) { - two_back = out - 2 * stride; - } - - if (delays) { - (*delays)[layers - 1U] = g.delay; - } - } - } while (u != 0); - - // free temp buffer; - STBI_FREE(g.out); - STBI_FREE(g.history); - STBI_FREE(g.background); - - // do the final conversion after loading everything; - if (req_comp && req_comp != 4) - out = stbi__convert_format(out, 4, req_comp, layers * g.w, g.h); - - *z = layers; - return out; - } else { - return stbi__errpuc("not GIF", "Image was not as a gif type."); - } -} - -static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) -{ - stbi_uc *u = 0; - stbi__gif g; - memset(&g, 0, sizeof(g)); - STBI_NOTUSED(ri); - - u = stbi__gif_load_next(s, &g, comp, req_comp, 0); - if (u == (stbi_uc *) s) u = 0; // end of animated gif marker - if (u) { - *x = g.w; - *y = g.h; - - // moved conversion to after successful load so that the same - // can be done for multiple frames. - if (req_comp && req_comp != 4) - u = stbi__convert_format(u, 4, req_comp, g.w, g.h); - } else if (g.out) { - // if there was an error and we allocated an image buffer, free it! - STBI_FREE(g.out); - } - - // free buffers needed for multiple frame loading; - STBI_FREE(g.history); - STBI_FREE(g.background); - - return u; -} - -static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp) -{ - return stbi__gif_info_raw(s,x,y,comp); -} -#endif - -// ************************************************************************************************* -// Radiance RGBE HDR loader -// originally by Nicolas Schulz -#ifndef STBI_NO_HDR -static int stbi__hdr_test_core(stbi__context *s, const char *signature) -{ - int i; - for (i=0; signature[i]; ++i) - if (stbi__get8(s) != signature[i]) - return 0; - stbi__rewind(s); - return 1; -} - -static int stbi__hdr_test(stbi__context* s) -{ - int r = stbi__hdr_test_core(s, "#?RADIANCE\n"); - stbi__rewind(s); - if(!r) { - r = stbi__hdr_test_core(s, "#?RGBE\n"); - stbi__rewind(s); - } - return r; -} - -#define STBI__HDR_BUFLEN 1024 -static char *stbi__hdr_gettoken(stbi__context *z, char *buffer) -{ - int len=0; - char c = '\0'; - - c = (char) stbi__get8(z); - - while (!stbi__at_eof(z) && c != '\n') { - buffer[len++] = c; - if (len == STBI__HDR_BUFLEN-1) { - // flush to end of line - while (!stbi__at_eof(z) && stbi__get8(z) != '\n') - ; - break; - } - c = (char) stbi__get8(z); - } - - buffer[len] = 0; - return buffer; -} - -static void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp) -{ - if ( input[3] != 0 ) { - float f1; - // Exponent - f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8)); - if (req_comp <= 2) - output[0] = (input[0] + input[1] + input[2]) * f1 / 3; - else { - output[0] = input[0] * f1; - output[1] = input[1] * f1; - output[2] = input[2] * f1; - } - if (req_comp == 2) output[1] = 1; - if (req_comp == 4) output[3] = 1; - } else { - switch (req_comp) { - case 4: output[3] = 1; /* fallthrough */ - case 3: output[0] = output[1] = output[2] = 0; - break; - case 2: output[1] = 1; /* fallthrough */ - case 1: output[0] = 0; - break; - } - } -} - -static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) -{ - char buffer[STBI__HDR_BUFLEN]; - char *token; - int valid = 0; - int width, height; - stbi_uc *scanline; - float *hdr_data; - int len; - unsigned char count, value; - int i, j, k, c1,c2, z; - const char *headerToken; - STBI_NOTUSED(ri); - - // Check identifier - headerToken = stbi__hdr_gettoken(s,buffer); - if (strcmp(headerToken, "#?RADIANCE") != 0 && strcmp(headerToken, "#?RGBE") != 0) - return stbi__errpf("not HDR", "Corrupt HDR image"); - - // Parse header - for(;;) { - token = stbi__hdr_gettoken(s,buffer); - if (token[0] == 0) break; - if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; - } - - if (!valid) return stbi__errpf("unsupported format", "Unsupported HDR format"); - - // Parse width and height - // can't use sscanf() if we're not using stdio! - token = stbi__hdr_gettoken(s,buffer); - if (strncmp(token, "-Y ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); - token += 3; - height = (int) strtol(token, &token, 10); - while (*token == ' ') ++token; - if (strncmp(token, "+X ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); - token += 3; - width = (int) strtol(token, NULL, 10); - - if (height > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)"); - if (width > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)"); - - *x = width; - *y = height; - - if (comp) *comp = 3; - if (req_comp == 0) req_comp = 3; - - if (!stbi__mad4sizes_valid(width, height, req_comp, sizeof(float), 0)) - return stbi__errpf("too large", "HDR image is too large"); - - // Read data - hdr_data = (float *) stbi__malloc_mad4(width, height, req_comp, sizeof(float), 0); - if (!hdr_data) - return stbi__errpf("outofmem", "Out of memory"); - - // Load image data - // image data is stored as some number of sca - if ( width < 8 || width >= 32768) { - // Read flat data - for (j=0; j < height; ++j) { - for (i=0; i < width; ++i) { - stbi_uc rgbe[4]; - main_decode_loop: - stbi__getn(s, rgbe, 4); - stbi__hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp); - } - } - } else { - // Read RLE-encoded data - scanline = NULL; - - for (j = 0; j < height; ++j) { - c1 = stbi__get8(s); - c2 = stbi__get8(s); - len = stbi__get8(s); - if (c1 != 2 || c2 != 2 || (len & 0x80)) { - // not run-length encoded, so we have to actually use THIS data as a decoded - // pixel (note this can't be a valid pixel--one of RGB must be >= 128) - stbi_uc rgbe[4]; - rgbe[0] = (stbi_uc) c1; - rgbe[1] = (stbi_uc) c2; - rgbe[2] = (stbi_uc) len; - rgbe[3] = (stbi_uc) stbi__get8(s); - stbi__hdr_convert(hdr_data, rgbe, req_comp); - i = 1; - j = 0; - STBI_FREE(scanline); - goto main_decode_loop; // yes, this makes no sense - } - len <<= 8; - len |= stbi__get8(s); - if (len != width) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); } - if (scanline == NULL) { - scanline = (stbi_uc *) stbi__malloc_mad2(width, 4, 0); - if (!scanline) { - STBI_FREE(hdr_data); - return stbi__errpf("outofmem", "Out of memory"); - } - } - - for (k = 0; k < 4; ++k) { - int nleft; - i = 0; - while ((nleft = width - i) > 0) { - count = stbi__get8(s); - if (count > 128) { - // Run - value = stbi__get8(s); - count -= 128; - if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } - for (z = 0; z < count; ++z) - scanline[i++ * 4 + k] = value; - } else { - // Dump - if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } - for (z = 0; z < count; ++z) - scanline[i++ * 4 + k] = stbi__get8(s); - } - } - } - for (i=0; i < width; ++i) - stbi__hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp); - } - if (scanline) - STBI_FREE(scanline); - } - - return hdr_data; -} - -static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp) -{ - char buffer[STBI__HDR_BUFLEN]; - char *token; - int valid = 0; - int dummy; - - if (!x) x = &dummy; - if (!y) y = &dummy; - if (!comp) comp = &dummy; - - if (stbi__hdr_test(s) == 0) { - stbi__rewind( s ); - return 0; - } - - for(;;) { - token = stbi__hdr_gettoken(s,buffer); - if (token[0] == 0) break; - if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; - } - - if (!valid) { - stbi__rewind( s ); - return 0; - } - token = stbi__hdr_gettoken(s,buffer); - if (strncmp(token, "-Y ", 3)) { - stbi__rewind( s ); - return 0; - } - token += 3; - *y = (int) strtol(token, &token, 10); - while (*token == ' ') ++token; - if (strncmp(token, "+X ", 3)) { - stbi__rewind( s ); - return 0; - } - token += 3; - *x = (int) strtol(token, NULL, 10); - *comp = 3; - return 1; -} -#endif // STBI_NO_HDR - -#ifndef STBI_NO_BMP -static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) -{ - void *p; - stbi__bmp_data info; - - info.all_a = 255; - p = stbi__bmp_parse_header(s, &info); - if (p == NULL) { - stbi__rewind( s ); - return 0; - } - if (x) *x = s->img_x; - if (y) *y = s->img_y; - if (comp) { - if (info.bpp == 24 && info.ma == 0xff000000) - *comp = 3; - else - *comp = info.ma ? 4 : 3; - } - return 1; -} -#endif - -#ifndef STBI_NO_PSD -static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) -{ - int channelCount, dummy, depth; - if (!x) x = &dummy; - if (!y) y = &dummy; - if (!comp) comp = &dummy; - if (stbi__get32be(s) != 0x38425053) { - stbi__rewind( s ); - return 0; - } - if (stbi__get16be(s) != 1) { - stbi__rewind( s ); - return 0; - } - stbi__skip(s, 6); - channelCount = stbi__get16be(s); - if (channelCount < 0 || channelCount > 16) { - stbi__rewind( s ); - return 0; - } - *y = stbi__get32be(s); - *x = stbi__get32be(s); - depth = stbi__get16be(s); - if (depth != 8 && depth != 16) { - stbi__rewind( s ); - return 0; - } - if (stbi__get16be(s) != 3) { - stbi__rewind( s ); - return 0; - } - *comp = 4; - return 1; -} - -static int stbi__psd_is16(stbi__context *s) -{ - int channelCount, depth; - if (stbi__get32be(s) != 0x38425053) { - stbi__rewind( s ); - return 0; - } - if (stbi__get16be(s) != 1) { - stbi__rewind( s ); - return 0; - } - stbi__skip(s, 6); - channelCount = stbi__get16be(s); - if (channelCount < 0 || channelCount > 16) { - stbi__rewind( s ); - return 0; - } - STBI_NOTUSED(stbi__get32be(s)); - STBI_NOTUSED(stbi__get32be(s)); - depth = stbi__get16be(s); - if (depth != 16) { - stbi__rewind( s ); - return 0; - } - return 1; -} -#endif - -#ifndef STBI_NO_PIC -static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) -{ - int act_comp=0,num_packets=0,chained,dummy; - stbi__pic_packet packets[10]; - - if (!x) x = &dummy; - if (!y) y = &dummy; - if (!comp) comp = &dummy; - - if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) { - stbi__rewind(s); - return 0; - } - - stbi__skip(s, 88); - - *x = stbi__get16be(s); - *y = stbi__get16be(s); - if (stbi__at_eof(s)) { - stbi__rewind( s); - return 0; - } - if ( (*x) != 0 && (1 << 28) / (*x) < (*y)) { - stbi__rewind( s ); - return 0; - } - - stbi__skip(s, 8); - - do { - stbi__pic_packet *packet; - - if (num_packets==sizeof(packets)/sizeof(packets[0])) - return 0; - - packet = &packets[num_packets++]; - chained = stbi__get8(s); - packet->size = stbi__get8(s); - packet->type = stbi__get8(s); - packet->channel = stbi__get8(s); - act_comp |= packet->channel; - - if (stbi__at_eof(s)) { - stbi__rewind( s ); - return 0; - } - if (packet->size != 8) { - stbi__rewind( s ); - return 0; - } - } while (chained); - - *comp = (act_comp & 0x10 ? 4 : 3); - - return 1; -} -#endif - -// ************************************************************************************************* -// Portable Gray Map and Portable Pixel Map loader -// by Ken Miller -// -// PGM: http://netpbm.sourceforge.net/doc/pgm.html -// PPM: http://netpbm.sourceforge.net/doc/ppm.html -// -// Known limitations: -// Does not support comments in the header section -// Does not support ASCII image data (formats P2 and P3) - -#ifndef STBI_NO_PNM - -static int stbi__pnm_test(stbi__context *s) -{ - char p, t; - p = (char) stbi__get8(s); - t = (char) stbi__get8(s); - if (p != 'P' || (t != '5' && t != '6')) { - stbi__rewind( s ); - return 0; - } - return 1; -} - -static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) -{ - stbi_uc *out; - STBI_NOTUSED(ri); - - ri->bits_per_channel = stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n); - if (ri->bits_per_channel == 0) - return 0; - - if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); - if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); - - *x = s->img_x; - *y = s->img_y; - if (comp) *comp = s->img_n; - - if (!stbi__mad4sizes_valid(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0)) - return stbi__errpuc("too large", "PNM too large"); - - out = (stbi_uc *) stbi__malloc_mad4(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0); - if (!out) return stbi__errpuc("outofmem", "Out of memory"); - stbi__getn(s, out, s->img_n * s->img_x * s->img_y * (ri->bits_per_channel / 8)); - - if (req_comp && req_comp != s->img_n) { - out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); - if (out == NULL) return out; // stbi__convert_format frees input on failure - } - return out; -} - -static int stbi__pnm_isspace(char c) -{ - return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r'; -} - -static void stbi__pnm_skip_whitespace(stbi__context *s, char *c) -{ - for (;;) { - while (!stbi__at_eof(s) && stbi__pnm_isspace(*c)) - *c = (char) stbi__get8(s); - - if (stbi__at_eof(s) || *c != '#') - break; - - while (!stbi__at_eof(s) && *c != '\n' && *c != '\r' ) - *c = (char) stbi__get8(s); - } -} - -static int stbi__pnm_isdigit(char c) -{ - return c >= '0' && c <= '9'; -} - -static int stbi__pnm_getinteger(stbi__context *s, char *c) -{ - int value = 0; - - while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) { - value = value*10 + (*c - '0'); - *c = (char) stbi__get8(s); - } - - return value; -} - -static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) -{ - int maxv, dummy; - char c, p, t; - - if (!x) x = &dummy; - if (!y) y = &dummy; - if (!comp) comp = &dummy; - - stbi__rewind(s); - - // Get identifier - p = (char) stbi__get8(s); - t = (char) stbi__get8(s); - if (p != 'P' || (t != '5' && t != '6')) { - stbi__rewind(s); - return 0; - } - - *comp = (t == '6') ? 3 : 1; // '5' is 1-component .pgm; '6' is 3-component .ppm - - c = (char) stbi__get8(s); - stbi__pnm_skip_whitespace(s, &c); - - *x = stbi__pnm_getinteger(s, &c); // read width - stbi__pnm_skip_whitespace(s, &c); - - *y = stbi__pnm_getinteger(s, &c); // read height - stbi__pnm_skip_whitespace(s, &c); - - maxv = stbi__pnm_getinteger(s, &c); // read max value - if (maxv > 65535) - return stbi__err("max value > 65535", "PPM image supports only 8-bit and 16-bit images"); - else if (maxv > 255) - return 16; - else - return 8; -} - -static int stbi__pnm_is16(stbi__context *s) -{ - if (stbi__pnm_info(s, NULL, NULL, NULL) == 16) - return 1; - return 0; -} -#endif - -static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp) -{ - #ifndef STBI_NO_JPEG - if (stbi__jpeg_info(s, x, y, comp)) return 1; - #endif - - #ifndef STBI_NO_PNG - if (stbi__png_info(s, x, y, comp)) return 1; - #endif - - #ifndef STBI_NO_GIF - if (stbi__gif_info(s, x, y, comp)) return 1; - #endif - - #ifndef STBI_NO_BMP - if (stbi__bmp_info(s, x, y, comp)) return 1; - #endif - - #ifndef STBI_NO_PSD - if (stbi__psd_info(s, x, y, comp)) return 1; - #endif - - #ifndef STBI_NO_PIC - if (stbi__pic_info(s, x, y, comp)) return 1; - #endif - - #ifndef STBI_NO_PNM - if (stbi__pnm_info(s, x, y, comp)) return 1; - #endif - - #ifndef STBI_NO_HDR - if (stbi__hdr_info(s, x, y, comp)) return 1; - #endif - - // test tga last because it's a crappy test! - #ifndef STBI_NO_TGA - if (stbi__tga_info(s, x, y, comp)) - return 1; - #endif - return stbi__err("unknown image type", "Image not of any known type, or corrupt"); -} - -static int stbi__is_16_main(stbi__context *s) -{ - #ifndef STBI_NO_PNG - if (stbi__png_is16(s)) return 1; - #endif - - #ifndef STBI_NO_PSD - if (stbi__psd_is16(s)) return 1; - #endif - - #ifndef STBI_NO_PNM - if (stbi__pnm_is16(s)) return 1; - #endif - return 0; -} - -#ifndef STBI_NO_STDIO -STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp) -{ - FILE *f = stbi__fopen(filename, "rb"); - int result; - if (!f) return stbi__err("can't fopen", "Unable to open file"); - result = stbi_info_from_file(f, x, y, comp); - fclose(f); - return result; -} - -STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp) -{ - int r; - stbi__context s; - long pos = ftell(f); - stbi__start_file(&s, f); - r = stbi__info_main(&s,x,y,comp); - fseek(f,pos,SEEK_SET); - return r; -} - -STBIDEF int stbi_is_16_bit(char const *filename) -{ - FILE *f = stbi__fopen(filename, "rb"); - int result; - if (!f) return stbi__err("can't fopen", "Unable to open file"); - result = stbi_is_16_bit_from_file(f); - fclose(f); - return result; -} - -STBIDEF int stbi_is_16_bit_from_file(FILE *f) -{ - int r; - stbi__context s; - long pos = ftell(f); - stbi__start_file(&s, f); - r = stbi__is_16_main(&s); - fseek(f,pos,SEEK_SET); - return r; -} -#endif // !STBI_NO_STDIO - -STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp) -{ - stbi__context s; - stbi__start_mem(&s,buffer,len); - return stbi__info_main(&s,x,y,comp); -} - -STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp) -{ - stbi__context s; - stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); - return stbi__info_main(&s,x,y,comp); -} - -STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len) -{ - stbi__context s; - stbi__start_mem(&s,buffer,len); - return stbi__is_16_main(&s); -} - -STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user) -{ - stbi__context s; - stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); - return stbi__is_16_main(&s); -} - -#endif // STB_IMAGE_IMPLEMENTATION - -/* - revision history: - 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs - 2.19 (2018-02-11) fix warning - 2.18 (2018-01-30) fix warnings - 2.17 (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug - 1-bit BMP - *_is_16_bit api - avoid warnings - 2.16 (2017-07-23) all functions have 16-bit variants; - STBI_NO_STDIO works again; - compilation fixes; - fix rounding in unpremultiply; - optimize vertical flip; - disable raw_len validation; - documentation fixes - 2.15 (2017-03-18) fix png-1,2,4 bug; now all Imagenet JPGs decode; - warning fixes; disable run-time SSE detection on gcc; - uniform handling of optional "return" values; - thread-safe initialization of zlib tables - 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs - 2.13 (2016-11-29) add 16-bit API, only supported for PNG right now - 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes - 2.11 (2016-04-02) allocate large structures on the stack - remove white matting for transparent PSD - fix reported channel count for PNG & BMP - re-enable SSE2 in non-gcc 64-bit - support RGB-formatted JPEG - read 16-bit PNGs (only as 8-bit) - 2.10 (2016-01-22) avoid warning introduced in 2.09 by STBI_REALLOC_SIZED - 2.09 (2016-01-16) allow comments in PNM files - 16-bit-per-pixel TGA (not bit-per-component) - info() for TGA could break due to .hdr handling - info() for BMP to shares code instead of sloppy parse - can use STBI_REALLOC_SIZED if allocator doesn't support realloc - code cleanup - 2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA - 2.07 (2015-09-13) fix compiler warnings - partial animated GIF support - limited 16-bpc PSD support - #ifdef unused functions - bug with < 92 byte PIC,PNM,HDR,TGA - 2.06 (2015-04-19) fix bug where PSD returns wrong '*comp' value - 2.05 (2015-04-19) fix bug in progressive JPEG handling, fix warning - 2.04 (2015-04-15) try to re-enable SIMD on MinGW 64-bit - 2.03 (2015-04-12) extra corruption checking (mmozeiko) - stbi_set_flip_vertically_on_load (nguillemot) - fix NEON support; fix mingw support - 2.02 (2015-01-19) fix incorrect assert, fix warning - 2.01 (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2 - 2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG - 2.00 (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg) - progressive JPEG (stb) - PGM/PPM support (Ken Miller) - STBI_MALLOC,STBI_REALLOC,STBI_FREE - GIF bugfix -- seemingly never worked - STBI_NO_*, STBI_ONLY_* - 1.48 (2014-12-14) fix incorrectly-named assert() - 1.47 (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb) - optimize PNG (ryg) - fix bug in interlaced PNG with user-specified channel count (stb) - 1.46 (2014-08-26) - fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG - 1.45 (2014-08-16) - fix MSVC-ARM internal compiler error by wrapping malloc - 1.44 (2014-08-07) - various warning fixes from Ronny Chevalier - 1.43 (2014-07-15) - fix MSVC-only compiler problem in code changed in 1.42 - 1.42 (2014-07-09) - don't define _CRT_SECURE_NO_WARNINGS (affects user code) - fixes to stbi__cleanup_jpeg path - added STBI_ASSERT to avoid requiring assert.h - 1.41 (2014-06-25) - fix search&replace from 1.36 that messed up comments/error messages - 1.40 (2014-06-22) - fix gcc struct-initialization warning - 1.39 (2014-06-15) - fix to TGA optimization when req_comp != number of components in TGA; - fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite) - add support for BMP version 5 (more ignored fields) - 1.38 (2014-06-06) - suppress MSVC warnings on integer casts truncating values - fix accidental rename of 'skip' field of I/O - 1.37 (2014-06-04) - remove duplicate typedef - 1.36 (2014-06-03) - convert to header file single-file library - if de-iphone isn't set, load iphone images color-swapped instead of returning NULL - 1.35 (2014-05-27) - various warnings - fix broken STBI_SIMD path - fix bug where stbi_load_from_file no longer left file pointer in correct place - fix broken non-easy path for 32-bit BMP (possibly never used) - TGA optimization by Arseny Kapoulkine - 1.34 (unknown) - use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case - 1.33 (2011-07-14) - make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements - 1.32 (2011-07-13) - support for "info" function for all supported filetypes (SpartanJ) - 1.31 (2011-06-20) - a few more leak fixes, bug in PNG handling (SpartanJ) - 1.30 (2011-06-11) - added ability to load files via callbacks to accomidate custom input streams (Ben Wenger) - removed deprecated format-specific test/load functions - removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway - error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha) - fix inefficiency in decoding 32-bit BMP (David Woo) - 1.29 (2010-08-16) - various warning fixes from Aurelien Pocheville - 1.28 (2010-08-01) - fix bug in GIF palette transparency (SpartanJ) - 1.27 (2010-08-01) - cast-to-stbi_uc to fix warnings - 1.26 (2010-07-24) - fix bug in file buffering for PNG reported by SpartanJ - 1.25 (2010-07-17) - refix trans_data warning (Won Chun) - 1.24 (2010-07-12) - perf improvements reading from files on platforms with lock-heavy fgetc() - minor perf improvements for jpeg - deprecated type-specific functions so we'll get feedback if they're needed - attempt to fix trans_data warning (Won Chun) - 1.23 fixed bug in iPhone support - 1.22 (2010-07-10) - removed image *writing* support - stbi_info support from Jetro Lauha - GIF support from Jean-Marc Lienher - iPhone PNG-extensions from James Brown - warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva) - 1.21 fix use of 'stbi_uc' in header (reported by jon blow) - 1.20 added support for Softimage PIC, by Tom Seddon - 1.19 bug in interlaced PNG corruption check (found by ryg) - 1.18 (2008-08-02) - fix a threading bug (local mutable static) - 1.17 support interlaced PNG - 1.16 major bugfix - stbi__convert_format converted one too many pixels - 1.15 initialize some fields for thread safety - 1.14 fix threadsafe conversion bug - header-file-only version (#define STBI_HEADER_FILE_ONLY before including) - 1.13 threadsafe - 1.12 const qualifiers in the API - 1.11 Support installable IDCT, colorspace conversion routines - 1.10 Fixes for 64-bit (don't use "unsigned long") - optimized upsampling by Fabian "ryg" Giesen - 1.09 Fix format-conversion for PSD code (bad global variables!) - 1.08 Thatcher Ulrich's PSD code integrated by Nicolas Schulz - 1.07 attempt to fix C++ warning/errors again - 1.06 attempt to fix C++ warning/errors again - 1.05 fix TGA loading to return correct *comp and use good luminance calc - 1.04 default float alpha is 1, not 255; use 'void *' for stbi_image_free - 1.03 bugfixes to STBI_NO_STDIO, STBI_NO_HDR - 1.02 support for (subset of) HDR files, float interface for preferred access to them - 1.01 fix bug: possible bug in handling right-side up bmps... not sure - fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all - 1.00 interface to zlib that skips zlib header - 0.99 correct handling of alpha in palette - 0.98 TGA loader by lonesock; dynamically add loaders (untested) - 0.97 jpeg errors on too large a file; also catch another malloc failure - 0.96 fix detection of invalid v value - particleman@mollyrocket forum - 0.95 during header scan, seek to markers in case of padding - 0.94 STBI_NO_STDIO to disable stdio usage; rename all #defines the same - 0.93 handle jpegtran output; verbose errors - 0.92 read 4,8,16,24,32-bit BMP files of several formats - 0.91 output 24-bit Windows 3.0 BMP files - 0.90 fix a few more warnings; bump version number to approach 1.0 - 0.61 bugfixes due to Marc LeBlanc, Christopher Lloyd - 0.60 fix compiling as c++ - 0.59 fix warnings: merge Dave Moore's -Wall fixes - 0.58 fix bug: zlib uncompressed mode len/nlen was wrong endian - 0.57 fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available - 0.56 fix bug: zlib uncompressed mode len vs. nlen - 0.55 fix bug: restart_interval not initialized to 0 - 0.54 allow NULL for 'int *comp' - 0.53 fix bug in png 3->4; speedup png decoding - 0.52 png handles req_comp=3,4 directly; minor cleanup; jpeg comments - 0.51 obey req_comp requests, 1-component jpegs return as 1-component, - on 'test' only check type, not whether we support this variant - 0.50 (2006-11-19) - first released version -*/ - - -/* ------------------------------------------------------------------------------- -This software is available under 2 licenses -- choose whichever you prefer. ------------------------------------------------------------------------------- -ALTERNATIVE A - MIT License -Copyright (c) 2017 Sean Barrett -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. -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 OR COPYRIGHT HOLDERS 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. ------------------------------------------------------------------------------- -ALTERNATIVE B - Public Domain (www.unlicense.org) -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. ------------------------------------------------------------------------------- -*/ \ No newline at end of file diff --git a/thirdparty/stb/src/stb_truetype.h b/thirdparty/stb/src/stb_truetype.h index 2ca3ff9..6c82c29 100644 --- a/thirdparty/stb/src/stb_truetype.h +++ b/thirdparty/stb/src/stb_truetype.h @@ -415,9 +415,9 @@ int main(int arg, char **argv) #pragma region ODIN: CUSTOM ALLOCATOR #ifdef STB_TRUETYPE_IMPLEMENTATION -#define GB_IMPLEMENTATION +#define ZPL_IMPLEMENTATION #endif -#include "gb/gb.h" +#include "zpl/zpl.h" #ifdef STBTT_STATIC #define STBTT_DEF static @@ -429,21 +429,21 @@ int main(int arg, char **argv) extern "C" { #endif -STBTT_DEF void stbtt_SetAllocator( gbAllocator allocator ); +STBTT_DEF void stbtt_SetAllocator( zpl_allocator allocator ); #ifdef __cplusplus } #endif #ifndef STBTT_malloc -#define STBTT_malloc(x,u) ((void)(u), gb_alloc(stbtt__allocator, x)) -#define STBTT_free(x,u) ((void)(u), gb_free(stbtt__allocator, x)) +#define STBTT_malloc(x,u) ((void)(u), zpl_alloc(stbtt__allocator, x)) +#define STBTT_free(x,u) ((void)(u), zpl_free(stbtt__allocator, x)) #endif #ifdef STB_TRUETYPE_IMPLEMENTATION -gb_global gbAllocator stbtt__allocator = { gb_heap_allocator_proc, NULL }; +zpl_global zpl_allocator stbtt__allocator = { zpl_heap_allocator_proc, NULL }; -STBTT_DEF void stbtt_SetAllocator( gbAllocator allocator ) { +STBTT_DEF void stbtt_SetAllocator( zpl_allocator allocator ) { stbtt__allocator = allocator; } #endif diff --git a/thirdparty/stb/truetype/stb_truetype.odin b/thirdparty/stb/truetype/stb_truetype.odin index f128ad0..59bbcc4 100644 --- a/thirdparty/stb/truetype/stb_truetype.odin +++ b/thirdparty/stb/truetype/stb_truetype.odin @@ -40,27 +40,27 @@ when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 { // CUSTOM: ODIN COMPATIBLE ALLOCATOR //----------------------------------------------------------------------------- -gbAllocationType :: enum(i32) { +zpl_allocator_type :: enum(i32) { Alloc, Free, FreeAll, Resize, } -gbAllocatorProc :: #type proc(allocator_data: rawptr, type: gbAllocationType, +zpl_allocator_proc :: #type proc(allocator_data: rawptr, type: zpl_allocator_type, size: c.ssize_t, alignment: c.ssize_t, old_memory: rawptr, old_size: c.ssize_t, flags : c.ulonglong ) -> rawptr -gbAllocator :: struct { - procedure: gbAllocatorProc, +zpl_allocator :: struct { + procedure: zpl_allocator_proc, data: rawptr, } @(default_calling_convention="c", link_prefix="stbtt_") foreign stbtt { - SetAllocator :: proc(allocator : gbAllocator) --- + SetAllocator :: proc(allocator : zpl_allocator) --- } //-----------------------------------------------------------------------------