2021-11-29 08:23:08 +00:00
/**
zpl - Pushing the boundaries of simplicity .
Usage :
# define ZPL_IMPLEMENTATION exactly in ONE source file right BEFORE including the library, like:
# define ZPL_IMPLEMENTATION
# include "zpl.h"
You can also use a lightweight version of zpl by using ZPL_NANO , like :
# define ZPL_IMPLEMENTATION
# define ZPL_NANO
# include "zpl.h"
There is also a distribution that provides only the essential modules , you can enable it by defining ZPL_PICO .
Currently , the distro offers : preprocessor helpers , debug module , memory API ( except vm ) and collections .
Some of these modules used to depend on zpl_printf , but they use the standard library if the distro is enabled now .
# define ZPL_IMPLEMENTATION
# define ZPL_PICO
# include "zpl.h"
Options :
ZPL_EXPOSE_TYPES - exposes all zpl defined types to the global namespace . This means type such as ` zpl_u32 ` is now available as ` u32 ` globally .
ZPL_DEFINE_NULL_MACRO - to let zpl define what NULL stands for in case it is undefined .
ZPL_NO_MATH_H - disables the use of math . h library and replaces it with custom routines or SIMD .
ZPL_HEAP_ANALYSIS - enables heap allocator analysis tools
2022-09-11 17:42:06 +00:00
ZPL_PARSER_DISABLE_ANALYSIS - disables the extra parsing logic that would collect more information about node ' s formatting and structure .
this is useful in scenarios where a raw parsing performance is preferred over a more complex analysis .
It is not recommended to serialise data back since we lack the extra information about the original source document .
2021-11-29 08:23:08 +00:00
GitHub :
https : //github.com/zpl-c/zpl
Version History :
2023-01-15 15:59:33 +00:00
18.1 .4 - fix zpl_random_gen_isize / zpl_random_range_isize 32 bit overflow
18.1 .3 - set parent to parsed JSON nodes
18.1 .2 - fix zpl sort procs
18.1 .1 - updated table _clear method
2022-09-18 15:35:53 +00:00
18.1 .0 - added table _clear method
18.0 .4 - fix memory arena alignment & added tests
2022-09-11 17:42:06 +00:00
18.0 .3 - fix emscripten support
18.0 .2 - fix global - buffer - overflow in print module
- raise ZPL_PRINTF_MAXLEN to 64 kb
18.0 .1 - fix ADT parser wrongly assuming that an IP address is a real number
18.0 .0 - removed coroutines module
- removed timer module
- rename zpl_adt_get - > zpl_adt_query
17.0 .0 - ADT API changes
zpl_adt_inset_ * - > zpl_adt_append_ *
zpl_adt_node now holds a parent field , methods no longer require a pointer to the parent
methods are now documented
- add zpl_thread_init_nowait ( gaopeng )
16.1 .1 - fix scientific notation parsing
16.1 .0 - introduce ZPL_PARSER_DISABLE_ANALYSIS that disables extra parsing capabilities to offer better raw performance
at a cost of lack of node metadata .
16.0 .0 - introduce a new zpl_adt_query method for flexible data retrieval
" 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 4 th element in " arr "
" arr/[apple] " retrieves the first element of value " apple " in " arr "
- fix memory leak when parsing a json array ( gaopeng )
- add zpl_strntok ( gaopeng )
- add zpl_semaphore_trywait ( gaopeng )
15.0 .3 - fix zpl_sign call in math failing to compile
on macos devices
2021-11-29 08:23:08 +00:00
15.0 .2 - zpl_sign0 was introduced
15.0 .1 - hashtable performance improvements
- zpl_sign ( 0 ) returns 0
15.0 .0 - Rework zpl ring buffer
- various code improvements
2022-09-11 17:42:06 +00:00
2021-11-29 08:23:08 +00:00
14.1 .7 - fix zpl_random_range_i64
- set thread ' s is_running before we start a thread
14.1 .6 - remove windows . h dependency for header part
14.1 .5 - fix array append_at
14.1 .4 - Fix win32 missing CRITICAL_SECTION definition if
- ZPL_NO_WINDOWS_H is defined
14.1 .0 - add hashtable map_mut method
14.0 .1 - fix zpl_array_remove_at boundary bug
14.0 .0 - heap memory allocator analysis
2022-09-11 17:42:06 +00:00
2021-11-29 08:23:08 +00:00
13.4 .1 - adt optimizations
13.4 .0 - new adt manipulation methods
13.3 .3 - fix zpl_str_skip_literal bug
13.3 .2 - escape strings in parser output
13.3 .1 - number parsing improvements
13.3 .0 - csv parse numbers
13.2 .0 - hashtable _map function
13.1 .5 - ZPL_DEBUG_TRAP for tcc
13.1 .4 - potential csv ub fix
13.1 .3 - tcc support improvements
13.1 .2 - fix ast - > adt filename
13.1 .1 - fix emscripten support
13.1 .0 - abstract data tree naming update
13.0 .0 - text parsers refactor
2022-09-11 17:42:06 +00:00
2021-11-29 08:23:08 +00:00
12.8 .0 - zpl_opts improvements
12.7 .0 - math improvements
12.6 .2 - remove register usage ( BeastLe9enD )
12.6 .1 - improve tar null padding code
12.6 .0 - introduce zpl_align_forward_u64 / i64
12.5 .1 - small type casting fixes
12.5 .0 - add zpl_asprintf
12.4 .0 - zpl_printf improvements
12.3 .2 - allow zpl_path_dirlist to include symlinks , but don ' t enter them
12.3 .1 - avoid symbolic link cycle in zpl_path_dirlist
12.3 .0 - add TAR archiving support
12.2 .1 - fix zpl_random_gen_f64
12.2 .0 - Add zpl_array_fill and zpl_array_appendv_at
12.1 .0 - Add rectangle partitioning
12.0 .1 - Optimize zpl_strlen
12.0 .0 - JSON API revamp + improvements
2022-09-11 17:42:06 +00:00
2021-11-29 08:23:08 +00:00
11.3 .0 - JSON zpl_json_str_to_flt + cleanup
11.2 .5 - fix small atomics typo
11.2 .4 - JSON rewrite core parser
11.2 .2 - JSON rewrite comment handling
11.2 .1 - JSON zero - initialise node
11.2 .0 - JSON API improvements
11.1 .2 - Improve atomics
11.1 .1 - Fix zpl_json_write_string providing incorrect length
11.1 .0 - Introduce new ZPL_PICO distro
11.0 .11 - remove stdatomic . h include
11.0 .10 - get rid of c11 atomics lib
11.0 .9 - stringlib uses ZPL_PRINTF_MAXLEN now
- zpl_printf family is now thread - safe
11.0 .7 - Add ZPL_PRINTF_MAXLEN
11.0 .6 - Fix zpl_printf left padding bug
11.0 .4 - Disable ZPL_NO_MATH_H on TinyC
11.0 .3 - Added support for TinyC compiler
11.0 .2 - Fixes for Apple M1 chip
11.0 .0 - New jobs system
- Rewrite the timer module
- zpl_ring rework
2022-09-11 17:42:06 +00:00
2021-11-29 08:23:08 +00:00
10.13 .0 - Initial ARM threading support
10.12 .1 - Fix missing zpL_alloc_str
10.12 .0 - Add zpl_crc64
10.11 .1 - Fix zpl_time_utc_ms on 32 - bit OSes
10.11 .0 - Added zpl_file_stream_buf
10.10 .3 - Math type - punning fixes
10.10 .1 - Fix memory writing issue + new write - only in - situ flag
10.10 .0 - Implement memory streaming API
10.9 .1 - Support ARMv6 , ARMv7 and ARMv8 - a builds
10.9 .0 - Improve the time API
10.8 .3 - zpl_file_close tempfile Windows fixes
10.8 .2 - zpl_file_temp disallow some operations
10.8 .1 - zpl_file_temp Windows fixes
10.8 .0 - Implemented zpl_json_write_string
10.7 .1 - Fix zpl_file_temp platform bug
10.7 .0 - Add zpl_file_write_contents
10.6 .6 - Fix type mismatch in Jobs system
10.6 .0 - Remove event system
10.5 .8 - Remove zpl__memcpy_4byte
10.5 .7 - zpl_file_new is now OS - agnostic constructor
10.5 .6 - Fix coroutine creation
10.5 .5 - Jobs system uses zpl_f32 for priority setting
10.5 .4 - zpl_buffer_free no longer takes the 2 nd argument ( allocator )
10.5 .3 - Removed crc64 and annotated some hashing methods
10.5 .2 - Don ' t expose ZPL types anymore
10.5 .1 - Fixed zpl_rdtsc for Emscripten
10.5 .0 - Changed casts to memcopy in random methods , added embed cmd
10.4 .1 - Jobs system now enqueues jobs with def priority of 1.0
10.4 .0 - [ META ] version bump
10.3 .0 - Pool allocator now supports zpl_free_all
10.2 .0 - [ META ] version bump
10.1 .0 - Additional math methods ( thanks to funZX and msmshazan )
10.0 .15 - WIP Emscripten fixes
10.0 .14 - FreeBSD support
10.0 .13 - OpenBSD support
10.0 .12 - Cygwin fixes
10.0 .11 - Tweak module dependencies
10.0 .10 - Fix zero - allocation regression in filesystem module
10.0 .9 - Fix multi - compilation unit builds
10.0 .8 - Fix zpl_printf " %0d " format specifier
10.0 .4 - Flush tester output to fix ordering
10.0 .3 - Fix ZPL_STATIC_ASSERT under MSVC
10.0 .0 - Major overhaul of the library
2022-09-11 17:42:06 +00:00
2021-11-29 08:23:08 +00:00
9.8 .10 - JSON fix array - based documents with objects
9.8 .9 - JSON document structured as array now properly recognizes the root object as array .
9.8 .8 - Fixed an incorrect parsing of empty array nodes .
9.8 .7 - Improve FreeBSD support
9.8 .6 - WIP : Handle inlined methods properly
9.8 .5 - Fix incorrect usage of EOF and opts dependency on JSON5 module ' s methods
9.8 .4 - Fix MSVC ZPL_NO_MATH_H code branch using incorrect methods internally
9.8 .3 - Fix MinGW GCC related issue with zpl_printf % lld format
9.8 .2 - Fix VS C4190 issue
9.8 .1 - Fix several C + + type casting quirks
9.8 .0 - Incorporated OpenGL into ZPL core as an optional module
9.7 .0 - Added co - routine module
9.6 .0 - Added process module for creation and manipulation
9.5 .2 - zpl_printf family now prints ( null ) on NULL string arguments
9.5 .1 - Fixed JSON5 real number export support + indentation fixes
9.5 .0 - Added base64 encode / decode methods
9.4 .10 - Small enum style changes
9.4 .9 - Remove # undef for cast and hard_cast ( sorry )
9.4 .8 - Fix quote - less JSON node name resolution
9.4 .7 - Additional change to the code
9.4 .6 - Fix issue where zpl_json_find would have false match on substrings
9.4 .5 - Mistakes were made , fixed compilation errors
9.4 .3 - Fix old API shenanigans
9.4 .2 - Fix small API typos
9.4 .1 - Reordered JSON5 constants to integrate better with conditions
9.4 .0 - JSON5 API changes made to zpl_json_find
9.3 .0 - Change how zpl uses basic types internally
9.2 .0 - Directory listing was added . Check dirlist_api . c test for more info
9.1 .1 - Fix WIN32_LEAN_AND_MEAN redefinition properly
9.1 .0 - get_env rework and fixes
9.0 .3 - Small fixes and removals
9.0 .0 - New documentation format , removed deprecated code , changed styles
2022-09-11 17:42:06 +00:00
2021-11-29 08:23:08 +00:00
8.14 .1 - Fix string library
8.14 .0 - Added zpl_re_match_all
8.13 .0 - Update system command API
8.12 .6 - Fix warning in CLI options parser
8.12 .5 - Support parametric options preceding positionals
8.12 .4 - Fixed opts positionals ordering
8.12 .3 - Fixed incorrect handling of flags preceding positionals
8.12 .2 - JSON parsing remark added
8.12 .1 - Fixed a lot of important stuff
8.12 .0 - Added helper constructors for containers
8.11 .2 - Fix bug in opts module
8.11 .1 - Small code improvements
8.11 .0 - Ported regex processor from https : //github.com/gingerBill/gb/ and applied fixes on top of it
8.10 .2 - Fix zpl_strtok
8.10 .1 - Replace zpl_strchr by zpl_char_last_occurence
8.10 .0 - Added zpl_strchr
8.9 .0 - API improvements for JSON5 parser
8.8 .4 - Add support for SJSON formatting http : //bitsquid.blogspot.com/2009/10/simplified-json-notation.html
2022-09-11 17:42:06 +00:00
2021-11-29 08:23:08 +00:00
6.8 .3 - JSON5 exp fix
6.8 .2 - Bugfixes applied from gb
6.8 .1 - Performance improvements for JSON5 parser
6.8 .0 - zpl . h is now generated by build . py
6.7 .0 - Several fixes and added switches
6.6 .0 - Several significant changes made to the repository
6.5 .0 - Ported platform layer from https : //github.com/gingerBill/gb/
6.4 .1 - Use zpl_strlen in zpl_strdup
6.4 .0 - Deprecated zpl_buffer_free and added zpl_array_end , zpl_buffer_end
6.3 .0 - Added zpl_strdup
6.2 .1 - Remove math redundancies
6.2 .0 - Integrated zpl_math . h into zpl . h
6.1 .1 - Added direct . h include for win c + + dir methods
6.1 .0 - Added zpl_path_mkdir , zpl_path_rmdir , and few new zplFileErrors
6.0 .4 - More MSVC ( + + ) satisfaction by fixing warnings
6.0 .3 - Satisfy MSVC by fixing a warning
6.0 .2 - Fixed warnings for json5 i64 printfs
6.0 .1 - Fixed warnings for particual win compiler in dirlist method
6.0 .0 - New build , include / was renamed to code /
2022-09-11 17:42:06 +00:00
2021-11-29 08:23:08 +00:00
5.8 .3 - Naming fixes
5.8 .2 - Job system now supports prioritized tasks
5.8 .1 - Renames zpl_pad to zpl_ring
5.8 .0 - Added instantiated scratch pad ( circular buffer )
5.7 .2 - Added Windows support for zpl_path_dirlist
5.7 .1 - Fixed few things in job system + macOS support for zpl_path_dirlist
5.7 .0 - Added a job system ( zpl_thread_pool )
5.6 .5 - Fixes extra error cases for zpl_opts when input is :
- missing a value for an option ,
- having an extra value for a flag ( e . g . - - enable - log shouldn ' t get a value . )
5.6 .4 - Several tweaks to the zpl_opts API
5.6 .3 - Added support for flags without values
5.6 .2 - Improve error handling for zpl_opts
5.6 .1 - Added support for strings with spaces in zpl_opts
5.6 .0 - Added zpl_opts for CLI argument parsing
5.5 .1 - Fixed time method for win
5.5 .0 - Integrate JSON5 writer into the core
5.4 .0 - Improved storage support for numbers in JSON5 parser
5.3 .0 - Integrated zpl_json into ZPL
5.2 .0 - Added zpl_string_sprintf
5.1 .1 - Added zpl_system_command_nores for output - less execution
5.1 .0 - Added event handler
5.0 .4 - Fix alias for zpl_list
5.0 .3 - Finalizing syntax changes
5.0 .2 - Fix segfault when using zpl_stack_memory
5.0 .1 - Small code improvements
5.0 .0 - Project structure changes
2022-09-11 17:42:06 +00:00
2021-11-29 08:23:08 +00:00
4.7 .2 - Got rid of size arg for zpl_str_split_lines
4.7 .1 - Added an example
4.7 .0 - Added zpl_path_dirlist
4.6 .1 - zpl_memcopy x86 patch from upstream
4.6 .0 - Added few string - related functions
4.5 .9 - Error fixes
4.5 .8 - Warning fixes
4.5 .7 - Fixed timer loops . zpl_time * related functions work with seconds now
4.5 .6 - Fixed zpl_time_now ( ) for Windows and Linux
4.5 .5 - Small cosmetic changes
4.5 .4 - Fixed issue when zpl_list_add would break the links
- when adding a new item between nodes
4.5 .3 - Fixed malformed enum values
4.5 .1 - Fixed some warnings
4.5 .0 - Added zpl_array_append_at
4.4 .0 - Added zpl_array_back , zpl_array_front
4.3 .0 - Added zpl_list
4.2 .0 - Added zpl_system_command_str
4.1 .2 - GG , fixed small compilation error
4.1 .1 - Fixed possible security issue in zpl_system_command
4.1 .0 - Added zpl_string_make_reserve and small fixes
4.0 .2 - Warning fix for _LARGEFILE64_SOURCE
4.0 .1 - include stdlib . h for getenv ( temp )
4.0 .0 - ARM support , coding style changes and various improvements
2022-09-11 17:42:06 +00:00
2021-11-29 08:23:08 +00:00
3.4 .1 - zpl_memcopy now uses memcpy for ARM arch - family
3.4 .0 - Removed obsolete code
3.3 .4 - Added Travis CI config
3.3 .3 - Small macro formatting changes + ZPL_SYSTEM_IOS
3.3 .2 - Fixes for android arm
3.3 .1 - Fixed some type cast warnings
3.3 .0 - Added Android support
3.1 .5 - Renamed userptr to user_data in timer
3.1 .4 - Fix for zpl_buffer not allocating correctly
3.1 .2 - Small fix in zpl_memcompare
3.1 .1 - Added char * conversion for data field in zpl_array_header
3.1 .0 - Added data field to zpl_array_header
3.0 .7 - Added timer userptr as argument to callback
3.0 .6 - Small changes
3.0 .5 - Fixed compilation for emscripten
3.0 .4 - Small fixes for tiny cpp warnings
3.0 .3 - Small fixes for various cpp warnings and errors
3.0 .2 - Fixed linux part , and removed trailing spaces
3.0 .1 - Small bugfix in zpl_file_open
3.0 .0 - Added several fixes and features
2022-09-11 17:42:06 +00:00
2021-11-29 08:23:08 +00:00
2.4 .0 - Added remove to hash table
2.3 .3 - Removed redundant code
2.3 .2 - Eliminated extra warnings
2.3 .1 - Warning hunt
2.3 .0 - Added the ability to copy array / buffer and fixed bug in hash table .
2.2 .1 - Used tmpfile ( ) for Windows
2.2 .0 - Added zpl_file_temp
2.1 .1 - Very small fix ( forgive me )
2.1 .0 - Added the ability to resize bitstream
2.0 .8 - Small adjustments
2.0 .7 - MinGW related fixes
2.0 .0 - New NPM based version
2022-09-11 17:42:06 +00:00
2021-11-29 08:23:08 +00:00
1.2 .2 - Small fix
1.2 .1 - Macro fixes
1.2 .0 - Added zpl_async macro
1.1 .0 - Added timer feature
1.0 .0 - Initial version
License :
This Software is dual licensed under the following licenses :
2022-09-11 17:42:06 +00:00
2021-11-29 08:23:08 +00:00
Unlicense
This is free and unencumbered software released into the public domain .
2022-09-11 17:42:06 +00:00
2021-11-29 08:23:08 +00:00
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 .
2022-09-11 17:42:06 +00:00
2021-11-29 08:23:08 +00:00
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 .
2022-09-11 17:42:06 +00:00
2021-11-29 08:23:08 +00:00
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 .
2022-09-11 17:42:06 +00:00
2021-11-29 08:23:08 +00:00
For more information , please refer to < http : //unlicense.org/>
2022-09-11 17:42:06 +00:00
2021-11-29 08:23:08 +00:00
BSD 3 - Clause
Copyright ( c ) 2016 - 2021 Dominik Madar á sz . All rights reserved .
2022-09-11 17:42:06 +00:00
2021-11-29 08:23:08 +00:00
Redistribution and use in source and binary forms , with or without
modification , are permitted provided that the following conditions are met :
2022-09-11 17:42:06 +00:00
2021-11-29 08:23:08 +00:00
1. Redistributions of source code must retain the above copyright notice , this
list of conditions and the following disclaimer .
2. Redistributions in binary form must reproduce the above copyright notice ,
this list of conditions and the following disclaimer in the documentation
and / or other materials provided with the distribution .
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission .
2022-09-11 17:42:06 +00:00
2021-11-29 08:23:08 +00:00
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS " AS IS " AND
ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL
DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY ,
OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*/
# ifndef ZPL_H
# define ZPL_H
2022-09-11 17:42:06 +00:00
# define ZPL_VERSION_MAJOR 18
2022-09-18 15:35:53 +00:00
# define ZPL_VERSION_MINOR 1
2023-01-15 15:59:33 +00:00
# define ZPL_VERSION_PATCH 4
2021-11-29 08:23:08 +00:00
# define ZPL_VERSION_PRE ""
2022-09-11 17:42:06 +00:00
// file: zpl_hedley.h
/* Hedley - https://nemequ.github.io/hedley
* Created by Evan Nemerson < evan @ nemerson . com >
*
* To the extent possible under law , the author ( s ) have dedicated all
* copyright and related and neighboring rights to this software to
* the public domain worldwide . This software is distributed without
* any warranty .
*
* For details , see < http : //creativecommons.org/publicdomain/zero/1.0/>.
* SPDX - License - Identifier : CC0 - 1.0
*/
# if !defined(ZPL_HEDLEY_VERSION) || (ZPL_HEDLEY_VERSION < 12)
# if defined(ZPL_HEDLEY_VERSION)
# undef ZPL_HEDLEY_VERSION
# endif
# define ZPL_HEDLEY_VERSION 12
# if defined(ZPL_STRINGIFY_EX)
# undef ZPL_STRINGIFY_EX
# endif
# define ZPL_STRINGIFY_EX(x) #x
# if defined(ZPL_STRINGIFY)
# undef ZPL_STRINGIFY
# endif
# define ZPL_STRINGIFY(x) ZPL_STRINGIFY_EX(x)
# if defined(ZPL_CONCAT_EX)
# undef ZPL_CONCAT_EX
# endif
# define ZPL_CONCAT_EX(a,b) a##b
# if defined(ZPL_CONCAT)
# undef ZPL_CONCAT
# endif
# define ZPL_CONCAT(a,b) ZPL_CONCAT_EX(a,b)
# if defined(ZPL_VERSION_ENCODE)
# undef ZPL_VERSION_ENCODE
# endif
# define ZPL_VERSION_ENCODE(major,minor,patch) (((major) * 1000000) + ((minor) * 1000) + (patch))
# if defined(ZPL_VERSION_DECODE_MAJOR)
# undef ZPL_VERSION_DECODE_MAJOR
# endif
# define ZPL_VERSION_DECODE_MAJOR(version) ((version) / 1000000)
# if defined(ZPL_VERSION_DECODE_MINOR)
# undef ZPL_VERSION_DECODE_MINOR
# endif
# define ZPL_VERSION_DECODE_MINOR(version) (((version) % 1000000) / 1000)
# if defined(ZPL_VERSION_DECODE_PATCH)
# undef ZPL_VERSION_DECODE_PATCH
# endif
# define ZPL_VERSION_DECODE_PATCH(version) ((version) % 1000)
# if defined(ZPL_VERSION_CHECK)
# undef ZPL_VERSION_CHECK
# endif
# define ZPL_VERSION_CHECK(major,minor,patch) (ZPL_VERSION_ENCODE(major,minor,patch) <= ZPL_VERSION)
# if defined(ZPL_GNUC_VERSION)
# undef ZPL_GNUC_VERSION
# endif
# if defined(__GNUC__) && defined(__GNUC_PATCHLEVEL__)
# define ZPL_GNUC_VERSION ZPL_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
# elif defined(__GNUC__)
# define ZPL_GNUC_VERSION ZPL_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, 0)
# endif
# if defined(ZPL_GNUC_VERSION_CHECK)
# undef ZPL_GNUC_VERSION_CHECK
# endif
# if defined(ZPL_GNUC_VERSION)
# define ZPL_GNUC_VERSION_CHECK(major,minor,patch) (ZPL_GNUC_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch))
# else
# define ZPL_GNUC_VERSION_CHECK(major,minor,patch) (0)
# endif
# if defined(ZPL_MSVC_VERSION)
# undef ZPL_MSVC_VERSION
# endif
# if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140000000)
# define ZPL_MSVC_VERSION ZPL_VERSION_ENCODE(_MSC_FULL_VER / 10000000, (_MSC_FULL_VER % 10000000) / 100000, (_MSC_FULL_VER % 100000) / 100)
# elif defined(_MSC_FULL_VER)
# define ZPL_MSVC_VERSION ZPL_VERSION_ENCODE(_MSC_FULL_VER / 1000000, (_MSC_FULL_VER % 1000000) / 10000, (_MSC_FULL_VER % 10000) / 10)
# elif defined(_MSC_VER)
# define ZPL_MSVC_VERSION ZPL_VERSION_ENCODE(_MSC_VER / 100, _MSC_VER % 100, 0)
# endif
# if defined(ZPL_MSVC_VERSION_CHECK)
# undef ZPL_MSVC_VERSION_CHECK
# endif
# if !defined(_MSC_VER)
# define ZPL_MSVC_VERSION_CHECK(major,minor,patch) (0)
# elif defined(_MSC_VER) && (_MSC_VER >= 1400)
# define ZPL_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch)))
# elif defined(_MSC_VER) && (_MSC_VER >= 1200)
# define ZPL_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 1000000) + (minor * 10000) + (patch)))
# else
# define ZPL_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_VER >= ((major * 100) + (minor)))
# endif
# if defined(ZPL_INTEL_VERSION)
# undef ZPL_INTEL_VERSION
# endif
# if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE)
# define ZPL_INTEL_VERSION ZPL_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, __INTEL_COMPILER_UPDATE)
# elif defined(__INTEL_COMPILER)
# define ZPL_INTEL_VERSION ZPL_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0)
# endif
# if defined(ZPL_INTEL_VERSION_CHECK)
# undef ZPL_INTEL_VERSION_CHECK
# endif
# if defined(ZPL_INTEL_VERSION)
# define ZPL_INTEL_VERSION_CHECK(major,minor,patch) (ZPL_INTEL_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch))
# else
# define ZPL_INTEL_VERSION_CHECK(major,minor,patch) (0)
# endif
# if defined(ZPL_PGI_VERSION)
# undef ZPL_PGI_VERSION
# endif
# if defined(__PGI) && defined(__PGIC__) && defined(__PGIC_MINOR__) && defined(__PGIC_PATCHLEVEL__)
# define ZPL_PGI_VERSION ZPL_VERSION_ENCODE(__PGIC__, __PGIC_MINOR__, __PGIC_PATCHLEVEL__)
# endif
# if defined(ZPL_PGI_VERSION_CHECK)
# undef ZPL_PGI_VERSION_CHECK
# endif
# if defined(ZPL_PGI_VERSION)
# define ZPL_PGI_VERSION_CHECK(major,minor,patch) (ZPL_PGI_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch))
# else
# define ZPL_PGI_VERSION_CHECK(major,minor,patch) (0)
# endif
# if defined(ZPL_SUNPRO_VERSION)
# undef ZPL_SUNPRO_VERSION
# endif
# if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000)
# define ZPL_SUNPRO_VERSION ZPL_VERSION_ENCODE((((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), (__SUNPRO_C & 0xf) * 10)
# elif defined(__SUNPRO_C)
# define ZPL_SUNPRO_VERSION ZPL_VERSION_ENCODE((__SUNPRO_C >> 8) & 0xf, (__SUNPRO_C >> 4) & 0xf, (__SUNPRO_C) & 0xf)
# elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000)
# define ZPL_SUNPRO_VERSION ZPL_VERSION_ENCODE((((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), (__SUNPRO_CC & 0xf) * 10)
# elif defined(__SUNPRO_CC)
# define ZPL_SUNPRO_VERSION ZPL_VERSION_ENCODE((__SUNPRO_CC >> 8) & 0xf, (__SUNPRO_CC >> 4) & 0xf, (__SUNPRO_CC) & 0xf)
# endif
# if defined(ZPL_SUNPRO_VERSION_CHECK)
# undef ZPL_SUNPRO_VERSION_CHECK
# endif
# if defined(ZPL_SUNPRO_VERSION)
# define ZPL_SUNPRO_VERSION_CHECK(major,minor,patch) (ZPL_SUNPRO_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch))
# else
# define ZPL_SUNPRO_VERSION_CHECK(major,minor,patch) (0)
# endif
# if defined(ZPL_EMSCRIPTEN_VERSION)
# undef ZPL_EMSCRIPTEN_VERSION
# endif
# if defined(__EMSCRIPTEN__)
# define ZPL_EMSCRIPTEN_VERSION ZPL_VERSION_ENCODE(__EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__)
# endif
# if defined(ZPL_EMSCRIPTEN_VERSION_CHECK)
# undef ZPL_EMSCRIPTEN_VERSION_CHECK
# endif
# if defined(ZPL_EMSCRIPTEN_VERSION)
# define ZPL_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (ZPL_EMSCRIPTEN_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch))
# else
# define ZPL_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (0)
# endif
# if defined(ZPL_ARM_VERSION)
# undef ZPL_ARM_VERSION
# endif
# if defined(__CC_ARM) && defined(__ARMCOMPILER_VERSION)
# define ZPL_ARM_VERSION ZPL_VERSION_ENCODE(__ARMCOMPILER_VERSION / 1000000, (__ARMCOMPILER_VERSION % 1000000) / 10000, (__ARMCOMPILER_VERSION % 10000) / 100)
# elif defined(__CC_ARM) && defined(__ARMCC_VERSION)
# define ZPL_ARM_VERSION ZPL_VERSION_ENCODE(__ARMCC_VERSION / 1000000, (__ARMCC_VERSION % 1000000) / 10000, (__ARMCC_VERSION % 10000) / 100)
# endif
# if defined(ZPL_ARM_VERSION_CHECK)
# undef ZPL_ARM_VERSION_CHECK
# endif
# if defined(ZPL_ARM_VERSION)
# define ZPL_ARM_VERSION_CHECK(major,minor,patch) (ZPL_ARM_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch))
# else
# define ZPL_ARM_VERSION_CHECK(major,minor,patch) (0)
# endif
# if defined(ZPL_IBM_VERSION)
# undef ZPL_IBM_VERSION
# endif
# if defined(__ibmxl__)
# define ZPL_IBM_VERSION ZPL_VERSION_ENCODE(__ibmxl_version__, __ibmxl_release__, __ibmxl_modification__)
# elif defined(__xlC__) && defined(__xlC_ver__)
# define ZPL_IBM_VERSION ZPL_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, (__xlC_ver__ >> 8) & 0xff)
# elif defined(__xlC__)
# define ZPL_IBM_VERSION ZPL_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, 0)
# endif
# if defined(ZPL_IBM_VERSION_CHECK)
# undef ZPL_IBM_VERSION_CHECK
# endif
# if defined(ZPL_IBM_VERSION)
# define ZPL_IBM_VERSION_CHECK(major,minor,patch) (ZPL_IBM_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch))
# else
# define ZPL_IBM_VERSION_CHECK(major,minor,patch) (0)
# endif
# if defined(ZPL_TI_VERSION)
# undef ZPL_TI_VERSION
# endif
# if \
defined ( __TI_COMPILER_VERSION__ ) & & \
( \
defined ( __TMS470__ ) | | defined ( __TI_ARM__ ) | | \
defined ( __MSP430__ ) | | \
defined ( __TMS320C2000__ ) \
)
# if (__TI_COMPILER_VERSION__ >= 16000000)
# define ZPL_TI_VERSION ZPL_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))
# endif
# endif
# if defined(ZPL_TI_VERSION_CHECK)
# undef ZPL_TI_VERSION_CHECK
# endif
# if defined(ZPL_TI_VERSION)
# define ZPL_TI_VERSION_CHECK(major,minor,patch) (ZPL_TI_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch))
# else
# define ZPL_TI_VERSION_CHECK(major,minor,patch) (0)
# endif
# if defined(ZPL_TI_CL2000_VERSION)
# undef ZPL_TI_CL2000_VERSION
# endif
# if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C2000__)
# define ZPL_TI_CL2000_VERSION ZPL_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))
# endif
# if defined(ZPL_TI_CL2000_VERSION_CHECK)
# undef ZPL_TI_CL2000_VERSION_CHECK
# endif
# if defined(ZPL_TI_CL2000_VERSION)
# define ZPL_TI_CL2000_VERSION_CHECK(major,minor,patch) (ZPL_TI_CL2000_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch))
# else
# define ZPL_TI_CL2000_VERSION_CHECK(major,minor,patch) (0)
# endif
# if defined(ZPL_TI_CL430_VERSION)
# undef ZPL_TI_CL430_VERSION
# endif
# if defined(__TI_COMPILER_VERSION__) && defined(__MSP430__)
# define ZPL_TI_CL430_VERSION ZPL_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))
# endif
# if defined(ZPL_TI_CL430_VERSION_CHECK)
# undef ZPL_TI_CL430_VERSION_CHECK
# endif
# if defined(ZPL_TI_CL430_VERSION)
# define ZPL_TI_CL430_VERSION_CHECK(major,minor,patch) (ZPL_TI_CL430_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch))
# else
# define ZPL_TI_CL430_VERSION_CHECK(major,minor,patch) (0)
# endif
# if defined(ZPL_TI_ARMCL_VERSION)
# undef ZPL_TI_ARMCL_VERSION
# endif
# if defined(__TI_COMPILER_VERSION__) && (defined(__TMS470__) || defined(__TI_ARM__))
# define ZPL_TI_ARMCL_VERSION ZPL_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))
# endif
# if defined(ZPL_TI_ARMCL_VERSION_CHECK)
# undef ZPL_TI_ARMCL_VERSION_CHECK
# endif
# if defined(ZPL_TI_ARMCL_VERSION)
# define ZPL_TI_ARMCL_VERSION_CHECK(major,minor,patch) (ZPL_TI_ARMCL_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch))
# else
# define ZPL_TI_ARMCL_VERSION_CHECK(major,minor,patch) (0)
# endif
# if defined(ZPL_TI_CL6X_VERSION)
# undef ZPL_TI_CL6X_VERSION
# endif
# if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C6X__)
# define ZPL_TI_CL6X_VERSION ZPL_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))
# endif
# if defined(ZPL_TI_CL6X_VERSION_CHECK)
# undef ZPL_TI_CL6X_VERSION_CHECK
# endif
# if defined(ZPL_TI_CL6X_VERSION)
# define ZPL_TI_CL6X_VERSION_CHECK(major,minor,patch) (ZPL_TI_CL6X_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch))
# else
# define ZPL_TI_CL6X_VERSION_CHECK(major,minor,patch) (0)
# endif
# if defined(ZPL_TI_CL7X_VERSION)
# undef ZPL_TI_CL7X_VERSION
# endif
# if defined(__TI_COMPILER_VERSION__) && defined(__C7000__)
# define ZPL_TI_CL7X_VERSION ZPL_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))
# endif
# if defined(ZPL_TI_CL7X_VERSION_CHECK)
# undef ZPL_TI_CL7X_VERSION_CHECK
# endif
# if defined(ZPL_TI_CL7X_VERSION)
# define ZPL_TI_CL7X_VERSION_CHECK(major,minor,patch) (ZPL_TI_CL7X_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch))
# else
# define ZPL_TI_CL7X_VERSION_CHECK(major,minor,patch) (0)
# endif
# if defined(ZPL_TI_CLPRU_VERSION)
# undef ZPL_TI_CLPRU_VERSION
# endif
# if defined(__TI_COMPILER_VERSION__) && defined(__PRU__)
# define ZPL_TI_CLPRU_VERSION ZPL_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))
# endif
# if defined(ZPL_TI_CLPRU_VERSION_CHECK)
# undef ZPL_TI_CLPRU_VERSION_CHECK
# endif
# if defined(ZPL_TI_CLPRU_VERSION)
# define ZPL_TI_CLPRU_VERSION_CHECK(major,minor,patch) (ZPL_TI_CLPRU_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch))
# else
# define ZPL_TI_CLPRU_VERSION_CHECK(major,minor,patch) (0)
# endif
# if defined(ZPL_CRAY_VERSION)
# undef ZPL_CRAY_VERSION
# endif
# if defined(_CRAYC)
# if defined(_RELEASE_PATCHLEVEL)
# define ZPL_CRAY_VERSION ZPL_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, _RELEASE_PATCHLEVEL)
# else
# define ZPL_CRAY_VERSION ZPL_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, 0)
# endif
# endif
# if defined(ZPL_CRAY_VERSION_CHECK)
# undef ZPL_CRAY_VERSION_CHECK
# endif
# if defined(ZPL_CRAY_VERSION)
# define ZPL_CRAY_VERSION_CHECK(major,minor,patch) (ZPL_CRAY_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch))
# else
# define ZPL_CRAY_VERSION_CHECK(major,minor,patch) (0)
# endif
# if defined(ZPL_IAR_VERSION)
# undef ZPL_IAR_VERSION
# endif
# if defined(__IAR_SYSTEMS_ICC__)
# if __VER__ > 1000
# define ZPL_IAR_VERSION ZPL_VERSION_ENCODE((__VER__ / 1000000), ((__VER__ / 1000) % 1000), (__VER__ % 1000))
# else
# define ZPL_IAR_VERSION ZPL_VERSION_ENCODE(VER / 100, __VER__ % 100, 0)
# endif
# endif
# if defined(ZPL_IAR_VERSION_CHECK)
# undef ZPL_IAR_VERSION_CHECK
# endif
# if defined(ZPL_IAR_VERSION)
# define ZPL_IAR_VERSION_CHECK(major,minor,patch) (ZPL_IAR_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch))
# else
# define ZPL_IAR_VERSION_CHECK(major,minor,patch) (0)
# endif
# if defined(ZPL_TINYC_VERSION)
# undef ZPL_TINYC_VERSION
# endif
# if defined(__TINYC__)
# define ZPL_TINYC_VERSION ZPL_VERSION_ENCODE(__TINYC__ / 1000, (__TINYC__ / 100) % 10, __TINYC__ % 100)
# endif
# if defined(ZPL_TINYC_VERSION_CHECK)
# undef ZPL_TINYC_VERSION_CHECK
# endif
# if defined(ZPL_TINYC_VERSION)
# define ZPL_TINYC_VERSION_CHECK(major,minor,patch) (ZPL_TINYC_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch))
# else
# define ZPL_TINYC_VERSION_CHECK(major,minor,patch) (0)
# endif
# if defined(ZPL_DMC_VERSION)
# undef ZPL_DMC_VERSION
# endif
# if defined(__DMC__)
# define ZPL_DMC_VERSION ZPL_VERSION_ENCODE(__DMC__ >> 8, (__DMC__ >> 4) & 0xf, __DMC__ & 0xf)
# endif
# if defined(ZPL_DMC_VERSION_CHECK)
# undef ZPL_DMC_VERSION_CHECK
# endif
# if defined(ZPL_DMC_VERSION)
# define ZPL_DMC_VERSION_CHECK(major,minor,patch) (ZPL_DMC_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch))
# else
# define ZPL_DMC_VERSION_CHECK(major,minor,patch) (0)
# endif
# if defined(ZPL_COMPCERT_VERSION)
# undef ZPL_COMPCERT_VERSION
# endif
# if defined(__COMPCERT_VERSION__)
# define ZPL_COMPCERT_VERSION ZPL_VERSION_ENCODE(__COMPCERT_VERSION__ / 10000, (__COMPCERT_VERSION__ / 100) % 100, __COMPCERT_VERSION__ % 100)
# endif
# if defined(ZPL_COMPCERT_VERSION_CHECK)
# undef ZPL_COMPCERT_VERSION_CHECK
# endif
# if defined(ZPL_COMPCERT_VERSION)
# define ZPL_COMPCERT_VERSION_CHECK(major,minor,patch) (ZPL_COMPCERT_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch))
# else
# define ZPL_COMPCERT_VERSION_CHECK(major,minor,patch) (0)
# endif
# if defined(ZPL_PELLES_VERSION)
# undef ZPL_PELLES_VERSION
# endif
# if defined(__POCC__)
# define ZPL_PELLES_VERSION ZPL_VERSION_ENCODE(__POCC__ / 100, __POCC__ % 100, 0)
# endif
# if defined(ZPL_PELLES_VERSION_CHECK)
# undef ZPL_PELLES_VERSION_CHECK
# endif
# if defined(ZPL_PELLES_VERSION)
# define ZPL_PELLES_VERSION_CHECK(major,minor,patch) (ZPL_PELLES_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch))
# else
# define ZPL_PELLES_VERSION_CHECK(major,minor,patch) (0)
# endif
# if defined(ZPL_GCC_VERSION)
# undef ZPL_GCC_VERSION
# endif
# if \
defined ( ZPL_GNUC_VERSION ) & & \
! defined ( __clang__ ) & & \
! defined ( ZPL_INTEL_VERSION ) & & \
! defined ( ZPL_PGI_VERSION ) & & \
! defined ( ZPL_ARM_VERSION ) & & \
! defined ( ZPL_TI_VERSION ) & & \
! defined ( ZPL_TI_ARMCL_VERSION ) & & \
! defined ( ZPL_TI_CL430_VERSION ) & & \
! defined ( ZPL_TI_CL2000_VERSION ) & & \
! defined ( ZPL_TI_CL6X_VERSION ) & & \
! defined ( ZPL_TI_CL7X_VERSION ) & & \
! defined ( ZPL_TI_CLPRU_VERSION ) & & \
! defined ( __COMPCERT__ )
# define ZPL_GCC_VERSION ZPL_GNUC_VERSION
# endif
# if defined(ZPL_GCC_VERSION_CHECK)
# undef ZPL_GCC_VERSION_CHECK
# endif
# if defined(ZPL_GCC_VERSION)
# define ZPL_GCC_VERSION_CHECK(major,minor,patch) (ZPL_GCC_VERSION >= ZPL_VERSION_ENCODE(major, minor, patch))
# else
# define ZPL_GCC_VERSION_CHECK(major,minor,patch) (0)
# endif
# if defined(ZPL_HAS_ATTRIBUTE)
# undef ZPL_HAS_ATTRIBUTE
# endif
# if defined(__has_attribute)
# define ZPL_HAS_ATTRIBUTE(attribute) __has_attribute(attribute)
# else
# define ZPL_HAS_ATTRIBUTE(attribute) (0)
# endif
# if defined(ZPL_GNUC_HAS_ATTRIBUTE)
# undef ZPL_GNUC_HAS_ATTRIBUTE
# endif
# if defined(__has_attribute)
# define ZPL_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) __has_attribute(attribute)
# else
# define ZPL_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) ZPL_GNUC_VERSION_CHECK(major,minor,patch)
# endif
# if defined(ZPL_GCC_HAS_ATTRIBUTE)
# undef ZPL_GCC_HAS_ATTRIBUTE
# endif
# if defined(__has_attribute)
# define ZPL_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) __has_attribute(attribute)
# else
# define ZPL_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) ZPL_GCC_VERSION_CHECK(major,minor,patch)
# endif
# if defined(ZPL_HAS_CPP_ATTRIBUTE)
# undef ZPL_HAS_CPP_ATTRIBUTE
# endif
# if \
defined ( __has_cpp_attribute ) & & \
defined ( __cplusplus ) & & \
( ! defined ( ZPL_SUNPRO_VERSION ) | | ZPL_SUNPRO_VERSION_CHECK ( 5 , 15 , 0 ) )
# define ZPL_HAS_CPP_ATTRIBUTE(attribute) __has_cpp_attribute(attribute)
# else
# define ZPL_HAS_CPP_ATTRIBUTE(attribute) (0)
# endif
# if defined(ZPL_HAS_CPP_ATTRIBUTE_NS)
# undef ZPL_HAS_CPP_ATTRIBUTE_NS
# endif
# if !defined(__cplusplus) || !defined(__has_cpp_attribute)
# define ZPL_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0)
# elif \
! defined ( ZPL_PGI_VERSION ) & & \
! defined ( ZPL_IAR_VERSION ) & & \
( ! defined ( ZPL_SUNPRO_VERSION ) | | ZPL_SUNPRO_VERSION_CHECK ( 5 , 15 , 0 ) ) & & \
( ! defined ( ZPL_MSVC_VERSION ) | | ZPL_MSVC_VERSION_CHECK ( 19 , 20 , 0 ) )
# define ZPL_HAS_CPP_ATTRIBUTE_NS(ns,attribute) ZPL_HAS_CPP_ATTRIBUTE(ns::attribute)
# else
# define ZPL_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0)
# endif
# if defined(ZPL_GNUC_HAS_CPP_ATTRIBUTE)
# undef ZPL_GNUC_HAS_CPP_ATTRIBUTE
# endif
# if defined(__has_cpp_attribute) && defined(__cplusplus)
# define ZPL_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute)
# else
# define ZPL_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) ZPL_GNUC_VERSION_CHECK(major,minor,patch)
# endif
# if defined(ZPL_GCC_HAS_CPP_ATTRIBUTE)
# undef ZPL_GCC_HAS_CPP_ATTRIBUTE
# endif
# if defined(__has_cpp_attribute) && defined(__cplusplus)
# define ZPL_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute)
# else
# define ZPL_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) ZPL_GCC_VERSION_CHECK(major,minor,patch)
# endif
# if defined(ZPL_HAS_BUILTIN)
# undef ZPL_HAS_BUILTIN
# endif
# if defined(__has_builtin)
# define ZPL_HAS_BUILTIN(builtin) __has_builtin(builtin)
# else
# define ZPL_HAS_BUILTIN(builtin) (0)
# endif
# if defined(ZPL_GNUC_HAS_BUILTIN)
# undef ZPL_GNUC_HAS_BUILTIN
# endif
# if defined(__has_builtin)
# define ZPL_GNUC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin)
# else
# define ZPL_GNUC_HAS_BUILTIN(builtin,major,minor,patch) ZPL_GNUC_VERSION_CHECK(major,minor,patch)
# endif
# if defined(ZPL_GCC_HAS_BUILTIN)
# undef ZPL_GCC_HAS_BUILTIN
# endif
# if defined(__has_builtin)
# define ZPL_GCC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin)
# else
# define ZPL_GCC_HAS_BUILTIN(builtin,major,minor,patch) ZPL_GCC_VERSION_CHECK(major,minor,patch)
# endif
# if defined(ZPL_HAS_FEATURE)
# undef ZPL_HAS_FEATURE
# endif
# if defined(__has_feature)
# define ZPL_HAS_FEATURE(feature) __has_feature(feature)
# else
# define ZPL_HAS_FEATURE(feature) (0)
# endif
# if defined(ZPL_GNUC_HAS_FEATURE)
# undef ZPL_GNUC_HAS_FEATURE
# endif
# if defined(__has_feature)
# define ZPL_GNUC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature)
# else
# define ZPL_GNUC_HAS_FEATURE(feature,major,minor,patch) ZPL_GNUC_VERSION_CHECK(major,minor,patch)
# endif
# if defined(ZPL_GCC_HAS_FEATURE)
# undef ZPL_GCC_HAS_FEATURE
# endif
# if defined(__has_feature)
# define ZPL_GCC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature)
# else
# define ZPL_GCC_HAS_FEATURE(feature,major,minor,patch) ZPL_GCC_VERSION_CHECK(major,minor,patch)
# endif
# if defined(ZPL_HAS_EXTENSION)
# undef ZPL_HAS_EXTENSION
# endif
# if defined(__has_extension)
# define ZPL_HAS_EXTENSION(extension) __has_extension(extension)
# else
# define ZPL_HAS_EXTENSION(extension) (0)
# endif
# if defined(ZPL_GNUC_HAS_EXTENSION)
# undef ZPL_GNUC_HAS_EXTENSION
# endif
# if defined(__has_extension)
# define ZPL_GNUC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension)
# else
# define ZPL_GNUC_HAS_EXTENSION(extension,major,minor,patch) ZPL_GNUC_VERSION_CHECK(major,minor,patch)
# endif
# if defined(ZPL_GCC_HAS_EXTENSION)
# undef ZPL_GCC_HAS_EXTENSION
# endif
# if defined(__has_extension)
# define ZPL_GCC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension)
# else
# define ZPL_GCC_HAS_EXTENSION(extension,major,minor,patch) ZPL_GCC_VERSION_CHECK(major,minor,patch)
# endif
# if defined(ZPL_HAS_DECLSPEC_ATTRIBUTE)
# undef ZPL_HAS_DECLSPEC_ATTRIBUTE
# endif
# if defined(__has_declspec_attribute)
# define ZPL_HAS_DECLSPEC_ATTRIBUTE(attribute) __has_declspec_attribute(attribute)
# else
# define ZPL_HAS_DECLSPEC_ATTRIBUTE(attribute) (0)
# endif
# if defined(ZPL_GNUC_HAS_DECLSPEC_ATTRIBUTE)
# undef ZPL_GNUC_HAS_DECLSPEC_ATTRIBUTE
# endif
# if defined(__has_declspec_attribute)
# define ZPL_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute)
# else
# define ZPL_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) ZPL_GNUC_VERSION_CHECK(major,minor,patch)
# endif
# if defined(ZPL_GCC_HAS_DECLSPEC_ATTRIBUTE)
# undef ZPL_GCC_HAS_DECLSPEC_ATTRIBUTE
# endif
# if defined(__has_declspec_attribute)
# define ZPL_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute)
# else
# define ZPL_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) ZPL_GCC_VERSION_CHECK(major,minor,patch)
# endif
# if defined(ZPL_HAS_WARNING)
# undef ZPL_HAS_WARNING
# endif
# if defined(__has_warning)
# define ZPL_HAS_WARNING(warning) __has_warning(warning)
# else
# define ZPL_HAS_WARNING(warning) (0)
# endif
# if defined(ZPL_GNUC_HAS_WARNING)
# undef ZPL_GNUC_HAS_WARNING
# endif
# if defined(__has_warning)
# define ZPL_GNUC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning)
# else
# define ZPL_GNUC_HAS_WARNING(warning,major,minor,patch) ZPL_GNUC_VERSION_CHECK(major,minor,patch)
# endif
# if defined(ZPL_GCC_HAS_WARNING)
# undef ZPL_GCC_HAS_WARNING
# endif
# if defined(__has_warning)
# define ZPL_GCC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning)
# else
# define ZPL_GCC_HAS_WARNING(warning,major,minor,patch) ZPL_GCC_VERSION_CHECK(major,minor,patch)
# endif
/* ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ is for
ZPL INTERNAL USE ONLY . API subject to change without notice . */
# if defined(ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_)
# undef ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_
# endif
# if defined(__cplusplus)
# if ZPL_HAS_WARNING("-Wc++98-compat")
# if ZPL_HAS_WARNING("-Wc++17-extensions")
# define ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \
ZPL_DIAGNOSTIC_PUSH \
_Pragma ( " clang diagnostic ignored \" -Wc++98-compat \" " ) \
_Pragma ( " clang diagnostic ignored \" -Wc++17-extensions \" " ) \
xpr \
ZPL_DIAGNOSTIC_POP
# else
# define ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \
ZPL_DIAGNOSTIC_PUSH \
_Pragma ( " clang diagnostic ignored \" -Wc++98-compat \" " ) \
xpr \
ZPL_DIAGNOSTIC_POP
# endif
# endif
# endif
# if !defined(ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_)
# define ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(x) x
# endif
# if defined(ZPL_CONST_CAST)
# undef ZPL_CONST_CAST
# endif
# if defined(__cplusplus)
# define ZPL_CONST_CAST(T, expr) (const_cast<T>(expr))
# elif \
ZPL_HAS_WARNING ( " -Wcast-qual " ) | | \
ZPL_GCC_VERSION_CHECK ( 4 , 6 , 0 ) | | \
ZPL_INTEL_VERSION_CHECK ( 13 , 0 , 0 )
# define ZPL_CONST_CAST(T, expr) (__extension__ ({ \
ZPL_DIAGNOSTIC_PUSH \
ZPL_DIAGNOSTIC_DISABLE_CAST_QUAL \
( ( T ) ( expr ) ) ; \
ZPL_DIAGNOSTIC_POP \
} ) )
# else
# define ZPL_CONST_CAST(T, expr) ((T) (expr))
# endif
# if defined(ZPL_REINTERPRET_CAST)
# undef ZPL_REINTERPRET_CAST
# endif
# if defined(__cplusplus)
# define ZPL_REINTERPRET_CAST(T, expr) (reinterpret_cast<T>(expr))
# else
# define ZPL_REINTERPRET_CAST(T, expr) ((T) (expr))
# endif
# if defined(ZPL_STATIC_CAST)
# undef ZPL_STATIC_CAST
# endif
# if defined(__cplusplus)
# define ZPL_STATIC_CAST(T, expr) (static_cast<T>(expr))
# else
# define ZPL_STATIC_CAST(T, expr) ((T) (expr))
# endif
# if defined(ZPL_CPP_CAST)
# undef ZPL_CPP_CAST
# endif
# if defined(__cplusplus)
# if ZPL_HAS_WARNING("-Wold-style-cast")
# define ZPL_CPP_CAST(T, expr) \
ZPL_DIAGNOSTIC_PUSH \
_Pragma ( " clang diagnostic ignored \" -Wold-style-cast \" " ) \
( ( T ) ( expr ) ) \
ZPL_DIAGNOSTIC_POP
# elif ZPL_IAR_VERSION_CHECK(8,3,0)
# define ZPL_CPP_CAST(T, expr) \
ZPL_DIAGNOSTIC_PUSH \
_Pragma ( " diag_suppress=Pe137 " ) \
ZPL_DIAGNOSTIC_POP \
# else
# define ZPL_CPP_CAST(T, expr) ((T) (expr))
# endif
# else
# define ZPL_CPP_CAST(T, expr) (expr)
# endif
# if \
( defined ( __STDC_VERSION__ ) & & ( __STDC_VERSION__ > = 199901L ) ) | | \
defined ( __clang__ ) | | \
ZPL_GCC_VERSION_CHECK ( 3 , 0 , 0 ) | | \
ZPL_INTEL_VERSION_CHECK ( 13 , 0 , 0 ) | | \
ZPL_IAR_VERSION_CHECK ( 8 , 0 , 0 ) | | \
ZPL_PGI_VERSION_CHECK ( 18 , 4 , 0 ) | | \
ZPL_ARM_VERSION_CHECK ( 4 , 1 , 0 ) | | \
ZPL_TI_VERSION_CHECK ( 15 , 12 , 0 ) | | \
ZPL_TI_ARMCL_VERSION_CHECK ( 4 , 7 , 0 ) | | \
ZPL_TI_CL430_VERSION_CHECK ( 2 , 0 , 1 ) | | \
ZPL_TI_CL2000_VERSION_CHECK ( 6 , 1 , 0 ) | | \
ZPL_TI_CL6X_VERSION_CHECK ( 7 , 0 , 0 ) | | \
ZPL_TI_CL7X_VERSION_CHECK ( 1 , 2 , 0 ) | | \
ZPL_TI_CLPRU_VERSION_CHECK ( 2 , 1 , 0 ) | | \
ZPL_CRAY_VERSION_CHECK ( 5 , 0 , 0 ) | | \
ZPL_TINYC_VERSION_CHECK ( 0 , 9 , 17 ) | | \
ZPL_SUNPRO_VERSION_CHECK ( 8 , 0 , 0 ) | | \
( ZPL_IBM_VERSION_CHECK ( 10 , 1 , 0 ) & & defined ( __C99_PRAGMA_OPERATOR ) )
# define ZPL_PRAGMA(value) _Pragma(#value)
# elif ZPL_MSVC_VERSION_CHECK(15,0,0)
# define ZPL_PRAGMA(value) __pragma(value)
# else
# define ZPL_PRAGMA(value)
# endif
# if defined(ZPL_DIAGNOSTIC_PUSH)
# undef ZPL_DIAGNOSTIC_PUSH
# endif
2023-01-15 15:59:33 +00:00
# if defined(ZPL_DIAGNOSTIC_PUSH_WARNLEVEL)
# undef ZPL_DIAGNOSTIC_PUSH_WARNLEVEL
# endif
2022-09-11 17:42:06 +00:00
# if defined(ZPL_DIAGNOSTIC_POP)
# undef ZPL_DIAGNOSTIC_POP
# endif
# if defined(__clang__)
# define ZPL_DIAGNOSTIC_PUSH _Pragma("clang diagnostic push")
2023-01-15 15:59:33 +00:00
# define ZPL_DIAGNOSTIC_PUSH_WARNLEVEL(x)
2022-09-11 17:42:06 +00:00
# define ZPL_DIAGNOSTIC_POP _Pragma("clang diagnostic pop")
# elif ZPL_INTEL_VERSION_CHECK(13,0,0)
# define ZPL_DIAGNOSTIC_PUSH _Pragma("warning(push)")
2023-01-15 15:59:33 +00:00
# define ZPL_DIAGNOSTIC_PUSH_WARNLEVEL(x)
2022-09-11 17:42:06 +00:00
# define ZPL_DIAGNOSTIC_POP _Pragma("warning(pop)")
# elif ZPL_GCC_VERSION_CHECK(4,6,0)
# define ZPL_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push")
2023-01-15 15:59:33 +00:00
# define ZPL_DIAGNOSTIC_PUSH_WARNLEVEL(x)
2022-09-11 17:42:06 +00:00
# define ZPL_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop")
# elif ZPL_MSVC_VERSION_CHECK(15,0,0)
# define ZPL_DIAGNOSTIC_PUSH __pragma(warning(push))
2023-01-15 15:59:33 +00:00
# define ZPL_DIAGNOSTIC_PUSH_WARNLEVEL(x) __pragma(warning(push, x))
2022-09-11 17:42:06 +00:00
# define ZPL_DIAGNOSTIC_POP __pragma(warning(pop))
# elif ZPL_ARM_VERSION_CHECK(5,6,0)
# define ZPL_DIAGNOSTIC_PUSH _Pragma("push")
# define ZPL_DIAGNOSTIC_POP _Pragma("pop")
# elif \
ZPL_TI_VERSION_CHECK ( 15 , 12 , 0 ) | | \
ZPL_TI_ARMCL_VERSION_CHECK ( 5 , 2 , 0 ) | | \
ZPL_TI_CL430_VERSION_CHECK ( 4 , 4 , 0 ) | | \
ZPL_TI_CL6X_VERSION_CHECK ( 8 , 1 , 0 ) | | \
ZPL_TI_CL7X_VERSION_CHECK ( 1 , 2 , 0 ) | | \
ZPL_TI_CLPRU_VERSION_CHECK ( 2 , 1 , 0 )
# define ZPL_DIAGNOSTIC_PUSH _Pragma("diag_push")
# define ZPL_DIAGNOSTIC_POP _Pragma("diag_pop")
# elif ZPL_PELLES_VERSION_CHECK(2,90,0)
# define ZPL_DIAGNOSTIC_PUSH _Pragma("warning(push)")
# define ZPL_DIAGNOSTIC_POP _Pragma("warning(pop)")
# else
# define ZPL_DIAGNOSTIC_PUSH
# define ZPL_DIAGNOSTIC_POP
# endif
# if defined(ZPL_DIAGNOSTIC_DISABLE_DEPRECATED)
# undef ZPL_DIAGNOSTIC_DISABLE_DEPRECATED
# endif
# if ZPL_HAS_WARNING("-Wdeprecated-declarations")
# define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"")
# elif ZPL_INTEL_VERSION_CHECK(13,0,0)
# define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warning(disable:1478 1786)")
# elif ZPL_PGI_VERSION_CHECK(17,10,0)
# define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444")
# elif ZPL_GCC_VERSION_CHECK(4,3,0)
# define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
# elif ZPL_MSVC_VERSION_CHECK(15,0,0)
# define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:4996))
# elif \
ZPL_TI_VERSION_CHECK ( 15 , 12 , 0 ) | | \
( ZPL_TI_ARMCL_VERSION_CHECK ( 4 , 8 , 0 ) & & defined ( __TI_GNU_ATTRIBUTE_SUPPORT__ ) ) | | \
ZPL_TI_ARMCL_VERSION_CHECK ( 5 , 2 , 0 ) | | \
( ZPL_TI_CL2000_VERSION_CHECK ( 6 , 0 , 0 ) & & defined ( __TI_GNU_ATTRIBUTE_SUPPORT__ ) ) | | \
ZPL_TI_CL2000_VERSION_CHECK ( 6 , 4 , 0 ) | | \
( ZPL_TI_CL430_VERSION_CHECK ( 4 , 0 , 0 ) & & defined ( __TI_GNU_ATTRIBUTE_SUPPORT__ ) ) | | \
ZPL_TI_CL430_VERSION_CHECK ( 4 , 3 , 0 ) | | \
( ZPL_TI_CL6X_VERSION_CHECK ( 7 , 2 , 0 ) & & defined ( __TI_GNU_ATTRIBUTE_SUPPORT__ ) ) | | \
ZPL_TI_CL6X_VERSION_CHECK ( 7 , 5 , 0 ) | | \
ZPL_TI_CL7X_VERSION_CHECK ( 1 , 2 , 0 ) | | \
ZPL_TI_CLPRU_VERSION_CHECK ( 2 , 1 , 0 )
# define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1291,1718")
# elif ZPL_SUNPRO_VERSION_CHECK(5,13,0) && !defined(__cplusplus)
# define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)")
# elif ZPL_SUNPRO_VERSION_CHECK(5,13,0) && defined(__cplusplus)
# define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,symdeprecated,symdeprecated2)")
# elif ZPL_IAR_VERSION_CHECK(8,0,0)
# define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress=Pe1444,Pe1215")
# elif ZPL_PELLES_VERSION_CHECK(2,90,0)
# define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warn(disable:2241)")
# else
# define ZPL_DIAGNOSTIC_DISABLE_DEPRECATED
# endif
# if defined(ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS)
# undef ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS
# endif
# if ZPL_HAS_WARNING("-Wunknown-pragmas")
# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"")
# elif ZPL_INTEL_VERSION_CHECK(13,0,0)
# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("warning(disable:161)")
# elif ZPL_PGI_VERSION_CHECK(17,10,0)
# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 1675")
# elif ZPL_GCC_VERSION_CHECK(4,3,0)
# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("GCC diagnostic ignored \"-Wunknown-pragmas\"")
# elif ZPL_MSVC_VERSION_CHECK(15,0,0)
# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:4068))
# elif \
ZPL_TI_VERSION_CHECK ( 16 , 9 , 0 ) | | \
ZPL_TI_CL6X_VERSION_CHECK ( 8 , 0 , 0 ) | | \
ZPL_TI_CL7X_VERSION_CHECK ( 1 , 2 , 0 ) | | \
ZPL_TI_CLPRU_VERSION_CHECK ( 2 , 3 , 0 )
# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163")
# elif ZPL_TI_CL6X_VERSION_CHECK(8,0,0)
# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163")
# elif ZPL_IAR_VERSION_CHECK(8,0,0)
# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress=Pe161")
# else
# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS
# endif
# if defined(ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES)
# undef ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES
# endif
# if ZPL_HAS_WARNING("-Wunknown-attributes")
# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("clang diagnostic ignored \"-Wunknown-attributes\"")
# elif ZPL_GCC_VERSION_CHECK(4,6,0)
# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
# elif ZPL_INTEL_VERSION_CHECK(17,0,0)
# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("warning(disable:1292)")
# elif ZPL_MSVC_VERSION_CHECK(19,0,0)
# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:5030))
# elif ZPL_PGI_VERSION_CHECK(17,10,0)
# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097")
# elif ZPL_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)
# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("error_messages(off,attrskipunsup)")
# elif \
ZPL_TI_VERSION_CHECK ( 18 , 1 , 0 ) | | \
ZPL_TI_CL6X_VERSION_CHECK ( 8 , 3 , 0 ) | | \
ZPL_TI_CL7X_VERSION_CHECK ( 1 , 2 , 0 )
# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1173")
# elif ZPL_IAR_VERSION_CHECK(8,0,0)
# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress=Pe1097")
# else
# define ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES
# endif
# if defined(ZPL_DIAGNOSTIC_DISABLE_CAST_QUAL)
# undef ZPL_DIAGNOSTIC_DISABLE_CAST_QUAL
# endif
# if ZPL_HAS_WARNING("-Wcast-qual")
# define ZPL_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("clang diagnostic ignored \"-Wcast-qual\"")
# elif ZPL_INTEL_VERSION_CHECK(13,0,0)
# define ZPL_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("warning(disable:2203 2331)")
# elif ZPL_GCC_VERSION_CHECK(3,0,0)
# define ZPL_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
# else
# define ZPL_DIAGNOSTIC_DISABLE_CAST_QUAL
# endif
# if defined(ZPL_DEPRECATED)
# undef ZPL_DEPRECATED
# endif
# if defined(ZPL_DEPRECATED_FOR)
# undef ZPL_DEPRECATED_FOR
# endif
# if defined(__cplusplus) && (__cplusplus >= 201402L)
# define ZPL_DEPRECATED(since) ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since)]])
# define ZPL_DEPRECATED_FOR(since, replacement) ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since "; use " #replacement)]])
# elif \
ZPL_HAS_EXTENSION ( attribute_deprecated_with_message ) | | \
ZPL_GCC_VERSION_CHECK ( 4 , 5 , 0 ) | | \
ZPL_INTEL_VERSION_CHECK ( 13 , 0 , 0 ) | | \
ZPL_ARM_VERSION_CHECK ( 5 , 6 , 0 ) | | \
ZPL_SUNPRO_VERSION_CHECK ( 5 , 13 , 0 ) | | \
ZPL_PGI_VERSION_CHECK ( 17 , 10 , 0 ) | | \
ZPL_TI_VERSION_CHECK ( 18 , 1 , 0 ) | | \
ZPL_TI_ARMCL_VERSION_CHECK ( 18 , 1 , 0 ) | | \
ZPL_TI_CL6X_VERSION_CHECK ( 8 , 3 , 0 ) | | \
ZPL_TI_CL7X_VERSION_CHECK ( 1 , 2 , 0 ) | | \
ZPL_TI_CLPRU_VERSION_CHECK ( 2 , 3 , 0 )
# define ZPL_DEPRECATED(since) __attribute__((__deprecated__("Since " #since)))
# define ZPL_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__("Since " #since "; use " #replacement)))
# elif \
ZPL_HAS_ATTRIBUTE ( deprecated ) | | \
ZPL_GCC_VERSION_CHECK ( 3 , 1 , 0 ) | | \
ZPL_ARM_VERSION_CHECK ( 4 , 1 , 0 ) | | \
ZPL_TI_VERSION_CHECK ( 15 , 12 , 0 ) | | \
( ZPL_TI_ARMCL_VERSION_CHECK ( 4 , 8 , 0 ) & & defined ( __TI_GNU_ATTRIBUTE_SUPPORT__ ) ) | | \
ZPL_TI_ARMCL_VERSION_CHECK ( 5 , 2 , 0 ) | | \
( ZPL_TI_CL2000_VERSION_CHECK ( 6 , 0 , 0 ) & & defined ( __TI_GNU_ATTRIBUTE_SUPPORT__ ) ) | | \
ZPL_TI_CL2000_VERSION_CHECK ( 6 , 4 , 0 ) | | \
( ZPL_TI_CL430_VERSION_CHECK ( 4 , 0 , 0 ) & & defined ( __TI_GNU_ATTRIBUTE_SUPPORT__ ) ) | | \
ZPL_TI_CL430_VERSION_CHECK ( 4 , 3 , 0 ) | | \
( ZPL_TI_CL6X_VERSION_CHECK ( 7 , 2 , 0 ) & & defined ( __TI_GNU_ATTRIBUTE_SUPPORT__ ) ) | | \
ZPL_TI_CL6X_VERSION_CHECK ( 7 , 5 , 0 ) | | \
ZPL_TI_CL7X_VERSION_CHECK ( 1 , 2 , 0 ) | | \
ZPL_TI_CLPRU_VERSION_CHECK ( 2 , 1 , 0 )
# define ZPL_DEPRECATED(since) __attribute__((__deprecated__))
# define ZPL_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__))
# elif ZPL_MSVC_VERSION_CHECK(14,0,0)
# define ZPL_DEPRECATED(since) __declspec(deprecated("Since " # since))
# define ZPL_DEPRECATED_FOR(since, replacement) __declspec(deprecated("Since " #since "; use " #replacement))
# elif \
ZPL_MSVC_VERSION_CHECK ( 13 , 10 , 0 ) | | \
ZPL_PELLES_VERSION_CHECK ( 6 , 50 , 0 )
# define ZPL_DEPRECATED(since) __declspec(deprecated)
# define ZPL_DEPRECATED_FOR(since, replacement) __declspec(deprecated)
# elif ZPL_IAR_VERSION_CHECK(8,0,0)
# define ZPL_DEPRECATED(since) _Pragma("deprecated")
# define ZPL_DEPRECATED_FOR(since, replacement) _Pragma("deprecated")
# else
# define ZPL_DEPRECATED(since)
# define ZPL_DEPRECATED_FOR(since, replacement)
# endif
# if defined(ZPL_UNAVAILABLE)
# undef ZPL_UNAVAILABLE
# endif
# if \
ZPL_HAS_ATTRIBUTE ( warning ) | | \
ZPL_GCC_VERSION_CHECK ( 4 , 3 , 0 ) | | \
ZPL_INTEL_VERSION_CHECK ( 13 , 0 , 0 )
# define ZPL_UNAVAILABLE(available_since) __attribute__((__warning__("Not available until " #available_since)))
# else
# define ZPL_UNAVAILABLE(available_since)
# endif
# if defined(ZPL_WARN_UNUSED_RESULT)
# undef ZPL_WARN_UNUSED_RESULT
# endif
# if defined(ZPL_WARN_UNUSED_RESULT_MSG)
# undef ZPL_WARN_UNUSED_RESULT_MSG
# endif
# if (ZPL_HAS_CPP_ATTRIBUTE(nodiscard) >= 201907L)
# define ZPL_WARN_UNUSED_RESULT ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]])
# define ZPL_WARN_UNUSED_RESULT_MSG(msg) ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard(msg)]])
# elif ZPL_HAS_CPP_ATTRIBUTE(nodiscard)
# define ZPL_WARN_UNUSED_RESULT ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]])
# define ZPL_WARN_UNUSED_RESULT_MSG(msg) ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]])
# elif \
ZPL_HAS_ATTRIBUTE ( warn_unused_result ) | | \
ZPL_GCC_VERSION_CHECK ( 3 , 4 , 0 ) | | \
ZPL_INTEL_VERSION_CHECK ( 13 , 0 , 0 ) | | \
ZPL_TI_VERSION_CHECK ( 15 , 12 , 0 ) | | \
( ZPL_TI_ARMCL_VERSION_CHECK ( 4 , 8 , 0 ) & & defined ( __TI_GNU_ATTRIBUTE_SUPPORT__ ) ) | | \
ZPL_TI_ARMCL_VERSION_CHECK ( 5 , 2 , 0 ) | | \
( ZPL_TI_CL2000_VERSION_CHECK ( 6 , 0 , 0 ) & & defined ( __TI_GNU_ATTRIBUTE_SUPPORT__ ) ) | | \
ZPL_TI_CL2000_VERSION_CHECK ( 6 , 4 , 0 ) | | \
( ZPL_TI_CL430_VERSION_CHECK ( 4 , 0 , 0 ) & & defined ( __TI_GNU_ATTRIBUTE_SUPPORT__ ) ) | | \
ZPL_TI_CL430_VERSION_CHECK ( 4 , 3 , 0 ) | | \
( ZPL_TI_CL6X_VERSION_CHECK ( 7 , 2 , 0 ) & & defined ( __TI_GNU_ATTRIBUTE_SUPPORT__ ) ) | | \
ZPL_TI_CL6X_VERSION_CHECK ( 7 , 5 , 0 ) | | \
ZPL_TI_CL7X_VERSION_CHECK ( 1 , 2 , 0 ) | | \
ZPL_TI_CLPRU_VERSION_CHECK ( 2 , 1 , 0 ) | | \
( ZPL_SUNPRO_VERSION_CHECK ( 5 , 15 , 0 ) & & defined ( __cplusplus ) ) | | \
ZPL_PGI_VERSION_CHECK ( 17 , 10 , 0 )
# define ZPL_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__))
# define ZPL_WARN_UNUSED_RESULT_MSG(msg) __attribute__((__warn_unused_result__))
# elif defined(_Check_return_) /* SAL */
# define ZPL_WARN_UNUSED_RESULT _Check_return_
# define ZPL_WARN_UNUSED_RESULT_MSG(msg) _Check_return_
# else
# define ZPL_WARN_UNUSED_RESULT
# define ZPL_WARN_UNUSED_RESULT_MSG(msg)
# endif
# if defined(ZPL_SENTINEL)
# undef ZPL_SENTINEL
# endif
# if \
ZPL_HAS_ATTRIBUTE ( sentinel ) | | \
ZPL_GCC_VERSION_CHECK ( 4 , 0 , 0 ) | | \
ZPL_INTEL_VERSION_CHECK ( 13 , 0 , 0 ) | | \
ZPL_ARM_VERSION_CHECK ( 5 , 4 , 0 )
# define ZPL_SENTINEL(position) __attribute__((__sentinel__(position)))
# else
# define ZPL_SENTINEL(position)
# endif
# if defined(ZPL_NO_RETURN)
# undef ZPL_NO_RETURN
# endif
# if ZPL_IAR_VERSION_CHECK(8,0,0)
# define ZPL_NO_RETURN __noreturn
# elif ZPL_INTEL_VERSION_CHECK(13,0,0)
# define ZPL_NO_RETURN __attribute__((__noreturn__))
# elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
# define ZPL_NO_RETURN _Noreturn
# elif defined(__cplusplus) && (__cplusplus >= 201103L)
# define ZPL_NO_RETURN ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[noreturn]])
# elif \
ZPL_HAS_ATTRIBUTE ( noreturn ) | | \
ZPL_GCC_VERSION_CHECK ( 3 , 2 , 0 ) | | \
ZPL_SUNPRO_VERSION_CHECK ( 5 , 11 , 0 ) | | \
ZPL_ARM_VERSION_CHECK ( 4 , 1 , 0 ) | | \
ZPL_IBM_VERSION_CHECK ( 10 , 1 , 0 ) | | \
ZPL_TI_VERSION_CHECK ( 15 , 12 , 0 ) | | \
( ZPL_TI_ARMCL_VERSION_CHECK ( 4 , 8 , 0 ) & & defined ( __TI_GNU_ATTRIBUTE_SUPPORT__ ) ) | | \
ZPL_TI_ARMCL_VERSION_CHECK ( 5 , 2 , 0 ) | | \
( ZPL_TI_CL2000_VERSION_CHECK ( 6 , 0 , 0 ) & & defined ( __TI_GNU_ATTRIBUTE_SUPPORT__ ) ) | | \
ZPL_TI_CL2000_VERSION_CHECK ( 6 , 4 , 0 ) | | \
( ZPL_TI_CL430_VERSION_CHECK ( 4 , 0 , 0 ) & & defined ( __TI_GNU_ATTRIBUTE_SUPPORT__ ) ) | | \
ZPL_TI_CL430_VERSION_CHECK ( 4 , 3 , 0 ) | | \
( ZPL_TI_CL6X_VERSION_CHECK ( 7 , 2 , 0 ) & & defined ( __TI_GNU_ATTRIBUTE_SUPPORT__ ) ) | | \
ZPL_TI_CL6X_VERSION_CHECK ( 7 , 5 , 0 ) | | \
ZPL_TI_CL7X_VERSION_CHECK ( 1 , 2 , 0 ) | | \
ZPL_TI_CLPRU_VERSION_CHECK ( 2 , 1 , 0 )
# define ZPL_NO_RETURN __attribute__((__noreturn__))
# elif ZPL_SUNPRO_VERSION_CHECK(5,10,0)
# define ZPL_NO_RETURN _Pragma("does_not_return")
# elif ZPL_MSVC_VERSION_CHECK(13,10,0)
# define ZPL_NO_RETURN __declspec(noreturn)
# elif ZPL_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus)
# define ZPL_NO_RETURN _Pragma("FUNC_NEVER_RETURNS;")
# elif ZPL_COMPCERT_VERSION_CHECK(3,2,0)
# define ZPL_NO_RETURN __attribute((noreturn))
# elif ZPL_PELLES_VERSION_CHECK(9,0,0)
# define ZPL_NO_RETURN __declspec(noreturn)
# else
# define ZPL_NO_RETURN
# endif
# if defined(ZPL_NO_ESCAPE)
# undef ZPL_NO_ESCAPE
# endif
# if ZPL_HAS_ATTRIBUTE(noescape)
# define ZPL_NO_ESCAPE __attribute__((__noescape__))
# else
# define ZPL_NO_ESCAPE
# endif
# if defined(ZPL_UNREACHABLE)
# undef ZPL_UNREACHABLE
# endif
# if defined(ZPL_UNREACHABLE_RETURN)
# undef ZPL_UNREACHABLE_RETURN
# endif
# if defined(ZPL_ASSUME)
# undef ZPL_ASSUME
# endif
# if \
ZPL_MSVC_VERSION_CHECK ( 13 , 10 , 0 ) | | \
ZPL_INTEL_VERSION_CHECK ( 13 , 0 , 0 )
# define ZPL_ASSUME(expr) __assume(expr)
# elif ZPL_HAS_BUILTIN(__builtin_assume)
# define ZPL_ASSUME(expr) __builtin_assume(expr)
# elif \
ZPL_TI_CL2000_VERSION_CHECK ( 6 , 2 , 0 ) | | \
ZPL_TI_CL6X_VERSION_CHECK ( 4 , 0 , 0 )
# if defined(__cplusplus)
# define ZPL_ASSUME(expr) std::_nassert(expr)
# else
# define ZPL_ASSUME(expr) _nassert(expr)
# endif
# endif
# if \
( ZPL_HAS_BUILTIN ( __builtin_unreachable ) & & ( ! defined ( ZPL_ARM_VERSION ) ) ) | | \
ZPL_GCC_VERSION_CHECK ( 4 , 5 , 0 ) | | \
ZPL_PGI_VERSION_CHECK ( 18 , 10 , 0 ) | | \
ZPL_INTEL_VERSION_CHECK ( 13 , 0 , 0 ) | | \
ZPL_IBM_VERSION_CHECK ( 13 , 1 , 5 )
# define ZPL_UNREACHABLE() __builtin_unreachable()
# elif defined(ZPL_ASSUME)
# define ZPL_UNREACHABLE() ZPL_ASSUME(0)
# endif
# if !defined(ZPL_ASSUME)
# if defined(ZPL_UNREACHABLE)
# define ZPL_ASSUME(expr) ZPL_STATIC_CAST(void, ((expr) ? 1 : (ZPL_UNREACHABLE(), 1)))
# else
# define ZPL_ASSUME(expr) ZPL_STATIC_CAST(void, expr)
# endif
# endif
# if defined(ZPL_UNREACHABLE)
# if \
ZPL_TI_CL2000_VERSION_CHECK ( 6 , 2 , 0 ) | | \
ZPL_TI_CL6X_VERSION_CHECK ( 4 , 0 , 0 )
# define ZPL_UNREACHABLE_RETURN(value) return (ZPL_STATIC_CAST(void, ZPL_ASSUME(0)), (value))
# else
# define ZPL_UNREACHABLE_RETURN(value) ZPL_UNREACHABLE()
# endif
# else
# define ZPL_UNREACHABLE_RETURN(value) return (value)
# endif
# if !defined(ZPL_UNREACHABLE)
# define ZPL_UNREACHABLE() ZPL_ASSUME(0)
# endif
ZPL_DIAGNOSTIC_PUSH
# if ZPL_HAS_WARNING("-Wpedantic")
# pragma clang diagnostic ignored "-Wpedantic"
# endif
# if ZPL_HAS_WARNING("-Wc++98-compat-pedantic") && defined(__cplusplus)
# pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
# endif
# if ZPL_GCC_HAS_WARNING("-Wvariadic-macros",4,0,0)
# if defined(__clang__)
# pragma clang diagnostic ignored "-Wvariadic-macros"
# elif defined(ZPL_GCC_VERSION)
# pragma GCC diagnostic ignored "-Wvariadic-macros"
# endif
# endif
# if defined(ZPL_NON_NULL)
# undef ZPL_NON_NULL
# endif
# if \
ZPL_HAS_ATTRIBUTE ( nonnull ) | | \
ZPL_GCC_VERSION_CHECK ( 3 , 3 , 0 ) | | \
ZPL_INTEL_VERSION_CHECK ( 13 , 0 , 0 ) | | \
ZPL_ARM_VERSION_CHECK ( 4 , 1 , 0 )
# define ZPL_NON_NULL(...) __attribute__((__nonnull__(__VA_ARGS__)))
# else
# define ZPL_NON_NULL(...)
# endif
ZPL_DIAGNOSTIC_POP
# if defined(ZPL_PRINTF_FORMAT)
# undef ZPL_PRINTF_FORMAT
# endif
# if defined(__MINGW32__) && ZPL_GCC_HAS_ATTRIBUTE(format,4,4,0) && !defined(__USE_MINGW_ANSI_STDIO)
# define ZPL_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(ms_printf, string_idx, first_to_check)))
# elif defined(__MINGW32__) && ZPL_GCC_HAS_ATTRIBUTE(format,4,4,0) && defined(__USE_MINGW_ANSI_STDIO)
# define ZPL_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(gnu_printf, string_idx, first_to_check)))
# elif \
ZPL_HAS_ATTRIBUTE ( format ) | | \
ZPL_GCC_VERSION_CHECK ( 3 , 1 , 0 ) | | \
ZPL_INTEL_VERSION_CHECK ( 13 , 0 , 0 ) | | \
ZPL_ARM_VERSION_CHECK ( 5 , 6 , 0 ) | | \
ZPL_IBM_VERSION_CHECK ( 10 , 1 , 0 ) | | \
ZPL_TI_VERSION_CHECK ( 15 , 12 , 0 ) | | \
( ZPL_TI_ARMCL_VERSION_CHECK ( 4 , 8 , 0 ) & & defined ( __TI_GNU_ATTRIBUTE_SUPPORT__ ) ) | | \
ZPL_TI_ARMCL_VERSION_CHECK ( 5 , 2 , 0 ) | | \
( ZPL_TI_CL2000_VERSION_CHECK ( 6 , 0 , 0 ) & & defined ( __TI_GNU_ATTRIBUTE_SUPPORT__ ) ) | | \
ZPL_TI_CL2000_VERSION_CHECK ( 6 , 4 , 0 ) | | \
( ZPL_TI_CL430_VERSION_CHECK ( 4 , 0 , 0 ) & & defined ( __TI_GNU_ATTRIBUTE_SUPPORT__ ) ) | | \
ZPL_TI_CL430_VERSION_CHECK ( 4 , 3 , 0 ) | | \
( ZPL_TI_CL6X_VERSION_CHECK ( 7 , 2 , 0 ) & & defined ( __TI_GNU_ATTRIBUTE_SUPPORT__ ) ) | | \
ZPL_TI_CL6X_VERSION_CHECK ( 7 , 5 , 0 ) | | \
ZPL_TI_CL7X_VERSION_CHECK ( 1 , 2 , 0 ) | | \
ZPL_TI_CLPRU_VERSION_CHECK ( 2 , 1 , 0 )
# define ZPL_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(__printf__, string_idx, first_to_check)))
# elif ZPL_PELLES_VERSION_CHECK(6,0,0)
# define ZPL_PRINTF_FORMAT(string_idx,first_to_check) __declspec(vaformat(printf,string_idx,first_to_check))
# else
# define ZPL_PRINTF_FORMAT(string_idx,first_to_check)
# endif
# if defined(ZPL_CONSTEXPR)
# undef ZPL_CONSTEXPR
# endif
# if defined(__cplusplus)
# if __cplusplus >= 201103L
# define ZPL_CONSTEXPR ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(constexpr)
# endif
# endif
# if !defined(ZPL_CONSTEXPR)
# define ZPL_CONSTEXPR
# endif
# if defined(ZPL_PREDICT)
# undef ZPL_PREDICT
# endif
# if defined(ZPL_LIKELY)
# undef ZPL_LIKELY
# endif
# if defined(ZPL_UNLIKELY)
# undef ZPL_UNLIKELY
# endif
# if defined(ZPL_UNPREDICTABLE)
# undef ZPL_UNPREDICTABLE
# endif
# if ZPL_HAS_BUILTIN(__builtin_unpredictable)
# define ZPL_UNPREDICTABLE(expr) __builtin_unpredictable((expr))
# endif
# if \
ZPL_HAS_BUILTIN ( __builtin_expect_with_probability ) | | \
ZPL_GCC_VERSION_CHECK ( 9 , 0 , 0 )
# define ZPL_PREDICT(expr, value, probability) __builtin_expect_with_probability( (expr), (value), (probability))
# define ZPL_PREDICT_TRUE(expr, probability) __builtin_expect_with_probability(!!(expr), 1 , (probability))
# define ZPL_PREDICT_FALSE(expr, probability) __builtin_expect_with_probability(!!(expr), 0 , (probability))
# define ZPL_LIKELY(expr) __builtin_expect (!!(expr), 1 )
# define ZPL_UNLIKELY(expr) __builtin_expect (!!(expr), 0 )
# elif \
ZPL_HAS_BUILTIN ( __builtin_expect ) | | \
ZPL_GCC_VERSION_CHECK ( 3 , 0 , 0 ) | | \
ZPL_INTEL_VERSION_CHECK ( 13 , 0 , 0 ) | | \
( ZPL_SUNPRO_VERSION_CHECK ( 5 , 15 , 0 ) & & defined ( __cplusplus ) ) | | \
ZPL_ARM_VERSION_CHECK ( 4 , 1 , 0 ) | | \
ZPL_IBM_VERSION_CHECK ( 10 , 1 , 0 ) | | \
ZPL_TI_VERSION_CHECK ( 15 , 12 , 0 ) | | \
ZPL_TI_ARMCL_VERSION_CHECK ( 4 , 7 , 0 ) | | \
ZPL_TI_CL430_VERSION_CHECK ( 3 , 1 , 0 ) | | \
ZPL_TI_CL2000_VERSION_CHECK ( 6 , 1 , 0 ) | | \
ZPL_TI_CL6X_VERSION_CHECK ( 6 , 1 , 0 ) | | \
ZPL_TI_CL7X_VERSION_CHECK ( 1 , 2 , 0 ) | | \
ZPL_TI_CLPRU_VERSION_CHECK ( 2 , 1 , 0 ) | | \
ZPL_TINYC_VERSION_CHECK ( 0 , 9 , 27 ) | | \
ZPL_CRAY_VERSION_CHECK ( 8 , 1 , 0 )
# define ZPL_PREDICT(expr, expected, probability) \
( ( ( probability ) > = 0.9 ) ? __builtin_expect ( ( expr ) , ( expected ) ) : ( ZPL_STATIC_CAST ( void , expected ) , ( expr ) ) )
# define ZPL_PREDICT_TRUE(expr, probability) \
( __extension__ ( { \
double zpl_probability_ = ( probability ) ; \
( ( zpl_probability_ > = 0.9 ) ? __builtin_expect ( ! ! ( expr ) , 1 ) : ( ( zpl_probability_ < = 0.1 ) ? __builtin_expect ( ! ! ( expr ) , 0 ) : ! ! ( expr ) ) ) ; \
} ) )
# define ZPL_PREDICT_FALSE(expr, probability) \
( __extension__ ( { \
double zpl_probability_ = ( probability ) ; \
( ( zpl_probability_ > = 0.9 ) ? __builtin_expect ( ! ! ( expr ) , 0 ) : ( ( zpl_probability_ < = 0.1 ) ? __builtin_expect ( ! ! ( expr ) , 1 ) : ! ! ( expr ) ) ) ; \
} ) )
# define ZPL_LIKELY(expr) __builtin_expect(!!(expr), 1)
# define ZPL_UNLIKELY(expr) __builtin_expect(!!(expr), 0)
# else
# define ZPL_PREDICT(expr, expected, probability) (ZPL_STATIC_CAST(void, expected), (expr))
# define ZPL_PREDICT_TRUE(expr, probability) (!!(expr))
# define ZPL_PREDICT_FALSE(expr, probability) (!!(expr))
# define ZPL_LIKELY(expr) (!!(expr))
# define ZPL_UNLIKELY(expr) (!!(expr))
# endif
# if !defined(ZPL_UNPREDICTABLE)
# define ZPL_UNPREDICTABLE(expr) ZPL_PREDICT(expr, 1, 0.5)
# endif
# if defined(ZPL_MALLOC)
# undef ZPL_MALLOC
# endif
# if \
ZPL_HAS_ATTRIBUTE ( malloc ) | | \
ZPL_GCC_VERSION_CHECK ( 3 , 1 , 0 ) | | \
ZPL_INTEL_VERSION_CHECK ( 13 , 0 , 0 ) | | \
ZPL_SUNPRO_VERSION_CHECK ( 5 , 11 , 0 ) | | \
ZPL_ARM_VERSION_CHECK ( 4 , 1 , 0 ) | | \
ZPL_IBM_VERSION_CHECK ( 12 , 1 , 0 ) | | \
ZPL_TI_VERSION_CHECK ( 15 , 12 , 0 ) | | \
( ZPL_TI_ARMCL_VERSION_CHECK ( 4 , 8 , 0 ) & & defined ( __TI_GNU_ATTRIBUTE_SUPPORT__ ) ) | | \
ZPL_TI_ARMCL_VERSION_CHECK ( 5 , 2 , 0 ) | | \
( ZPL_TI_CL2000_VERSION_CHECK ( 6 , 0 , 0 ) & & defined ( __TI_GNU_ATTRIBUTE_SUPPORT__ ) ) | | \
ZPL_TI_CL2000_VERSION_CHECK ( 6 , 4 , 0 ) | | \
( ZPL_TI_CL430_VERSION_CHECK ( 4 , 0 , 0 ) & & defined ( __TI_GNU_ATTRIBUTE_SUPPORT__ ) ) | | \
ZPL_TI_CL430_VERSION_CHECK ( 4 , 3 , 0 ) | | \
( ZPL_TI_CL6X_VERSION_CHECK ( 7 , 2 , 0 ) & & defined ( __TI_GNU_ATTRIBUTE_SUPPORT__ ) ) | | \
ZPL_TI_CL6X_VERSION_CHECK ( 7 , 5 , 0 ) | | \
ZPL_TI_CL7X_VERSION_CHECK ( 1 , 2 , 0 ) | | \
ZPL_TI_CLPRU_VERSION_CHECK ( 2 , 1 , 0 )
# define ZPL_MALLOC __attribute__((__malloc__))
# elif ZPL_SUNPRO_VERSION_CHECK(5,10,0)
# define ZPL_MALLOC _Pragma("returns_new_memory")
# elif ZPL_MSVC_VERSION_CHECK(14, 0, 0)
# define ZPL_MALLOC __declspec(restrict)
# else
# define ZPL_MALLOC
# endif
# if defined(ZPL_PURE)
# undef ZPL_PURE
# endif
# if \
ZPL_HAS_ATTRIBUTE ( pure ) | | \
ZPL_GCC_VERSION_CHECK ( 2 , 96 , 0 ) | | \
ZPL_INTEL_VERSION_CHECK ( 13 , 0 , 0 ) | | \
ZPL_SUNPRO_VERSION_CHECK ( 5 , 11 , 0 ) | | \
ZPL_ARM_VERSION_CHECK ( 4 , 1 , 0 ) | | \
ZPL_IBM_VERSION_CHECK ( 10 , 1 , 0 ) | | \
ZPL_TI_VERSION_CHECK ( 15 , 12 , 0 ) | | \
( ZPL_TI_ARMCL_VERSION_CHECK ( 4 , 8 , 0 ) & & defined ( __TI_GNU_ATTRIBUTE_SUPPORT__ ) ) | | \
ZPL_TI_ARMCL_VERSION_CHECK ( 5 , 2 , 0 ) | | \
( ZPL_TI_CL2000_VERSION_CHECK ( 6 , 0 , 0 ) & & defined ( __TI_GNU_ATTRIBUTE_SUPPORT__ ) ) | | \
ZPL_TI_CL2000_VERSION_CHECK ( 6 , 4 , 0 ) | | \
( ZPL_TI_CL430_VERSION_CHECK ( 4 , 0 , 0 ) & & defined ( __TI_GNU_ATTRIBUTE_SUPPORT__ ) ) | | \
ZPL_TI_CL430_VERSION_CHECK ( 4 , 3 , 0 ) | | \
( ZPL_TI_CL6X_VERSION_CHECK ( 7 , 2 , 0 ) & & defined ( __TI_GNU_ATTRIBUTE_SUPPORT__ ) ) | | \
ZPL_TI_CL6X_VERSION_CHECK ( 7 , 5 , 0 ) | | \
ZPL_TI_CL7X_VERSION_CHECK ( 1 , 2 , 0 ) | | \
ZPL_TI_CLPRU_VERSION_CHECK ( 2 , 1 , 0 ) | | \
ZPL_PGI_VERSION_CHECK ( 17 , 10 , 0 )
# define ZPL_PURE __attribute__((__pure__))
# elif ZPL_SUNPRO_VERSION_CHECK(5,10,0)
# define ZPL_PURE _Pragma("does_not_write_global_data")
# elif defined(__cplusplus) && \
( \
ZPL_TI_CL430_VERSION_CHECK ( 2 , 0 , 1 ) | | \
ZPL_TI_CL6X_VERSION_CHECK ( 4 , 0 , 0 ) | | \
ZPL_TI_CL7X_VERSION_CHECK ( 1 , 2 , 0 ) \
)
# define ZPL_PURE _Pragma("FUNC_IS_PURE;")
# else
# define ZPL_PURE
# endif
# if defined(ZPL_CONST)
# undef ZPL_CONST
# endif
# if \
ZPL_HAS_ATTRIBUTE ( const ) | | \
ZPL_GCC_VERSION_CHECK ( 2 , 5 , 0 ) | | \
ZPL_INTEL_VERSION_CHECK ( 13 , 0 , 0 ) | | \
ZPL_SUNPRO_VERSION_CHECK ( 5 , 11 , 0 ) | | \
ZPL_ARM_VERSION_CHECK ( 4 , 1 , 0 ) | | \
ZPL_IBM_VERSION_CHECK ( 10 , 1 , 0 ) | | \
ZPL_TI_VERSION_CHECK ( 15 , 12 , 0 ) | | \
( ZPL_TI_ARMCL_VERSION_CHECK ( 4 , 8 , 0 ) & & defined ( __TI_GNU_ATTRIBUTE_SUPPORT__ ) ) | | \
ZPL_TI_ARMCL_VERSION_CHECK ( 5 , 2 , 0 ) | | \
( ZPL_TI_CL2000_VERSION_CHECK ( 6 , 0 , 0 ) & & defined ( __TI_GNU_ATTRIBUTE_SUPPORT__ ) ) | | \
ZPL_TI_CL2000_VERSION_CHECK ( 6 , 4 , 0 ) | | \
( ZPL_TI_CL430_VERSION_CHECK ( 4 , 0 , 0 ) & & defined ( __TI_GNU_ATTRIBUTE_SUPPORT__ ) ) | | \
ZPL_TI_CL430_VERSION_CHECK ( 4 , 3 , 0 ) | | \
( ZPL_TI_CL6X_VERSION_CHECK ( 7 , 2 , 0 ) & & defined ( __TI_GNU_ATTRIBUTE_SUPPORT__ ) ) | | \
ZPL_TI_CL6X_VERSION_CHECK ( 7 , 5 , 0 ) | | \
ZPL_TI_CL7X_VERSION_CHECK ( 1 , 2 , 0 ) | | \
ZPL_TI_CLPRU_VERSION_CHECK ( 2 , 1 , 0 ) | | \
ZPL_PGI_VERSION_CHECK ( 17 , 10 , 0 )
# define ZPL_CONST __attribute__((__const__))
# elif \
ZPL_SUNPRO_VERSION_CHECK ( 5 , 10 , 0 )
# define ZPL_CONST _Pragma("no_side_effect")
# else
# define ZPL_CONST ZPL_PURE
# endif
# if defined(ZPL_RESTRICT)
# undef ZPL_RESTRICT
# endif
# if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && !defined(__cplusplus)
# define ZPL_RESTRICT restrict
# elif \
ZPL_GCC_VERSION_CHECK ( 3 , 1 , 0 ) | | \
ZPL_MSVC_VERSION_CHECK ( 14 , 0 , 0 ) | | \
ZPL_INTEL_VERSION_CHECK ( 13 , 0 , 0 ) | | \
ZPL_ARM_VERSION_CHECK ( 4 , 1 , 0 ) | | \
ZPL_IBM_VERSION_CHECK ( 10 , 1 , 0 ) | | \
ZPL_PGI_VERSION_CHECK ( 17 , 10 , 0 ) | | \
ZPL_TI_CL430_VERSION_CHECK ( 4 , 3 , 0 ) | | \
ZPL_TI_CL2000_VERSION_CHECK ( 6 , 2 , 4 ) | | \
ZPL_TI_CL6X_VERSION_CHECK ( 8 , 1 , 0 ) | | \
ZPL_TI_CL7X_VERSION_CHECK ( 1 , 2 , 0 ) | | \
( ZPL_SUNPRO_VERSION_CHECK ( 5 , 14 , 0 ) & & defined ( __cplusplus ) ) | | \
ZPL_IAR_VERSION_CHECK ( 8 , 0 , 0 ) | | \
defined ( __clang__ )
# define ZPL_RESTRICT __restrict
# elif ZPL_SUNPRO_VERSION_CHECK(5,3,0) && !defined(__cplusplus)
# define ZPL_RESTRICT _Restrict
# else
# define ZPL_RESTRICT
# endif
# if defined(ZPL_INLINE)
# undef ZPL_INLINE
# endif
# if \
( defined ( __STDC_VERSION__ ) & & ( __STDC_VERSION__ > = 199901L ) ) | | \
( defined ( __cplusplus ) & & ( __cplusplus > = 199711L ) )
# define ZPL_INLINE inline
# elif \
defined ( ZPL_GCC_VERSION ) | | \
ZPL_ARM_VERSION_CHECK ( 6 , 2 , 0 )
# define ZPL_INLINE __inline__
# elif \
ZPL_MSVC_VERSION_CHECK ( 12 , 0 , 0 ) | | \
ZPL_ARM_VERSION_CHECK ( 4 , 1 , 0 ) | | \
ZPL_TI_ARMCL_VERSION_CHECK ( 5 , 1 , 0 ) | | \
ZPL_TI_CL430_VERSION_CHECK ( 3 , 1 , 0 ) | | \
ZPL_TI_CL2000_VERSION_CHECK ( 6 , 2 , 0 ) | | \
ZPL_TI_CL6X_VERSION_CHECK ( 8 , 0 , 0 ) | | \
ZPL_TI_CL7X_VERSION_CHECK ( 1 , 2 , 0 ) | | \
ZPL_TI_CLPRU_VERSION_CHECK ( 2 , 1 , 0 )
# define ZPL_INLINE __inline
# else
# define ZPL_INLINE
# endif
# if defined(ZPL_ALWAYS_INLINE)
# undef ZPL_ALWAYS_INLINE
# endif
# if \
ZPL_HAS_ATTRIBUTE ( always_inline ) | | \
ZPL_GCC_VERSION_CHECK ( 4 , 0 , 0 ) | | \
ZPL_INTEL_VERSION_CHECK ( 13 , 0 , 0 ) | | \
ZPL_SUNPRO_VERSION_CHECK ( 5 , 11 , 0 ) | | \
ZPL_ARM_VERSION_CHECK ( 4 , 1 , 0 ) | | \
ZPL_IBM_VERSION_CHECK ( 10 , 1 , 0 ) | | \
ZPL_TI_VERSION_CHECK ( 15 , 12 , 0 ) | | \
( ZPL_TI_ARMCL_VERSION_CHECK ( 4 , 8 , 0 ) & & defined ( __TI_GNU_ATTRIBUTE_SUPPORT__ ) ) | | \
ZPL_TI_ARMCL_VERSION_CHECK ( 5 , 2 , 0 ) | | \
( ZPL_TI_CL2000_VERSION_CHECK ( 6 , 0 , 0 ) & & defined ( __TI_GNU_ATTRIBUTE_SUPPORT__ ) ) | | \
ZPL_TI_CL2000_VERSION_CHECK ( 6 , 4 , 0 ) | | \
( ZPL_TI_CL430_VERSION_CHECK ( 4 , 0 , 0 ) & & defined ( __TI_GNU_ATTRIBUTE_SUPPORT__ ) ) | | \
ZPL_TI_CL430_VERSION_CHECK ( 4 , 3 , 0 ) | | \
( ZPL_TI_CL6X_VERSION_CHECK ( 7 , 2 , 0 ) & & defined ( __TI_GNU_ATTRIBUTE_SUPPORT__ ) ) | | \
ZPL_TI_CL6X_VERSION_CHECK ( 7 , 5 , 0 ) | | \
ZPL_TI_CL7X_VERSION_CHECK ( 1 , 2 , 0 ) | | \
ZPL_TI_CLPRU_VERSION_CHECK ( 2 , 1 , 0 )
# define ZPL_ALWAYS_INLINE __attribute__((__always_inline__)) ZPL_INLINE
# elif ZPL_MSVC_VERSION_CHECK(12,0,0)
# define ZPL_ALWAYS_INLINE __forceinline
# elif defined(__cplusplus) && \
( \
ZPL_TI_ARMCL_VERSION_CHECK ( 5 , 2 , 0 ) | | \
ZPL_TI_CL430_VERSION_CHECK ( 4 , 3 , 0 ) | | \
ZPL_TI_CL2000_VERSION_CHECK ( 6 , 4 , 0 ) | | \
ZPL_TI_CL6X_VERSION_CHECK ( 6 , 1 , 0 ) | | \
ZPL_TI_CL7X_VERSION_CHECK ( 1 , 2 , 0 ) | | \
ZPL_TI_CLPRU_VERSION_CHECK ( 2 , 1 , 0 ) \
)
# define ZPL_ALWAYS_INLINE _Pragma("FUNC_ALWAYS_INLINE;")
# elif ZPL_IAR_VERSION_CHECK(8,0,0)
# define ZPL_ALWAYS_INLINE _Pragma("inline=forced")
# else
# define ZPL_ALWAYS_INLINE ZPL_INLINE
# endif
# undef ZPL_ALWAYS_INLINE
# define ZPL_ALWAYS_INLINE ZPL_INLINE
# if defined(ZPL_NEVER_INLINE)
# undef ZPL_NEVER_INLINE
# endif
# if \
ZPL_HAS_ATTRIBUTE ( noinline ) | | \
ZPL_GCC_VERSION_CHECK ( 4 , 0 , 0 ) | | \
ZPL_INTEL_VERSION_CHECK ( 13 , 0 , 0 ) | | \
ZPL_SUNPRO_VERSION_CHECK ( 5 , 11 , 0 ) | | \
ZPL_ARM_VERSION_CHECK ( 4 , 1 , 0 ) | | \
ZPL_IBM_VERSION_CHECK ( 10 , 1 , 0 ) | | \
ZPL_TI_VERSION_CHECK ( 15 , 12 , 0 ) | | \
( ZPL_TI_ARMCL_VERSION_CHECK ( 4 , 8 , 0 ) & & defined ( __TI_GNU_ATTRIBUTE_SUPPORT__ ) ) | | \
ZPL_TI_ARMCL_VERSION_CHECK ( 5 , 2 , 0 ) | | \
( ZPL_TI_CL2000_VERSION_CHECK ( 6 , 0 , 0 ) & & defined ( __TI_GNU_ATTRIBUTE_SUPPORT__ ) ) | | \
ZPL_TI_CL2000_VERSION_CHECK ( 6 , 4 , 0 ) | | \
( ZPL_TI_CL430_VERSION_CHECK ( 4 , 0 , 0 ) & & defined ( __TI_GNU_ATTRIBUTE_SUPPORT__ ) ) | | \
ZPL_TI_CL430_VERSION_CHECK ( 4 , 3 , 0 ) | | \
( ZPL_TI_CL6X_VERSION_CHECK ( 7 , 2 , 0 ) & & defined ( __TI_GNU_ATTRIBUTE_SUPPORT__ ) ) | | \
ZPL_TI_CL6X_VERSION_CHECK ( 7 , 5 , 0 ) | | \
ZPL_TI_CL7X_VERSION_CHECK ( 1 , 2 , 0 ) | | \
ZPL_TI_CLPRU_VERSION_CHECK ( 2 , 1 , 0 )
# define ZPL_NEVER_INLINE __attribute__((__noinline__))
# elif ZPL_MSVC_VERSION_CHECK(13,10,0)
# define ZPL_NEVER_INLINE __declspec(noinline)
# elif ZPL_PGI_VERSION_CHECK(10,2,0)
# define ZPL_NEVER_INLINE _Pragma("noinline")
# elif ZPL_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus)
# define ZPL_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;")
# elif ZPL_IAR_VERSION_CHECK(8,0,0)
# define ZPL_NEVER_INLINE _Pragma("inline=never")
# elif ZPL_COMPCERT_VERSION_CHECK(3,2,0)
# define ZPL_NEVER_INLINE __attribute((noinline))
# elif ZPL_PELLES_VERSION_CHECK(9,0,0)
# define ZPL_NEVER_INLINE __declspec(noinline)
# else
# define ZPL_NEVER_INLINE
# endif
# if defined(ZPL_PRIVATE)
# undef ZPL_PRIVATE
# endif
# if defined(ZPL_PUBLIC)
# undef ZPL_PUBLIC
# endif
# if defined(ZPL_IMPORT)
# undef ZPL_IMPORT
# endif
# if defined(_WIN32) || defined(__CYGWIN__)
# define ZPL_PRIVATE
# define ZPL_PUBLIC __declspec(dllexport)
# define ZPL_IMPORT __declspec(dllimport)
# else
# if \
ZPL_HAS_ATTRIBUTE ( visibility ) | | \
ZPL_GCC_VERSION_CHECK ( 3 , 3 , 0 ) | | \
ZPL_SUNPRO_VERSION_CHECK ( 5 , 11 , 0 ) | | \
ZPL_INTEL_VERSION_CHECK ( 13 , 0 , 0 ) | | \
ZPL_ARM_VERSION_CHECK ( 4 , 1 , 0 ) | | \
ZPL_IBM_VERSION_CHECK ( 13 , 1 , 0 ) | | \
( \
defined ( __TI_EABI__ ) & & \
( \
( ZPL_TI_CL6X_VERSION_CHECK ( 7 , 2 , 0 ) & & defined ( __TI_GNU_ATTRIBUTE_SUPPORT__ ) ) | | \
ZPL_TI_CL6X_VERSION_CHECK ( 7 , 5 , 0 ) \
) \
)
# define ZPL_PRIVATE __attribute__((__visibility__("hidden")))
# define ZPL_PUBLIC __attribute__((__visibility__("default")))
# else
# define ZPL_PRIVATE
# define ZPL_PUBLIC
# endif
# define ZPL_IMPORT extern
# endif
# if defined(ZPL_NO_THROW)
# undef ZPL_NO_THROW
# endif
# if \
ZPL_HAS_ATTRIBUTE ( nothrow ) | | \
ZPL_GCC_VERSION_CHECK ( 3 , 3 , 0 ) | | \
ZPL_INTEL_VERSION_CHECK ( 13 , 0 , 0 )
# define ZPL_NO_THROW __attribute__((__nothrow__))
# elif \
ZPL_MSVC_VERSION_CHECK ( 13 , 1 , 0 ) | | \
ZPL_ARM_VERSION_CHECK ( 4 , 1 , 0 )
# define ZPL_NO_THROW __declspec(nothrow)
# else
# define ZPL_NO_THROW
# endif
# if defined(ZPL_FALL_THROUGH)
# undef ZPL_FALL_THROUGH
# endif
# if ZPL_GNUC_HAS_ATTRIBUTE(fallthrough,7,0,0) && !defined(ZPL_PGI_VERSION)
# define ZPL_FALL_THROUGH __attribute__((__fallthrough__))
# elif ZPL_HAS_CPP_ATTRIBUTE_NS(clang,fallthrough)
# define ZPL_FALL_THROUGH ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[clang::fallthrough]])
# elif ZPL_HAS_CPP_ATTRIBUTE(fallthrough)
# define ZPL_FALL_THROUGH ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[fallthrough]])
# elif defined(__fallthrough) /* SAL */
# define ZPL_FALL_THROUGH __fallthrough
# else
# define ZPL_FALL_THROUGH
# endif
# if defined(ZPL_RETURNS_NON_NULL)
# undef ZPL_RETURNS_NON_NULL
# endif
# if \
ZPL_HAS_ATTRIBUTE ( returns_nonnull ) | | \
ZPL_GCC_VERSION_CHECK ( 4 , 9 , 0 )
# define ZPL_RETURNS_NON_NULL __attribute__((__returns_nonnull__))
# elif defined(_Ret_notnull_) /* SAL */
# define ZPL_RETURNS_NON_NULL _Ret_notnull_
# else
# define ZPL_RETURNS_NON_NULL
# endif
# if defined(ZPL_ARRAY_PARAM)
# undef ZPL_ARRAY_PARAM
# endif
# if \
defined ( __STDC_VERSION__ ) & & ( __STDC_VERSION__ > = 199901L ) & & \
! defined ( __STDC_NO_VLA__ ) & & \
! defined ( __cplusplus ) & & \
! defined ( ZPL_PGI_VERSION ) & & \
! defined ( ZPL_TINYC_VERSION )
# define ZPL_ARRAY_PARAM(name) (name)
# else
# define ZPL_ARRAY_PARAM(name)
# endif
# if defined(ZPL_IS_CONSTANT)
# undef ZPL_IS_CONSTANT
# endif
# if defined(ZPL_REQUIRE_CONSTEXPR)
# undef ZPL_REQUIRE_CONSTEXPR
# endif
/* ZPL_IS_CONSTEXPR_ is for
ZPL INTERNAL USE ONLY . API subject to change without notice . */
# if defined(ZPL_IS_CONSTEXPR_)
# undef ZPL_IS_CONSTEXPR_
# endif
# if \
ZPL_HAS_BUILTIN ( __builtin_constant_p ) | | \
ZPL_GCC_VERSION_CHECK ( 3 , 4 , 0 ) | | \
ZPL_INTEL_VERSION_CHECK ( 13 , 0 , 0 ) | | \
ZPL_TINYC_VERSION_CHECK ( 0 , 9 , 19 ) | | \
ZPL_ARM_VERSION_CHECK ( 4 , 1 , 0 ) | | \
ZPL_IBM_VERSION_CHECK ( 13 , 1 , 0 ) | | \
ZPL_TI_CL6X_VERSION_CHECK ( 6 , 1 , 0 ) | | \
( ZPL_SUNPRO_VERSION_CHECK ( 5 , 10 , 0 ) & & ! defined ( __cplusplus ) ) | | \
ZPL_CRAY_VERSION_CHECK ( 8 , 1 , 0 )
# define ZPL_IS_CONSTANT(expr) __builtin_constant_p(expr)
# endif
# if !defined(__cplusplus)
# if \
ZPL_HAS_BUILTIN ( __builtin_types_compatible_p ) | | \
ZPL_GCC_VERSION_CHECK ( 3 , 4 , 0 ) | | \
ZPL_INTEL_VERSION_CHECK ( 13 , 0 , 0 ) | | \
ZPL_IBM_VERSION_CHECK ( 13 , 1 , 0 ) | | \
ZPL_CRAY_VERSION_CHECK ( 8 , 1 , 0 ) | | \
ZPL_ARM_VERSION_CHECK ( 5 , 4 , 0 ) | | \
ZPL_TINYC_VERSION_CHECK ( 0 , 9 , 24 )
# if defined(__INTPTR_TYPE__)
# define ZPL_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0)), int*)
# else
# include <stdint.h>
# define ZPL_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((intptr_t) ((expr) * 0)) : (int*) 0)), int*)
# endif
# elif \
( \
defined ( __STDC_VERSION__ ) & & ( __STDC_VERSION__ > = 201112L ) & & \
! defined ( ZPL_SUNPRO_VERSION ) & & \
! defined ( ZPL_PGI_VERSION ) & & \
! defined ( ZPL_IAR_VERSION ) ) | | \
ZPL_HAS_EXTENSION ( c_generic_selections ) | | \
ZPL_GCC_VERSION_CHECK ( 4 , 9 , 0 ) | | \
ZPL_INTEL_VERSION_CHECK ( 17 , 0 , 0 ) | | \
ZPL_IBM_VERSION_CHECK ( 12 , 1 , 0 ) | | \
ZPL_ARM_VERSION_CHECK ( 5 , 3 , 0 )
# if defined(__INTPTR_TYPE__)
# define ZPL_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0), int*: 1, void*: 0)
# else
# include <stdint.h>
# define ZPL_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((intptr_t) * 0) : (int*) 0), int*: 1, void*: 0)
# endif
# elif \
defined ( ZPL_GCC_VERSION ) | | \
defined ( ZPL_INTEL_VERSION ) | | \
defined ( ZPL_TINYC_VERSION ) | | \
defined ( ZPL_TI_ARMCL_VERSION ) | | \
ZPL_TI_CL430_VERSION_CHECK ( 18 , 12 , 0 ) | | \
defined ( ZPL_TI_CL2000_VERSION ) | | \
defined ( ZPL_TI_CL6X_VERSION ) | | \
defined ( ZPL_TI_CL7X_VERSION ) | | \
defined ( ZPL_TI_CLPRU_VERSION ) | | \
defined ( __clang__ )
# define ZPL_IS_CONSTEXPR_(expr) ( \
sizeof ( void ) ! = \
sizeof ( * ( \
1 ? \
( ( void * ) ( ( expr ) * 0L ) ) : \
( ( struct { char v [ sizeof ( void ) * 2 ] ; } * ) 1 ) \
) \
) \
)
# endif
# endif
# if defined(ZPL_IS_CONSTEXPR_)
# if !defined(ZPL_IS_CONSTANT)
# define ZPL_IS_CONSTANT(expr) ZPL_IS_CONSTEXPR_(expr)
# endif
# define ZPL_REQUIRE_CONSTEXPR(expr) (ZPL_IS_CONSTEXPR_(expr) ? (expr) : (-1))
# else
# if !defined(ZPL_IS_CONSTANT)
# define ZPL_IS_CONSTANT(expr) (0)
# endif
# define ZPL_REQUIRE_CONSTEXPR(expr) (expr)
# endif
# if defined(ZPL_BEGIN_C_DECLS)
# undef ZPL_BEGIN_C_DECLS
# endif
# if defined(ZPL_END_C_DECLS)
# undef ZPL_END_C_DECLS
# endif
# if defined(ZPL_C_DECL)
# undef ZPL_C_DECL
# endif
# if defined(__cplusplus)
# define ZPL_BEGIN_C_DECLS extern "C" {
# define ZPL_END_C_DECLS }
# define ZPL_C_DECL extern "C"
# else
# define ZPL_BEGIN_C_DECLS
# define ZPL_END_C_DECLS
# define ZPL_C_DECL
# endif
# if defined(ZPL_STATIC_ASSERT)
# undef ZPL_STATIC_ASSERT
# endif
# if \
! defined ( __cplusplus ) & & ( \
( defined ( __STDC_VERSION__ ) & & ( __STDC_VERSION__ > = 201112L ) ) | | \
ZPL_HAS_FEATURE ( c_static_assert ) | | \
ZPL_GCC_VERSION_CHECK ( 6 , 0 , 0 ) | | \
ZPL_INTEL_VERSION_CHECK ( 13 , 0 , 0 ) | | \
defined ( _Static_assert ) \
)
# define ZPL_STATIC_ASSERT(expr, message) _Static_assert(expr, message)
# elif \
( defined ( __cplusplus ) & & ( __cplusplus > = 201103L ) ) | | \
ZPL_MSVC_VERSION_CHECK ( 16 , 0 , 0 )
# define ZPL_STATIC_ASSERT(expr, message) ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(static_assert(expr, message))
# else
# define ZPL_STATIC_ASSERT3(cond, msg) typedef char static_assertion_##msg[(!!(cond)) * 2 - 1]
# define ZPL_STATIC_ASSERT2(cond, line) ZPL_STATIC_ASSERT3(cond, static_assertion_at_line_##line)
# define ZPL_STATIC_ASSERT1(cond, line) ZPL_STATIC_ASSERT2(cond, line)
# define ZPL_STATIC_ASSERT(cond, unused) ZPL_STATIC_ASSERT1(cond, __LINE__)
# endif
# if defined(ZPL_NULL)
# undef ZPL_NULL
# endif
# if defined(__cplusplus)
# if __cplusplus >= 201103L
# define ZPL_NULL ZPL_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(nullptr)
# elif defined(NULL)
# define ZPL_NULL NULL
# else
# define ZPL_NULL ZPL_STATIC_CAST(void*, 0)
# endif
# elif defined(NULL)
# define ZPL_NULL NULL
# else
# define ZPL_NULL ((void*) 0)
# endif
# if defined(ZPL_MESSAGE)
# undef ZPL_MESSAGE
# endif
# if ZPL_HAS_WARNING("-Wunknown-pragmas")
# define ZPL_MESSAGE(msg) \
ZPL_DIAGNOSTIC_PUSH \
ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \
ZPL_PRAGMA ( message msg ) \
ZPL_DIAGNOSTIC_POP
# elif \
ZPL_GCC_VERSION_CHECK ( 4 , 4 , 0 ) | | \
ZPL_INTEL_VERSION_CHECK ( 13 , 0 , 0 )
# define ZPL_MESSAGE(msg) ZPL_PRAGMA(message msg)
# elif ZPL_CRAY_VERSION_CHECK(5,0,0)
# define ZPL_MESSAGE(msg) ZPL_PRAGMA(_CRI message msg)
# elif ZPL_IAR_VERSION_CHECK(8,0,0)
# define ZPL_MESSAGE(msg) ZPL_PRAGMA(message(msg))
# elif ZPL_PELLES_VERSION_CHECK(2,0,0)
# define ZPL_MESSAGE(msg) ZPL_PRAGMA(message(msg))
# else
# define ZPL_MESSAGE(msg)
# endif
# if defined(ZPL_WARNING)
# undef ZPL_WARNING
# endif
# if ZPL_HAS_WARNING("-Wunknown-pragmas")
# define ZPL_WARNING(msg) \
ZPL_DIAGNOSTIC_PUSH \
ZPL_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \
ZPL_PRAGMA ( clang warning msg ) \
ZPL_DIAGNOSTIC_POP
# elif \
ZPL_GCC_VERSION_CHECK ( 4 , 8 , 0 ) | | \
ZPL_PGI_VERSION_CHECK ( 18 , 4 , 0 ) | | \
ZPL_INTEL_VERSION_CHECK ( 13 , 0 , 0 )
# define ZPL_WARNING(msg) ZPL_PRAGMA(GCC warning msg)
# elif ZPL_MSVC_VERSION_CHECK(15,0,0)
# define ZPL_WARNING(msg) ZPL_PRAGMA(message(msg))
# else
# define ZPL_WARNING(msg) ZPL_MESSAGE(msg)
# endif
# if defined(ZPL_REQUIRE)
# undef ZPL_REQUIRE
# endif
# if defined(ZPL_REQUIRE_MSG)
# undef ZPL_REQUIRE_MSG
# endif
# if ZPL_HAS_ATTRIBUTE(diagnose_if)
# if ZPL_HAS_WARNING("-Wgcc-compat")
# define ZPL_REQUIRE(expr) \
ZPL_DIAGNOSTIC_PUSH \
_Pragma ( " clang diagnostic ignored \" -Wgcc-compat \" " ) \
__attribute__ ( ( diagnose_if ( ! ( expr ) , # expr , " error " ) ) ) \
ZPL_DIAGNOSTIC_POP
# define ZPL_REQUIRE_MSG(expr,msg) \
ZPL_DIAGNOSTIC_PUSH \
_Pragma ( " clang diagnostic ignored \" -Wgcc-compat \" " ) \
__attribute__ ( ( diagnose_if ( ! ( expr ) , msg , " error " ) ) ) \
ZPL_DIAGNOSTIC_POP
# else
# define ZPL_REQUIRE(expr) __attribute__((diagnose_if(!(expr), #expr, "error")))
# define ZPL_REQUIRE_MSG(expr,msg) __attribute__((diagnose_if(!(expr), msg, "error")))
# endif
# else
# define ZPL_REQUIRE(expr)
# define ZPL_REQUIRE_MSG(expr,msg)
# endif
# if defined(ZPL_FLAGS)
# undef ZPL_FLAGS
# endif
# if ZPL_HAS_ATTRIBUTE(flag_enum)
# define ZPL_FLAGS __attribute__((__flag_enum__))
# endif
# if defined(ZPL_FLAGS_CAST)
# undef ZPL_FLAGS_CAST
# endif
# if ZPL_INTEL_VERSION_CHECK(19,0,0)
# define ZPL_FLAGS_CAST(T, expr) (__extension__ ({ \
ZPL_DIAGNOSTIC_PUSH \
_Pragma ( " warning(disable:188) " ) \
( ( T ) ( expr ) ) ; \
ZPL_DIAGNOSTIC_POP \
} ) )
# else
# define ZPL_FLAGS_CAST(T, expr) ZPL_STATIC_CAST(T, expr)
# endif
# if defined(ZPL_EMPTY_BASES)
# undef ZPL_EMPTY_BASES
# endif
# if ZPL_MSVC_VERSION_CHECK(19,0,23918) && !ZPL_MSVC_VERSION_CHECK(20,0,0)
# define ZPL_EMPTY_BASES __declspec(empty_bases)
# else
# define ZPL_EMPTY_BASES
# endif
/* Remaining macros are deprecated. */
# if defined(ZPL_GCC_NOT_CLANG_VERSION_CHECK)
# undef ZPL_GCC_NOT_CLANG_VERSION_CHECK
# endif
# if defined(__clang__)
# define ZPL_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) (0)
# else
# define ZPL_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) ZPL_GCC_VERSION_CHECK(major,minor,patch)
# endif
# if defined(ZPL_CLANG_HAS_ATTRIBUTE)
# undef ZPL_CLANG_HAS_ATTRIBUTE
# endif
# define ZPL_CLANG_HAS_ATTRIBUTE(attribute) ZPL_HAS_ATTRIBUTE(attribute)
# if defined(ZPL_CLANG_HAS_CPP_ATTRIBUTE)
# undef ZPL_CLANG_HAS_CPP_ATTRIBUTE
# endif
# define ZPL_CLANG_HAS_CPP_ATTRIBUTE(attribute) ZPL_HAS_CPP_ATTRIBUTE(attribute)
# if defined(ZPL_CLANG_HAS_BUILTIN)
# undef ZPL_CLANG_HAS_BUILTIN
# endif
# define ZPL_CLANG_HAS_BUILTIN(builtin) ZPL_HAS_BUILTIN(builtin)
# if defined(ZPL_CLANG_HAS_FEATURE)
# undef ZPL_CLANG_HAS_FEATURE
# endif
# define ZPL_CLANG_HAS_FEATURE(feature) ZPL_HAS_FEATURE(feature)
# if defined(ZPL_CLANG_HAS_EXTENSION)
# undef ZPL_CLANG_HAS_EXTENSION
# endif
# define ZPL_CLANG_HAS_EXTENSION(extension) ZPL_HAS_EXTENSION(extension)
# if defined(ZPL_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE)
# undef ZPL_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE
# endif
# define ZPL_CLANG_HAS_DECLSPEC_ATTRIBUTE(attribute) ZPL_HAS_DECLSPEC_ATTRIBUTE(attribute)
# if defined(ZPL_CLANG_HAS_WARNING)
# undef ZPL_CLANG_HAS_WARNING
# endif
# define ZPL_CLANG_HAS_WARNING(warning) ZPL_HAS_WARNING(warning)
# endif /* !defined(ZPL_HEDLEY_VERSION) || (ZPL_HEDLEY_VERSION < X) */
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
# define ZPL_VERSION ZPL_VERSION_ENCODE(ZPL_VERSION_MAJOR, ZPL_VERSION_MINOR, ZPL_VERSION_PATCH)
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
# ifdef ZPL_IMPL
# ifndef ZPL_IMPLEMENTATION
# define ZPL_IMPLEMENTATION
# endif
2021-11-29 08:23:08 +00:00
# endif
2022-09-11 17:42:06 +00:00
# if defined(__cplusplus) && !defined(ZPL_EXTERN)
# define ZPL_EXTERN extern "C"
# else
# define ZPL_EXTERN extern
2021-11-29 08:23:08 +00:00
# endif
2022-09-11 17:42:06 +00:00
# ifndef ZPL_DEF
# if defined(ZPL_SHARED_LIB)
# ifdef ZPL_IMPLEMENTATION
# define ZPL_DEF ZPL_PUBLIC
# else
# define ZPL_DEF ZPL_IMPORT
# endif
# elif defined(ZPL_STATIC_LIB)
# ifdef ZPL_IMPLEMENTATION
# define ZPL_DEF
# else
# define ZPL_DEF ZPL_EXTERN
# endif
# elif defined(ZPL_STATIC)
# define ZPL_DEF static
# else
# define ZPL_DEF ZPL_EXTERN
# endif
2021-11-29 08:23:08 +00:00
# endif
2022-09-11 17:42:06 +00:00
# ifndef ZPL_DEF_INLINE
# if defined(ZPL_STATIC)
# define ZPL_DEF_INLINE
# define ZPL_IMPL_INLINE
# else
# define ZPL_DEF_INLINE static
# define ZPL_IMPL_INLINE static inline
# endif
2021-11-29 08:23:08 +00:00
# endif
2022-09-11 17:42:06 +00:00
/* builtin overrides */
# if defined(__TINYC__) || defined(__EMSCRIPTEN__)
# if defined(ZPL_ENFORCE_THREADING)
# define ZPL_ENABLE_THREADING
# else
# define ZPL_DISABLE_THREADING
# endif
2021-11-29 08:23:08 +00:00
# endif
2022-09-11 17:42:06 +00:00
/* Distributions */
# ifndef ZPL_CUSTOM_MODULES
/* default distribution */
# define ZPL_MODULE_ESSENTIALS
# define ZPL_MODULE_CORE
# define ZPL_MODULE_TIMER
# define ZPL_MODULE_HASHING
# define ZPL_MODULE_REGEX
# define ZPL_MODULE_EVENT
# define ZPL_MODULE_DLL
# define ZPL_MODULE_OPTS
# define ZPL_MODULE_PROCESS
# define ZPL_MODULE_MATH
# define ZPL_MODULE_THREADING
# define ZPL_MODULE_JOBS
# define ZPL_MODULE_PARSER
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
/* zpl nano distribution */
# if defined(ZPL_NANO) || defined(ZPL_PICO)
# undef ZPL_MODULE_TIMER
# undef ZPL_MODULE_HASHING
# undef ZPL_MODULE_REGEX
# undef ZPL_MODULE_EVENT
# undef ZPL_MODULE_DLL
# undef ZPL_MODULE_OPTS
# undef ZPL_MODULE_PROCESS
# undef ZPL_MODULE_MATH
# undef ZPL_MODULE_THREADING
# undef ZPL_MODULE_JOBS
# undef ZPL_MODULE_PARSER
# endif
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
# if defined(ZPL_PICO)
# undef ZPL_MODULE_CORE
# endif
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
/* module enabling overrides */
# if defined(ZPL_ENABLE_CORE) && !defined(ZPL_MODULE_CORE)
# define ZPL_MODULE_CORE
# endif
# if defined(ZPL_ENABLE_HASHING) && !defined(ZPL_MODULE_HASHING)
# define ZPL_MODULE_HASHING
# endif
# if defined(ZPL_ENABLE_REGEX) && !defined(ZPL_MODULE_REGEX)
# define ZPL_MODULE_REGEX
# endif
# if defined(ZPL_ENABLE_DLL) && !defined(ZPL_MODULE_DLL)
# define ZPL_MODULE_DLL
# endif
# if defined(ZPL_ENABLE_OPTS) && !defined(ZPL_MODULE_OPTS)
# define ZPL_MODULE_OPTS
# endif
# if defined(ZPL_ENABLE_PROCESS) && !defined(ZPL_MODULE_PROCESS)
# define ZPL_MODULE_PROCESS
# endif
# if defined(ZPL_ENABLE_MATH) && !defined(ZPL_MODULE_MATH)
# define ZPL_MODULE_MATH
# endif
# if defined(ZPL_ENABLE_THREADING) && !defined(ZPL_MODULE_THREADING)
# define ZPL_MODULE_THREADING
# endif
# if defined(ZPL_ENABLE_JOBS) && !defined(ZPL_MODULE_JOBS)
# ifndef ZPL_MODULE_THREADING
# define ZPL_MODULE_THREADING /* dependency */
# endif
# define ZPL_MODULE_JOBS
# endif
# if defined(ZPL_ENABLE_PARSER) && !defined(ZPL_MODULE_PARSER)
# define ZPL_MODULE_PARSER
# endif
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
/* module disabling overrides */
# if defined(ZPL_DISABLE_CORE) && defined(ZPL_MODULE_CORE)
# undef ZPL_MODULE_CORE
# endif
# if defined(ZPL_DISABLE_HASHING) && defined(ZPL_MODULE_HASHING)
# undef ZPL_MODULE_HASHING
# endif
# if defined(ZPL_DISABLE_REGEX) && defined(ZPL_MODULE_REGEX)
# undef ZPL_MODULE_REGEX
# endif
# if defined(ZPL_DISABLE_DLL) && defined(ZPL_MODULE_DLL)
# undef ZPL_MODULE_DLL
# endif
# if defined(ZPL_DISABLE_OPTS) && defined(ZPL_MODULE_OPTS)
# undef ZPL_MODULE_OPTS
# endif
# if defined(ZPL_DISABLE_PROCESS) && defined(ZPL_MODULE_PROCESS)
# undef ZPL_MODULE_PROCESS
# endif
# if defined(ZPL_DISABLE_MATH) && defined(ZPL_MODULE_MATH)
# undef ZPL_MODULE_MATH
# endif
# if defined(ZPL_DISABLE_THREADING) && defined(ZPL_MODULE_THREADING)
# ifdef ZPL_MODULE_JOBS
# undef ZPL_MODULE_JOBS /* user */
# endif
# undef ZPL_MODULE_THREADING
# endif
# if defined(ZPL_DISABLE_JOBS) && defined(ZPL_MODULE_JOBS)
# undef ZPL_MODULE_JOBS
# endif
# if defined(ZPL_DISABLE_PARSER) && defined(ZPL_MODULE_PARSER)
# undef ZPL_MODULE_PARSER
# endif
2021-11-29 08:23:08 +00:00
# endif
2022-09-11 17:42:06 +00:00
# if defined(__GCC__) || defined(__GNUC__) || defined(__clang__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wunused-function"
# pragma GCC diagnostic ignored "-Wmissing-field-initializers"
# pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
2021-11-29 08:23:08 +00:00
# endif
2022-09-11 17:42:06 +00:00
# if defined(_MSC_VER)
# pragma warning(push)
# pragma warning(disable : 4201)
# pragma warning(disable : 4127) // Conditional expression is constant
2021-11-29 08:23:08 +00:00
# endif
2022-09-11 17:42:06 +00:00
/* general purpose includes */
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
// file: header/core/system.h
ZPL_BEGIN_C_DECLS
/* Platform architecture */
# if defined(_WIN64) || defined(__x86_64__) || defined(_M_X64) || defined(__64BIT__) || defined(__powerpc64__) || \
defined ( __ppc64__ ) | | defined ( __aarch64__ )
# ifndef ZPL_ARCH_64_BIT
# define ZPL_ARCH_64_BIT 1
# endif
# else
# ifndef ZPL_ARCH_32_BIT
# define ZPL_ARCH_32_BIT 1
# endif
# endif
/* Platform endiannes */
# ifndef ZPL_ENDIAN_ORDER
# define ZPL_ENDIAN_ORDER
# define ZPL_IS_BIG_ENDIAN (!*(zpl_u8 *)&(zpl_u16){ 1 })
# define ZPL_IS_LITTLE_ENDIAN (!ZPL_IS_BIG_ENDIAN)
# endif
/* Platform OS */
# if defined(_WIN32) || defined(_WIN64)
# ifndef ZPL_SYSTEM_WINDOWS
# define ZPL_SYSTEM_WINDOWS 1
# endif
# elif defined(__APPLE__) && defined(__MACH__)
# ifndef ZPL_SYSTEM_OSX
# define ZPL_SYSTEM_OSX 1
# endif
# ifndef ZPL_SYSTEM_MACOS
# define ZPL_SYSTEM_MACOS 1
# endif
# include <TargetConditionals.h>
# if TARGET_IPHONE_SIMULATOR == 1 || TARGET_OS_IPHONE == 1
# ifndef ZPL_SYSTEM_IOS
# define ZPL_SYSTEM_IOS 1
# endif
# endif
# elif defined(__unix__)
# ifndef ZPL_SYSTEM_UNIX
# define ZPL_SYSTEM_UNIX 1
# endif
# if defined(ANDROID) || defined(__ANDROID__)
# ifndef ZPL_SYSTEM_ANDROID
# define ZPL_SYSTEM_ANDROID 1
# endif
# ifndef ZPL_SYSTEM_LINUX
# define ZPL_SYSTEM_LINUX 1
# endif
# elif defined(__linux__)
# ifndef ZPL_SYSTEM_LINUX
# define ZPL_SYSTEM_LINUX 1
# endif
# elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
# ifndef ZPL_SYSTEM_FREEBSD
# define ZPL_SYSTEM_FREEBSD 1
# endif
# elif defined(__OpenBSD__)
# ifndef ZPL_SYSTEM_OPENBSD
# define ZPL_SYSTEM_OPENBSD 1
# endif
# elif defined(__EMSCRIPTEN__)
# ifndef ZPL_SYSTEM_EMSCRIPTEN
# define ZPL_SYSTEM_EMSCRIPTEN 1
# endif
# elif defined(__CYGWIN__)
# ifndef ZPL_SYSTEM_CYGWIN
# define ZPL_SYSTEM_CYGWIN 1
# endif
# else
# error This UNIX operating system is not supported
# endif
# else
# error This operating system is not supported
# endif
/* Platform compiler */
# if defined(_MSC_VER)
# define ZPL_COMPILER_MSVC 1
# elif defined(__GNUC__)
# define ZPL_COMPILER_GCC 1
# elif defined(__clang__)
# define ZPL_COMPILER_CLANG 1
# elif defined(__MINGW32__)
# define ZPL_COMPILER_MINGW 1
# elif defined(__TINYC__)
# define ZPL_COMPILER_TINYC 1
# else
# error Unknown compiler
# endif
/* Platform CPU */
# if defined(__arm__) || defined(__aarch64__) || defined(__ARM_ARCH)
# ifndef ZPL_CPU_ARM
# define ZPL_CPU_ARM 1
# endif
# ifndef ZPL_CACHE_LINE_SIZE
# define ZPL_CACHE_LINE_SIZE 64
# endif
# elif defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__x86_64__) || defined(ZPL_SYSTEM_EMSCRIPTEN)
# ifndef ZPL_CPU_X86
# define ZPL_CPU_X86 1
# endif
# ifndef ZPL_CACHE_LINE_SIZE
# define ZPL_CACHE_LINE_SIZE 64
# endif
# elif defined(_M_PPC) || defined(__powerpc__) || defined(__powerpc64__)
# ifndef ZPL_CPU_PPC
# define ZPL_CPU_PPC 1
# endif
# ifndef ZPL_CACHE_LINE_SIZE
# define ZPL_CACHE_LINE_SIZE 128
# endif
# elif defined(__MIPSEL__) || defined(__mips_isa_rev)
# ifndef ZPL_CPU_MIPS
# define ZPL_CPU_MIPS 1
# endif
# ifndef ZPL_CACHE_LINE_SIZE
# define ZPL_CACHE_LINE_SIZE 64
# endif
# else
# error Unknown CPU Type
# endif
// TODO(ZaKlaus): Find a better way to get this flag in MinGW.
# if (defined(ZPL_COMPILER_GCC) && !defined(WC_ERR_INVALID_CHARS)) || defined(ZPL_COMPILER_TINYC)
# define WC_ERR_INVALID_CHARS 0x0080
# endif
# if defined(ZPL_COMPILER_GCC) && defined(ZPL_SYSTEM_WINDOWS)
# ifndef ZPL_COMPILER_MINGW
# define ZPL_COMPILER_MINGW // assume we use mingw as a compiler
# endif
# endif
# if defined(ZPL_SYSTEM_UNIX)
# ifndef _GNU_SOURCE
# define _GNU_SOURCE
# endif
# ifndef _LARGEFILE64_SOURCE
# define _LARGEFILE64_SOURCE
# endif
# endif
# if ZPL_GNUC_VERSION_CHECK(3, 3, 0)
# define ZPL_INFINITY (__builtin_inff())
# define ZPL_NAN (__builtin_nanf(""))
# elif defined(ZPL_COMPILER_MSVC)
# if !defined(ZPL__HACK_INFINITY)
typedef union zpl__msvc_inf_hack {
unsigned __int8 bytes [ 4 ] ;
float value ;
} zpl__msvc_inf_hack ;
static union zpl__msvc_inf_hack ZPL__INFINITY_HACK = { { 0x00 , 0x00 , 0x80 , 0x7F } } ;
# define ZPL__HACK_INFINITY (ZPL__INFINITY_HACK.value)
# endif
# define ZPL_INFINITY (ZPL__HACK_INFINITY)
# define ZPL_NAN (0)
# else
# define ZPL_INFINITY (1e10000f)
# define ZPL_NAN (0.0f / 0.0f)
# endif
ZPL_END_C_DECLS
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
# include <stdarg.h>
# include <stddef.h>
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
# if defined(ZPL_SYSTEM_WINDOWS)
# include <intrin.h>
2021-11-29 08:23:08 +00:00
# endif
2022-09-11 17:42:06 +00:00
// file: header/essentials/types.h
ZPL_BEGIN_C_DECLS
/* Basic types */
# if defined(ZPL_COMPILER_MSVC)
# if _MSC_VER < 1300
typedef unsigned char zpl_u8 ;
typedef signed char zpl_i8 ;
typedef unsigned short zpl_u16 ;
typedef signed short zpl_i16 ;
typedef unsigned int zpl_u32 ;
typedef signed int zpl_i32 ;
# else
typedef unsigned __int8 zpl_u8 ;
typedef signed __int8 zpl_i8 ;
typedef unsigned __int16 zpl_u16 ;
typedef signed __int16 zpl_i16 ;
typedef unsigned __int32 zpl_u32 ;
typedef signed __int32 zpl_i32 ;
# endif
typedef unsigned __int64 zpl_u64 ;
typedef signed __int64 zpl_i64 ;
# else
# include <stdint.h>
typedef uint8_t zpl_u8 ;
typedef int8_t zpl_i8 ;
typedef uint16_t zpl_u16 ;
typedef int16_t zpl_i16 ;
typedef uint32_t zpl_u32 ;
typedef int32_t zpl_i32 ;
typedef uint64_t zpl_u64 ;
typedef int64_t zpl_i64 ;
# endif
ZPL_STATIC_ASSERT ( sizeof ( zpl_u8 ) = = sizeof ( zpl_i8 ) , " sizeof(zpl_u8) != sizeof(zpl_i8) " ) ;
ZPL_STATIC_ASSERT ( sizeof ( zpl_u16 ) = = sizeof ( zpl_i16 ) , " sizeof(zpl_u16) != sizeof(zpl_i16) " ) ;
ZPL_STATIC_ASSERT ( sizeof ( zpl_u32 ) = = sizeof ( zpl_i32 ) , " sizeof(zpl_u32) != sizeof(zpl_i32) " ) ;
ZPL_STATIC_ASSERT ( sizeof ( zpl_u64 ) = = sizeof ( zpl_i64 ) , " sizeof(zpl_u64) != sizeof(zpl_i64) " ) ;
ZPL_STATIC_ASSERT ( sizeof ( zpl_u8 ) = = 1 , " sizeof(zpl_u8) != 1 " ) ;
ZPL_STATIC_ASSERT ( sizeof ( zpl_u16 ) = = 2 , " sizeof(zpl_u16) != 2 " ) ;
ZPL_STATIC_ASSERT ( sizeof ( zpl_u32 ) = = 4 , " sizeof(zpl_u32) != 4 " ) ;
ZPL_STATIC_ASSERT ( sizeof ( zpl_u64 ) = = 8 , " sizeof(zpl_u64) != 8 " ) ;
typedef size_t zpl_usize ;
typedef ptrdiff_t zpl_isize ;
ZPL_STATIC_ASSERT ( sizeof ( zpl_usize ) = = sizeof ( zpl_isize ) , " sizeof(zpl_usize) != sizeof(zpl_isize) " ) ;
// NOTE: (u)zpl_intptr is only here for semantic reasons really as this library will only support 32/64 bit OSes.
# if defined(_WIN64)
typedef signed __int64 zpl_intptr ;
typedef unsigned __int64 zpl_uintptr ;
# elif defined(_WIN32)
// NOTE; To mark types changing their size, e.g. zpl_intptr
# ifndef _W64
# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
# define _W64 __w64
# else
# define _W64
# endif
# endif
typedef _W64 signed int zpl_intptr ;
typedef _W64 unsigned int zpl_uintptr ;
# else
typedef uintptr_t zpl_uintptr ;
typedef intptr_t zpl_intptr ;
# endif
ZPL_STATIC_ASSERT ( sizeof ( zpl_uintptr ) = = sizeof ( zpl_intptr ) , " sizeof(zpl_uintptr) != sizeof(zpl_intptr) " ) ;
typedef float zpl_f32 ;
typedef double zpl_f64 ;
ZPL_STATIC_ASSERT ( sizeof ( zpl_f32 ) = = 4 , " sizeof(zpl_f32) != 4 " ) ;
ZPL_STATIC_ASSERT ( sizeof ( zpl_f64 ) = = 8 , " sizeof(zpl_f64) != 8 " ) ;
typedef zpl_i32 zpl_rune ; // NOTE: Unicode codepoint
typedef zpl_i32 zpl_char32 ;
# define ZPL_RUNE_INVALID cast(zpl_rune)(0xfffd)
# define ZPL_RUNE_MAX cast(zpl_rune)(0x0010ffff)
# define ZPL_RUNE_BOM cast(zpl_rune)(0xfeff)
# define ZPL_RUNE_EOF cast(zpl_rune)(-1)
typedef zpl_i8 zpl_b8 ;
typedef zpl_i16 zpl_b16 ;
typedef zpl_i32 zpl_b32 ;
# if !defined(__cplusplus)
# if (defined(_MSC_VER) && _MSC_VER < 1800) || (!defined(_MSC_VER) && !defined(__STDC_VERSION__))
# ifndef true
# define true(0 == 0)
# endif
# ifndef false
# define false(0 != 0)
# endif
typedef zpl_b8 bool ;
# else
# include <stdbool.h>
# endif
# endif
# ifndef ZPL_U8_MIN
# define ZPL_U8_MIN 0u
# define ZPL_U8_MAX 0xffu
# define ZPL_I8_MIN (-0x7f - 1)
# define ZPL_I8_MAX 0x7f
# define ZPL_U16_MIN 0u
# define ZPL_U16_MAX 0xffffu
# define ZPL_I16_MIN (-0x7fff - 1)
# define ZPL_I16_MAX 0x7fff
# define ZPL_U32_MIN 0u
# define ZPL_U32_MAX 0xffffffffu
# define ZPL_I32_MIN (-0x7fffffff - 1)
# define ZPL_I32_MAX 0x7fffffff
# define ZPL_U64_MIN 0ull
# define ZPL_U64_MAX 0xffffffffffffffffull
# define ZPL_I64_MIN (-0x7fffffffffffffffll - 1)
# define ZPL_I64_MAX 0x7fffffffffffffffll
# if defined(ZPL_ARCH_32_BIT)
# define ZPL_USIZE_MIN ZPL_U32_MIN
# define ZPL_USIZE_MAX ZPL_U32_MAX
# define ZPL_ISIZE_MIN ZPL_S32_MIN
# define ZPL_ISIZE_MAX ZPL_S32_MAX
# elif defined(ZPL_ARCH_64_BIT)
# define ZPL_USIZE_MIN ZPL_U64_MIN
# define ZPL_USIZE_MAX ZPL_U64_MAX
# define ZPL_ISIZE_MIN ZPL_I64_MIN
# define ZPL_ISIZE_MAX ZPL_I64_MAX
# else
# error Unknown architecture size. This library only supports 32 bit and 64 bit architectures.
# endif
# define ZPL_F32_MIN 1.17549435e-38f
# define ZPL_F32_MAX 3.40282347e+38f
# define ZPL_F64_MIN 2.2250738585072014e-308
# define ZPL_F64_MAX 1.7976931348623157e+308
# endif
# ifdef ZPL_DEFINE_NULL_MACRO
# ifndef NULL
# define NULL ZPL_NULL
# endif
# endif
ZPL_END_C_DECLS
// file: header/essentials/helpers.h
/* Various macro based helpers */
ZPL_BEGIN_C_DECLS
# ifndef cast
# define cast(Type) (Type)
# endif
# ifndef zpl_size_of
# define zpl_size_of(x) (zpl_isize)(sizeof(x))
# endif
# ifndef zpl_count_of
# define zpl_count_of(x) ((zpl_size_of(x) / zpl_size_of(0 [x])) / ((zpl_isize)(!(zpl_size_of(x) % zpl_size_of(0 [x])))))
# endif
# ifndef zpl_offset_of
# if defined(_MSC_VER) || defined(ZPL_COMPILER_TINYC)
# define zpl_offset_of(Type, element) ((zpl_isize) & (((Type *)0)->element))
# else
# define zpl_offset_of(Type, element) __builtin_offsetof(Type, element)
# endif
# endif
# if defined(__cplusplus)
# ifndef zpl_align_of
# if __cplusplus >= 201103L
# define zpl_align_of(Type) (zpl_isize)alignof(Type)
# else
extern " C++ " {
template < typename T > struct zpl_alignment_trick {
char c ;
T member ;
} ;
}
# define zpl_align_of(Type) zpl_offset_of(zpl_alignment_trick<Type>, member)
# endif
# endif
# else
# ifndef zpl_align_of
# define zpl_align_of(Type) \
zpl_offset_of ( \
struct { \
char c ; \
Type member ; \
} , \
member )
# endif
# endif
# ifndef zpl_swap
# define zpl_swap(Type, a, b) \
do { \
Type tmp = ( a ) ; \
( a ) = ( b ) ; \
( b ) = tmp ; \
} while ( 0 )
# endif
# ifndef zpl_global
# define zpl_global static // Global variables
# endif
# ifndef zpl_internal
# define zpl_internal static // Internal linkage
# endif
# ifndef zpl_local_persist
# define zpl_local_persist static // Local Persisting variables
# endif
# ifndef zpl_unused
# if defined(_MSC_VER)
# define zpl_unused(x) (__pragma(warning(suppress : 4100))(x))
# elif defined(__GCC__)
# define zpl_unused(x) __attribute__((__unused__))(x)
# else
# define zpl_unused(x) ((void)(zpl_size_of(x)))
# endif
# endif
# ifndef ZPL_JOIN_MACROS
# define ZPL_JOIN_MACROS
# define ZPL_JOIN2 ZPL_CONCAT
# define ZPL_JOIN3(a, b, c) ZPL_JOIN2(ZPL_JOIN2(a, b), c)
# define ZPL_JOIN4(a, b, c, d) ZPL_JOIN2(ZPL_JOIN2(ZPL_JOIN2(a, b), c), d)
# endif
# ifndef ZPL_BIT
# define ZPL_BIT(x) (1 << (x))
# endif
# ifndef zpl_min
# define zpl_min(a, b) ((a) < (b) ? (a) : (b))
# endif
# ifndef zpl_max
# define zpl_max(a, b) ((a) > (b) ? (a) : (b))
# endif
# ifndef zpl_min3
# define zpl_min3(a, b, c) zpl_min(zpl_min(a, b), c)
# endif
# ifndef zpl_max3
# define zpl_max3(a, b, c) zpl_max(zpl_max(a, b), c)
# endif
# ifndef zpl_clamp
# define zpl_clamp(x, lower, upper) zpl_min(zpl_max((x), (lower)), (upper))
# endif
# ifndef zpl_clamp01
# define zpl_clamp01(x) zpl_clamp((x), 0, 1)
# endif
# ifndef zpl_is_between
# define zpl_is_between(x, lower, upper) (((lower) <= (x)) && ((x) <= (upper)))
# endif
# ifndef zpl_is_between_limit
# define zpl_is_between_limit(x, lower, upper) (((lower) <= (x)) && ((x) < (upper)))
# endif
# ifndef zpl_step
# define zpl_step(x,y) (((x) / (y))*(y))
# endif
# ifndef zpl_abs
# define zpl_abs(x) ((x) < 0 ? -(x) : (x))
# endif
# ifndef ZPL_MASK_SET
# define ZPL_MASK_SET(var, set, mask) \
do { \
if ( set ) \
( var ) | = ( mask ) ; \
else \
( var ) & = ~ ( mask ) ; \
} while ( 0 )
# endif
// Multiline string literals in C99!
# ifndef ZPL_MULTILINE
# define ZPL_MULTILINE(...) #__VA_ARGS__
# endif
ZPL_END_C_DECLS
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
# if defined(ZPL_MODULE_ESSENTIALS)
// file: header/essentials/debug.h
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
/* Debugging stuff */
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_BEGIN_C_DECLS
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
# ifndef ZPL_DEBUG_TRAP
# if defined(_MSC_VER)
# if _MSC_VER < 1300
# define ZPL_DEBUG_TRAP( ) __asm int 3 /* Trap to debugger! */
# else
# define ZPL_DEBUG_TRAP( ) __debugbreak( )
# endif
# elif defined(ZPL_COMPILER_TINYC)
# define ZPL_DEBUG_TRAP( ) zpl_exit(1)
# else
# define ZPL_DEBUG_TRAP( ) __builtin_trap( )
# endif
# endif
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
# ifndef ZPL_ASSERT_MSG
# define ZPL_ASSERT_MSG(cond, msg, ...) \
do { \
if ( ! ( cond ) ) { \
zpl_assert_handler ( # cond , __FILE__ , cast ( zpl_i64 ) __LINE__ , msg , # # __VA_ARGS__ ) ; \
ZPL_DEBUG_TRAP ( ) ; \
} \
} while ( 0 )
# endif
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
# ifndef ZPL_ASSERT
# define ZPL_ASSERT(cond) ZPL_ASSERT_MSG(cond, NULL)
# endif
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
# ifndef ZPL_ASSERT_NOT_NULL
# define ZPL_ASSERT_NOT_NULL(ptr) ZPL_ASSERT_MSG((ptr) != NULL, #ptr " must not be NULL")
# endif
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
// NOTE: Things that shouldn't happen with a message!
# ifndef ZPL_PANIC
# define ZPL_PANIC(msg, ...) ZPL_ASSERT_MSG(0, msg, ##__VA_ARGS__)
# endif
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
# ifndef ZPL_NOT_IMPLEMENTED
# define ZPL_NOT_IMPLEMENTED ZPL_PANIC("not implemented")
# endif
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
/* Functions */
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_DEF void zpl_assert_handler ( char const * condition , char const * file , zpl_i32 line , char const * msg , . . . ) ;
ZPL_DEF zpl_i32 zpl_assert_crash ( char const * condition ) ;
ZPL_DEF void zpl_exit ( zpl_u32 code ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_END_C_DECLS
// file: header/essentials/memory.h
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
/** @file mem.c
@ brief Memory manipulation and helpers .
@ defgroup memman Memory management
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
Consists of pointer arithmetic methods , virtual memory management and custom memory allocators .
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
@ {
*/
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_BEGIN_C_DECLS
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Checks if value is power of 2.
ZPL_DEF_INLINE zpl_b32 zpl_is_power_of_two ( zpl_isize x ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Aligns address to specified alignment.
ZPL_DEF_INLINE void * zpl_align_forward ( void * ptr , zpl_isize alignment ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Aligns value to a specified alignment.
ZPL_DEF_INLINE zpl_i64 zpl_align_forward_i64 ( zpl_i64 value , zpl_isize alignment ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Aligns value to a specified alignment.
ZPL_DEF_INLINE zpl_u64 zpl_align_forward_u64 ( zpl_u64 value , zpl_usize alignment ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Moves pointer forward by bytes.
ZPL_DEF_INLINE void * zpl_pointer_add ( void * ptr , zpl_isize bytes ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Moves pointer backward by bytes.
ZPL_DEF_INLINE void * zpl_pointer_sub ( void * ptr , zpl_isize bytes ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Moves pointer forward by bytes.
ZPL_DEF_INLINE void const * zpl_pointer_add_const ( void const * ptr , zpl_isize bytes ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Moves pointer backward by bytes.
ZPL_DEF_INLINE void const * zpl_pointer_sub_const ( void const * ptr , zpl_isize bytes ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Calculates difference between two addresses.
ZPL_DEF_INLINE zpl_isize zpl_pointer_diff ( void const * begin , void const * end ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
# define zpl_ptr_add zpl_pointer_add
# define zpl_ptr_sub zpl_pointer_sub
# define zpl_ptr_add_const zpl_pointer_add_const
# define zpl_ptr_sub_const zpl_pointer_sub_const
# define zpl_ptr_diff zpl_pointer_diff
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Clears up memory at location by specified size.
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! @param ptr Memory location to clear up.
//! @param size The size to clear up with.
ZPL_DEF_INLINE void zpl_zero_size ( void * ptr , zpl_isize size ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
# ifndef zpl_zero_item
//! Clears up an item.
# define zpl_zero_item(t) zpl_zero_size((t), zpl_size_of(*(t))) // NOTE: Pass pointer of struct
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Clears up an array.
# define zpl_zero_array(a, count) zpl_zero_size((a), zpl_size_of(*(a)) * count)
# endif
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Copy memory from source to destination.
ZPL_DEF_INLINE void * zpl_memmove ( void * dest , void const * source , zpl_isize size ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Set constant value at memory location with specified size.
ZPL_DEF_INLINE void * zpl_memset ( void * data , zpl_u8 byte_value , zpl_isize size ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Compare two memory locations with specified size.
ZPL_DEF_INLINE zpl_i32 zpl_memcompare ( void const * s1 , void const * s2 , zpl_isize size ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Swap memory contents between 2 locations with size.
ZPL_DEF void zpl_memswap ( void * i , void * j , zpl_isize size ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Search for a constant value within the size limit at memory location.
ZPL_DEF void const * zpl_memchr ( void const * data , zpl_u8 byte_value , zpl_isize size ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Search for a constant value within the size limit at memory location in backwards.
ZPL_DEF void const * zpl_memrchr ( void const * data , zpl_u8 byte_value , zpl_isize size ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Copy non-overlapping memory from source to destination.
ZPL_DEF void * zpl_memcopy ( void * dest , void const * source , zpl_isize size ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
# ifndef zpl_memcopy_array
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Copy non-overlapping array.
# define zpl_memcopy_array(dst, src, count) zpl_memcopy((dst), (src), zpl_size_of(*(dst)) * (count))
# endif
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Copy an array.
# ifndef zpl_memmove_array
# define zpl_memmove_array(dst, src, count) zpl_memmove((dst), (src), zpl_size_of(*(dst)) * (count))
# endif
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
# ifndef ZPL_BIT_CAST
# define ZPL_BIT_CAST(dest, source) \
do { \
ZPL_STATIC_ASSERT ( zpl_size_of ( * ( dest ) ) < = zpl_size_of ( source ) , " zpl_size_of(*(dest)) !<= zpl_size_of(source) " ) ; \
zpl_memcopy ( ( dest ) , & ( source ) , zpl_size_of ( * dest ) ) ; \
} while ( 0 )
# endif
# ifndef zpl_kilobytes
# define zpl_kilobytes(x) ((x) * (zpl_i64)(1024))
# define zpl_megabytes(x) (zpl_kilobytes(x) * (zpl_i64)(1024))
# define zpl_gigabytes(x) (zpl_megabytes(x) * (zpl_i64)(1024))
# define zpl_terabytes(x) (zpl_gigabytes(x) * (zpl_i64)(1024))
# endif
/* inlines */
# define ZPL__ONES (cast(zpl_usize) - 1 / ZPL_U8_MAX)
# define ZPL__HIGHS (ZPL__ONES * (ZPL_U8_MAX / 2 + 1))
# define ZPL__HAS_ZERO(x) (((x)-ZPL__ONES) & ~(x)&ZPL__HIGHS)
ZPL_IMPL_INLINE void * zpl_align_forward ( void * ptr , zpl_isize alignment ) {
zpl_uintptr p ;
ZPL_ASSERT ( zpl_is_power_of_two ( alignment ) ) ;
p = cast ( zpl_uintptr ) ptr ;
return cast ( void * ) ( ( p + ( alignment - 1 ) ) & ~ ( alignment - 1 ) ) ;
}
ZPL_IMPL_INLINE zpl_i64 zpl_align_forward_i64 ( zpl_i64 value , zpl_isize alignment ) {
return value + ( alignment - value % alignment ) % alignment ;
}
ZPL_IMPL_INLINE zpl_u64 zpl_align_forward_u64 ( zpl_u64 value , zpl_usize alignment ) {
return value + ( alignment - value % alignment ) % alignment ;
}
ZPL_IMPL_INLINE void * zpl_pointer_add ( void * ptr , zpl_isize bytes ) { return cast ( void * ) ( cast ( zpl_u8 * ) ptr + bytes ) ; }
ZPL_IMPL_INLINE void * zpl_pointer_sub ( void * ptr , zpl_isize bytes ) { return cast ( void * ) ( cast ( zpl_u8 * ) ptr - bytes ) ; }
ZPL_IMPL_INLINE void const * zpl_pointer_add_const ( void const * ptr , zpl_isize bytes ) {
return cast ( void const * ) ( cast ( zpl_u8 const * ) ptr + bytes ) ;
}
ZPL_IMPL_INLINE void const * zpl_pointer_sub_const ( void const * ptr , zpl_isize bytes ) {
return cast ( void const * ) ( cast ( zpl_u8 const * ) ptr - bytes ) ;
}
ZPL_IMPL_INLINE zpl_isize zpl_pointer_diff ( void const * begin , void const * end ) {
return cast ( zpl_isize ) ( cast ( zpl_u8 const * ) end - cast ( zpl_u8 const * ) begin ) ;
}
ZPL_IMPL_INLINE void zpl_zero_size ( void * ptr , zpl_isize size ) { zpl_memset ( ptr , 0 , size ) ; }
# if defined(_MSC_VER) && !defined(__clang__)
# pragma intrinsic(__movsb)
# endif
ZPL_IMPL_INLINE void * zpl_memmove ( void * dest , void const * source , zpl_isize n ) {
if ( dest = = NULL ) { return NULL ; }
zpl_u8 * d = cast ( zpl_u8 * ) dest ;
zpl_u8 const * s = cast ( zpl_u8 const * ) source ;
if ( d = = s ) return d ;
if ( s + n < = d | | d + n < = s ) // NOTE: Non-overlapping
return zpl_memcopy ( d , s , n ) ;
if ( d < s ) {
if ( cast ( zpl_uintptr ) s % zpl_size_of ( zpl_isize ) = = cast ( zpl_uintptr ) d % zpl_size_of ( zpl_isize ) ) {
while ( cast ( zpl_uintptr ) d % zpl_size_of ( zpl_isize ) ) {
if ( ! n - - ) return dest ;
* d + + = * s + + ;
}
while ( n > = zpl_size_of ( zpl_isize ) ) {
* cast ( zpl_isize * ) d = * cast ( zpl_isize * ) s ;
n - = zpl_size_of ( zpl_isize ) ;
d + = zpl_size_of ( zpl_isize ) ;
s + = zpl_size_of ( zpl_isize ) ;
}
}
for ( ; n ; n - - ) * d + + = * s + + ;
} else {
if ( ( cast ( zpl_uintptr ) s % zpl_size_of ( zpl_isize ) ) = = ( cast ( zpl_uintptr ) d % zpl_size_of ( zpl_isize ) ) ) {
while ( cast ( zpl_uintptr ) ( d + n ) % zpl_size_of ( zpl_isize ) ) {
if ( ! n - - ) return dest ;
d [ n ] = s [ n ] ;
}
while ( n > = zpl_size_of ( zpl_isize ) ) {
n - = zpl_size_of ( zpl_isize ) ;
* cast ( zpl_isize * ) ( d + n ) = * cast ( zpl_isize * ) ( s + n ) ;
}
}
while ( n ) n - - , d [ n ] = s [ n ] ;
}
return dest ;
}
ZPL_IMPL_INLINE void * zpl_memset ( void * dest , zpl_u8 c , zpl_isize n ) {
if ( dest = = NULL ) { return NULL ; }
zpl_u8 * s = cast ( zpl_u8 * ) dest ;
zpl_isize k ;
zpl_u32 c32 = ( ( zpl_u32 ) - 1 ) / 255 * c ;
if ( n = = 0 ) return dest ;
s [ 0 ] = s [ n - 1 ] = c ;
if ( n < 3 ) return dest ;
s [ 1 ] = s [ n - 2 ] = c ;
s [ 2 ] = s [ n - 3 ] = c ;
if ( n < 7 ) return dest ;
s [ 3 ] = s [ n - 4 ] = c ;
if ( n < 9 ) return dest ;
k = - cast ( zpl_intptr ) s & 3 ;
s + = k ;
n - = k ;
n & = - 4 ;
* cast ( zpl_u32 * ) ( s + 0 ) = c32 ;
* cast ( zpl_u32 * ) ( s + n - 4 ) = c32 ;
if ( n < 9 ) return dest ;
* cast ( zpl_u32 * ) ( s + 4 ) = c32 ;
* cast ( zpl_u32 * ) ( s + 8 ) = c32 ;
* cast ( zpl_u32 * ) ( s + n - 12 ) = c32 ;
* cast ( zpl_u32 * ) ( s + n - 8 ) = c32 ;
if ( n < 25 ) return dest ;
* cast ( zpl_u32 * ) ( s + 12 ) = c32 ;
* cast ( zpl_u32 * ) ( s + 16 ) = c32 ;
* cast ( zpl_u32 * ) ( s + 20 ) = c32 ;
* cast ( zpl_u32 * ) ( s + 24 ) = c32 ;
* cast ( zpl_u32 * ) ( s + n - 28 ) = c32 ;
* cast ( zpl_u32 * ) ( s + n - 24 ) = c32 ;
* cast ( zpl_u32 * ) ( s + n - 20 ) = c32 ;
* cast ( zpl_u32 * ) ( s + n - 16 ) = c32 ;
k = 24 + ( cast ( zpl_uintptr ) s & 4 ) ;
s + = k ;
n - = k ;
{
zpl_u64 c64 = ( cast ( zpl_u64 ) c32 < < 32 ) | c32 ;
while ( n > 31 ) {
* cast ( zpl_u64 * ) ( s + 0 ) = c64 ;
* cast ( zpl_u64 * ) ( s + 8 ) = c64 ;
* cast ( zpl_u64 * ) ( s + 16 ) = c64 ;
* cast ( zpl_u64 * ) ( s + 24 ) = c64 ;
n - = 32 ;
s + = 32 ;
}
}
return dest ;
}
ZPL_IMPL_INLINE zpl_i32 zpl_memcompare ( void const * s1 , void const * s2 , zpl_isize size ) {
zpl_u8 const * s1p8 = cast ( zpl_u8 const * ) s1 ;
zpl_u8 const * s2p8 = cast ( zpl_u8 const * ) s2 ;
if ( s1 = = NULL | | s2 = = NULL ) { return 0 ; }
while ( size - - ) {
zpl_isize d ;
if ( ( d = ( * s1p8 + + - * s2p8 + + ) ) ! = 0 ) return cast ( zpl_i32 ) d ;
}
return 0 ;
}
ZPL_IMPL_INLINE zpl_b32 zpl_is_power_of_two ( zpl_isize x ) {
if ( x < = 0 ) return false ;
return ! ( x & ( x - 1 ) ) ;
}
ZPL_END_C_DECLS
// file: header/essentials/memory_custom.h
////////////////////////////////////////////////////////////////
//
// Custom Allocation
//
//
ZPL_BEGIN_C_DECLS
typedef enum zpl_alloc_type {
ZPL_ALLOCATION_ALLOC ,
ZPL_ALLOCATION_FREE ,
ZPL_ALLOCATION_FREE_ALL ,
ZPL_ALLOCATION_RESIZE ,
} zpl_alloc_type ;
// NOTE: This is useful so you can define an allocator of the same type and parameters
# define ZPL_ALLOCATOR_PROC(name) \
void * name ( void * allocator_data , zpl_alloc_type type , zpl_isize size , zpl_isize alignment , void * old_memory , \
zpl_isize old_size , zpl_u64 flags )
typedef ZPL_ALLOCATOR_PROC ( zpl_allocator_proc ) ;
typedef struct zpl_allocator {
zpl_allocator_proc * proc ;
void * data ;
} zpl_allocator ;
typedef enum zpl_alloc_flag {
ZPL_ALLOCATOR_FLAG_CLEAR_TO_ZERO = ZPL_BIT ( 0 ) ,
} zpl_alloc_flag ;
# ifndef ZPL_DEFAULT_MEMORY_ALIGNMENT
# define ZPL_DEFAULT_MEMORY_ALIGNMENT (2 * zpl_size_of(void *))
# endif
# ifndef ZPL_DEFAULT_ALLOCATOR_FLAGS
# define ZPL_DEFAULT_ALLOCATOR_FLAGS (ZPL_ALLOCATOR_FLAG_CLEAR_TO_ZERO)
# endif
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Allocate memory with specified alignment.
ZPL_DEF_INLINE void * zpl_alloc_align ( zpl_allocator a , zpl_isize size , zpl_isize alignment ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Allocate memory with default alignment.
ZPL_DEF_INLINE void * zpl_alloc ( zpl_allocator a , zpl_isize size ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Free allocated memory.
ZPL_DEF_INLINE void zpl_free ( zpl_allocator a , void * ptr ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Free all memory allocated by an allocator.
ZPL_DEF_INLINE void zpl_free_all ( zpl_allocator a ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Resize an allocated memory.
ZPL_DEF_INLINE void * zpl_resize ( zpl_allocator a , void * ptr , zpl_isize old_size , zpl_isize new_size ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Resize an allocated memory with specified alignment.
ZPL_DEF_INLINE void * zpl_resize_align ( zpl_allocator a , void * ptr , zpl_isize old_size , zpl_isize new_size , zpl_isize alignment ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Allocate memory and copy data into it.
ZPL_DEF_INLINE void * zpl_alloc_copy ( zpl_allocator a , void const * src , zpl_isize size ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Allocate memory with specified alignment and copy data into it.
ZPL_DEF_INLINE void * zpl_alloc_copy_align ( zpl_allocator a , void const * src , zpl_isize size , zpl_isize alignment ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Allocate memory for null-terminated C-String.
ZPL_DEF char * zpl_alloc_str ( zpl_allocator a , char const * str ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Allocate memory for C-String with specified size.
ZPL_DEF_INLINE char * zpl_alloc_str_len ( zpl_allocator a , char const * str , zpl_isize len ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
# ifndef zpl_alloc_item
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Allocate memory for an item.
# define zpl_alloc_item(allocator_, Type) (Type *)zpl_alloc(allocator_, zpl_size_of(Type))
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Allocate memory for an array of items.
# define zpl_alloc_array(allocator_, Type, count) (Type *)zpl_alloc(allocator_, zpl_size_of(Type) * (count))
# endif
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
/* heap memory analysis tools */
/* define ZPL_HEAP_ANALYSIS to enable this feature */
/* call zpl_heap_stats_init at the beginning of the entry point */
/* you can call zpl_heap_stats_check near the end of the execution to validate any possible leaks */
ZPL_DEF void zpl_heap_stats_init ( void ) ;
ZPL_DEF zpl_isize zpl_heap_stats_used_memory ( void ) ;
ZPL_DEF zpl_isize zpl_heap_stats_alloc_count ( void ) ;
ZPL_DEF void zpl_heap_stats_check ( void ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Allocate/Resize memory using default options.
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Use this if you don't need a "fancy" resize allocation
ZPL_DEF_INLINE void * zpl_default_resize_align ( zpl_allocator a , void * ptr , zpl_isize old_size , zpl_isize new_size , zpl_isize alignment ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! The heap allocator backed by operating system's memory manager.
ZPL_DEF_INLINE zpl_allocator zpl_heap_allocator ( void ) ;
ZPL_DEF ZPL_ALLOCATOR_PROC ( zpl_heap_allocator_proc ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
# ifndef zpl_malloc
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Helper to allocate memory using heap allocator.
# define zpl_malloc(sz) zpl_alloc(zpl_heap_allocator( ), sz)
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Helper to free memory allocated by heap allocator.
# define zpl_mfree(ptr) zpl_free(zpl_heap_allocator( ), ptr)
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Alias to heap allocator.
# define zpl_heap zpl_heap_allocator
# endif
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//
// Arena Allocator
//
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
typedef struct zpl_arena {
zpl_allocator backing ;
void * physical_start ;
zpl_isize total_size ;
zpl_isize total_allocated ;
zpl_isize temp_count ;
} zpl_arena ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Initialize memory arena from existing memory region.
ZPL_DEF_INLINE void zpl_arena_init_from_memory ( zpl_arena * arena , void * start , zpl_isize size ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Initialize memory arena using existing memory allocator.
ZPL_DEF_INLINE void zpl_arena_init_from_allocator ( zpl_arena * arena , zpl_allocator backing , zpl_isize size ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Initialize memory arena within an existing parent memory arena.
ZPL_DEF_INLINE void zpl_arena_init_sub ( zpl_arena * arena , zpl_arena * parent_arena , zpl_isize size ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Release the memory used by memory arena.
ZPL_DEF_INLINE void zpl_arena_free ( zpl_arena * arena ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Retrieve memory arena's aligned allocation address.
ZPL_DEF_INLINE zpl_isize zpl_arena_alignment_of ( zpl_arena * arena , zpl_isize alignment ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Retrieve memory arena's remaining size.
ZPL_DEF_INLINE zpl_isize zpl_arena_size_remaining ( zpl_arena * arena , zpl_isize alignment ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Check whether memory arena has any temporary snapshots.
ZPL_DEF_INLINE void zpl_arena_check ( zpl_arena * arena ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Allocation Types: alloc, free_all, resize
ZPL_DEF_INLINE zpl_allocator zpl_arena_allocator ( zpl_arena * arena ) ;
ZPL_DEF ZPL_ALLOCATOR_PROC ( zpl_arena_allocator_proc ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
typedef struct zpl_arena_snapshot {
zpl_arena * arena ;
zpl_isize original_count ;
} zpl_arena_snapshot ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Capture a snapshot of used memory in a memory arena.
ZPL_DEF_INLINE zpl_arena_snapshot zpl_arena_snapshot_begin ( zpl_arena * arena ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Reset memory arena's usage by a captured snapshot.
ZPL_DEF_INLINE void zpl_arena_snapshot_end ( zpl_arena_snapshot tmp_mem ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//
// Pool Allocator
//
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
typedef struct zpl_pool {
zpl_allocator backing ;
void * physical_start ;
void * free_list ;
zpl_isize block_size ;
zpl_isize block_align ;
zpl_isize total_size ;
zpl_isize num_blocks ;
} zpl_pool ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Initialize pool allocator.
ZPL_DEF_INLINE void zpl_pool_init ( zpl_pool * pool , zpl_allocator backing , zpl_isize num_blocks , zpl_isize block_size ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Initialize pool allocator with specific block alignment.
ZPL_DEF void zpl_pool_init_align ( zpl_pool * pool , zpl_allocator backing , zpl_isize num_blocks , zpl_isize block_size ,
zpl_isize block_align ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Release the resources used by pool allocator.
ZPL_DEF_INLINE void zpl_pool_free ( zpl_pool * pool ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Allocation Types: alloc, free
ZPL_DEF_INLINE zpl_allocator zpl_pool_allocator ( zpl_pool * pool ) ;
ZPL_DEF ZPL_ALLOCATOR_PROC ( zpl_pool_allocator_proc ) ;
//
// Scratch Memory Allocator - Ring Buffer Based Arena
//
typedef struct zpl_allocation_header_ev {
zpl_isize size ;
} zpl_allocation_header_ev ;
ZPL_DEF_INLINE zpl_allocation_header_ev * zpl_allocation_header ( void * data ) ;
ZPL_DEF_INLINE void zpl_allocation_header_fill ( zpl_allocation_header_ev * header , void * data , zpl_isize size ) ;
# if defined(ZPL_ARCH_32_BIT)
# define ZPL_ISIZE_HIGH_BIT 0x80000000
# elif defined(ZPL_ARCH_64_BIT)
# define ZPL_ISIZE_HIGH_BIT 0x8000000000000000ll
# else
# error
# endif
typedef struct zpl_scratch_memory {
void * physical_start ;
zpl_isize total_size ;
void * alloc_point ;
void * free_point ;
} zpl_scratch_memory ;
//! Initialize ring buffer arena.
ZPL_DEF void zpl_scratch_memory_init ( zpl_scratch_memory * s , void * start , zpl_isize size ) ;
//! Check whether ring buffer arena is in use.
ZPL_DEF zpl_b32 zpl_scratch_memory_is_in_use ( zpl_scratch_memory * s , void * ptr ) ;
//! Allocation Types: alloc, free, free_all, resize
ZPL_DEF zpl_allocator zpl_scratch_allocator ( zpl_scratch_memory * s ) ;
ZPL_DEF ZPL_ALLOCATOR_PROC ( zpl_scratch_allocator_proc ) ;
//
// Stack Memory Allocator
//
typedef struct zpl_stack_memory {
zpl_allocator backing ;
void * physical_start ;
zpl_usize total_size ;
zpl_usize allocated ;
} zpl_stack_memory ;
//! Initialize stack allocator from existing memory.
ZPL_DEF_INLINE void zpl_stack_memory_init_from_memory ( zpl_stack_memory * s , void * start , zpl_isize size ) ;
//! Initialize stack allocator using existing memory allocator.
ZPL_DEF_INLINE void zpl_stack_memory_init ( zpl_stack_memory * s , zpl_allocator backing , zpl_isize size ) ;
//! Check whether stack allocator is in use.
ZPL_DEF_INLINE zpl_b32 zpl_stack_memory_is_in_use ( zpl_stack_memory * s , void * ptr ) ;
//! Release the resources used by stack allocator.
ZPL_DEF_INLINE void zpl_stack_memory_free ( zpl_stack_memory * s ) ;
//! Allocation Types: alloc, free, free_all
ZPL_DEF_INLINE zpl_allocator zpl_stack_allocator ( zpl_stack_memory * s ) ;
ZPL_DEF ZPL_ALLOCATOR_PROC ( zpl_stack_allocator_proc ) ;
/* inlines */
ZPL_IMPL_INLINE void * zpl_alloc_align ( zpl_allocator a , zpl_isize size , zpl_isize alignment ) {
return a . proc ( a . data , ZPL_ALLOCATION_ALLOC , size , alignment , NULL , 0 , ZPL_DEFAULT_ALLOCATOR_FLAGS ) ;
}
ZPL_IMPL_INLINE void * zpl_alloc ( zpl_allocator a , zpl_isize size ) {
return zpl_alloc_align ( a , size , ZPL_DEFAULT_MEMORY_ALIGNMENT ) ;
}
ZPL_IMPL_INLINE void zpl_free ( zpl_allocator a , void * ptr ) {
if ( ptr ! = NULL ) a . proc ( a . data , ZPL_ALLOCATION_FREE , 0 , 0 , ptr , 0 , ZPL_DEFAULT_ALLOCATOR_FLAGS ) ;
}
ZPL_IMPL_INLINE void zpl_free_all ( zpl_allocator a ) {
a . proc ( a . data , ZPL_ALLOCATION_FREE_ALL , 0 , 0 , NULL , 0 , ZPL_DEFAULT_ALLOCATOR_FLAGS ) ;
}
ZPL_IMPL_INLINE void * zpl_resize ( zpl_allocator a , void * ptr , zpl_isize old_size , zpl_isize new_size ) {
return zpl_resize_align ( a , ptr , old_size , new_size , ZPL_DEFAULT_MEMORY_ALIGNMENT ) ;
}
ZPL_IMPL_INLINE void * zpl_resize_align ( zpl_allocator a , void * ptr , zpl_isize old_size , zpl_isize new_size , zpl_isize alignment ) {
return a . proc ( a . data , ZPL_ALLOCATION_RESIZE , new_size , alignment , ptr , old_size , ZPL_DEFAULT_ALLOCATOR_FLAGS ) ;
}
ZPL_IMPL_INLINE void * zpl_alloc_copy ( zpl_allocator a , void const * src , zpl_isize size ) {
return zpl_memcopy ( zpl_alloc ( a , size ) , src , size ) ;
}
ZPL_IMPL_INLINE void * zpl_alloc_copy_align ( zpl_allocator a , void const * src , zpl_isize size , zpl_isize alignment ) {
return zpl_memcopy ( zpl_alloc_align ( a , size , alignment ) , src , size ) ;
}
ZPL_IMPL_INLINE char * zpl_alloc_str_len ( zpl_allocator a , char const * str , zpl_isize len ) {
char * result ;
result = cast ( char * ) zpl_alloc ( a , len + 1 ) ;
zpl_memmove ( result , str , len ) ;
result [ len ] = ' \0 ' ;
return result ;
}
ZPL_IMPL_INLINE void * zpl_default_resize_align ( zpl_allocator a , void * old_memory , zpl_isize old_size , zpl_isize new_size ,
zpl_isize alignment ) {
if ( ! old_memory ) return zpl_alloc_align ( a , new_size , alignment ) ;
if ( new_size = = 0 ) {
zpl_free ( a , old_memory ) ;
return NULL ;
}
if ( new_size < old_size ) new_size = old_size ;
if ( old_size = = new_size ) {
return old_memory ;
} else {
void * new_memory = zpl_alloc_align ( a , new_size , alignment ) ;
if ( ! new_memory ) return NULL ;
zpl_memmove ( new_memory , old_memory , zpl_min ( new_size , old_size ) ) ;
zpl_free ( a , old_memory ) ;
return new_memory ;
}
}
//
// Heap Allocator
//
ZPL_IMPL_INLINE zpl_allocator zpl_heap_allocator ( void ) {
zpl_allocator a ;
a . proc = zpl_heap_allocator_proc ;
a . data = NULL ;
return a ;
}
//
// Arena Allocator
//
ZPL_IMPL_INLINE void zpl_arena_init_from_memory ( zpl_arena * arena , void * start , zpl_isize size ) {
arena - > backing . proc = NULL ;
arena - > backing . data = NULL ;
arena - > physical_start = start ;
arena - > total_size = size ;
arena - > total_allocated = 0 ;
arena - > temp_count = 0 ;
}
ZPL_IMPL_INLINE void zpl_arena_init_from_allocator ( zpl_arena * arena , zpl_allocator backing , zpl_isize size ) {
arena - > backing = backing ;
arena - > physical_start = zpl_alloc ( backing , size ) ; // NOTE: Uses default alignment
arena - > total_size = size ;
arena - > total_allocated = 0 ;
arena - > temp_count = 0 ;
}
ZPL_IMPL_INLINE void zpl_arena_init_sub ( zpl_arena * arena , zpl_arena * parent_arena , zpl_isize size ) {
zpl_arena_init_from_allocator ( arena , zpl_arena_allocator ( parent_arena ) , size ) ;
}
ZPL_IMPL_INLINE void zpl_arena_free ( zpl_arena * arena ) {
if ( arena - > backing . proc ) {
zpl_free ( arena - > backing , arena - > physical_start ) ;
arena - > physical_start = NULL ;
}
}
ZPL_IMPL_INLINE zpl_isize zpl_arena_alignment_of ( zpl_arena * arena , zpl_isize alignment ) {
zpl_isize alignment_offset , result_pointer , mask ;
ZPL_ASSERT ( zpl_is_power_of_two ( alignment ) ) ;
alignment_offset = 0 ;
result_pointer = cast ( zpl_isize ) arena - > physical_start + arena - > total_allocated ;
mask = alignment - 1 ;
if ( result_pointer & mask ) alignment_offset = alignment - ( result_pointer & mask ) ;
return alignment_offset ;
}
ZPL_IMPL_INLINE zpl_isize zpl_arena_size_remaining ( zpl_arena * arena , zpl_isize alignment ) {
zpl_isize result = arena - > total_size - ( arena - > total_allocated + zpl_arena_alignment_of ( arena , alignment ) ) ;
return result ;
}
ZPL_IMPL_INLINE void zpl_arena_check ( zpl_arena * arena ) { ZPL_ASSERT ( arena - > temp_count = = 0 ) ; }
ZPL_IMPL_INLINE zpl_allocator zpl_arena_allocator ( zpl_arena * arena ) {
zpl_allocator allocator ;
allocator . proc = zpl_arena_allocator_proc ;
allocator . data = arena ;
return allocator ;
}
ZPL_IMPL_INLINE zpl_arena_snapshot zpl_arena_snapshot_begin ( zpl_arena * arena ) {
zpl_arena_snapshot tmp ;
tmp . arena = arena ;
tmp . original_count = arena - > total_allocated ;
arena - > temp_count + + ;
return tmp ;
}
ZPL_IMPL_INLINE void zpl_arena_snapshot_end ( zpl_arena_snapshot tmp ) {
ZPL_ASSERT ( tmp . arena - > total_allocated > = tmp . original_count ) ;
ZPL_ASSERT ( tmp . arena - > temp_count > 0 ) ;
tmp . arena - > total_allocated = tmp . original_count ;
tmp . arena - > temp_count - - ;
}
//
// Pool Allocator
//
ZPL_IMPL_INLINE void zpl_pool_init ( zpl_pool * pool , zpl_allocator backing , zpl_isize num_blocks , zpl_isize block_size ) {
zpl_pool_init_align ( pool , backing , num_blocks , block_size , ZPL_DEFAULT_MEMORY_ALIGNMENT ) ;
}
ZPL_IMPL_INLINE void zpl_pool_free ( zpl_pool * pool ) {
if ( pool - > backing . proc ) { zpl_free ( pool - > backing , pool - > physical_start ) ; }
}
ZPL_IMPL_INLINE zpl_allocator zpl_pool_allocator ( zpl_pool * pool ) {
zpl_allocator allocator ;
allocator . proc = zpl_pool_allocator_proc ;
allocator . data = pool ;
return allocator ;
}
ZPL_IMPL_INLINE zpl_allocation_header_ev * zpl_allocation_header ( void * data ) {
zpl_isize * p = cast ( zpl_isize * ) data ;
while ( p [ - 1 ] = = cast ( zpl_isize ) ( - 1 ) ) p - - ;
return cast ( zpl_allocation_header_ev * ) p - 1 ;
}
ZPL_IMPL_INLINE void zpl_allocation_header_fill ( zpl_allocation_header_ev * header , void * data , zpl_isize size ) {
zpl_isize * ptr ;
header - > size = size ;
ptr = cast ( zpl_isize * ) ( header + 1 ) ;
while ( cast ( void * ) ptr < data ) * ptr + + = cast ( zpl_isize ) ( - 1 ) ;
}
//
// Stack Memory Allocator
//
# define ZPL_STACK_ALLOC_OFFSET sizeof(zpl_u64)
ZPL_STATIC_ASSERT ( ZPL_STACK_ALLOC_OFFSET = = 8 , " ZPL_STACK_ALLOC_OFFSET != 8 " ) ;
ZPL_IMPL_INLINE void zpl_stack_memory_init_from_memory ( zpl_stack_memory * s , void * start , zpl_isize size ) {
s - > physical_start = start ;
s - > total_size = size ;
s - > allocated = 0 ;
}
ZPL_IMPL_INLINE void zpl_stack_memory_init ( zpl_stack_memory * s , zpl_allocator backing , zpl_isize size ) {
s - > backing = backing ;
s - > physical_start = zpl_alloc ( backing , size ) ;
s - > total_size = size ;
s - > allocated = 0 ;
}
ZPL_IMPL_INLINE zpl_b32 zpl_stack_memory_is_in_use ( zpl_stack_memory * s , void * ptr ) {
if ( s - > allocated = = 0 ) return false ;
if ( ptr > s - > physical_start & & ptr < zpl_pointer_add ( s - > physical_start , s - > total_size ) ) { return true ; }
return false ;
}
ZPL_IMPL_INLINE void zpl_stack_memory_free ( zpl_stack_memory * s ) {
if ( s - > backing . proc ) {
zpl_free ( s - > backing , s - > physical_start ) ;
s - > physical_start = NULL ;
}
}
ZPL_IMPL_INLINE zpl_allocator zpl_stack_allocator ( zpl_stack_memory * s ) {
zpl_allocator a ;
a . proc = zpl_stack_allocator_proc ;
a . data = s ;
return a ;
}
ZPL_END_C_DECLS
// file: header/essentials/collections/array.h
////////////////////////////////////////////////////////////////
//
// Dynamic Array (POD Types)
//
// zpl_array(Type) works like zpl_string or zpl_buffer where the actual type is just a pointer to the first
// element.
//
// Available Procedures for zpl_array(Type)
// zpl_array_init
// zpl_array_free
// zpl_array_set_capacity
// zpl_array_grow
// zpl_array_append
// zpl_array_appendv
// zpl_array_pop
// zpl_array_clear
// zpl_array_back
// zpl_array_front
// zpl_array_resize
// zpl_array_reserve
//
#if 0 // Example
void foo ( void ) {
zpl_isize i ;
int test_values [ ] = { 4 , 2 , 1 , 7 } ;
zpl_allocator a = zpl_heap_allocator ( ) ;
zpl_array ( int ) items ;
zpl_array_init ( items , a ) ;
zpl_array_append ( items , 1 ) ;
zpl_array_append ( items , 4 ) ;
zpl_array_append ( items , 9 ) ;
zpl_array_append ( items , 16 ) ;
items [ 1 ] = 3 ; // Manually set value
// NOTE: No array bounds checking
for ( i = 0 ; i < items . count ; i + + )
zpl_printf ( " %d \n " , items [ i ] ) ;
// 1
// 3
// 9
// 16
zpl_array_clear ( items ) ;
zpl_array_appendv ( items , test_values , zpl_count_of ( test_values ) ) ;
for ( i = 0 ; i < items . count ; i + + )
zpl_printf ( " %d \n " , items [ i ] ) ;
// 4
// 2
// 1
// 7
zpl_array_free ( items ) ;
}
# endif
ZPL_BEGIN_C_DECLS
typedef struct zpl_array_header {
char * data ;
zpl_isize count ;
zpl_isize capacity ;
zpl_allocator allocator ;
} zpl_array_header ;
# define zpl_array(Type) Type *
# define zpl_array_make(Type, Name, allocator) Type *Name; zpl_array_init(Name, allocator)
# ifndef ZPL_ARRAY_GROW_FORMULA
# define ZPL_ARRAY_GROW_FORMULA(x) (2 * (x) + 8)
# endif
ZPL_STATIC_ASSERT ( ZPL_ARRAY_GROW_FORMULA ( 0 ) > 0 , " ZPL_ARRAY_GROW_FORMULA(0) <= 0 " ) ;
# define ZPL_ARRAY_HEADER(x) (cast(zpl_array_header *)(x) - 1)
# define zpl_array_allocator(x) (ZPL_ARRAY_HEADER(x)->allocator)
# define zpl_array_count(x) (ZPL_ARRAY_HEADER(x)->count)
# define zpl_array_capacity(x) (ZPL_ARRAY_HEADER(x)->capacity)
# define zpl_array_end(x) (x + (zpl_array_count(x) - 1))
# define zpl_array_init_reserve(x, allocator_, cap) \
do { \
void * * zpl__array_ = cast ( void * * ) & ( x ) ; \
zpl_array_header * zpl__ah = \
cast ( zpl_array_header * ) zpl_alloc ( allocator_ , zpl_size_of ( zpl_array_header ) + zpl_size_of ( * ( x ) ) * ( cap ) ) ; \
zpl__ah - > allocator = allocator_ ; \
zpl__ah - > count = 0 ; \
zpl__ah - > data = ( char * ) x ; \
zpl__ah - > capacity = cap ; \
* zpl__array_ = cast ( void * ) ( zpl__ah + 1 ) ; \
} while ( 0 )
// NOTE: Give it an initial default capacity
# define zpl_array_init(x, allocator) zpl_array_init_reserve(x, allocator, ZPL_ARRAY_GROW_FORMULA(0))
# define zpl_array_free(x) \
do { \
zpl_array_header * zpl__ah = ZPL_ARRAY_HEADER ( x ) ; \
zpl_free ( zpl__ah - > allocator , zpl__ah ) ; \
} while ( 0 )
# define zpl_array_set_capacity(x, capacity) \
do { \
if ( x ) { \
void * * zpl__array_ = cast ( void * * ) & ( x ) ; \
* zpl__array_ = zpl__array_set_capacity ( ( x ) , ( capacity ) , zpl_size_of ( * ( x ) ) ) ; \
} \
} while ( 0 )
// NOTE: Do not use the thing below directly, use the macro
ZPL_DEF void * zpl__array_set_capacity ( void * array , zpl_isize capacity , zpl_isize element_size ) ;
# define zpl_array_grow(x, min_capacity) \
do { \
zpl_isize new_capacity = ZPL_ARRAY_GROW_FORMULA ( zpl_array_capacity ( x ) ) ; \
if ( new_capacity < ( min_capacity ) ) new_capacity = ( min_capacity ) ; \
zpl_array_set_capacity ( x , new_capacity ) ; \
} while ( 0 )
# define zpl_array_append(x, item) \
do { \
if ( zpl_array_capacity ( x ) < zpl_array_count ( x ) + 1 ) zpl_array_grow ( x , 0 ) ; \
( x ) [ zpl_array_count ( x ) + + ] = ( item ) ; \
} while ( 0 )
# define zpl_array_append_at(x, item, ind) \
do { \
if ( ind > = zpl_array_count ( x ) ) { zpl_array_append ( x , item ) ; break ; } \
if ( zpl_array_capacity ( x ) < zpl_array_count ( x ) + 1 ) zpl_array_grow ( x , 0 ) ; \
zpl_memmove ( & ( x ) [ ind + 1 ] , ( x + ind ) , zpl_size_of ( x [ 0 ] ) * ( zpl_array_count ( x ) - ind ) ) ; \
x [ ind ] = item ; \
zpl_array_count ( x ) + + ; \
} while ( 0 )
# define zpl_array_appendv(x, items, item_count) \
do { \
ZPL_ASSERT ( zpl_size_of ( ( items ) [ 0 ] ) = = zpl_size_of ( ( x ) [ 0 ] ) ) ; \
if ( zpl_array_capacity ( x ) < zpl_array_count ( x ) + ( item_count ) ) zpl_array_grow ( x , zpl_array_count ( x ) + ( item_count ) ) ; \
zpl_memcopy ( & ( x ) [ zpl_array_count ( x ) ] , ( items ) , zpl_size_of ( ( x ) [ 0 ] ) * ( item_count ) ) ; \
zpl_array_count ( x ) + = ( item_count ) ; \
} while ( 0 )
# define zpl_array_appendv_at(x, items, item_count, ind) \
do { \
if ( ind > = zpl_array_count ( x ) ) { zpl_array_appendv ( x , items , item_count ) ; break ; } \
ZPL_ASSERT ( zpl_size_of ( ( items ) [ 0 ] ) = = zpl_size_of ( ( x ) [ 0 ] ) ) ; \
if ( zpl_array_capacity ( x ) < zpl_array_count ( x ) + ( item_count ) ) zpl_array_grow ( x , zpl_array_count ( x ) + ( item_count ) ) ; \
zpl_memmove ( x + ind + ( item_count ) , x + ind , zpl_size_of ( ( x ) [ 0 ] ) * zpl_array_count ( x ) ) ; \
zpl_memcopy ( & ( x ) [ ind ] , ( items ) , zpl_size_of ( ( x ) [ 0 ] ) * ( item_count ) ) ; \
zpl_array_count ( x ) + = ( item_count ) ; \
} while ( 0 )
# define zpl_array_fill(x, begin, end, value) \
do { \
ZPL_ASSERT ( ( begin ) > = 0 & & ( end ) < zpl_array_count ( x ) ) ; \
ZPL_ASSERT ( zpl_size_of ( value ) = = zpl_size_of ( ( x ) [ 0 ] ) ) ; \
for ( zpl_isize i = ( begin ) ; i < ( end ) ; i + + ) { x [ i ] = value ; } \
} while ( 0 )
# define zpl_array_remove_at(x, index) \
do { \
zpl_array_header * zpl__ah = ZPL_ARRAY_HEADER ( x ) ; \
ZPL_ASSERT ( index < zpl__ah - > count ) ; \
zpl_memmove ( x + index , x + index + 1 , zpl_size_of ( x [ 0 ] ) * ( zpl__ah - > count - index - 1 ) ) ; \
- - zpl__ah - > count ; \
} while ( 0 )
# define zpl_array_copy_init(y, x) \
do { \
zpl_array_init_reserve ( y , zpl_array_allocator ( x ) , zpl_array_capacity ( x ) ) ; \
zpl_memcopy ( y , x , zpl_array_capacity ( x ) * zpl_size_of ( * x ) ) ; \
zpl_array_count ( y ) = zpl_array_count ( x ) ; \
} while ( 0 )
# define zpl_array_pop(x) \
do { \
ZPL_ASSERT ( ZPL_ARRAY_HEADER ( x ) - > count > 0 ) ; \
ZPL_ARRAY_HEADER ( x ) - > count - - ; \
} while ( 0 )
# define zpl_array_back(x) x[ZPL_ARRAY_HEADER(x)->count - 1]
# define zpl_array_front(x) x[0]
# define zpl_array_clear(x) \
do { ZPL_ARRAY_HEADER ( x ) - > count = 0 ; } while ( 0 )
# define zpl_array_resize(x, new_count) \
do { \
if ( ZPL_ARRAY_HEADER ( x ) - > capacity < ( new_count ) ) zpl_array_grow ( x , ( new_count ) ) ; \
ZPL_ARRAY_HEADER ( x ) - > count = ( new_count ) ; \
} while ( 0 )
# define zpl_array_reserve(x, new_capacity) \
do { \
if ( ZPL_ARRAY_HEADER ( x ) - > capacity < ( new_capacity ) ) zpl_array_set_capacity ( x , new_capacity ) ; \
} while ( 0 )
ZPL_END_C_DECLS
// file: header/essentials/collections/buffer.h
////////////////////////////////////////////////////////////////
//
// Fixed Capacity Buffer (POD Types)
//
//
// zpl_buffer(Type) works like zpl_string or zpl_array where the actual type is just a pointer to the first
// element.
//
// Available Procedures for zpl_buffer(Type)
// zpl_buffer_init
// zpl_buffer_free
// zpl_buffer_append
// zpl_buffer_appendv
// zpl_buffer_pop
// zpl_buffer_clear
ZPL_BEGIN_C_DECLS
typedef struct zpl_buffer_header {
zpl_allocator backing ;
zpl_isize count ;
zpl_isize capacity ;
} zpl_buffer_header ;
# define zpl_buffer(Type) Type *
# define zpl_buffer_make(Type, Name, allocator, cap) Type *Name; zpl_buffer_init(Name, allocator, cap)
# define ZPL_BUFFER_HEADER(x) (cast(zpl_buffer_header *)(x) - 1)
# define zpl_buffer_count(x) (ZPL_BUFFER_HEADER(x)->count)
# define zpl_buffer_capacity(x) (ZPL_BUFFER_HEADER(x)->capacity)
# define zpl_buffer_end(x) (x + (zpl_buffer_count(x) - 1))
# define zpl_buffer_init(x, allocator, cap) \
do { \
void * * nx = cast ( void * * ) & ( x ) ; \
zpl_buffer_header * zpl__bh = \
cast ( zpl_buffer_header * ) zpl_alloc ( ( allocator ) , sizeof ( zpl_buffer_header ) + ( cap ) * zpl_size_of ( * ( x ) ) ) ; \
zpl__bh - > backing = allocator ; \
zpl__bh - > count = 0 ; \
zpl__bh - > capacity = cap ; \
* nx = cast ( void * ) ( zpl__bh + 1 ) ; \
} while ( 0 )
# define zpl_buffer_free(x) (zpl_free(ZPL_BUFFER_HEADER(x)->backing, ZPL_BUFFER_HEADER(x)))
# define zpl_buffer_append(x, item) \
do { ( x ) [ zpl_buffer_count ( x ) + + ] = ( item ) ; } while ( 0 )
# define zpl_buffer_appendv(x, items, item_count) \
do { \
ZPL_ASSERT ( zpl_size_of ( * ( items ) ) = = zpl_size_of ( * ( x ) ) ) ; \
ZPL_ASSERT ( zpl_buffer_count ( x ) + item_count < = zpl_buffer_capacity ( x ) ) ; \
zpl_memcopy ( & ( x ) [ zpl_buffer_count ( x ) ] , ( items ) , zpl_size_of ( * ( x ) ) * ( item_count ) ) ; \
zpl_buffer_count ( x ) + = ( item_count ) ; \
} while ( 0 )
# define zpl_buffer_copy_init(y, x) \
do { \
zpl_buffer_init_reserve ( y , zpl_buffer_allocator ( x ) , zpl_buffer_capacity ( x ) ) ; \
zpl_memcopy ( y , x , zpl_buffer_capacity ( x ) * zpl_size_of ( * x ) ) ; \
zpl_buffer_count ( y ) = zpl_buffer_count ( x ) ; \
} while ( 0 )
# define zpl_buffer_pop(x) \
do { \
ZPL_ASSERT ( zpl_buffer_count ( x ) > 0 ) ; \
zpl_buffer_count ( x ) - - ; \
} while ( 0 )
# define zpl_buffer_clear(x) \
do { zpl_buffer_count ( x ) = 0 ; } while ( 0 )
ZPL_END_C_DECLS
// file: header/essentials/collections/list.h
////////////////////////////////////////////////////////////////
//
// Linked List
//
// zpl_list encapsulates pointer to data and points to the next and the previous element in the list.
//
// Available Procedures for zpl_list
// zpl_list_init
// zpl_list_add
// zpl_list_remove
ZPL_BEGIN_C_DECLS
#if 0
# define ZPL_IMPLEMENTATION
# include "zpl.h"
int main ( void )
{
zpl_list s , * head , * cursor ;
zpl_list_init ( & s , " it is optional to call init: " ) ;
head = cursor = & s ;
// since we can construct an element implicitly this way
// the second field gets overwritten once we add it to a list.
zpl_list a = { " hello " } ;
cursor = zpl_list_add ( cursor , & a ) ;
zpl_list b = { " world " } ;
cursor = zpl_list_add ( cursor , & b ) ;
zpl_list c = { " !!! OK " } ;
cursor = zpl_list_add ( cursor , & c ) ;
for ( zpl_list * l = head ; l ; l = l - > next ) {
zpl_printf ( " %s " , cast ( char * ) l - > ptr ) ;
}
zpl_printf ( " \n " ) ;
return 0 ;
}
# endif
typedef struct zpl__list {
void const * ptr ;
struct zpl__list * next , * prev ;
} zpl_list ;
ZPL_DEF_INLINE void zpl_list_init ( zpl_list * list , void const * ptr ) ;
ZPL_DEF_INLINE zpl_list * zpl_list_add ( zpl_list * list , zpl_list * item ) ;
// NOTE(zaklaus): Returns a pointer to the next node (or NULL if the removed node has no trailing node.)
ZPL_DEF_INLINE zpl_list * zpl_list_remove ( zpl_list * list ) ;
ZPL_IMPL_INLINE void zpl_list_init ( zpl_list * list , void const * ptr ) {
zpl_list list_ = { 0 } ;
* list = list_ ;
list - > ptr = ptr ;
}
ZPL_IMPL_INLINE zpl_list * zpl_list_add ( zpl_list * list , zpl_list * item ) {
item - > next = NULL ;
if ( list - > next ) { item - > next = list - > next ; }
list - > next = item ;
item - > prev = list ;
return item ;
}
ZPL_IMPL_INLINE zpl_list * zpl_list_remove ( zpl_list * list ) {
if ( list - > prev ) { list - > prev - > next = list - > next ; }
return list - > next ;
}
ZPL_END_C_DECLS
// file: header/essentials/collections/ring.h
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
////////////////////////////////////////////////////////////////
//
// Instantiated Circular buffer
//
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
/*
Buffer type and function declaration , call : ZPL_RING_DECLARE ( PREFIX , FUNC , VALUE )
Buffer function definitions , call : ZPL_RING_DEFINE ( PREFIX , FUNC , VALUE )
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
PREFIX - a prefix for function prototypes e . g . extern , static , etc .
FUNC - the name will prefix function names
VALUE - the type of the value to be stored
funcname_init ( VALUE * pad , zpl_allocator a , zpl_isize max_size )
funcname_free ( VALUE * pad )
funcname_full ( VALUE * pad )
funcname_empty ( VALUE * pad )
funcname_append ( VALUE * pad , type data )
funcname_append_array ( VALUE * pad , zpl_array ( type ) data )
funcname_get ( VALUE * pad )
funcname_get_array ( VALUE * pad , zpl_usize max_size , zpl_allocator a )
*/
ZPL_BEGIN_C_DECLS
# define ZPL_RING(PREFIX, FUNC, VALUE) \
ZPL_RING_DECLARE ( PREFIX , FUNC , VALUE ) ; \
ZPL_RING_DEFINE ( FUNC , VALUE ) ;
# define ZPL_RING_DECLARE(prefix,func,type) \
typedef struct { \
zpl_allocator backing ; \
zpl_buffer ( type ) buf ; \
zpl_usize head , tail ; \
zpl_usize capacity ; \
} ZPL_JOIN2 ( func , type ) ; \
\
prefix void ZPL_JOIN2 ( func , init ) ( ZPL_JOIN2 ( func , type ) * pad , zpl_allocator a , zpl_isize max_size ) ; \
prefix void ZPL_JOIN2 ( func , free ) ( ZPL_JOIN2 ( func , type ) * pad ) ; \
prefix zpl_b32 ZPL_JOIN2 ( func , full ) ( ZPL_JOIN2 ( func , type ) * pad ) ; \
prefix zpl_b32 ZPL_JOIN2 ( func , empty ) ( ZPL_JOIN2 ( func , type ) * pad ) ; \
prefix void ZPL_JOIN2 ( func , append ) ( ZPL_JOIN2 ( func , type ) * pad , type data ) ; \
prefix void ZPL_JOIN2 ( func , append_array ) ( ZPL_JOIN2 ( func , type ) * pad , zpl_array ( type ) data ) ; \
prefix type * ZPL_JOIN2 ( func , get ) ( ZPL_JOIN2 ( func , type ) * pad ) ; \
prefix zpl_array ( type ) \
ZPL_JOIN2 ( func , get_array ) ( ZPL_JOIN2 ( func , type ) * pad , zpl_usize max_size , zpl_allocator a ) ;
# define ZPL_RING_DEFINE(func,type) \
void ZPL_JOIN2 ( func , init ) ( ZPL_JOIN2 ( func , type ) * pad , zpl_allocator a , zpl_isize max_size ) { \
ZPL_JOIN2 ( func , type ) pad_ = { 0 } ; \
* pad = pad_ ; \
\
pad - > backing = a ; \
zpl_buffer_init ( pad - > buf , a , max_size + 1 ) ; \
pad - > capacity = max_size + 1 ; \
pad - > head = pad - > tail = 0 ; \
} \
void ZPL_JOIN2 ( func , free ) ( ZPL_JOIN2 ( func , type ) * pad ) { \
zpl_buffer_free ( pad - > buf ) ; \
} \
\
zpl_b32 ZPL_JOIN2 ( func , full ) ( ZPL_JOIN2 ( func , type ) * pad ) { \
return ( ( pad - > head + 1 ) % pad - > capacity ) = = pad - > tail ; \
} \
\
zpl_b32 ZPL_JOIN2 ( func , empty ) ( ZPL_JOIN2 ( func , type ) * pad ) { return pad - > head = = pad - > tail ; } \
\
void ZPL_JOIN2 ( func , append ) ( ZPL_JOIN2 ( func , type ) * pad , type data ) { \
pad - > buf [ pad - > head ] = data ; \
pad - > head = ( pad - > head + 1 ) % pad - > capacity ; \
\
if ( pad - > head = = pad - > tail ) { pad - > tail = ( pad - > tail + 1 ) % pad - > capacity ; } \
} \
\
void ZPL_JOIN2 ( func , append_array ) ( ZPL_JOIN2 ( func , type ) * pad , zpl_array ( type ) data ) { \
zpl_usize c = zpl_array_count ( data ) ; \
for ( zpl_usize i = 0 ; i < c ; + + i ) { ZPL_JOIN2 ( func , append ) ( pad , data [ i ] ) ; } \
} \
\
type * ZPL_JOIN2 ( func , get ) ( ZPL_JOIN2 ( func , type ) * pad ) { \
if ( ZPL_JOIN2 ( func , empty ) ( pad ) ) { return NULL ; } \
\
type * data = & pad - > buf [ pad - > tail ] ; \
pad - > tail = ( pad - > tail + 1 ) % pad - > capacity ; \
\
return data ; \
} \
\
zpl_array ( type ) \
ZPL_JOIN2 ( func , get_array ) ( ZPL_JOIN2 ( func , type ) * pad , zpl_usize max_size , zpl_allocator a ) { \
zpl_array ( type ) vals = 0 ; \
zpl_array_init ( vals , a ) ; \
while ( - - max_size & & ! ZPL_JOIN2 ( func , empty ) ( pad ) ) { \
zpl_array_append ( vals , * ZPL_JOIN2 ( func , get ) ( pad ) ) ; \
} \
return vals ; \
}
ZPL_END_C_DECLS
// file: header/essentials/collections/hashtable.h
2022-09-18 15:35:53 +00:00
2022-09-11 17:42:06 +00:00
/** @file hashtable.c
@ brief Instantiated hash table
@ defgroup hashtable Instantiated hash table
2022-09-18 15:35:53 +00:00
2022-09-11 17:42:06 +00:00
This is an attempt to implement a templated hash table
NOTE : The key is always a zpl_u64 for simplicity and you will _probably_ _never_ need anything bigger .
2022-09-18 15:35:53 +00:00
2022-09-11 17:42:06 +00:00
Hash table type and function declaration , call : ZPL_TABLE_DECLARE ( PREFIX , NAME , FUNC , VALUE )
Hash table function definitions , call : ZPL_TABLE_DEFINE ( NAME , FUNC , VALUE )
2022-09-18 15:35:53 +00:00
2022-09-11 17:42:06 +00:00
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
2022-09-18 15:35:53 +00:00
tablename_init ( NAME * h , zpl_allocator a ) ;
tablename_destroy ( NAME * h ) ;
tablename_get ( NAME * h , zpl_u64 key ) ;
tablename_set ( NAME * h , zpl_u64 key , VALUE value ) ;
tablename_grow ( NAME * h ) ;
tablename_map ( NAME * h , void ( * map_proc ) ( zpl_u64 key , VALUE value ) )
tablename_map_mut ( NAME * h , void ( * map_proc ) ( zpl_u64 key , VALUE * value ) )
tablename_rehash ( NAME * h , zpl_isize new_count ) ;
tablename_remove ( NAME * h , zpl_u64 key ) ;
2022-09-11 17:42:06 +00:00
@ {
*/
2022-09-18 15:35:53 +00:00
2022-09-11 17:42:06 +00:00
ZPL_BEGIN_C_DECLS
2022-09-18 15:35:53 +00:00
2022-09-11 17:42:06 +00:00
typedef struct zpl_hash_table_find_result {
zpl_isize hash_index ;
zpl_isize entry_prev ;
zpl_isize entry_index ;
} zpl_hash_table_find_result ;
2022-09-18 15:35:53 +00:00
/**
* Combined macro for a quick delcaration + definition
*/
# define ZPL_TABLE(PREFIX, NAME, FUNC, VALUE) \
ZPL_TABLE_DECLARE ( PREFIX , NAME , FUNC , VALUE ) ; \
ZPL_TABLE_DEFINE ( NAME , FUNC , VALUE ) ;
/**
* Table delcaration macro that generates the interface
*/
# define ZPL_TABLE_DECLARE(PREFIX, NAME, FUNC, VALUE) \
typedef struct ZPL_JOIN2 ( NAME , Entry ) { \
zpl_u64 key ; \
zpl_isize next ; \
VALUE value ; \
} ZPL_JOIN2 ( NAME , Entry ) ; \
\
typedef struct NAME { \
zpl_array ( zpl_isize ) hashes ; \
zpl_array ( ZPL_JOIN2 ( NAME , Entry ) ) entries ; \
} NAME ; \
\
PREFIX void ZPL_JOIN2 ( FUNC , init ) ( NAME * h , zpl_allocator a ) ; \
PREFIX void ZPL_JOIN2 ( FUNC , destroy ) ( NAME * h ) ; \
PREFIX void ZPL_JOIN2 ( FUNC , clear ) ( NAME * h ) ; \
PREFIX VALUE * ZPL_JOIN2 ( FUNC , get ) ( NAME * h , zpl_u64 key ) ; \
PREFIX zpl_isize ZPL_JOIN2 ( FUNC , slot ) ( NAME * h , zpl_u64 key ) ; \
PREFIX void ZPL_JOIN2 ( FUNC , set ) ( NAME * h , zpl_u64 key , VALUE value ) ; \
PREFIX void ZPL_JOIN2 ( FUNC , grow ) ( NAME * h ) ; \
PREFIX void ZPL_JOIN2 ( FUNC , rehash ) ( NAME * h , zpl_isize new_count ) ; \
PREFIX void ZPL_JOIN2 ( FUNC , rehash_fast ) ( NAME * h ) ; \
PREFIX void ZPL_JOIN2 ( FUNC , map ) ( NAME * h , void ( * map_proc ) ( zpl_u64 key , VALUE value ) ) ; \
PREFIX void ZPL_JOIN2 ( FUNC , map_mut ) ( NAME * h , void ( * map_proc ) ( zpl_u64 key , VALUE * value ) ) ; \
PREFIX void ZPL_JOIN2 ( FUNC , remove ) ( NAME * h , zpl_u64 key ) ; \
PREFIX void ZPL_JOIN2 ( FUNC , remove_entry ) ( NAME * h , zpl_isize idx ) ;
/**
* Table definition interfaces that generates the implementation
*/
# define ZPL_TABLE_DEFINE(NAME, FUNC, VALUE) \
void ZPL_JOIN2 ( FUNC , init ) ( NAME * h , zpl_allocator a ) { \
zpl_array_init ( h - > hashes , a ) ; \
zpl_array_init ( h - > entries , a ) ; \
} \
\
void ZPL_JOIN2 ( FUNC , destroy ) ( NAME * h ) { \
if ( h - > entries ) zpl_array_free ( h - > entries ) ; \
if ( h - > hashes ) zpl_array_free ( h - > hashes ) ; \
} \
\
void ZPL_JOIN2 ( FUNC , clear ) ( NAME * h ) { \
for ( int i = 0 ; i < zpl_array_count ( h - > hashes ) ; i + + ) h - > hashes [ i ] = - 1 ; \
zpl_array_clear ( h - > entries ) ; \
} \
\
zpl_isize ZPL_JOIN2 ( FUNC , slot ) ( NAME * h , zpl_u64 key ) { \
for ( zpl_isize i = 0 ; i < zpl_array_count ( h - > entries ) ; i + + ) { \
if ( h - > entries [ i ] . key = = key ) { \
return i ; \
} \
} \
return - 1 ; \
} \
\
zpl_internal zpl_isize ZPL_JOIN2 ( FUNC , _add_entry ) ( NAME * h , zpl_u64 key ) { \
zpl_isize index ; \
ZPL_JOIN2 ( NAME , Entry ) e = { 0 } ; \
e . key = key ; \
e . next = - 1 ; \
index = zpl_array_count ( h - > entries ) ; \
zpl_array_append ( h - > entries , e ) ; \
return index ; \
} \
\
zpl_internal zpl_hash_table_find_result ZPL_JOIN2 ( FUNC , _find ) ( NAME * h , zpl_u64 key ) { \
zpl_hash_table_find_result r = { - 1 , - 1 , - 1 } ; \
if ( zpl_array_count ( h - > hashes ) > 0 ) { \
r . hash_index = key % zpl_array_count ( h - > hashes ) ; \
r . entry_index = h - > hashes [ r . hash_index ] ; \
while ( r . entry_index > = 0 ) { \
if ( h - > entries [ r . entry_index ] . key = = key ) return r ; \
r . entry_prev = r . entry_index ; \
r . entry_index = h - > entries [ r . entry_index ] . next ; \
} \
} \
return r ; \
} \
\
zpl_internal zpl_b32 ZPL_JOIN2 ( FUNC , _full ) ( NAME * h ) { \
return 0.75f * zpl_array_count ( h - > hashes ) < zpl_array_count ( h - > entries ) ; \
} \
\
void ZPL_JOIN2 ( FUNC , grow ) ( NAME * h ) { \
zpl_isize new_count = ZPL_ARRAY_GROW_FORMULA ( zpl_array_count ( h - > entries ) ) ; \
ZPL_JOIN2 ( FUNC , rehash ) ( h , new_count ) ; \
} \
\
void ZPL_JOIN2 ( FUNC , rehash ) ( NAME * h , zpl_isize new_count ) { \
zpl_isize i , j ; \
NAME nh = { 0 } ; \
ZPL_JOIN2 ( FUNC , init ) ( & nh , zpl_array_allocator ( h - > hashes ) ) ; \
zpl_array_resize ( nh . hashes , new_count ) ; \
zpl_array_reserve ( nh . entries , zpl_array_count ( h - > entries ) ) ; \
for ( i = 0 ; i < new_count ; i + + ) nh . hashes [ i ] = - 1 ; \
for ( i = 0 ; i < zpl_array_count ( h - > entries ) ; i + + ) { \
ZPL_JOIN2 ( NAME , Entry ) * e ; \
zpl_hash_table_find_result fr ; \
if ( zpl_array_count ( nh . hashes ) = = 0 ) ZPL_JOIN2 ( FUNC , grow ) ( & nh ) ; \
e = & h - > entries [ i ] ; \
fr = ZPL_JOIN2 ( FUNC , _find ) ( & nh , e - > key ) ; \
j = ZPL_JOIN2 ( FUNC , _add_entry ) ( & nh , e - > key ) ; \
if ( fr . entry_prev < 0 ) \
nh . hashes [ fr . hash_index ] = j ; \
else \
nh . entries [ fr . entry_prev ] . next = j ; \
nh . entries [ j ] . next = fr . entry_index ; \
nh . entries [ j ] . value = e - > value ; \
} \
ZPL_JOIN2 ( FUNC , destroy ) ( h ) ; \
h - > hashes = nh . hashes ; \
h - > entries = nh . entries ; \
} \
\
void ZPL_JOIN2 ( FUNC , rehash_fast ) ( NAME * h ) { \
zpl_isize i ; \
for ( i = 0 ; i < zpl_array_count ( h - > entries ) ; i + + ) h - > entries [ i ] . next = - 1 ; \
for ( i = 0 ; i < zpl_array_count ( h - > hashes ) ; i + + ) h - > hashes [ i ] = - 1 ; \
for ( i = 0 ; i < zpl_array_count ( h - > entries ) ; i + + ) { \
ZPL_JOIN2 ( NAME , Entry ) * e ; \
zpl_hash_table_find_result fr ; \
e = & h - > entries [ i ] ; \
fr = ZPL_JOIN2 ( FUNC , _find ) ( h , e - > key ) ; \
if ( fr . entry_prev < 0 ) \
h - > hashes [ fr . hash_index ] = i ; \
else \
h - > entries [ fr . entry_prev ] . next = i ; \
} \
} \
\
VALUE * ZPL_JOIN2 ( FUNC , get ) ( NAME * h , zpl_u64 key ) { \
zpl_isize index = ZPL_JOIN2 ( FUNC , _find ) ( h , key ) . entry_index ; \
if ( index > = 0 ) return & h - > entries [ index ] . value ; \
return NULL ; \
} \
\
void ZPL_JOIN2 ( FUNC , remove ) ( NAME * h , zpl_u64 key ) { \
zpl_hash_table_find_result fr = ZPL_JOIN2 ( FUNC , _find ) ( h , key ) ; \
if ( fr . entry_index > = 0 ) { \
zpl_array_remove_at ( h - > entries , fr . entry_index ) ; \
ZPL_JOIN2 ( FUNC , rehash_fast ) ( h ) ; \
} \
} \
\
void ZPL_JOIN2 ( FUNC , remove_entry ) ( NAME * h , zpl_isize idx ) { \
zpl_array_remove_at ( h - > entries , idx ) ; \
} \
\
void ZPL_JOIN2 ( FUNC , map ) ( NAME * h , void ( * map_proc ) ( zpl_u64 key , VALUE value ) ) { \
ZPL_ASSERT_NOT_NULL ( h ) ; \
ZPL_ASSERT_NOT_NULL ( map_proc ) ; \
for ( zpl_isize i = 0 ; i < zpl_array_count ( h - > entries ) ; + + i ) { \
map_proc ( h - > entries [ i ] . key , h - > entries [ i ] . value ) ; \
} \
} \
\
void ZPL_JOIN2 ( FUNC , map_mut ) ( NAME * h , void ( * map_proc ) ( zpl_u64 key , VALUE * value ) ) { \
ZPL_ASSERT_NOT_NULL ( h ) ; \
ZPL_ASSERT_NOT_NULL ( map_proc ) ; \
for ( zpl_isize i = 0 ; i < zpl_array_count ( h - > entries ) ; + + i ) { \
map_proc ( h - > entries [ i ] . key , & h - > entries [ i ] . value ) ; \
} \
} \
\
void ZPL_JOIN2 ( FUNC , set ) ( NAME * h , zpl_u64 key , VALUE value ) { \
zpl_isize index ; \
zpl_hash_table_find_result fr ; \
if ( zpl_array_count ( h - > hashes ) = = 0 ) ZPL_JOIN2 ( FUNC , grow ) ( h ) ; \
fr = ZPL_JOIN2 ( FUNC , _find ) ( h , key ) ; \
if ( fr . entry_index > = 0 ) { \
index = fr . entry_index ; \
} else { \
index = ZPL_JOIN2 ( FUNC , _add_entry ) ( h , key ) ; \
if ( fr . entry_prev > = 0 ) { \
h - > entries [ fr . entry_prev ] . next = index ; \
} else { \
h - > hashes [ fr . hash_index ] = index ; \
} \
} \
h - > entries [ index ] . value = value ; \
if ( ZPL_JOIN2 ( FUNC , _full ) ( h ) ) ZPL_JOIN2 ( FUNC , grow ) ( h ) ; \
}
2022-09-11 17:42:06 +00:00
//! @}
2022-09-18 15:35:53 +00:00
2022-09-11 17:42:06 +00:00
ZPL_END_C_DECLS
# if defined(ZPL_MODULE_CORE)
// file: header/core/memory_virtual.h
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
////////////////////////////////////////////////////////////////
//
// Virtual Memory
//
//
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_BEGIN_C_DECLS
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
typedef struct zpl_virtual_memory {
void * data ;
zpl_isize size ;
} zpl_virtual_memory ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Initialize virtual memory from existing data.
ZPL_DEF zpl_virtual_memory zpl_vm ( void * data , zpl_isize size ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Allocate virtual memory at address with size.
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! @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.
ZPL_DEF zpl_virtual_memory zpl_vm_alloc ( void * addr , zpl_isize size ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Release the virtual memory.
ZPL_DEF zpl_b32 zpl_vm_free ( zpl_virtual_memory vm ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Trim virtual memory.
ZPL_DEF zpl_virtual_memory zpl_vm_trim ( zpl_virtual_memory vm , zpl_isize lead_size , zpl_isize size ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Purge virtual memory.
ZPL_DEF zpl_b32 zpl_vm_purge ( zpl_virtual_memory vm ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Retrieve VM's page size and alignment.
ZPL_DEF zpl_isize zpl_virtual_memory_page_size ( zpl_isize * alignment_out ) ;
ZPL_END_C_DECLS
// file: header/core/string.h
/** @file string.c
@ brief String operations and library
@ defgroup string String library
Offers methods for c - string manipulation , but also a string library based on gb_string , which is c - string friendly .
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
@ {
*/
////////////////////////////////////////////////////////////////
//
// Char Functions
//
//
ZPL_BEGIN_C_DECLS
ZPL_DEF_INLINE char zpl_char_to_lower ( char c ) ;
ZPL_DEF_INLINE char zpl_char_to_upper ( char c ) ;
ZPL_DEF_INLINE zpl_b32 zpl_char_is_space ( char c ) ;
ZPL_DEF_INLINE zpl_b32 zpl_char_is_digit ( char c ) ;
ZPL_DEF_INLINE zpl_b32 zpl_char_is_hex_digit ( char c ) ;
ZPL_DEF_INLINE zpl_b32 zpl_char_is_alpha ( char c ) ;
ZPL_DEF_INLINE zpl_b32 zpl_char_is_alphanumeric ( char c ) ;
ZPL_DEF_INLINE zpl_i32 zpl_digit_to_int ( char c ) ;
ZPL_DEF_INLINE zpl_i32 zpl_hex_digit_to_int ( char c ) ;
ZPL_DEF_INLINE zpl_u8 zpl_char_to_hex_digit ( char c ) ;
ZPL_DEF_INLINE zpl_b32 zpl_char_is_control ( char c ) ;
// NOTE: ASCII only
ZPL_DEF_INLINE void zpl_str_to_lower ( char * str ) ;
ZPL_DEF_INLINE void zpl_str_to_upper ( char * str ) ;
ZPL_DEF_INLINE char const * zpl_str_trim ( char const * str , zpl_b32 catch_newline ) ;
ZPL_DEF_INLINE char const * zpl_str_skip ( char const * str , char c ) ;
ZPL_DEF_INLINE char const * zpl_str_skip_any ( char const * str , char const * char_list ) ;
ZPL_DEF_INLINE char const * zpl_str_skip_literal ( char const * str , char c ) ;
ZPL_DEF_INLINE char const * zpl_str_control_skip ( char const * str , char c ) ;
ZPL_DEF_INLINE zpl_isize zpl_strlen ( const char * str ) ;
ZPL_DEF_INLINE zpl_isize zpl_strnlen ( const char * str , zpl_isize max_len ) ;
ZPL_DEF_INLINE zpl_i32 zpl_strcmp ( const char * s1 , const char * s2 ) ;
ZPL_DEF_INLINE zpl_i32 zpl_strncmp ( const char * s1 , const char * s2 , zpl_isize len ) ;
ZPL_DEF_INLINE char * zpl_strcpy ( char * dest , const char * source ) ;
ZPL_DEF_INLINE char * zpl_strcat ( char * dest , const char * source ) ;
ZPL_DEF_INLINE char * zpl_strncpy ( char * dest , const char * source , zpl_isize len ) ;
ZPL_DEF_INLINE zpl_isize zpl_strlcpy ( char * dest , const char * source , zpl_isize len ) ;
ZPL_DEF_INLINE char * zpl_strrev ( char * str ) ; // NOTE: ASCII only
ZPL_DEF_INLINE const char * zpl_strtok ( char * output , const char * src , const char * delimit ) ;
ZPL_DEF_INLINE const char * zpl_strntok ( char * output , zpl_isize len , const char * src , const char * delimit ) ;
ZPL_DEF_INLINE char * zpl_strdup ( zpl_allocator a , char * src , zpl_isize max_len ) ;
ZPL_DEF_INLINE char * * zpl_str_split_lines ( zpl_allocator alloc , char * source , zpl_b32 strip_whitespace ) ;
# define zpl_str_expand(str) str, zpl_strlen(str)
# define zpl_str_advance_while(str, cond) \
do { \
+ + str ; \
} while ( ( cond ) ) ;
ZPL_DEF_INLINE zpl_b32 zpl_str_has_prefix ( const char * str , const char * prefix ) ;
ZPL_DEF_INLINE zpl_b32 zpl_str_has_suffix ( const char * str , const char * suffix ) ;
ZPL_DEF_INLINE const char * zpl_char_first_occurence ( const char * str , char c ) ;
ZPL_DEF_INLINE const char * zpl_char_last_occurence ( const char * str , char c ) ;
# define zpl_strchr zpl_char_first_occurence
ZPL_DEF_INLINE void zpl_str_concat ( char * dest , zpl_isize dest_len , const char * src_a , zpl_isize src_a_len , const char * src_b , zpl_isize src_b_len ) ;
ZPL_DEF zpl_u64 zpl_str_to_u64 ( const char * str , char * * end_ptr , zpl_i32 base ) ; // TODO: Support more than just decimal and hexadecimal
ZPL_DEF zpl_i64 zpl_str_to_i64 ( const char * str , char * * end_ptr , zpl_i32 base ) ; // TODO: Support more than just decimal and hexadecimal
ZPL_DEF zpl_f64 zpl_str_to_f64 ( const char * str , char * * end_ptr ) ;
ZPL_DEF void zpl_i64_to_str ( zpl_i64 value , char * string , zpl_i32 base ) ;
ZPL_DEF void zpl_u64_to_str ( zpl_u64 value , char * string , zpl_i32 base ) ;
ZPL_DEF_INLINE zpl_f32 zpl_str_to_f32 ( const char * str , char * * end_ptr ) ;
////////////////////////////////////////////////////////////////
//
// UTF-8 Handling
//
//
// NOTE: Does not check if utf-8 string is valid
ZPL_IMPL_INLINE zpl_isize zpl_utf8_strlen ( zpl_u8 const * str ) ;
ZPL_IMPL_INLINE zpl_isize zpl_utf8_strnlen ( zpl_u8 const * str , zpl_isize max_len ) ;
// NOTE: Windows doesn't handle 8 bit filenames well
ZPL_DEF zpl_u16 * zpl_utf8_to_ucs2 ( zpl_u16 * buffer , zpl_isize len , zpl_u8 const * str ) ;
ZPL_DEF zpl_u8 * zpl_ucs2_to_utf8 ( zpl_u8 * buffer , zpl_isize len , zpl_u16 const * str ) ;
ZPL_DEF zpl_u16 * zpl_utf8_to_ucs2_buf ( zpl_u8 const * str ) ; // NOTE: Uses locally persisting buffer
ZPL_DEF zpl_u8 * zpl_ucs2_to_utf8_buf ( zpl_u16 const * str ) ; // NOTE: Uses locally persisting buffer
// NOTE: Returns size of codepoint in bytes
ZPL_DEF zpl_isize zpl_utf8_decode ( zpl_u8 const * str , zpl_isize str_len , zpl_rune * codepoint ) ;
ZPL_DEF zpl_isize zpl_utf8_codepoint_size ( zpl_u8 const * str , zpl_isize str_len ) ;
ZPL_DEF zpl_isize zpl_utf8_encode_rune ( zpl_u8 buf [ 4 ] , zpl_rune r ) ;
/* inlines */
ZPL_IMPL_INLINE char zpl_char_to_lower ( char c ) {
if ( c > = ' A ' & & c < = ' Z ' ) return ' a ' + ( c - ' A ' ) ;
return c ;
}
ZPL_IMPL_INLINE char zpl_char_to_upper ( char c ) {
if ( c > = ' a ' & & c < = ' z ' ) return ' A ' + ( c - ' a ' ) ;
return c ;
}
ZPL_IMPL_INLINE zpl_b32 zpl_char_is_space ( char c ) {
if ( c = = ' ' | | c = = ' \t ' | | c = = ' \n ' | | c = = ' \r ' | | c = = ' \f ' | | c = = ' \v ' ) return true ;
return false ;
}
ZPL_IMPL_INLINE zpl_b32 zpl_char_is_digit ( char c ) {
if ( c > = ' 0 ' & & c < = ' 9 ' ) return true ;
return false ;
}
ZPL_IMPL_INLINE zpl_b32 zpl_char_is_hex_digit ( char c ) {
if ( zpl_char_is_digit ( c ) | | ( c > = ' a ' & & c < = ' f ' ) | | ( c > = ' A ' & & c < = ' F ' ) ) return true ;
return false ;
}
ZPL_IMPL_INLINE zpl_b32 zpl_char_is_alpha ( char c ) {
if ( ( c > = ' A ' & & c < = ' Z ' ) | | ( c > = ' a ' & & c < = ' z ' ) ) return true ;
return false ;
}
ZPL_IMPL_INLINE zpl_b32 zpl_char_is_alphanumeric ( char c ) { return zpl_char_is_alpha ( c ) | | zpl_char_is_digit ( c ) ; }
ZPL_IMPL_INLINE zpl_i32 zpl_digit_to_int ( char c ) { return zpl_char_is_digit ( c ) ? c - ' 0 ' : c - ' W ' ; }
ZPL_IMPL_INLINE zpl_i32 zpl_hex_digit_to_int ( char c ) {
if ( zpl_char_is_digit ( c ) )
return zpl_digit_to_int ( c ) ;
else if ( zpl_is_between ( c , ' a ' , ' f ' ) )
return c - ' a ' + 10 ;
else if ( zpl_is_between ( c , ' A ' , ' F ' ) )
return c - ' A ' + 10 ;
return - 1 ;
}
ZPL_IMPL_INLINE zpl_u8 zpl_char_to_hex_digit ( char c ) {
if ( c > = ' 0 ' & & c < = ' 9 ' )
return ( zpl_u8 ) ( c - ' 0 ' ) ;
if ( c > = ' a ' & & c < = ' f ' )
return ( zpl_u8 ) ( c - ' a ' ) ;
if ( c > = ' A ' & & c < = ' F ' )
return ( zpl_u8 ) ( c - ' A ' ) ;
return 0 ;
}
ZPL_IMPL_INLINE void zpl_str_to_lower ( char * str ) {
if ( ! str ) return ;
while ( * str ) {
* str = zpl_char_to_lower ( * str ) ;
str + + ;
}
}
ZPL_IMPL_INLINE void zpl_str_to_upper ( char * str ) {
if ( ! str ) return ;
while ( * str ) {
* str = zpl_char_to_upper ( * str ) ;
str + + ;
}
}
ZPL_IMPL_INLINE zpl_isize zpl_strlen ( const char * str ) {
if ( str = = NULL ) { return 0 ; }
const char * p = str ;
while ( * str ) str + + ;
return str - p ;
}
ZPL_IMPL_INLINE zpl_isize zpl_strnlen ( const char * str , zpl_isize max_len ) {
const char * end = cast ( const char * ) zpl_memchr ( str , 0 , max_len ) ;
if ( end ) return end - str ;
return max_len ;
}
ZPL_IMPL_INLINE zpl_isize zpl_utf8_strlen ( zpl_u8 const * str ) {
zpl_isize count = 0 ;
for ( ; * str ; count + + ) {
zpl_u8 c = * str ;
zpl_isize inc = 0 ;
if ( c < 0x80 )
inc = 1 ;
else if ( ( c & 0xe0 ) = = 0xc0 )
inc = 2 ;
else if ( ( c & 0xf0 ) = = 0xe0 )
inc = 3 ;
else if ( ( c & 0xf8 ) = = 0xf0 )
inc = 4 ;
else
return - 1 ;
str + = inc ;
}
return count ;
}
ZPL_IMPL_INLINE zpl_isize zpl_utf8_strnlen ( zpl_u8 const * str , zpl_isize max_len ) {
zpl_isize count = 0 ;
for ( ; * str & & max_len > 0 ; count + + ) {
zpl_u8 c = * str ;
zpl_isize inc = 0 ;
if ( c < 0x80 )
inc = 1 ;
else if ( ( c & 0xe0 ) = = 0xc0 )
inc = 2 ;
else if ( ( c & 0xf0 ) = = 0xe0 )
inc = 3 ;
else if ( ( c & 0xf8 ) = = 0xf0 )
inc = 4 ;
else
return - 1 ;
str + = inc ;
max_len - = inc ;
}
return count ;
}
ZPL_IMPL_INLINE zpl_i32 zpl_strcmp ( const char * s1 , const char * s2 ) {
while ( * s1 & & ( * s1 = = * s2 ) ) { s1 + + , s2 + + ; }
return * ( zpl_u8 * ) s1 - * ( zpl_u8 * ) s2 ;
}
ZPL_IMPL_INLINE char * zpl_strcpy ( char * dest , const char * source ) {
ZPL_ASSERT_NOT_NULL ( dest ) ;
if ( source ) {
char * str = dest ;
while ( * source ) * str + + = * source + + ;
}
return dest ;
}
ZPL_IMPL_INLINE char * zpl_strcat ( char * dest , const char * source ) {
ZPL_ASSERT_NOT_NULL ( dest ) ;
if ( source ) {
char * str = dest ;
while ( * str ) + + str ;
while ( * source ) * str + + = * source + + ;
}
return dest ;
}
ZPL_IMPL_INLINE char * zpl_strncpy ( char * dest , const char * source , zpl_isize len ) {
ZPL_ASSERT_NOT_NULL ( dest ) ;
if ( source ) {
char * str = dest ;
while ( len > 0 & & * source ) {
* str + + = * source + + ;
len - - ;
}
while ( len > 0 ) {
* str + + = ' \0 ' ;
len - - ;
}
}
return dest ;
}
ZPL_IMPL_INLINE zpl_isize zpl_strlcpy ( char * dest , const char * source , zpl_isize len ) {
zpl_isize result = 0 ;
ZPL_ASSERT_NOT_NULL ( dest ) ;
if ( source ) {
const char * source_start = source ;
char * str = dest ;
while ( len > 0 & & * source ) {
* str + + = * source + + ;
len - - ;
}
while ( len > 0 ) {
* str + + = ' \0 ' ;
len - - ;
}
result = source - source_start ;
}
return result ;
}
ZPL_IMPL_INLINE char * zpl_strrev ( char * str ) {
zpl_isize len = zpl_strlen ( str ) ;
char * a = str + 0 ;
char * b = str + len - 1 ;
len / = 2 ;
while ( len - - ) {
zpl_swap ( char , * a , * b ) ;
a + + , b - - ;
}
return str ;
}
ZPL_IMPL_INLINE zpl_i32 zpl_strncmp ( const char * s1 , const char * s2 , zpl_isize len ) {
for ( ; len > 0 ; s1 + + , s2 + + , len - - ) {
if ( * s1 ! = * s2 )
return ( ( s1 < s2 ) ? - 1 : + 1 ) ;
else if ( * s1 = = ' \0 ' )
return 0 ;
}
return 0 ;
}
ZPL_IMPL_INLINE const char * zpl_strtok ( char * output , const char * src , const char * delimit ) {
while ( * src & & zpl_char_first_occurence ( delimit , * src ) = = NULL ) * output + + = * src + + ;
* output = 0 ;
return * src ? src + 1 : src ;
}
ZPL_IMPL_INLINE const char * zpl_strntok ( char * output , zpl_isize len , const char * src , const char * delimit ) {
ZPL_ASSERT ( len > 0 ) ;
* ( output + len - 1 ) = 0 ;
while ( * src & & zpl_char_first_occurence ( delimit , * src ) = = NULL & & len > 0 ) {
* output + + = * src + + ;
len - - ;
}
if ( len > 0 )
* output = 0 ;
return * src ? src + 1 : src ;
}
ZPL_IMPL_INLINE zpl_b32 zpl_char_is_control ( char c ) {
return ! ! zpl_strchr ( " \" \\ /bfnrt " , c ) ;
}
ZPL_IMPL_INLINE zpl_b32 zpl__is_special_char ( char c ) { return ! ! zpl_strchr ( " <>:/ " , c ) ; }
ZPL_IMPL_INLINE zpl_b32 zpl__is_assign_char ( char c ) { return ! ! zpl_strchr ( " :=| " , c ) ; }
ZPL_IMPL_INLINE zpl_b32 zpl__is_delim_char ( char c ) { return ! ! zpl_strchr ( " ,| \n " , c ) ; }
ZPL_IMPL_INLINE char const * zpl_str_control_skip ( char const * str , char c ) {
while ( ( * str & & * str ! = c ) | | ( * ( str - 1 ) = = ' \\ ' & & * str = = c & & zpl_char_is_control ( c ) ) ) { + + str ; }
return str ;
}
ZPL_IMPL_INLINE zpl_b32 zpl_str_has_prefix ( const char * str , const char * prefix ) {
while ( * prefix ) {
if ( * str + + ! = * prefix + + ) return false ;
}
return true ;
}
ZPL_IMPL_INLINE zpl_b32 zpl_str_has_suffix ( const char * str , const char * suffix ) {
zpl_isize i = zpl_strlen ( str ) ;
zpl_isize j = zpl_strlen ( suffix ) ;
if ( j < = i ) return zpl_strcmp ( str + i - j , suffix ) = = 0 ;
return false ;
}
ZPL_IMPL_INLINE const char * zpl_char_first_occurence ( const char * s , char c ) {
char ch = c ;
for ( ; * s ! = ch ; s + + ) {
if ( * s = = ' \0 ' ) return NULL ;
}
return s ;
}
ZPL_IMPL_INLINE const char * zpl_char_last_occurence ( const char * s , char c ) {
char * result = ( char * ) NULL ;
do {
if ( * s = = c ) result = ( char * ) s ;
} while ( * s + + ) ;
return result ;
}
ZPL_IMPL_INLINE char const * zpl_str_trim ( char const * str , zpl_b32 catch_newline )
{
while ( * str & & zpl_char_is_space ( * str ) & & ( ! catch_newline | | ( catch_newline & & * str ! = ' \n ' ) ) ) { + + str ; }
return str ;
}
ZPL_IMPL_INLINE char const * zpl_str_skip ( char const * str , char c ) {
while ( * str & & * str ! = c ) { + + str ; }
return str ;
}
ZPL_IMPL_INLINE char const * zpl_str_skip_any ( char const * str , char const * char_list ) {
char const * closest_ptr = cast ( char const * ) zpl_ptr_add ( ( void * ) str , zpl_strlen ( str ) ) ;
zpl_isize char_list_count = zpl_strlen ( char_list ) ;
for ( zpl_isize i = 0 ; i < char_list_count ; i + + ) {
char const * p = zpl_str_skip ( str , char_list [ i ] ) ;
closest_ptr = zpl_min ( closest_ptr , p ) ;
}
return closest_ptr ;
}
ZPL_IMPL_INLINE char const * zpl_str_skip_literal ( char const * str , char c ) {
while ( ( * str & & * str ! = c ) | | ( * str = = c & & * ( str - 1 ) = = ' \\ ' ) ) { + + str ; }
return str ;
}
ZPL_IMPL_INLINE void zpl_str_concat ( char * dest , zpl_isize dest_len , const char * src_a , zpl_isize src_a_len , const char * src_b ,
zpl_isize src_b_len ) {
ZPL_ASSERT ( dest_len > = src_a_len + src_b_len + 1 ) ;
if ( dest ) {
zpl_memcopy ( dest , src_a , src_a_len ) ;
zpl_memcopy ( dest + src_a_len , src_b , src_b_len ) ;
dest [ src_a_len + src_b_len ] = ' \0 ' ;
}
}
ZPL_IMPL_INLINE zpl_f32 zpl_str_to_f32 ( const char * str , char * * end_ptr ) {
zpl_f64 f = zpl_str_to_f64 ( str , end_ptr ) ;
zpl_f32 r = cast ( zpl_f32 ) f ;
return r ;
}
ZPL_IMPL_INLINE char * zpl_strdup ( zpl_allocator a , char * src , zpl_isize max_len ) {
ZPL_ASSERT_NOT_NULL ( src ) ;
zpl_isize len = zpl_strlen ( src ) ;
char * dest = cast ( char * ) zpl_alloc ( a , max_len ) ;
zpl_memset ( dest + len , 0 , max_len - len ) ;
zpl_strncpy ( dest , src , max_len ) ;
return dest ;
}
ZPL_IMPL_INLINE char * * zpl_str_split_lines ( zpl_allocator alloc , char * source , zpl_b32 strip_whitespace ) {
char * * lines = NULL , * p = source , * pd = p ;
zpl_array_init ( lines , alloc ) ;
while ( * p ) {
if ( * pd = = ' \n ' ) {
* pd = 0 ;
if ( * ( pd - 1 ) = = ' \r ' ) * ( pd - 1 ) = 0 ;
if ( strip_whitespace & & ( pd - p ) = = 0 ) {
p = pd + 1 ;
continue ;
}
zpl_array_append ( lines , p ) ;
p = pd + 1 ;
}
+ + pd ;
}
return lines ;
}
ZPL_END_C_DECLS
// file: header/core/stringlib.h
ZPL_BEGIN_C_DECLS
typedef char * zpl_string ;
typedef struct zpl_string_header {
zpl_allocator allocator ;
zpl_isize length ;
zpl_isize capacity ;
} zpl_string_header ;
# define ZPL_STRING_HEADER(str) (cast(zpl_string_header *)(str) - 1)
ZPL_DEF zpl_string zpl_string_make_reserve ( zpl_allocator a , zpl_isize capacity ) ;
ZPL_DEF zpl_string zpl_string_make_length ( zpl_allocator a , void const * str , zpl_isize num_bytes ) ;
ZPL_DEF zpl_string zpl_string_sprintf ( zpl_allocator a , char * buf , zpl_isize num_bytes , const char * fmt , . . . ) ;
ZPL_DEF zpl_string zpl_string_sprintf_buf ( zpl_allocator a , const char * fmt , . . . ) ; // NOTE: Uses locally persistent buffer
ZPL_DEF zpl_string zpl_string_append_length ( zpl_string str , void const * other , zpl_isize num_bytes ) ;
ZPL_DEF zpl_string zpl_string_appendc ( zpl_string str , const char * other ) ;
ZPL_DEF zpl_string zpl_string_join ( zpl_allocator a , const char * * parts , zpl_isize count , const char * glue ) ;
ZPL_DEF zpl_string zpl_string_set ( zpl_string str , const char * cstr ) ;
ZPL_DEF zpl_string zpl_string_make_space_for ( zpl_string str , zpl_isize add_len ) ;
ZPL_DEF zpl_isize zpl_string_allocation_size ( zpl_string const str ) ;
ZPL_DEF zpl_b32 zpl_string_are_equal ( zpl_string const lhs , zpl_string const rhs ) ;
ZPL_DEF zpl_string zpl_string_trim ( zpl_string str , const char * cut_set ) ;
ZPL_DEF zpl_string zpl_string_append_rune ( zpl_string str , zpl_rune r ) ;
ZPL_DEF zpl_string zpl_string_append_fmt ( zpl_string str , const char * fmt , . . . ) ;
ZPL_DEF_INLINE zpl_string zpl_string_make ( zpl_allocator a , const char * str ) ;
ZPL_DEF_INLINE void zpl_string_free ( zpl_string str ) ;
ZPL_DEF_INLINE void zpl_string_clear ( zpl_string str ) ;
ZPL_DEF_INLINE zpl_string zpl_string_duplicate ( zpl_allocator a , zpl_string const str ) ;
ZPL_DEF_INLINE zpl_isize zpl_string_length ( zpl_string const str ) ;
ZPL_DEF_INLINE zpl_isize zpl_string_capacity ( zpl_string const str ) ;
ZPL_DEF_INLINE zpl_isize zpl_string_available_space ( zpl_string const str ) ;
ZPL_DEF_INLINE zpl_string zpl_string_append ( zpl_string str , zpl_string const other ) ;
ZPL_DEF_INLINE zpl_string zpl_string_trim_space ( zpl_string str ) ; // Whitespace ` \t\r\n\v\f`
ZPL_DEF_INLINE void zpl__set_string_length ( zpl_string str , zpl_isize len ) ;
ZPL_DEF_INLINE void zpl__set_string_capacity ( zpl_string str , zpl_isize cap ) ;
ZPL_IMPL_INLINE void zpl__set_string_length ( zpl_string str , zpl_isize len ) { ZPL_STRING_HEADER ( str ) - > length = len ; }
ZPL_IMPL_INLINE void zpl__set_string_capacity ( zpl_string str , zpl_isize cap ) { ZPL_STRING_HEADER ( str ) - > capacity = cap ; }
ZPL_IMPL_INLINE zpl_string zpl_string_make ( zpl_allocator a , const char * str ) {
zpl_isize len = str ? zpl_strlen ( str ) : 0 ;
return zpl_string_make_length ( a , str , len ) ;
}
ZPL_IMPL_INLINE void zpl_string_free ( zpl_string str ) {
if ( str ) {
zpl_string_header * header = ZPL_STRING_HEADER ( str ) ;
zpl_free ( header - > allocator , header ) ;
}
}
ZPL_IMPL_INLINE zpl_string zpl_string_duplicate ( zpl_allocator a , zpl_string const str ) {
return zpl_string_make_length ( a , str , zpl_string_length ( str ) ) ;
}
ZPL_IMPL_INLINE zpl_isize zpl_string_length ( zpl_string const str ) { return ZPL_STRING_HEADER ( str ) - > length ; }
ZPL_IMPL_INLINE zpl_isize zpl_string_capacity ( zpl_string const str ) { return ZPL_STRING_HEADER ( str ) - > capacity ; }
ZPL_IMPL_INLINE zpl_isize zpl_string_available_space ( zpl_string const str ) {
zpl_string_header * h = ZPL_STRING_HEADER ( str ) ;
if ( h - > capacity > h - > length ) return h - > capacity - h - > length ;
return 0 ;
}
ZPL_IMPL_INLINE void zpl_string_clear ( zpl_string str ) {
zpl__set_string_length ( str , 0 ) ;
str [ 0 ] = ' \0 ' ;
}
ZPL_IMPL_INLINE zpl_string zpl_string_append ( zpl_string str , zpl_string const other ) {
return zpl_string_append_length ( str , other , zpl_string_length ( other ) ) ;
}
ZPL_IMPL_INLINE zpl_string zpl_string_trim_space ( zpl_string str ) { return zpl_string_trim ( str , " \t \r \n \v \f " ) ; }
ZPL_END_C_DECLS
// file: header/core/file.h
/** @file file.c
@ brief File handling
@ defgroup fileio File handling
File I / O operations as well as path and folder structure manipulation methods . With threading enabled , it also offers async read / write methods .
@ {
*/
ZPL_BEGIN_C_DECLS
typedef zpl_u32 zpl_file_mode ;
typedef enum zpl_file_mode_flag {
ZPL_FILE_MODE_READ = ZPL_BIT ( 0 ) ,
ZPL_FILE_MODE_WRITE = ZPL_BIT ( 1 ) ,
ZPL_FILE_MODE_APPEND = ZPL_BIT ( 2 ) ,
ZPL_FILE_MODE_RW = ZPL_BIT ( 3 ) ,
ZPL_FILE_MODES = ZPL_FILE_MODE_READ | ZPL_FILE_MODE_WRITE | ZPL_FILE_MODE_APPEND | ZPL_FILE_MODE_RW ,
} zpl_file_mode_flag ;
// NOTE: Only used internally and for the file operations
typedef enum zpl_seek_whence_type {
ZPL_SEEK_WHENCE_BEGIN = 0 ,
ZPL_SEEK_WHENCE_CURRENT = 1 ,
ZPL_SEEK_WHENCE_END = 2 ,
} zpl_seek_whence_type ;
typedef enum zpl_file_error {
ZPL_FILE_ERROR_NONE ,
ZPL_FILE_ERROR_INVALID ,
ZPL_FILE_ERROR_INVALID_FILENAME ,
ZPL_FILE_ERROR_EXISTS ,
ZPL_FILE_ERROR_NOT_EXISTS ,
ZPL_FILE_ERROR_PERMISSION ,
ZPL_FILE_ERROR_TRUNCATION_FAILURE ,
ZPL_FILE_ERROR_NOT_EMPTY ,
ZPL_FILE_ERROR_NAME_TOO_LONG ,
ZPL_FILE_ERROR_UNKNOWN ,
} zpl_file_error ;
typedef union zpl_file_descriptor {
void * p ;
zpl_intptr i ;
zpl_uintptr u ;
} zpl_file_descriptor ;
typedef struct zpl_file_operations zpl_file_operations ;
# define ZPL_FILE_OPEN_PROC(name) zpl_file_error name(zpl_file_descriptor *fd, zpl_file_operations *ops, zpl_file_mode mode, char const *filename)
# define ZPL_FILE_READ_AT_PROC(name) zpl_b32 name(zpl_file_descriptor fd, void *buffer, zpl_isize size, zpl_i64 offset, zpl_isize *bytes_read, zpl_b32 stop_at_newline)
# define ZPL_FILE_WRITE_AT_PROC(name) zpl_b32 name(zpl_file_descriptor fd, void const *buffer, zpl_isize size, zpl_i64 offset, zpl_isize *bytes_written)
# define ZPL_FILE_SEEK_PROC(name) zpl_b32 name(zpl_file_descriptor fd, zpl_i64 offset, zpl_seek_whence_type whence, zpl_i64 *new_offset)
# define ZPL_FILE_CLOSE_PROC(name) void name(zpl_file_descriptor fd)
typedef ZPL_FILE_OPEN_PROC ( zpl_file_open_proc ) ;
typedef ZPL_FILE_READ_AT_PROC ( zpl_file_read_proc ) ;
typedef ZPL_FILE_WRITE_AT_PROC ( zpl_file_write_proc ) ;
typedef ZPL_FILE_SEEK_PROC ( zpl_file_seek_proc ) ;
typedef ZPL_FILE_CLOSE_PROC ( zpl_file_close_proc ) ;
struct zpl_file_operations {
zpl_file_read_proc * read_at ;
zpl_file_write_proc * write_at ;
zpl_file_seek_proc * seek ;
zpl_file_close_proc * close ;
} ;
extern zpl_file_operations const zpl_default_file_operations ;
typedef zpl_u64 zpl_file_time ;
typedef enum zpl_dir_type {
ZPL_DIR_TYPE_FILE ,
ZPL_DIR_TYPE_FOLDER ,
ZPL_DIR_TYPE_UNKNOWN ,
} zpl_dir_type ;
struct zpl_dir_info ;
typedef struct zpl_dir_entry {
char const * filename ;
struct zpl_dir_info * dir_info ;
zpl_u8 type ;
} zpl_dir_entry ;
typedef struct zpl_dir_info {
char const * fullpath ;
zpl_dir_entry * entries ; // zpl_array
// Internals
char * * filenames ; // zpl_array
zpl_string buf ;
} zpl_dir_info ;
typedef struct zpl_file {
zpl_file_operations ops ;
zpl_file_descriptor fd ;
zpl_b32 is_temp ;
char const * filename ;
zpl_file_time last_write_time ;
zpl_dir_entry * dir ;
} zpl_file ;
typedef enum zpl_file_standard_type {
ZPL_FILE_STANDARD_INPUT ,
ZPL_FILE_STANDARD_OUTPUT ,
ZPL_FILE_STANDARD_ERROR ,
ZPL_FILE_STANDARD_COUNT ,
} zpl_file_standard_type ;
/**
* Get standard file I / O .
* @ param std Check zpl_file_standard_type
* @ return File handle to standard I / O
*/
ZPL_DEF zpl_file * zpl_file_get_standard ( zpl_file_standard_type std ) ;
/**
* Connects a system handle to a zpl file .
* @ param file Pointer to zpl file
* @ param handle Low - level OS handle to connect
*/
ZPL_DEF void zpl_file_connect_handle ( zpl_file * file , void * handle ) ;
/**
* Creates a new file
* @ param file
* @ param filename
*/
ZPL_DEF zpl_file_error zpl_file_create ( zpl_file * file , char const * filename ) ;
/**
* Opens a file
* @ param file
* @ param filename
*/
ZPL_DEF zpl_file_error zpl_file_open ( zpl_file * file , char const * filename ) ;
/**
* Opens a file using a specified mode
* @ param file
* @ param mode Access mode to use
* @ param filename
*/
ZPL_DEF zpl_file_error zpl_file_open_mode ( zpl_file * file , zpl_file_mode mode , char const * filename ) ;
/**
* Constructs a new file from data
* @ param file
* @ param fd Low - level file descriptor to use
* @ param ops File operations to rely upon
* @ param filename
*/
ZPL_DEF zpl_file_error zpl_file_new ( zpl_file * file , zpl_file_descriptor fd , zpl_file_operations ops , char const * filename ) ;
/**
* Returns a size of the file
* @ param file
* @ return File size
*/
ZPL_DEF zpl_i64 zpl_file_size ( zpl_file * file ) ;
/**
* Returns the currently opened file ' s name
* @ param file
*/
ZPL_DEF char const * zpl_file_name ( zpl_file * file ) ;
/**
* Truncates the file by a specified size
* @ param file
* @ param size Size to truncate
*/
ZPL_DEF zpl_file_error zpl_file_truncate ( zpl_file * file , zpl_i64 size ) ;
/**
* Checks whether a file ' s been changed since the last check
* @ param file
*/
ZPL_DEF zpl_b32 zpl_file_has_changed ( zpl_file * file ) ;
/**
* Retrieves a directory listing relative to the file
* @ param file
*/
ZPL_DEF void zpl_file_dirinfo_refresh ( zpl_file * file ) ;
/**
* Creates a temporary file
* @ param file
*/
zpl_file_error zpl_file_temp ( zpl_file * file ) ;
/**
* Closes the file
* @ param file
*/
ZPL_DEF zpl_file_error zpl_file_close ( zpl_file * file ) ;
/**
* Reads file safely
* @ param file
* @ param buffer Buffer to read to
* @ param size Size to read
* @ param offset Offset to read from
* @ param bytes_read How much data we ' ve actually read
*/
ZPL_DEF_INLINE zpl_b32 zpl_file_read_at_check ( zpl_file * file , void * buffer , zpl_isize size , zpl_i64 offset , zpl_isize * bytes_read ) ;
/**
* Writes to file safely
* @ param file
* @ param buffer Buffer to read from
* @ param size Size to write
* @ param offset Offset to write to
* @ param bytes_written How much data we ' ve actually written
*/
ZPL_DEF_INLINE zpl_b32 zpl_file_write_at_check ( zpl_file * file , void const * buffer , zpl_isize size , zpl_i64 offset , zpl_isize * bytes_written ) ;
/**
* Reads file at a specific offset
* @ param file
* @ param buffer Buffer to read to
* @ param size Size to read
* @ param offset Offset to read from
* @ param bytes_read How much data we ' ve actually read
*/
ZPL_DEF_INLINE zpl_b32 zpl_file_read_at ( zpl_file * file , void * buffer , zpl_isize size , zpl_i64 offset ) ;
/**
* Writes to file at a specific offset
* @ param file
* @ param buffer Buffer to read from
* @ param size Size to write
* @ param offset Offset to write to
* @ param bytes_written How much data we ' ve actually written
*/
ZPL_DEF_INLINE zpl_b32 zpl_file_write_at ( zpl_file * file , void const * buffer , zpl_isize size , zpl_i64 offset ) ;
/**
* Seeks the file cursor from the beginning of file to a specific position
* @ param file
* @ param offset Offset to seek to
*/
ZPL_DEF_INLINE zpl_i64 zpl_file_seek ( zpl_file * file , zpl_i64 offset ) ;
/**
* Seeks the file cursor to the end of the file
* @ param file
*/
ZPL_DEF_INLINE zpl_i64 zpl_file_seek_to_end ( zpl_file * file ) ;
/**
* Skips N bytes at the current position
* @ param file
* @ param bytes Bytes to skip
*/
ZPL_DEF_INLINE zpl_i64 zpl_file_skip ( zpl_file * file , zpl_i64 bytes ) ; // NOTE: Skips a certain amount of bytes
/**
* Returns the length from the beginning of the file we ' ve read so far
* @ param file
* @ return Our current position in file
*/
ZPL_DEF_INLINE zpl_i64 zpl_file_tell ( zpl_file * file ) ;
/**
* Reads from a file
* @ param file
* @ param buffer Buffer to read to
* @ param size Size to read
*/
ZPL_DEF_INLINE zpl_b32 zpl_file_read ( zpl_file * file , void * buffer , zpl_isize size ) ;
/**
* Writes to a file
* @ param file
* @ param buffer Buffer to read from
* @ param size Size to read
*/
ZPL_DEF_INLINE zpl_b32 zpl_file_write ( zpl_file * file , void const * buffer , zpl_isize size ) ;
typedef struct zpl_file_contents {
zpl_allocator allocator ;
void * data ;
zpl_isize size ;
} zpl_file_contents ;
/**
* Reads the whole file contents
* @ param a Allocator to use
* @ param zero_terminate End the read data with null terminator
* @ param filepath Path to the file
* @ return File contents data
*/
ZPL_DEF zpl_file_contents zpl_file_read_contents ( zpl_allocator a , zpl_b32 zero_terminate , char const * filepath ) ;
/**
* Frees the file content data previously read
* @ param fc
*/
ZPL_DEF void zpl_file_free_contents ( zpl_file_contents * fc ) ;
/**
* Writes content to a file
*/
ZPL_DEF zpl_b32 zpl_file_write_contents ( char const * filepath , void const * buffer , zpl_isize size , zpl_file_error * err ) ;
/**
* Reads the file as array of lines
*
* Make sure you free both the returned buffer and the lines ( zpl_array )
* @ param alloc Allocator to use
* @ param lines Reference to zpl_array container we store lines to
* @ param filename Path to the file
* @ param strip_whitespace Strip whitespace when we split to lines ?
* @ return File content we ' ve read itself
*/
ZPL_DEF char * zpl_file_read_lines ( zpl_allocator alloc , zpl_array ( char * ) * lines , char const * filename , zpl_b32 strip_whitespace ) ;
//! @}
/* inlines */
ZPL_IMPL_INLINE zpl_b32 zpl_file_read_at_check ( zpl_file * f , void * buffer , zpl_isize size , zpl_i64 offset , zpl_isize * bytes_read ) {
if ( ! f - > ops . read_at ) f - > ops = zpl_default_file_operations ;
return f - > ops . read_at ( f - > fd , buffer , size , offset , bytes_read , false ) ;
}
ZPL_IMPL_INLINE zpl_b32 zpl_file_write_at_check ( zpl_file * f , void const * buffer , zpl_isize size , zpl_i64 offset , zpl_isize * bytes_written ) {
if ( ! f - > ops . read_at ) f - > ops = zpl_default_file_operations ;
return f - > ops . write_at ( f - > fd , buffer , size , offset , bytes_written ) ;
}
ZPL_IMPL_INLINE zpl_b32 zpl_file_read_at ( zpl_file * f , void * buffer , zpl_isize size , zpl_i64 offset ) {
return zpl_file_read_at_check ( f , buffer , size , offset , NULL ) ;
}
ZPL_IMPL_INLINE zpl_b32 zpl_file_write_at ( zpl_file * f , void const * buffer , zpl_isize size , zpl_i64 offset ) {
return zpl_file_write_at_check ( f , buffer , size , offset , NULL ) ;
}
ZPL_IMPL_INLINE zpl_i64 zpl_file_seek ( zpl_file * f , zpl_i64 offset ) {
zpl_i64 new_offset = 0 ;
if ( ! f - > ops . read_at ) f - > ops = zpl_default_file_operations ;
f - > ops . seek ( f - > fd , offset , ZPL_SEEK_WHENCE_BEGIN , & new_offset ) ;
return new_offset ;
}
ZPL_IMPL_INLINE zpl_i64 zpl_file_seek_to_end ( zpl_file * f ) {
zpl_i64 new_offset = 0 ;
if ( ! f - > ops . read_at ) f - > ops = zpl_default_file_operations ;
f - > ops . seek ( f - > fd , 0 , ZPL_SEEK_WHENCE_END , & new_offset ) ;
return new_offset ;
}
// NOTE: Skips a certain amount of bytes
ZPL_IMPL_INLINE zpl_i64 zpl_file_skip ( zpl_file * f , zpl_i64 bytes ) {
zpl_i64 new_offset = 0 ;
if ( ! f - > ops . read_at ) f - > ops = zpl_default_file_operations ;
f - > ops . seek ( f - > fd , bytes , ZPL_SEEK_WHENCE_CURRENT , & new_offset ) ;
return new_offset ;
}
ZPL_IMPL_INLINE zpl_i64 zpl_file_tell ( zpl_file * f ) {
zpl_i64 new_offset = 0 ;
if ( ! f - > ops . read_at ) f - > ops = zpl_default_file_operations ;
f - > ops . seek ( f - > fd , 0 , ZPL_SEEK_WHENCE_CURRENT , & new_offset ) ;
return new_offset ;
}
ZPL_IMPL_INLINE zpl_b32 zpl_file_read ( zpl_file * f , void * buffer , zpl_isize size ) {
zpl_i64 cur_offset = zpl_file_tell ( f ) ;
zpl_b32 result = zpl_file_read_at ( f , buffer , size , zpl_file_tell ( f ) ) ;
zpl_file_seek ( f , cur_offset + size ) ;
return result ;
}
ZPL_IMPL_INLINE zpl_b32 zpl_file_write ( zpl_file * f , void const * buffer , zpl_isize size ) {
zpl_i64 cur_offset = zpl_file_tell ( f ) ;
zpl_b32 result = zpl_file_write_at ( f , buffer , size , zpl_file_tell ( f ) ) ;
zpl_file_seek ( f , cur_offset + size ) ;
return result ;
}
ZPL_END_C_DECLS
// file: header/core/file_stream.h
/** @file file_stream.c
@ brief File stream
@ defgroup fileio File stream
File streaming operations on memory .
@ {
*/
ZPL_BEGIN_C_DECLS
typedef enum {
/* Allows us to write to the buffer directly. Beware: you can not append a new data! */
ZPL_FILE_STREAM_WRITABLE = ZPL_BIT ( 0 ) ,
/* Clones the input buffer so you can write (zpl_file_write*) data into it. */
/* Since we work with a clone, the buffer size can dynamically grow as well. */
ZPL_FILE_STREAM_CLONE_WRITABLE = ZPL_BIT ( 1 ) ,
} zpl_file_stream_flags ;
/**
* Opens a new memory stream
* @ param file
* @ param allocator
*/
ZPL_DEF void zpl_file_stream_new ( zpl_file * file , zpl_allocator allocator ) ;
/**
* Opens a memory stream over an existing buffer
* @ param file
* @ param allocator
* @ param buffer Memory to create stream from
* @ param size Buffer ' s size
* @ param flags
*/
ZPL_DEF void zpl_file_stream_open ( zpl_file * file , zpl_allocator allocator , zpl_u8 * buffer , zpl_isize size , zpl_file_stream_flags flags ) ;
/**
* Retrieves the stream ' s underlying buffer and buffer size .
* @ param file memory stream
* @ param size ( Optional ) buffer size
*/
ZPL_DEF zpl_u8 * zpl_file_stream_buf ( zpl_file * file , zpl_isize * size ) ;
extern zpl_file_operations const zpl_memory_file_operations ;
//! @}
ZPL_END_C_DECLS
// file: header/core/file_misc.h
ZPL_BEGIN_C_DECLS
# ifndef ZPL_PATH_SEPARATOR
# if defined(ZPL_SYSTEM_WINDOWS)
# define ZPL_PATH_SEPARATOR '\\'
# else
# define ZPL_PATH_SEPARATOR ' / '
# endif
# endif
# ifndef ZPL_MAX_PATH
# if defined(ZPL_SYSTEM_WINDOWS)
# define ZPL_MAX_PATH MAX_PATH
# elif defined(ZPL_SYSTEM_UNIX) && !defined(ZPL_SYSTEM_EMSCRIPTEN)
# define ZPL_MAX_PATH PATH_MAX
# else
# define ZPL_MAX_PATH 4096
# endif
# endif
/**
* Checks if file / directory exists
* @ param filepath
*/
ZPL_DEF zpl_b32 zpl_fs_exists ( char const * filepath ) ;
/**
* Retrieves node ' s type ( file , folder , . . . )
* @ param path
*/
ZPL_DEF zpl_u8 zpl_fs_get_type ( char const * path ) ;
/**
* Retrieves file ' s last write time
* @ param filepath
*/
ZPL_DEF zpl_file_time zpl_fs_last_write_time ( char const * filepath ) ;
/**
* Copies the file to a directory
* @ param existing_filename
* @ param new_filename
* @ param fail_if_exists
*/
ZPL_DEF zpl_b32 zpl_fs_copy ( char const * existing_filename , char const * new_filename , zpl_b32 fail_if_exists ) ;
/**
* Moves the file to a directory
* @ param existing_filename
* @ param new_filename
*/
ZPL_DEF zpl_b32 zpl_fs_move ( char const * existing_filename , char const * new_filename ) ;
/**
* Removes a file from a directory
* @ param filename
*/
ZPL_DEF zpl_b32 zpl_fs_remove ( char const * filename ) ;
ZPL_DEF_INLINE zpl_b32 zpl_path_is_absolute ( char const * path ) ;
ZPL_DEF_INLINE zpl_b32 zpl_path_is_relative ( char const * path ) ;
ZPL_DEF_INLINE zpl_b32 zpl_path_is_root ( char const * path ) ;
ZPL_DEF_INLINE char const * zpl_path_base_name ( char const * path ) ;
ZPL_DEF_INLINE char const * zpl_path_extension ( char const * path ) ;
ZPL_DEF void zpl_path_fix_slashes ( char * path ) ;
ZPL_DEF zpl_file_error zpl_path_mkdir ( char const * path , zpl_i32 mode ) ;
ZPL_DEF zpl_isize zpl_path_mkdir_recursive ( char const * path , zpl_i32 mode ) ;
ZPL_DEF zpl_file_error zpl_path_rmdir ( char const * path ) ;
ZPL_DEF char * zpl_path_get_full_name ( zpl_allocator a , char const * path ) ;
/**
* Returns file paths terminated by newline ( \ n )
* @ param alloc [ description ]
* @ param dirname [ description ]
* @ param recurse [ description ]
* @ return [ description ]
*/
ZPL_DEF /*zpl_string*/ char * zpl_path_dirlist ( zpl_allocator alloc , char const * dirname , zpl_b32 recurse ) ;
/**
* Initialize dirinfo from specified path
* @ param dir [ description ]
* @ param path [ description ]
*/
ZPL_DEF void zpl_dirinfo_init ( zpl_dir_info * dir , char const * path ) ;
ZPL_DEF void zpl_dirinfo_free ( zpl_dir_info * dir ) ;
/**
* Analyze the entry ' s dirinfo
* @ param dir_entry [ description ]
*/
ZPL_DEF void zpl_dirinfo_step ( zpl_dir_entry * dir_entry ) ;
/* inlines */
ZPL_IMPL_INLINE zpl_b32 zpl_path_is_absolute ( char const * path ) {
zpl_b32 result = false ;
ZPL_ASSERT_NOT_NULL ( path ) ;
# if defined(ZPL_SYSTEM_WINDOWS)
result = ( zpl_strlen ( path ) > 2 ) & & zpl_char_is_alpha ( path [ 0 ] ) & & ( path [ 1 ] = = ' : ' & & path [ 2 ] = = ZPL_PATH_SEPARATOR ) ;
# else
result = ( zpl_strlen ( path ) > 0 & & path [ 0 ] = = ZPL_PATH_SEPARATOR ) ;
# endif
return result ;
}
ZPL_IMPL_INLINE zpl_b32 zpl_path_is_relative ( char const * path ) { return ! zpl_path_is_absolute ( path ) ; }
ZPL_IMPL_INLINE zpl_b32 zpl_path_is_root ( char const * path ) {
zpl_b32 result = false ;
ZPL_ASSERT_NOT_NULL ( path ) ;
# if defined(ZPL_SYSTEM_WINDOWS)
result = zpl_path_is_absolute ( path ) & & ( zpl_strlen ( path ) = = 3 ) ;
# else
result = zpl_path_is_absolute ( path ) & & ( zpl_strlen ( path ) = = 1 ) ;
# endif
return result ;
}
ZPL_IMPL_INLINE char const * zpl_path_base_name ( char const * path ) {
char const * ls ;
ZPL_ASSERT_NOT_NULL ( path ) ;
zpl_path_fix_slashes ( ( char * ) path ) ;
ls = zpl_char_last_occurence ( path , ZPL_PATH_SEPARATOR ) ;
return ( ls = = NULL ) ? path : ls + 1 ;
}
ZPL_IMPL_INLINE char const * zpl_path_extension ( char const * path ) {
char const * ld ;
ZPL_ASSERT_NOT_NULL ( path ) ;
ld = zpl_char_last_occurence ( path , ' . ' ) ;
return ( ld = = NULL ) ? NULL : ld + 1 ;
}
ZPL_END_C_DECLS
// file: header/core/file_tar.h
/** @file file_tar.c
@ brief Tar archiving module
@ defgroup fileio Tar module
Allows to easily pack / unpack files .
Based on : https : //github.com/rxi/microtar/
Disclaimer : The pack method does not support file permissions nor GID / UID information . Only regular files are supported .
Use zpl_tar_pack_dir to pack an entire directory recursively . Empty folders are ignored .
@ {
*/
ZPL_BEGIN_C_DECLS
typedef enum {
ZPL_TAR_ERROR_NONE ,
ZPL_TAR_ERROR_INTERRUPTED ,
ZPL_TAR_ERROR_IO_ERROR ,
ZPL_TAR_ERROR_BAD_CHECKSUM ,
ZPL_TAR_ERROR_FILE_NOT_FOUND ,
ZPL_TAR_ERROR_INVALID_INPUT ,
} zpl_tar_errors ;
typedef enum {
ZPL_TAR_TYPE_REGULAR = ' 0 ' ,
ZPL_TAR_TYPE_LINK = ' 1 ' ,
ZPL_TAR_TYPE_SYMBOL = ' 2 ' ,
ZPL_TAR_TYPE_CHR = ' 3 ' ,
ZPL_TAR_TYPE_BLK = ' 4 ' ,
ZPL_TAR_TYPE_DIR = ' 5 ' ,
ZPL_TAR_TYPE_FIFO = ' 6 '
} zpl_tar_file_type ;
typedef struct {
char type ;
char * path ;
zpl_i64 offset ;
zpl_i64 length ;
zpl_isize error ;
} zpl_tar_record ;
# define ZPL_TAR_UNPACK_PROC(name) zpl_isize name(zpl_file *archive, zpl_tar_record *file, void* user_data)
typedef ZPL_TAR_UNPACK_PROC ( zpl_tar_unpack_proc ) ;
/**
* @ brief Packs a list of files
* Packs a list of provided files . Note that this method only supports regular files
* and does not provide extended info such as GID / UID or permissions .
* @ param archive archive we pack files into
* @ param paths list of files
* @ param paths_len number of files provided
* @ return error
*/
ZPL_DEF zpl_isize zpl_tar_pack ( zpl_file * archive , char const * * paths , zpl_isize paths_len ) ;
/**
* @ brief Packs an entire directory
* Packs an entire directory of files recursively .
* @ param archive archive we pack files to
* @ param path folder to pack
* @ param alloc memory allocator to use ( ex . zpl_heap ( ) )
* @ return error
*/
ZPL_DEF zpl_isize zpl_tar_pack_dir ( zpl_file * archive , char const * path , zpl_allocator alloc ) ;
/**
* @ brief Unpacks an existing archive
* Unpacks an existing archive . Users provide a callback in which information about file is provided .
* Library does not unpack files to the filesystem nor reads any file data .
* @ param archive archive we unpack files from
* @ param unpack_proc callback we call per each file parsed
* @ param user_data user provided data
* @ return error
*/
ZPL_DEF zpl_isize zpl_tar_unpack ( zpl_file * archive , zpl_tar_unpack_proc * unpack_proc , void * user_data ) ;
/**
* @ brief Unpacks an existing archive into directory
* Unpacks an existing archive into directory . The folder structure will be re - created automatically .
* @ param archive archive we unpack files from
* @ param dest directory to unpack files to
* @ return error
*/
ZPL_DEF_INLINE zpl_isize zpl_tar_unpack_dir ( zpl_file * archive , char const * dest ) ;
ZPL_DEF ZPL_TAR_UNPACK_PROC ( zpl_tar_default_list_file ) ;
ZPL_DEF ZPL_TAR_UNPACK_PROC ( zpl_tar_default_unpack_file ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! @}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_IMPL_INLINE zpl_isize zpl_tar_unpack_dir ( zpl_file * archive , char const * dest ) {
return zpl_tar_unpack ( archive , zpl_tar_default_unpack_file , cast ( void * ) dest ) ;
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_END_C_DECLS
// file: header/core/print.h
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
/** @file print.c
@ brief Printing methods
@ defgroup print Printing methods
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
Various printing methods .
@ {
*/
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_BEGIN_C_DECLS
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
# ifndef ZPL_PRINTF_MAXLEN
# define ZPL_PRINTF_MAXLEN 65536
# endif
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_DEF zpl_isize zpl_printf ( char const * fmt , . . . ) ;
ZPL_DEF zpl_isize zpl_printf_va ( char const * fmt , va_list va ) ;
ZPL_DEF zpl_isize zpl_printf_err ( char const * fmt , . . . ) ;
ZPL_DEF zpl_isize zpl_printf_err_va ( char const * fmt , va_list va ) ;
ZPL_DEF zpl_isize zpl_fprintf ( zpl_file * f , char const * fmt , . . . ) ;
ZPL_DEF zpl_isize zpl_fprintf_va ( zpl_file * f , char const * fmt , va_list va ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
// NOTE: A locally persisting buffer is used internally
ZPL_DEF char * zpl_bprintf ( char const * fmt , . . . ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
// NOTE: A locally persisting buffer is used internally
ZPL_DEF char * zpl_bprintf_va ( char const * fmt , va_list va ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_DEF zpl_isize zpl_asprintf ( zpl_allocator allocator , char * * buffer , char const * fmt , . . . ) ;
ZPL_DEF zpl_isize zpl_asprintf_va ( zpl_allocator allocator , char * * buffer , char const * fmt , va_list va ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_DEF zpl_isize zpl_snprintf ( char * str , zpl_isize n , char const * fmt , . . . ) ;
ZPL_DEF zpl_isize zpl_snprintf_va ( char * str , zpl_isize n , char const * fmt , va_list va ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_END_C_DECLS
// file: header/core/time.h
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
/** @file time.c
@ brief Time helper methods .
@ defgroup time Time helpers
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
Helper methods for retrieving the current time in many forms under different precisions . It also offers a simple to use timer library .
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
@ {
*/
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_BEGIN_C_DECLS
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Return CPU timestamp.
ZPL_DEF zpl_u64 zpl_rdtsc ( void ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Return relative time (in seconds) since the application start.
ZPL_DEF zpl_f64 zpl_time_rel ( void ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Return relative time since the application start.
ZPL_DEF zpl_u64 zpl_time_rel_ms ( void ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Return time (in seconds) since 1601-01-01 UTC.
ZPL_DEF zpl_f64 zpl_time_utc ( void ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Return time since 1601-01-01 UTC.
ZPL_DEF zpl_u64 zpl_time_utc_ms ( void ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Return local system time since 1601-01-01
ZPL_DEF zpl_u64 zpl_time_tz_ms ( void ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Return local system time in seconds since 1601-01-01
ZPL_DEF zpl_f64 zpl_time_tz ( void ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Convert Win32 epoch (1601-01-01 UTC) to UNIX (1970-01-01 UTC)
ZPL_DEF_INLINE zpl_u64 zpl_time_win32_to_unix ( zpl_u64 ms ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Convert UNIX (1970-01-01 UTC) to Win32 epoch (1601-01-01 UTC)
ZPL_DEF_INLINE zpl_u64 zpl_time_unix_to_win32 ( zpl_u64 ms ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Sleep for specified number of milliseconds.
ZPL_DEF void zpl_sleep_ms ( zpl_u32 ms ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Sleep for specified number of seconds.
ZPL_DEF_INLINE void zpl_sleep ( zpl_f32 s ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
// Deprecated methods
ZPL_DEPRECATED_FOR ( 10.9 .0 , zpl_time_rel )
ZPL_DEF_INLINE zpl_f64 zpl_time_now ( void ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_DEPRECATED_FOR ( 10.9 .0 , zpl_time_utc )
ZPL_DEF_INLINE zpl_f64 zpl_utc_time_now ( void ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
# ifndef ZPL__UNIX_TO_WIN32_EPOCH
# define ZPL__UNIX_TO_WIN32_EPOCH 11644473600000ull
# endif
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_IMPL_INLINE zpl_u64 zpl_time_win32_to_unix ( zpl_u64 ms ) {
return ms - ZPL__UNIX_TO_WIN32_EPOCH ;
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_IMPL_INLINE zpl_u64 zpl_time_unix_to_win32 ( zpl_u64 ms ) {
return ms + ZPL__UNIX_TO_WIN32_EPOCH ;
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_IMPL_INLINE void zpl_sleep ( zpl_f32 s ) {
zpl_sleep_ms ( ( zpl_u32 ) ( s * 1000 ) ) ;
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_IMPL_INLINE zpl_f64 zpl_time_now ( ) {
return zpl_time_rel ( ) ;
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_IMPL_INLINE zpl_f64 zpl_utc_time_now ( ) {
return zpl_time_utc ( ) ;
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_END_C_DECLS
// file: header/core/random.h
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_BEGIN_C_DECLS
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
typedef struct zpl_random {
zpl_u32 offsets [ 8 ] ;
zpl_u32 value ;
} zpl_random ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
// NOTE: Generates from numerous sources to produce a decent pseudo-random seed
ZPL_DEF void zpl_random_init ( zpl_random * r ) ;
ZPL_DEF zpl_u32 zpl_random_gen_u32 ( zpl_random * r ) ;
ZPL_DEF zpl_u32 zpl_random_gen_u32_unique ( zpl_random * r ) ;
ZPL_DEF zpl_u64 zpl_random_gen_u64 ( zpl_random * r ) ; // NOTE: (zpl_random_gen_u32() << 32) | zpl_random_gen_u32()
ZPL_DEF zpl_isize zpl_random_gen_isize ( zpl_random * r ) ;
ZPL_DEF zpl_i64 zpl_random_range_i64 ( zpl_random * r , zpl_i64 lower_inc , zpl_i64 higher_inc ) ;
ZPL_DEF zpl_isize zpl_random_range_isize ( zpl_random * r , zpl_isize lower_inc , zpl_isize higher_inc ) ;
ZPL_DEF zpl_f64 zpl_random_range_f64 ( zpl_random * r , zpl_f64 lower_inc , zpl_f64 higher_inc ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_END_C_DECLS
// file: header/core/misc.h
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
/** @file misc.c
@ brief Various other stuff
@ defgroup misc Various other stuff
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
Methods that don ' t belong anywhere but are still very useful in many occasions .
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
@ {
*/
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_BEGIN_C_DECLS
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_DEF void zpl_yield ( void ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Returns allocated buffer
ZPL_DEF const char * zpl_get_env ( const char * name ) ;
ZPL_DEF const char * zpl_get_env_buf ( const char * name ) ;
ZPL_DEF zpl_string zpl_get_env_str ( const char * name ) ;
ZPL_DEF void zpl_set_env ( const char * name , const char * value ) ;
ZPL_DEF void zpl_unset_env ( const char * name ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_DEF zpl_u32 zpl_system_command ( const char * command , zpl_usize buffer_len , char * buffer ) ;
ZPL_DEF zpl_string zpl_system_command_str ( const char * command , zpl_allocator backing ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_DEF_INLINE zpl_u16 zpl_endian_swap16 ( zpl_u16 i ) ;
ZPL_DEF_INLINE zpl_u32 zpl_endian_swap32 ( zpl_u32 i ) ;
ZPL_DEF_INLINE zpl_u64 zpl_endian_swap64 ( zpl_u64 i ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_DEF_INLINE zpl_isize zpl_count_set_bits ( zpl_u64 mask ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! @}
//$$
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_IMPL_INLINE zpl_u16 zpl_endian_swap16 ( zpl_u16 i ) {
return ( i > > 8 ) | ( i < < 8 ) ;
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_IMPL_INLINE zpl_u32 zpl_endian_swap32 ( zpl_u32 i ) {
return ( i > > 24 ) | ( i < < 24 ) |
( ( i & 0x00ff0000u ) > > 8 ) | ( ( i & 0x0000ff00u ) < < 8 ) ;
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_IMPL_INLINE zpl_u64 zpl_endian_swap64 ( zpl_u64 i ) {
return ( i > > 56 ) | ( i < < 56 ) |
( ( i & 0x00ff000000000000ull ) > > 40 ) | ( ( i & 0x000000000000ff00ull ) < < 40 ) |
( ( i & 0x0000ff0000000000ull ) > > 24 ) | ( ( i & 0x0000000000ff0000ull ) < < 24 ) |
( ( i & 0x000000ff00000000ull ) > > 8 ) | ( ( i & 0x00000000ff000000ull ) < < 8 ) ;
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_IMPL_INLINE zpl_i32 zpl_next_pow2 ( zpl_i32 x ) {
x - - ;
x | = x > > 1 ;
x | = x > > 2 ;
x | = x > > 4 ;
x | = x > > 8 ;
x | = x > > 16 ;
return x + 1 ;
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_IMPL_INLINE void zpl_bit_set ( zpl_u32 * x , zpl_u32 bit ) { * x = * x | ( 1 < < bit ) ; }
ZPL_IMPL_INLINE zpl_b8 zpl_bit_get ( zpl_u32 x , zpl_u32 bit ) { return ( x & ( 1 < < bit ) ) ; }
ZPL_IMPL_INLINE void zpl_bit_reset ( zpl_u32 * x , zpl_u32 bit ) { * x = * x & ~ ( 1 < < bit ) ; }
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_IMPL_INLINE zpl_isize zpl_count_set_bits ( zpl_u64 mask ) {
zpl_isize count = 0 ;
while ( mask ) {
count + = ( mask & 1 ) ;
mask > > = 1 ;
}
return count ;
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_END_C_DECLS
// file: header/core/sort.h
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
/** @file sort.c
@ brief Sorting and searching methods .
@ defgroup sort Sorting and searching
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
Methods for sorting arrays using either Quick / Merge - sort combo or Radix sort . It also contains simple implementation of binary search , as well as an easy to use API to define your own comparators .
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
@ {
*/
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_BEGIN_C_DECLS
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
# define ZPL_COMPARE_PROC(name) int name(void const *a, void const *b)
typedef ZPL_COMPARE_PROC ( zpl_compare_proc ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
# define ZPL_COMPARE_PROC_PTR(def) ZPL_COMPARE_PROC((*def))
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
// Procedure pointers
// NOTE: The offset parameter specifies the offset in the structure
// e.g. zpl_i32_cmp(zpl_offset_of(Thing, value))
// Use 0 if it's just the type instead.
2021-11-29 08:23:08 +00:00
2022-10-15 21:10:46 +00:00
ZPL_DEF ZPL_COMPARE_PROC_PTR ( zpl_i16_cmp ( zpl_isize offset ) ) ;
ZPL_DEF ZPL_COMPARE_PROC_PTR ( zpl_u8_cmp ( zpl_isize offset ) ) ;
ZPL_DEF ZPL_COMPARE_PROC_PTR ( zpl_i32_cmp ( zpl_isize offset ) ) ;
ZPL_DEF ZPL_COMPARE_PROC_PTR ( zpl_i64_cmp ( zpl_isize offset ) ) ;
ZPL_DEF ZPL_COMPARE_PROC_PTR ( zpl_isize_cmp ( zpl_isize offset ) ) ;
ZPL_DEF ZPL_COMPARE_PROC_PTR ( zpl_str_cmp ( zpl_isize offset ) ) ;
ZPL_DEF ZPL_COMPARE_PROC_PTR ( zpl_f32_cmp ( zpl_isize offset ) ) ;
ZPL_DEF ZPL_COMPARE_PROC_PTR ( zpl_f64_cmp ( zpl_isize offset ) ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
// TODO: Better sorting algorithms
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Sorts an array.
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Uses quick sort for large arrays but insertion sort for small ones.
# define zpl_sort_array(array, count, compare_proc) zpl_sort(array, count, zpl_size_of(*(array)), compare_proc)
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Perform sorting operation on a memory location with a specified item count and size.
ZPL_DEF void zpl_sort ( void * base , zpl_isize count , zpl_isize size , zpl_compare_proc compare_proc ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
// NOTE: the count of temp == count of items
# define zpl_radix_sort(Type) zpl_radix_sort_##Type
# define ZPL_RADIX_SORT_PROC(Type) void zpl_radix_sort(Type)(zpl_##Type * items, zpl_##Type * temp, zpl_isize count)
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_DEF ZPL_RADIX_SORT_PROC ( u8 ) ;
ZPL_DEF ZPL_RADIX_SORT_PROC ( u16 ) ;
ZPL_DEF ZPL_RADIX_SORT_PROC ( u32 ) ;
ZPL_DEF ZPL_RADIX_SORT_PROC ( u64 ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Performs binary search on an array.
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Returns index or -1 if not found
# define zpl_binary_search_array(array, count, key, compare_proc) \
zpl_binary_search ( array , count , zpl_size_of ( * ( array ) ) , key , compare_proc )
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Performs binary search on a memory location with specified item count and size.
ZPL_DEF_INLINE zpl_isize zpl_binary_search ( void const * base , zpl_isize count , zpl_isize size , void const * key ,
zpl_compare_proc compare_proc ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
# define zpl_shuffle_array(array, count) zpl_shuffle(array, count, zpl_size_of(*(array)))
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Shuffles a memory.
ZPL_DEF void zpl_shuffle ( void * base , zpl_isize count , zpl_isize size ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
# define zpl_reverse_array(array, count) zpl_reverse(array, count, zpl_size_of(*(array)))
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Reverses memory's contents
ZPL_DEF void zpl_reverse ( void * base , zpl_isize count , zpl_isize size ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! @}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_IMPL_INLINE zpl_isize zpl_binary_search ( void const * base , zpl_isize count , zpl_isize size , void const * key ,
zpl_compare_proc compare_proc ) {
zpl_isize start = 0 ;
zpl_isize end = count ;
while ( start < end ) {
zpl_isize mid = start + ( end - start ) / 2 ;
zpl_isize result = compare_proc ( key , cast ( zpl_u8 * ) base + mid * size ) ;
if ( result < 0 )
end = mid ;
else if ( result > 0 )
start = mid + 1 ;
else
return mid ;
}
return - 1 ;
}
ZPL_END_C_DECLS
# endif
2021-11-29 08:23:08 +00:00
# endif
2022-09-11 17:42:06 +00:00
# if defined(ZPL_MODULE_HASHING)
// file: header/hashing.h
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
/** @file hashing.c
@ brief Hashing and Checksum Functions
@ defgroup hashing Hashing and Checksum Functions
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
Several hashing methods used by zpl internally but possibly useful outside of it . Contains : adler32 , crc32 / 64 , fnv32 / 64 / a and murmur32 / 64
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
@ {
*/
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_BEGIN_C_DECLS
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_DEF zpl_u32 zpl_adler32 ( void const * data , zpl_isize len ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_DEF zpl_u32 zpl_crc32 ( void const * data , zpl_isize len ) ;
ZPL_DEF zpl_u64 zpl_crc64 ( void const * data , zpl_isize len ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
// These use FNV-1 algorithm
ZPL_DEF zpl_u32 zpl_fnv32 ( void const * data , zpl_isize len ) ;
ZPL_DEF zpl_u64 zpl_fnv64 ( void const * data , zpl_isize len ) ;
ZPL_DEF zpl_u32 zpl_fnv32a ( void const * data , zpl_isize len ) ;
ZPL_DEF zpl_u64 zpl_fnv64a ( void const * data , zpl_isize len ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_DEF zpl_u8 * zpl_base64_encode ( zpl_allocator a , void const * data , zpl_isize len ) ;
ZPL_DEF zpl_u8 * zpl_base64_decode ( zpl_allocator a , void const * data , zpl_isize len ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Based on MurmurHash3
ZPL_DEF zpl_u32 zpl_murmur32_seed ( void const * data , zpl_isize len , zpl_u32 seed ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Based on MurmurHash2
ZPL_DEF zpl_u64 zpl_murmur64_seed ( void const * data , zpl_isize len , zpl_u64 seed ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Default seed of 0x9747b28c
ZPL_DEF_INLINE zpl_u32 zpl_murmur32 ( void const * data , zpl_isize len ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Default seed of 0x9747b28c
ZPL_DEF_INLINE zpl_u64 zpl_murmur64 ( void const * data , zpl_isize len ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! @}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_IMPL_INLINE zpl_u32 zpl_murmur32 ( void const * data , zpl_isize len ) { return zpl_murmur32_seed ( data , len , 0x9747b28c ) ; }
ZPL_IMPL_INLINE zpl_u64 zpl_murmur64 ( void const * data , zpl_isize len ) { return zpl_murmur64_seed ( data , len , 0x9747b28c ) ; }
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_END_C_DECLS
# endif
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
# if defined(ZPL_MODULE_REGEX)
// file: header/regex.h
/** @file regex.c
@ brief Regular expressions parser .
@ defgroup regex Regex processor
Port of gb_regex with several bugfixes applied . This is a simple regex library and is fast to perform .
Supported Matching :
@ n ^ - Beginning of string
@ n $ - End of string
@ n . - Match one ( anything )
@ n | - Branch ( or )
@ n ( ) - Capturing group
@ n [ ] - Any character included in set
@ n [ ^ ] - Any character excluded from set
@ n + - One or more ( greedy )
@ n + ? - One or more ( non - greedy )
@ n * - Zero or more ( greedy )
@ n * ? - Zero or more ( non - greedy )
@ n ? - Zero or once
@ n [ BACKSLASH ] XX - Hex decimal digit ( must be 2 digits )
@ n [ BACKSLASH ] meta - Meta character
@ n [ BACKSLASH ] s - Whitespace
@ n [ BACKSLASH ] S - Not whitespace
@ n [ BACKSLASH ] d - Digit
@ n [ BACKSLASH ] D - Not digit
@ n [ BACKSLASH ] a - Alphabetic character
@ n [ BACKSLASH ] l - Lower case letter
@ n [ BACKSLASH ] u - Upper case letter
@ n [ BACKSLASH ] w - Word
@ n [ BACKSLASH ] W - Not word
@ n [ BACKSLASH ] x - Hex Digit
@ n [ BACKSLASH ] p - Printable ASCII character
@ n - - Whitespace - -
@ n [ BACKSLASH ] t - Tab
@ n [ BACKSLASH ] n - New line
@ n [ BACKSLASH ] r - Return carriage
@ n [ BACKSLASH ] v - Vertical Tab
@ n [ BACKSLASH ] f - Form feed
@ {
*/
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_BEGIN_C_DECLS
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
typedef struct zpl_re {
zpl_allocator backing ;
zpl_isize capture_count ;
char * buf ;
zpl_isize buf_len , buf_cap ;
zpl_b32 can_realloc ;
} zpl_re ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
typedef struct zpl_re_capture {
char const * str ;
zpl_isize len ;
} zpl_re_capture ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
# define zplRegexError zpl_regex_error
typedef enum zpl_regex_error {
ZPL_RE_ERROR_NONE ,
ZPL_RE_ERROR_NO_MATCH ,
ZPL_RE_ERROR_TOO_LONG ,
ZPL_RE_ERROR_MISMATCHED_CAPTURES ,
ZPL_RE_ERROR_MISMATCHED_BLOCKS ,
ZPL_RE_ERROR_BRANCH_FAILURE ,
ZPL_RE_ERROR_INVALID_QUANTIFIER ,
ZPL_RE_ERROR_INTERNAL_FAILURE ,
} zpl_regex_error ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Compile regex pattern.
ZPL_DEF zpl_regex_error zpl_re_compile ( zpl_re * re , zpl_allocator backing , char const * pattern , zpl_isize pattern_len ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Compile regex pattern using a buffer.
ZPL_DEF zpl_regex_error zpl_re_compile_from_buffer ( zpl_re * re , char const * pattern , zpl_isize pattern_len , void * buffer , zpl_isize buffer_len ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Destroy regex object.
ZPL_DEF void zpl_re_destroy ( zpl_re * re ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Retrieve number of retrievable captures.
ZPL_DEF zpl_isize zpl_re_capture_count ( zpl_re * re ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Match input string and output captures of the occurence.
ZPL_DEF zpl_b32 zpl_re_match ( zpl_re * re , char const * str , zpl_isize str_len , zpl_re_capture * captures , zpl_isize max_capture_count , zpl_isize * offset ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Match all occurences in an input string and output them into captures. Array of captures is allocated on the heap and needs to be freed afterwards.
ZPL_DEF zpl_b32 zpl_re_match_all ( zpl_re * re , char const * str , zpl_isize str_len , zpl_isize max_capture_count , zpl_re_capture * * out_captures ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_END_C_DECLS
# endif
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
# if defined(ZPL_MODULE_DLL)
// file: header/dll.h
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
/** @file dll.c
@ brief DLL Handling
@ defgroup dll DLL handling
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
@ {
*/
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_BEGIN_C_DECLS
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
typedef void * zpl_dll_handle ;
typedef void ( * zpl_dll_proc ) ( void ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_DEF zpl_dll_handle zpl_dll_load ( char const * filepath ) ;
ZPL_DEF void zpl_dll_unload ( zpl_dll_handle dll ) ;
ZPL_DEF zpl_dll_proc zpl_dll_proc_address ( zpl_dll_handle dll , char const * proc_name ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! @}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_END_C_DECLS
2021-11-29 08:23:08 +00:00
# endif
2022-09-11 17:42:06 +00:00
# if defined(ZPL_MODULE_OPTS)
// file: header/opts.h
/** @file opts.c
@ brief CLI options processor
@ defgroup cli CLI options processor
Opts is a CLI options parser , it can parse flags , switches and arguments from command line
and offers an easy way to express input errors as well as the ability to display help screen .
@ {
*/
ZPL_BEGIN_C_DECLS
typedef enum {
ZPL_OPTS_STRING ,
ZPL_OPTS_FLOAT ,
ZPL_OPTS_FLAG ,
ZPL_OPTS_INT ,
} zpl_opts_types ;
typedef struct {
char const * name , * lname , * desc ;
zpl_u8 type ;
zpl_b32 met , pos ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! values
union {
zpl_string text ;
zpl_i64 integer ;
zpl_f64 real ;
} ;
} zpl_opts_entry ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
typedef enum {
ZPL_OPTS_ERR_VALUE ,
ZPL_OPTS_ERR_OPTION ,
ZPL_OPTS_ERR_EXTRA_VALUE ,
ZPL_OPTS_ERR_MISSING_VALUE ,
} zpl_opts_err_type ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
typedef struct {
char * val ;
zpl_u8 type ;
} zpl_opts_err ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
typedef struct {
zpl_allocator alloc ;
zpl_opts_entry * entries ; ///< zpl_array
zpl_opts_err * errors ; ///< zpl_array
zpl_opts_entry * * positioned ; ///< zpl_array
char const * appname ;
} zpl_opts ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Initializes options parser.
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Initializes CLI options parser using specified memory allocator and provided application name.
//! @param opts Options parser to initialize.
//! @param allocator Memory allocator to use. (ex. zpl_heap())
//! @param app Application name displayed in help screen.
ZPL_DEF void zpl_opts_init ( zpl_opts * opts , zpl_allocator allocator , char const * app ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Releases the resources used by options parser.
ZPL_DEF void zpl_opts_free ( zpl_opts * opts ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Registers an option.
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Registers an option with its short and long name, specifies option's type and its description.
//! @param opts Options parser to add to.
//! @param lname Shorter name of option. (ex. "f")
//! @param name Full name of option. (ex. "foo") Note that rest of the module uses longer names to manipulate opts.
//! @param desc Description shown in the help screen.
//! @param type Option's type (see zpl_opts_types)
//! @see zpl_opts_types
ZPL_DEF void zpl_opts_add ( zpl_opts * opts , char const * name , char const * lname , const char * desc , zpl_u8 type ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Registers option as positional.
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Registers added option as positional, so that we can pass it anonymously. Arguments are expected on the command input in the same order they were registered as.
//! @param opts
//! @param name Name of already registered option.
ZPL_DEF void zpl_opts_positional_add ( zpl_opts * opts , char const * name ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Compiles CLI arguments.
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
// This method takes CLI arguments as input and processes them based on rules that were set up.
//! @param opts
//! @param argc Argument count in an array.
//! @param argv Array of arguments.
ZPL_DEF zpl_b32 zpl_opts_compile ( zpl_opts * opts , int argc , char * * argv ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Prints out help screen.
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Prints out help screen with example usage of application as well as with all the flags available.
ZPL_DEF void zpl_opts_print_help ( zpl_opts * opts ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Prints out parsing errors.
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Prints out possible errors caused by CLI input.
ZPL_DEF void zpl_opts_print_errors ( zpl_opts * opts ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Fetches a string from an option.
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! @param opts
//! @param name Name of an option.
//! @param fallback Fallback string we return if option wasn't found.
ZPL_DEF zpl_string zpl_opts_string ( zpl_opts * opts , char const * name , char const * fallback ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Fetches a real number from an option.
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! @param opts
//! @param name Name of an option.
//! @param fallback Fallback real number we return if option was not found.
ZPL_DEF zpl_f64 zpl_opts_real ( zpl_opts * opts , char const * name , zpl_f64 fallback ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Fetches an integer number from an option.
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! @param opts
//! @param name Name of an option.
//! @param fallback Fallback integer number we return if option was not found.
ZPL_DEF zpl_i64 zpl_opts_integer ( zpl_opts * opts , char const * name , zpl_i64 fallback ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Checks whether an option was used.
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! @param opts
//! @param name Name of an option.
ZPL_DEF zpl_b32 zpl_opts_has_arg ( zpl_opts * opts , char const * name ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Checks whether all positionals have been passed in.
ZPL_DEF zpl_b32 zpl_opts_positionals_filled ( zpl_opts * opts ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! @}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_END_C_DECLS
# endif
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
# if defined(ZPL_MODULE_PROCESS)
// file: header/process.h
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
/** @file process.c
@ brief Process creation and manipulation methods
@ defgroup process Process creation and manipulation methods
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
Gives you the ability to create a new process , wait for it to end or terminate it .
It also exposes standard I / O with configurable options .
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
@ {
*/
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_BEGIN_C_DECLS
// TODO(zaklaus): Add Linux support
typedef enum {
ZPL_PR_OPTS_COMBINE_STD_OUTPUT = ZPL_BIT ( 1 ) ,
ZPL_PR_OPTS_INHERIT_ENV = ZPL_BIT ( 2 ) ,
ZPL_PR_OPTS_CUSTOM_ENV = ZPL_BIT ( 3 ) ,
} zpl_pr_opts ;
typedef struct {
zpl_file in , out , err ;
void * f_stdin , * f_stdout , * f_stderr ;
# ifdef ZPL_SYSTEM_WINDOWS
void * win32_handle ;
# else
// todo
# endif
} zpl_pr ;
typedef struct {
char * con_title ;
char * workdir ;
zpl_isize env_count ;
char * * env ; // format: "var=name"
zpl_u32 posx , posy ;
zpl_u32 resx , resy ;
zpl_u32 bufx , bufy ;
zpl_u32 fill_attr ;
zpl_u32 flags ;
zpl_b32 show_window ;
} zpl_pr_si ;
ZPL_DEF zpl_i32 zpl_pr_create ( zpl_pr * process , const char * * args , zpl_isize argc , zpl_pr_si si , zpl_pr_opts options ) ;
ZPL_DEF void zpl_pr_destroy ( zpl_pr * process ) ;
ZPL_DEF void zpl_pr_terminate ( zpl_pr * process , zpl_i32 err_code ) ;
ZPL_DEF zpl_i32 zpl_pr_join ( zpl_pr * process ) ;
//! @}
ZPL_END_C_DECLS
2021-11-29 08:23:08 +00:00
# endif
2022-09-11 17:42:06 +00:00
# if defined(ZPL_MODULE_MATH)
2023-01-15 15:59:33 +00:00
// file: header/math.h
/** @file math.c
@ brief Math operations
@ defgroup math Math operations
OpenGL gamedev friendly library for math .
@ {
*/
ZPL_BEGIN_C_DECLS
typedef union zpl_vec2 {
struct {
zpl_f32 x , y ;
} ;
struct {
zpl_f32 s , t ;
} ;
zpl_f32 e [ 2 ] ;
} zpl_vec2 ;
typedef union zpl_vec3 {
struct {
zpl_f32 x , y , z ;
} ;
struct {
zpl_f32 r , g , b ;
} ;
struct {
zpl_f32 s , t , p ;
} ;
zpl_vec2 xy ;
zpl_vec2 st ;
zpl_f32 e [ 3 ] ;
} zpl_vec3 ;
typedef union zpl_vec4 {
struct {
zpl_f32 x , y , z , w ;
} ;
struct {
zpl_f32 r , g , b , a ;
} ;
struct {
zpl_f32 s , t , p , q ;
} ;
struct {
zpl_vec2 xy , zw ;
} ;
struct {
zpl_vec2 st , pq ;
} ;
zpl_vec3 xyz ;
zpl_vec3 rgb ;
zpl_f32 e [ 4 ] ;
} zpl_vec4 ;
typedef union zpl_mat2 {
struct {
zpl_vec2 x , y ;
} ;
zpl_vec2 col [ 2 ] ;
zpl_f32 e [ 4 ] ;
} zpl_mat2 ;
typedef union zpl_mat3 {
struct {
zpl_vec3 x , y , z ;
} ;
zpl_vec3 col [ 3 ] ;
zpl_f32 e [ 9 ] ;
} zpl_mat3 ;
typedef union zpl_mat4 {
struct {
zpl_vec4 x , y , z , w ;
} ;
zpl_vec4 col [ 4 ] ;
zpl_f32 e [ 16 ] ;
} zpl_mat4 ;
typedef union zpl_quat {
struct {
zpl_f32 x , y , z , w ;
} ;
zpl_vec4 xyzw ;
zpl_vec3 xyz ;
zpl_f32 e [ 4 ] ;
} zpl_quat ;
typedef union zpl_plane {
struct {
zpl_f32 a , b , c , d ;
} ;
zpl_vec4 xyzw ;
zpl_vec3 n ;
zpl_f32 e [ 4 ] ;
} zpl_plane ;
typedef struct zpl_frustum {
zpl_plane x1 ;
zpl_plane x2 ;
zpl_plane y1 ;
zpl_plane y2 ;
zpl_plane z1 ;
zpl_plane z2 ;
} zpl_frustum ;
typedef zpl_f32 zpl_float2 [ 2 ] ;
typedef zpl_f32 zpl_float3 [ 3 ] ;
typedef zpl_f32 zpl_float4 [ 4 ] ;
typedef struct zpl_rect2 {
zpl_vec2 pos , dim ;
} zpl_rect2 ;
typedef struct zpl_rect3 {
zpl_vec3 pos , dim ;
} zpl_rect3 ;
typedef struct zpl_aabb2 {
zpl_vec2 min , max ;
} zpl_aabb2 ;
typedef struct zpl_aabb3 {
zpl_vec3 min , max ;
} zpl_aabb3 ;
typedef short zpl_half ;
# ifndef ZPL_CONSTANTS
# define ZPL_CONSTANTS
# define ZPL_EPSILON 1.19209290e-7f
# define ZPL_ZERO 0.0f
# define ZPL_ONE 1.0f
# define ZPL_TWO_THIRDS 0.666666666666666666666666666666666666667f
# define ZPL_TAU 6.28318530717958647692528676655900576f
# define ZPL_PI 3.14159265358979323846264338327950288f
# define ZPL_ONE_OVER_TAU 0.636619772367581343075535053490057448f
# define ZPL_ONE_OVER_PI 0.159154943091895335768883763372514362f
# define ZPL_TAU_OVER_2 3.14159265358979323846264338327950288f
# define ZPL_TAU_OVER_4 1.570796326794896619231321691639751442f
# define ZPL_TAU_OVER_8 0.785398163397448309615660845819875721f
# define ZPL_E 2.71828182845904523536f
# define ZPL_SQRT_TWO 1.41421356237309504880168872420969808f
# define ZPL_SQRT_THREE 1.73205080756887729352744634150587236f
# define ZPL_SQRT_FIVE 2.23606797749978969640917366873127623f
# define ZPL_LOG_TWO 0.693147180559945309417232121458176568f
# define ZPL_LOG_TEN 2.30258509299404568401799145468436421f
# endif // ZPL_CONSTANTS
# ifndef zpl_square
# define zpl_square(x) ((x) * (x))
# endif
# ifndef zpl_cube
# define zpl_cube(x) ((x) * (x) * (x))
# endif
# ifndef zpl_sign
# define zpl_sign(x) ((x) >= 0.0f ? 1.0f : -1.0f)
# endif
# ifndef zpl_sign0
# define zpl_sign0(x) ((x == 0.0f) ? 0.0f : ((x) >= 0.0f ? 1.0f : -1.0f))
# endif
ZPL_DEF zpl_f32 zpl_to_radians ( zpl_f32 degrees ) ;
ZPL_DEF zpl_f32 zpl_to_degrees ( zpl_f32 radians ) ;
/* NOTE: Because to interpolate angles */
ZPL_DEF zpl_f32 zpl_angle_diff ( zpl_f32 radians_a , zpl_f32 radians_b ) ;
ZPL_DEF zpl_f32 zpl_copy_sign ( zpl_f32 x , zpl_f32 y ) ;
ZPL_DEF zpl_f32 zpl_remainder ( zpl_f32 x , zpl_f32 y ) ;
ZPL_DEF zpl_f32 zpl_mod ( zpl_f32 x , zpl_f32 y ) ;
ZPL_DEF zpl_f64 zpl_copy_sign64 ( zpl_f64 x , zpl_f64 y ) ;
ZPL_DEF zpl_f64 zpl_floor64 ( zpl_f64 x ) ;
ZPL_DEF zpl_f64 zpl_ceil64 ( zpl_f64 x ) ;
ZPL_DEF zpl_f64 zpl_round64 ( zpl_f64 x ) ;
ZPL_DEF zpl_f64 zpl_remainder64 ( zpl_f64 x , zpl_f64 y ) ;
ZPL_DEF zpl_f64 zpl_abs64 ( zpl_f64 x ) ;
ZPL_DEF zpl_f64 zpl_sign64 ( zpl_f64 x ) ;
ZPL_DEF zpl_f64 zpl_mod64 ( zpl_f64 x , zpl_f64 y ) ;
ZPL_DEF zpl_f32 zpl_sqrt ( zpl_f32 a ) ;
ZPL_DEF zpl_f32 zpl_rsqrt ( zpl_f32 a ) ;
ZPL_DEF zpl_f32 zpl_quake_rsqrt ( zpl_f32 a ) ; /* NOTE: It's probably better to use 1.0f/zpl_sqrt(a)
* And for simd , there is usually isqrt functions too !
*/
ZPL_DEF zpl_f32 zpl_sin ( zpl_f32 radians ) ;
ZPL_DEF zpl_f32 zpl_cos ( zpl_f32 radians ) ;
ZPL_DEF zpl_f32 zpl_tan ( zpl_f32 radians ) ;
ZPL_DEF zpl_f32 zpl_arcsin ( zpl_f32 a ) ;
ZPL_DEF zpl_f32 zpl_arccos ( zpl_f32 a ) ;
ZPL_DEF zpl_f32 zpl_arctan ( zpl_f32 a ) ;
ZPL_DEF zpl_f32 zpl_arctan2 ( zpl_f32 y , zpl_f32 x ) ;
ZPL_DEF zpl_f32 zpl_exp ( zpl_f32 x ) ;
ZPL_DEF zpl_f32 zpl_exp2 ( zpl_f32 x ) ;
ZPL_DEF zpl_f32 zpl_log ( zpl_f32 x ) ;
ZPL_DEF zpl_f32 zpl_log2 ( zpl_f32 x ) ;
ZPL_DEF zpl_f32 zpl_fast_exp ( zpl_f32 x ) ; /* NOTE: Only valid from -1 <= x <= +1 */
ZPL_DEF zpl_f32 zpl_fast_exp2 ( zpl_f32 x ) ; /* NOTE: Only valid from -1 <= x <= +1 */
ZPL_DEF zpl_f32 zpl_pow ( zpl_f32 x , zpl_f32 y ) ; /* x^y */
ZPL_DEF zpl_f32 zpl_round ( zpl_f32 x ) ;
ZPL_DEF zpl_f32 zpl_floor ( zpl_f32 x ) ;
ZPL_DEF zpl_f32 zpl_ceil ( zpl_f32 x ) ;
ZPL_DEF zpl_f32 zpl_half_to_float ( zpl_half value ) ;
ZPL_DEF zpl_half zpl_float_to_half ( zpl_f32 value ) ;
ZPL_DEF zpl_vec2 zpl_vec2f_zero ( void ) ;
ZPL_DEF zpl_vec2 zpl_vec2f ( zpl_f32 x , zpl_f32 y ) ;
ZPL_DEF zpl_vec2 zpl_vec2fv ( zpl_f32 x [ 2 ] ) ;
ZPL_DEF zpl_vec3 zpl_vec3f_zero ( void ) ;
ZPL_DEF zpl_vec3 zpl_vec3f ( zpl_f32 x , zpl_f32 y , zpl_f32 z ) ;
ZPL_DEF zpl_vec3 zpl_vec3fv ( zpl_f32 x [ 3 ] ) ;
ZPL_DEF zpl_vec4 zpl_vec4f_zero ( void ) ;
ZPL_DEF zpl_vec4 zpl_vec4f ( zpl_f32 x , zpl_f32 y , zpl_f32 z , zpl_f32 w ) ;
ZPL_DEF zpl_vec4 zpl_vec4fv ( zpl_f32 x [ 4 ] ) ;
ZPL_DEF zpl_f32 zpl_vec2_max ( zpl_vec2 v ) ;
ZPL_DEF zpl_f32 zpl_vec2_side ( zpl_vec2 p , zpl_vec2 q , zpl_vec2 r ) ;
ZPL_DEF void zpl_vec2_add ( zpl_vec2 * d , zpl_vec2 v0 , zpl_vec2 v1 ) ;
ZPL_DEF void zpl_vec2_sub ( zpl_vec2 * d , zpl_vec2 v0 , zpl_vec2 v1 ) ;
ZPL_DEF void zpl_vec2_mul ( zpl_vec2 * d , zpl_vec2 v , zpl_f32 s ) ;
ZPL_DEF void zpl_vec2_div ( zpl_vec2 * d , zpl_vec2 v , zpl_f32 s ) ;
ZPL_DEF zpl_f32 zpl_vec3_max ( zpl_vec3 v ) ;
ZPL_DEF void zpl_vec3_add ( zpl_vec3 * d , zpl_vec3 v0 , zpl_vec3 v1 ) ;
ZPL_DEF void zpl_vec3_sub ( zpl_vec3 * d , zpl_vec3 v0 , zpl_vec3 v1 ) ;
ZPL_DEF void zpl_vec3_mul ( zpl_vec3 * d , zpl_vec3 v , zpl_f32 s ) ;
ZPL_DEF void zpl_vec3_div ( zpl_vec3 * d , zpl_vec3 v , zpl_f32 s ) ;
ZPL_DEF void zpl_vec4_add ( zpl_vec4 * d , zpl_vec4 v0 , zpl_vec4 v1 ) ;
ZPL_DEF void zpl_vec4_sub ( zpl_vec4 * d , zpl_vec4 v0 , zpl_vec4 v1 ) ;
ZPL_DEF void zpl_vec4_mul ( zpl_vec4 * d , zpl_vec4 v , zpl_f32 s ) ;
ZPL_DEF void zpl_vec4_div ( zpl_vec4 * d , zpl_vec4 v , zpl_f32 s ) ;
ZPL_DEF void zpl_vec2_addeq ( zpl_vec2 * d , zpl_vec2 v ) ;
ZPL_DEF void zpl_vec2_subeq ( zpl_vec2 * d , zpl_vec2 v ) ;
ZPL_DEF void zpl_vec2_muleq ( zpl_vec2 * d , zpl_f32 s ) ;
ZPL_DEF void zpl_vec2_diveq ( zpl_vec2 * d , zpl_f32 s ) ;
ZPL_DEF void zpl_vec3_addeq ( zpl_vec3 * d , zpl_vec3 v ) ;
ZPL_DEF void zpl_vec3_subeq ( zpl_vec3 * d , zpl_vec3 v ) ;
ZPL_DEF void zpl_vec3_muleq ( zpl_vec3 * d , zpl_f32 s ) ;
ZPL_DEF void zpl_vec3_diveq ( zpl_vec3 * d , zpl_f32 s ) ;
ZPL_DEF void zpl_vec4_addeq ( zpl_vec4 * d , zpl_vec4 v ) ;
ZPL_DEF void zpl_vec4_subeq ( zpl_vec4 * d , zpl_vec4 v ) ;
ZPL_DEF void zpl_vec4_muleq ( zpl_vec4 * d , zpl_f32 s ) ;
ZPL_DEF void zpl_vec4_diveq ( zpl_vec4 * d , zpl_f32 s ) ;
ZPL_DEF zpl_f32 zpl_vec2_dot ( zpl_vec2 v0 , zpl_vec2 v1 ) ;
ZPL_DEF zpl_f32 zpl_vec3_dot ( zpl_vec3 v0 , zpl_vec3 v1 ) ;
ZPL_DEF zpl_f32 zpl_vec4_dot ( zpl_vec4 v0 , zpl_vec4 v1 ) ;
ZPL_DEF void zpl_vec2_cross ( zpl_f32 * d , zpl_vec2 v0 , zpl_vec2 v1 ) ;
ZPL_DEF void zpl_vec3_cross ( zpl_vec3 * d , zpl_vec3 v0 , zpl_vec3 v1 ) ;
ZPL_DEF zpl_f32 zpl_vec2_mag2 ( zpl_vec2 v ) ;
ZPL_DEF zpl_f32 zpl_vec3_mag2 ( zpl_vec3 v ) ;
ZPL_DEF zpl_f32 zpl_vec4_mag2 ( zpl_vec4 v ) ;
ZPL_DEF zpl_f32 zpl_vec2_mag ( zpl_vec2 v ) ;
ZPL_DEF zpl_f32 zpl_vec3_mag ( zpl_vec3 v ) ;
ZPL_DEF zpl_f32 zpl_vec4_mag ( zpl_vec4 v ) ;
ZPL_DEF void zpl_vec2_norm ( zpl_vec2 * d , zpl_vec2 v ) ;
ZPL_DEF void zpl_vec3_norm ( zpl_vec3 * d , zpl_vec3 v ) ;
ZPL_DEF void zpl_vec4_norm ( zpl_vec4 * d , zpl_vec4 v ) ;
ZPL_DEF void zpl_vec2_norm0 ( zpl_vec2 * d , zpl_vec2 v ) ;
ZPL_DEF void zpl_vec3_norm0 ( zpl_vec3 * d , zpl_vec3 v ) ;
ZPL_DEF void zpl_vec4_norm0 ( zpl_vec4 * d , zpl_vec4 v ) ;
ZPL_DEF void zpl_vec2_reflect ( zpl_vec2 * d , zpl_vec2 i , zpl_vec2 n ) ;
ZPL_DEF void zpl_vec3_reflect ( zpl_vec3 * d , zpl_vec3 i , zpl_vec3 n ) ;
ZPL_DEF void zpl_vec2_refract ( zpl_vec2 * d , zpl_vec2 i , zpl_vec2 n , zpl_f32 eta ) ;
ZPL_DEF void zpl_vec3_refract ( zpl_vec3 * d , zpl_vec3 i , zpl_vec3 n , zpl_f32 eta ) ;
ZPL_DEF zpl_f32 zpl_vec2_aspect_ratio ( zpl_vec2 v ) ;
ZPL_DEF void zpl_mat2_identity ( zpl_mat2 * m ) ;
ZPL_DEF void zpl_float22_identity ( zpl_f32 m [ 2 ] [ 2 ] ) ;
ZPL_DEF void zpl_mat2_transpose ( zpl_mat2 * m ) ;
ZPL_DEF void zpl_mat2_mul ( zpl_mat2 * out , zpl_mat2 * m1 , zpl_mat2 * m2 ) ;
ZPL_DEF void zpl_mat2_mul_vec2 ( zpl_vec2 * out , zpl_mat2 * m , zpl_vec2 in ) ;
ZPL_DEF void zpl_mat2_inverse ( zpl_mat2 * out , zpl_mat2 * in ) ;
ZPL_DEF zpl_f32 zpl_mat2_determinate ( zpl_mat2 * m ) ;
ZPL_DEF zpl_mat2 * zpl_mat2_v ( zpl_vec2 m [ 2 ] ) ;
ZPL_DEF zpl_mat2 * zpl_mat2_f ( zpl_f32 m [ 2 ] [ 2 ] ) ;
ZPL_DEF zpl_float2 * zpl_float22_m ( zpl_mat2 * m ) ;
ZPL_DEF zpl_float2 * zpl_float22_v ( zpl_vec2 m [ 2 ] ) ;
ZPL_DEF zpl_float2 * zpl_float22_4 ( zpl_f32 m [ 4 ] ) ;
ZPL_DEF void zpl_float22_transpose ( zpl_f32 ( * vec ) [ 2 ] ) ;
ZPL_DEF void zpl_float22_mul ( zpl_f32 ( * out ) [ 2 ] , zpl_f32 ( * mat1 ) [ 2 ] , zpl_f32 ( * mat2 ) [ 2 ] ) ;
ZPL_DEF void zpl_float22_mul_vec2 ( zpl_vec2 * out , zpl_f32 m [ 2 ] [ 2 ] , zpl_vec2 in ) ;
ZPL_DEF void zpl_mat3_identity ( zpl_mat3 * m ) ;
ZPL_DEF void zpl_float33_identity ( zpl_f32 m [ 3 ] [ 3 ] ) ;
ZPL_DEF void zpl_mat3_transpose ( zpl_mat3 * m ) ;
ZPL_DEF void zpl_mat3_mul ( zpl_mat3 * out , zpl_mat3 * m1 , zpl_mat3 * m2 ) ;
ZPL_DEF void zpl_mat3_mul_vec3 ( zpl_vec3 * out , zpl_mat3 * m , zpl_vec3 in ) ;
ZPL_DEF void zpl_mat3_inverse ( zpl_mat3 * out , zpl_mat3 * in ) ;
ZPL_DEF zpl_f32 zpl_mat3_determinate ( zpl_mat3 * m ) ;
ZPL_DEF zpl_mat3 * zpl_mat3_v ( zpl_vec3 m [ 3 ] ) ;
ZPL_DEF zpl_mat3 * zpl_mat3_f ( zpl_f32 m [ 3 ] [ 3 ] ) ;
ZPL_DEF zpl_float3 * zpl_float33_m ( zpl_mat3 * m ) ;
ZPL_DEF zpl_float3 * zpl_float33_v ( zpl_vec3 m [ 3 ] ) ;
ZPL_DEF zpl_float3 * zpl_float33_9 ( zpl_f32 m [ 9 ] ) ;
ZPL_DEF void zpl_float33_transpose ( zpl_f32 ( * vec ) [ 3 ] ) ;
ZPL_DEF void zpl_float33_mul ( zpl_f32 ( * out ) [ 3 ] , zpl_f32 ( * mat1 ) [ 3 ] , zpl_f32 ( * mat2 ) [ 3 ] ) ;
ZPL_DEF void zpl_float33_mul_vec3 ( zpl_vec3 * out , zpl_f32 m [ 3 ] [ 3 ] , zpl_vec3 in ) ;
ZPL_DEF void zpl_mat4_identity ( zpl_mat4 * m ) ;
ZPL_DEF void zpl_float44_identity ( zpl_f32 m [ 4 ] [ 4 ] ) ;
ZPL_DEF void zpl_mat4_copy ( zpl_mat4 * out , zpl_mat4 * m ) ;
ZPL_DEF void zpl_mat4_transpose ( zpl_mat4 * m ) ;
ZPL_DEF void zpl_mat4_mul ( zpl_mat4 * out , zpl_mat4 * m1 , zpl_mat4 * m2 ) ;
ZPL_DEF void zpl_mat4_mul_vec4 ( zpl_vec4 * out , zpl_mat4 * m , zpl_vec4 in ) ;
ZPL_DEF void zpl_mat4_inverse ( zpl_mat4 * out , zpl_mat4 * in ) ;
ZPL_DEF zpl_mat4 * zpl_mat4_v ( zpl_vec4 m [ 4 ] ) ;
ZPL_DEF zpl_mat4 * zpl_mat4_f ( zpl_f32 m [ 4 ] [ 4 ] ) ;
ZPL_DEF zpl_float4 * zpl_float44_m ( zpl_mat4 * m ) ;
ZPL_DEF zpl_float4 * zpl_float44_v ( zpl_vec4 m [ 4 ] ) ;
ZPL_DEF zpl_float4 * zpl_float44_16 ( zpl_f32 m [ 16 ] ) ;
ZPL_DEF void zpl_float44_transpose ( zpl_f32 ( * vec ) [ 4 ] ) ;
ZPL_DEF void zpl_float44_mul ( zpl_f32 ( * out ) [ 4 ] , zpl_f32 ( * mat1 ) [ 4 ] , zpl_f32 ( * mat2 ) [ 4 ] ) ;
ZPL_DEF void zpl_float44_mul_vec4 ( zpl_vec4 * out , zpl_f32 m [ 4 ] [ 4 ] , zpl_vec4 in ) ;
ZPL_DEF void zpl_mat4_axis_angle ( zpl_mat4 * out , zpl_vec3 v , zpl_f32 angle_radians ) ;
ZPL_DEF void zpl_mat4_to_translate ( zpl_mat4 * out , zpl_vec3 v ) ;
ZPL_DEF void zpl_mat4_to_rotate ( zpl_mat4 * out , zpl_vec3 v , zpl_f32 angle_radians ) ;
ZPL_DEF void zpl_mat4_to_scale ( zpl_mat4 * out , zpl_vec3 v ) ;
ZPL_DEF void zpl_mat4_to_scalef ( zpl_mat4 * out , zpl_f32 s ) ;
ZPL_DEF void zpl_mat4_translate ( zpl_mat4 * out , zpl_vec3 v ) ;
ZPL_DEF void zpl_mat4_rotate ( zpl_mat4 * out , zpl_vec3 v , zpl_f32 angle_radians ) ;
ZPL_DEF void zpl_mat4_scale ( zpl_mat4 * out , zpl_vec3 v ) ;
ZPL_DEF void zpl_mat4_scalef ( zpl_mat4 * out , zpl_f32 s ) ;
ZPL_DEF void zpl_mat4_ortho2d ( zpl_mat4 * out , zpl_f32 left , zpl_f32 right , zpl_f32 bottom , zpl_f32 top ) ;
ZPL_DEF void zpl_mat4_ortho3d ( zpl_mat4 * out , zpl_f32 left , zpl_f32 right , zpl_f32 bottom , zpl_f32 top , zpl_f32 z_near , zpl_f32 z_far ) ;
ZPL_DEF void zpl_mat4_perspective ( zpl_mat4 * out , zpl_f32 fovy , zpl_f32 aspect , zpl_f32 z_near , zpl_f32 z_far ) ;
ZPL_DEF void zpl_mat4_infinite_perspective ( zpl_mat4 * out , zpl_f32 fovy , zpl_f32 aspect , zpl_f32 z_near ) ;
ZPL_DEF void zpl_mat4_ortho2d_dx ( zpl_mat4 * out , zpl_f32 left , zpl_f32 right , zpl_f32 bottom , zpl_f32 top ) ;
ZPL_DEF void zpl_mat4_ortho3d_dx ( zpl_mat4 * out , zpl_f32 left , zpl_f32 right , zpl_f32 bottom , zpl_f32 top , zpl_f32 z_near , zpl_f32 z_far ) ;
ZPL_DEF void zpl_mat4_perspective_dx ( zpl_mat4 * out , zpl_f32 fovy , zpl_f32 aspect , zpl_f32 z_near , zpl_f32 z_far ) ;
ZPL_DEF void zpl_mat4_infinite_perspective_dx ( zpl_mat4 * out , zpl_f32 fovy , zpl_f32 aspect , zpl_f32 z_near ) ;
ZPL_DEF void zpl_mat4_look_at ( zpl_mat4 * out , zpl_vec3 eye , zpl_vec3 centre , zpl_vec3 up ) ;
ZPL_DEF void zpl_mat4_look_at_lh ( zpl_mat4 * out , zpl_vec3 eye , zpl_vec3 centre , zpl_vec3 up ) ;
ZPL_DEF zpl_quat zpl_quatf ( zpl_f32 x , zpl_f32 y , zpl_f32 z , zpl_f32 w ) ;
ZPL_DEF zpl_quat zpl_quatfv ( zpl_f32 e [ 4 ] ) ;
ZPL_DEF zpl_quat zpl_quat_axis_angle ( zpl_vec3 axis , zpl_f32 angle_radians ) ;
ZPL_DEF zpl_quat zpl_quat_euler_angles ( zpl_f32 pitch , zpl_f32 yaw , zpl_f32 roll ) ;
ZPL_DEF zpl_quat zpl_quat_identity ( void ) ;
ZPL_DEF void zpl_quat_add ( zpl_quat * d , zpl_quat q0 , zpl_quat q1 ) ;
ZPL_DEF void zpl_quat_sub ( zpl_quat * d , zpl_quat q0 , zpl_quat q1 ) ;
ZPL_DEF void zpl_quat_mul ( zpl_quat * d , zpl_quat q0 , zpl_quat q1 ) ;
ZPL_DEF void zpl_quat_div ( zpl_quat * d , zpl_quat q0 , zpl_quat q1 ) ;
ZPL_DEF void zpl_quat_mulf ( zpl_quat * d , zpl_quat q , zpl_f32 s ) ;
ZPL_DEF void zpl_quat_divf ( zpl_quat * d , zpl_quat q , zpl_f32 s ) ;
ZPL_DEF void zpl_quat_addeq ( zpl_quat * d , zpl_quat q ) ;
ZPL_DEF void zpl_quat_subeq ( zpl_quat * d , zpl_quat q ) ;
ZPL_DEF void zpl_quat_muleq ( zpl_quat * d , zpl_quat q ) ;
ZPL_DEF void zpl_quat_diveq ( zpl_quat * d , zpl_quat q ) ;
ZPL_DEF void zpl_quat_muleqf ( zpl_quat * d , zpl_f32 s ) ;
ZPL_DEF void zpl_quat_diveqf ( zpl_quat * d , zpl_f32 s ) ;
ZPL_DEF zpl_f32 zpl_quat_dot ( zpl_quat q0 , zpl_quat q1 ) ;
ZPL_DEF zpl_f32 zpl_quat_mag ( zpl_quat q ) ;
ZPL_DEF void zpl_quat_norm ( zpl_quat * d , zpl_quat q ) ;
ZPL_DEF void zpl_quat_conj ( zpl_quat * d , zpl_quat q ) ;
ZPL_DEF void zpl_quat_inverse ( zpl_quat * d , zpl_quat q ) ;
ZPL_DEF void zpl_quat_axis ( zpl_vec3 * axis , zpl_quat q ) ;
ZPL_DEF zpl_f32 zpl_quat_angle ( zpl_quat q ) ;
ZPL_DEF zpl_f32 zpl_quat_pitch ( zpl_quat q ) ;
ZPL_DEF zpl_f32 zpl_quat_yaw ( zpl_quat q ) ;
ZPL_DEF zpl_f32 zpl_quat_roll ( zpl_quat q ) ;
/* NOTE: Rotate v by q */
ZPL_DEF void zpl_quat_rotate_vec3 ( zpl_vec3 * d , zpl_quat q , zpl_vec3 v ) ;
ZPL_DEF void zpl_mat4_from_quat ( zpl_mat4 * out , zpl_quat q ) ;
ZPL_DEF void zpl_quat_from_mat4 ( zpl_quat * out , zpl_mat4 * m ) ;
/* Plane math. */
ZPL_DEF zpl_f32 zpl_plane_distance ( zpl_plane * p , zpl_vec3 v ) ;
/* Frustum culling. */
ZPL_DEF void zpl_frustum_create ( zpl_frustum * out , zpl_mat4 * camera , zpl_mat4 * proj ) ;
ZPL_DEF zpl_b8 zpl_frustum_sphere_inside ( zpl_frustum * frustum , zpl_vec3 center , zpl_f32 radius ) ;
ZPL_DEF zpl_b8 zpl_frustum_point_inside ( zpl_frustum * frustum , zpl_vec3 point ) ;
ZPL_DEF zpl_b8 zpl_frustum_box_inside ( zpl_frustum * frustum , zpl_aabb3 box ) ;
/* Interpolations */
ZPL_DEF zpl_f32 zpl_lerp ( zpl_f32 a , zpl_f32 b , zpl_f32 t ) ;
ZPL_DEF zpl_f32 zpl_unlerp ( zpl_f32 t , zpl_f32 a , zpl_f32 b ) ;
ZPL_DEF zpl_f32 zpl_smooth_step ( zpl_f32 a , zpl_f32 b , zpl_f32 t ) ;
ZPL_DEF zpl_f32 zpl_smoother_step ( zpl_f32 a , zpl_f32 b , zpl_f32 t ) ;
ZPL_DEF void zpl_vec2_lerp ( zpl_vec2 * d , zpl_vec2 a , zpl_vec2 b , zpl_f32 t ) ;
ZPL_DEF void zpl_vec3_lerp ( zpl_vec3 * d , zpl_vec3 a , zpl_vec3 b , zpl_f32 t ) ;
ZPL_DEF void zpl_vec4_lerp ( zpl_vec4 * d , zpl_vec4 a , zpl_vec4 b , zpl_f32 t ) ;
ZPL_DEF void zpl_vec2_cslerp ( zpl_vec2 * d , zpl_vec2 a , zpl_vec2 v0 , zpl_vec2 b , zpl_vec2 v1 , zpl_f32 t ) ;
ZPL_DEF void zpl_vec3_cslerp ( zpl_vec3 * d , zpl_vec3 a , zpl_vec3 v0 , zpl_vec3 b , zpl_vec3 v1 , zpl_f32 t ) ;
ZPL_DEF void zpl_vec2_dcslerp ( zpl_vec2 * d , zpl_vec2 a , zpl_vec2 v0 , zpl_vec2 b , zpl_vec2 v1 , zpl_f32 t ) ;
ZPL_DEF void zpl_vec3_dcslerp ( zpl_vec3 * d , zpl_vec3 a , zpl_vec3 v0 , zpl_vec3 b , zpl_vec3 v1 , zpl_f32 t ) ;
ZPL_DEF void zpl_quat_lerp ( zpl_quat * d , zpl_quat a , zpl_quat b , zpl_f32 t ) ;
ZPL_DEF void zpl_quat_nlerp ( zpl_quat * d , zpl_quat a , zpl_quat b , zpl_f32 t ) ;
ZPL_DEF void zpl_quat_slerp ( zpl_quat * d , zpl_quat a , zpl_quat b , zpl_f32 t ) ;
ZPL_DEF void zpl_quat_nquad ( zpl_quat * d , zpl_quat p , zpl_quat a , zpl_quat b , zpl_quat q , zpl_f32 t ) ;
ZPL_DEF void zpl_quat_squad ( zpl_quat * d , zpl_quat p , zpl_quat a , zpl_quat b , zpl_quat q , zpl_f32 t ) ;
ZPL_DEF void zpl_quat_slerp_approx ( zpl_quat * d , zpl_quat a , zpl_quat b , zpl_f32 t ) ;
ZPL_DEF void zpl_quat_squad_approx ( zpl_quat * d , zpl_quat p , zpl_quat a , zpl_quat b , zpl_quat q , zpl_f32 t ) ;
/* rects */
ZPL_DEF zpl_rect2 zpl_rect2f ( zpl_vec2 pos , zpl_vec2 dim ) ;
ZPL_DEF zpl_rect3 zpl_rect3f ( zpl_vec3 pos , zpl_vec3 dim ) ;
ZPL_DEF zpl_aabb2 zpl_aabb2f ( zpl_f32 minx , zpl_f32 miny , zpl_f32 maxx , zpl_f32 maxy ) ;
ZPL_DEF zpl_aabb3 zpl_aabb3f ( zpl_f32 minx , zpl_f32 miny , zpl_f32 minz , zpl_f32 maxx , zpl_f32 maxy , zpl_f32 maxz ) ;
ZPL_DEF zpl_aabb2 zpl_aabb2_rect2 ( zpl_rect2 a ) ;
ZPL_DEF zpl_aabb3 zpl_aabb3_rect3 ( zpl_rect3 a ) ;
ZPL_DEF zpl_rect2 zpl_rect2_aabb2 ( zpl_aabb2 a ) ;
ZPL_DEF zpl_rect3 zpl_rect3_aabb3 ( zpl_aabb3 a ) ;
ZPL_DEF int zpl_rect2_contains ( zpl_rect2 a , zpl_f32 x , zpl_f32 y ) ;
ZPL_DEF int zpl_rect2_contains_vec2 ( zpl_rect2 a , zpl_vec2 p ) ;
ZPL_DEF int zpl_rect2_intersects ( zpl_rect2 a , zpl_rect2 b ) ;
ZPL_DEF int zpl_rect2_intersection_result ( zpl_rect2 a , zpl_rect2 b , zpl_rect2 * intersection ) ;
ZPL_DEF int zpl_aabb2_contains ( zpl_aabb2 a , zpl_f32 x , zpl_f32 y ) ;
ZPL_DEF int zpl_aabb3_contains ( zpl_aabb3 a , zpl_f32 x , zpl_f32 y , zpl_f32 z ) ;
/* rectangle partitioning: based on https://halt.software/dead-simple-layouts/ */
ZPL_DEF zpl_aabb2 zpl_aabb2_cut_left ( zpl_aabb2 * a , zpl_f32 b ) ;
ZPL_DEF zpl_aabb2 zpl_aabb2_cut_right ( zpl_aabb2 * a , zpl_f32 b ) ;
ZPL_DEF zpl_aabb2 zpl_aabb2_cut_top ( zpl_aabb2 * a , zpl_f32 b ) ;
ZPL_DEF zpl_aabb2 zpl_aabb2_cut_bottom ( zpl_aabb2 * a , zpl_f32 b ) ;
ZPL_DEF zpl_aabb2 zpl_aabb2_get_left ( const zpl_aabb2 * a , zpl_f32 b ) ;
ZPL_DEF zpl_aabb2 zpl_aabb2_get_right ( const zpl_aabb2 * a , zpl_f32 b ) ;
ZPL_DEF zpl_aabb2 zpl_aabb2_get_top ( const zpl_aabb2 * a , zpl_f32 b ) ;
ZPL_DEF zpl_aabb2 zpl_aabb2_get_bottom ( const zpl_aabb2 * a , zpl_f32 b ) ;
ZPL_DEF zpl_aabb2 zpl_aabb2_add_left ( const zpl_aabb2 * a , zpl_f32 b ) ;
ZPL_DEF zpl_aabb2 zpl_aabb2_add_right ( const zpl_aabb2 * a , zpl_f32 b ) ;
ZPL_DEF zpl_aabb2 zpl_aabb2_add_top ( const zpl_aabb2 * a , zpl_f32 b ) ;
ZPL_DEF zpl_aabb2 zpl_aabb2_add_bottom ( const zpl_aabb2 * a , zpl_f32 b ) ;
ZPL_DEF zpl_aabb2 zpl_aabb2_contract ( const zpl_aabb2 * a , zpl_f32 b ) ;
ZPL_DEF zpl_aabb2 zpl_aabb2_expand ( const zpl_aabb2 * a , zpl_f32 b ) ;
//! @}
ZPL_END_C_DECLS
# if defined(__cplusplus)
ZPL_INLINE bool operator = = ( zpl_vec2 a , zpl_vec2 b ) { return ( a . x = = b . x ) & & ( a . y = = b . y ) ; }
ZPL_INLINE bool operator ! = ( zpl_vec2 a , zpl_vec2 b ) { return ! operator = = ( a , b ) ; }
ZPL_INLINE zpl_vec2 operator + ( zpl_vec2 a ) { return a ; }
ZPL_INLINE zpl_vec2 operator - ( zpl_vec2 a ) { zpl_vec2 r = { - a . x , - a . y } ; return r ; }
ZPL_INLINE zpl_vec2 operator + ( zpl_vec2 a , zpl_vec2 b ) { zpl_vec2 r ; zpl_vec2_add ( & r , a , b ) ; return r ; }
ZPL_INLINE zpl_vec2 operator - ( zpl_vec2 a , zpl_vec2 b ) { zpl_vec2 r ; zpl_vec2_sub ( & r , a , b ) ; return r ; }
ZPL_INLINE zpl_vec2 operator * ( zpl_vec2 a , float scalar ) { zpl_vec2 r ; zpl_vec2_mul ( & r , a , scalar ) ; return r ; }
ZPL_INLINE zpl_vec2 operator * ( float scalar , zpl_vec2 a ) { return operator * ( a , scalar ) ; }
ZPL_INLINE zpl_vec2 operator / ( zpl_vec2 a , float scalar ) { return operator * ( a , 1.0f / scalar ) ; }
/* Hadamard Product */
ZPL_INLINE zpl_vec2 operator * ( zpl_vec2 a , zpl_vec2 b ) { zpl_vec2 r = { a . x * b . x , a . y * b . y } ; return r ; }
ZPL_INLINE zpl_vec2 operator / ( zpl_vec2 a , zpl_vec2 b ) { zpl_vec2 r = { a . x / b . x , a . y / b . y } ; return r ; }
ZPL_INLINE zpl_vec2 & operator + = ( zpl_vec2 & a , zpl_vec2 b ) { return ( a = a + b ) ; }
ZPL_INLINE zpl_vec2 & operator - = ( zpl_vec2 & a , zpl_vec2 b ) { return ( a = a - b ) ; }
ZPL_INLINE zpl_vec2 & operator * = ( zpl_vec2 & a , float scalar ) { return ( a = a * scalar ) ; }
ZPL_INLINE zpl_vec2 & operator / = ( zpl_vec2 & a , float scalar ) { return ( a = a / scalar ) ; }
ZPL_INLINE bool operator = = ( zpl_vec3 a , zpl_vec3 b ) { return ( a . x = = b . x ) & & ( a . y = = b . y ) & & ( a . z = = b . z ) ; }
ZPL_INLINE bool operator ! = ( zpl_vec3 a , zpl_vec3 b ) { return ! operator = = ( a , b ) ; }
ZPL_INLINE zpl_vec3 operator + ( zpl_vec3 a ) { return a ; }
ZPL_INLINE zpl_vec3 operator - ( zpl_vec3 a ) { zpl_vec3 r = { - a . x , - a . y , - a . z } ; return r ; }
ZPL_INLINE zpl_vec3 operator + ( zpl_vec3 a , zpl_vec3 b ) { zpl_vec3 r ; zpl_vec3_add ( & r , a , b ) ; return r ; }
ZPL_INLINE zpl_vec3 operator - ( zpl_vec3 a , zpl_vec3 b ) { zpl_vec3 r ; zpl_vec3_sub ( & r , a , b ) ; return r ; }
ZPL_INLINE zpl_vec3 operator * ( zpl_vec3 a , float scalar ) { zpl_vec3 r ; zpl_vec3_mul ( & r , a , scalar ) ; return r ; }
ZPL_INLINE zpl_vec3 operator * ( float scalar , zpl_vec3 a ) { return operator * ( a , scalar ) ; }
ZPL_INLINE zpl_vec3 operator / ( zpl_vec3 a , float scalar ) { return operator * ( a , 1.0f / scalar ) ; }
/* Hadamard Product */
ZPL_INLINE zpl_vec3 operator * ( zpl_vec3 a , zpl_vec3 b ) { zpl_vec3 r = { a . x * b . x , a . y * b . y , a . z * b . z } ; return r ; }
ZPL_INLINE zpl_vec3 operator / ( zpl_vec3 a , zpl_vec3 b ) { zpl_vec3 r = { a . x / b . x , a . y / b . y , a . z / b . z } ; return r ; }
ZPL_INLINE zpl_vec3 & operator + = ( zpl_vec3 & a , zpl_vec3 b ) { return ( a = a + b ) ; }
ZPL_INLINE zpl_vec3 & operator - = ( zpl_vec3 & a , zpl_vec3 b ) { return ( a = a - b ) ; }
ZPL_INLINE zpl_vec3 & operator * = ( zpl_vec3 & a , float scalar ) { return ( a = a * scalar ) ; }
ZPL_INLINE zpl_vec3 & operator / = ( zpl_vec3 & a , float scalar ) { return ( a = a / scalar ) ; }
ZPL_INLINE bool operator = = ( zpl_vec4 a , zpl_vec4 b ) { return ( a . x = = b . x ) & & ( a . y = = b . y ) & & ( a . z = = b . z ) & & ( a . w = = b . w ) ; }
ZPL_INLINE bool operator ! = ( zpl_vec4 a , zpl_vec4 b ) { return ! operator = = ( a , b ) ; }
ZPL_INLINE zpl_vec4 operator + ( zpl_vec4 a ) { return a ; }
ZPL_INLINE zpl_vec4 operator - ( zpl_vec4 a ) { zpl_vec4 r = { - a . x , - a . y , - a . z , - a . w } ; return r ; }
ZPL_INLINE zpl_vec4 operator + ( zpl_vec4 a , zpl_vec4 b ) { zpl_vec4 r ; zpl_vec4_add ( & r , a , b ) ; return r ; }
ZPL_INLINE zpl_vec4 operator - ( zpl_vec4 a , zpl_vec4 b ) { zpl_vec4 r ; zpl_vec4_sub ( & r , a , b ) ; return r ; }
ZPL_INLINE zpl_vec4 operator * ( zpl_vec4 a , float scalar ) { zpl_vec4 r ; zpl_vec4_mul ( & r , a , scalar ) ; return r ; }
ZPL_INLINE zpl_vec4 operator * ( float scalar , zpl_vec4 a ) { return operator * ( a , scalar ) ; }
ZPL_INLINE zpl_vec4 operator / ( zpl_vec4 a , float scalar ) { return operator * ( a , 1.0f / scalar ) ; }
/* Hadamard Product */
ZPL_INLINE zpl_vec4 operator * ( zpl_vec4 a , zpl_vec4 b ) { zpl_vec4 r = { a . x * b . x , a . y * b . y , a . z * b . z , a . w * b . w } ; return r ; }
ZPL_INLINE zpl_vec4 operator / ( zpl_vec4 a , zpl_vec4 b ) { zpl_vec4 r = { a . x / b . x , a . y / b . y , a . z / b . z , a . w / b . w } ; return r ; }
ZPL_INLINE zpl_vec4 & operator + = ( zpl_vec4 & a , zpl_vec4 b ) { return ( a = a + b ) ; }
ZPL_INLINE zpl_vec4 & operator - = ( zpl_vec4 & a , zpl_vec4 b ) { return ( a = a - b ) ; }
ZPL_INLINE zpl_vec4 & operator * = ( zpl_vec4 & a , float scalar ) { return ( a = a * scalar ) ; }
ZPL_INLINE zpl_vec4 & operator / = ( zpl_vec4 & a , float scalar ) { return ( a = a / scalar ) ; }
ZPL_INLINE zpl_mat2 operator + ( zpl_mat2 const & a , zpl_mat2 const & b ) {
int i , j ;
zpl_mat2 r = { 0 } ;
for ( j = 0 ; j < 2 ; j + + ) {
for ( i = 0 ; i < 2 ; i + + )
r . e [ 2 * j + i ] = a . e [ 2 * j + i ] + b . e [ 2 * j + i ] ;
}
return r ;
}
ZPL_INLINE zpl_mat2 operator - ( zpl_mat2 const & a , zpl_mat2 const & b ) {
int i , j ;
zpl_mat2 r = { 0 } ;
for ( j = 0 ; j < 2 ; j + + ) {
for ( i = 0 ; i < 2 ; i + + )
r . e [ 2 * j + i ] = a . e [ 2 * j + i ] - b . e [ 2 * j + i ] ;
}
return r ;
}
ZPL_INLINE zpl_mat2 operator * ( zpl_mat2 const & a , zpl_mat2 const & b ) { zpl_mat2 r ; zpl_mat2_mul ( & r , ( zpl_mat2 * ) & a , ( zpl_mat2 * ) & b ) ; return r ; }
ZPL_INLINE zpl_vec2 operator * ( zpl_mat2 const & a , zpl_vec2 v ) { zpl_vec2 r ; zpl_mat2_mul_vec2 ( & r , ( zpl_mat2 * ) & a , v ) ; return r ; }
ZPL_INLINE zpl_mat2 operator * ( zpl_mat2 const & a , float scalar ) {
zpl_mat2 r = { 0 } ;
int i ;
for ( i = 0 ; i < 2 * 2 ; i + + ) r . e [ i ] = a . e [ i ] * scalar ;
return r ;
}
ZPL_INLINE zpl_mat2 operator * ( float scalar , zpl_mat2 const & a ) { return operator * ( a , scalar ) ; }
ZPL_INLINE zpl_mat2 operator / ( zpl_mat2 const & a , float scalar ) { return operator * ( a , 1.0f / scalar ) ; }
ZPL_INLINE zpl_mat2 & operator + = ( zpl_mat2 & a , zpl_mat2 const & b ) { return ( a = a + b ) ; }
ZPL_INLINE zpl_mat2 & operator - = ( zpl_mat2 & a , zpl_mat2 const & b ) { return ( a = a - b ) ; }
ZPL_INLINE zpl_mat2 & operator * = ( zpl_mat2 & a , zpl_mat2 const & b ) { return ( a = a * b ) ; }
ZPL_INLINE zpl_mat3 operator + ( zpl_mat3 const & a , zpl_mat3 const & b ) {
int i , j ;
zpl_mat3 r = { 0 } ;
for ( j = 0 ; j < 3 ; j + + ) {
for ( i = 0 ; i < 3 ; i + + )
r . e [ 3 * j + i ] = a . e [ 3 * j + i ] + b . e [ 3 * j + i ] ;
}
return r ;
}
ZPL_INLINE zpl_mat3 operator - ( zpl_mat3 const & a , zpl_mat3 const & b ) {
int i , j ;
zpl_mat3 r = { 0 } ;
for ( j = 0 ; j < 3 ; j + + ) {
for ( i = 0 ; i < 3 ; i + + )
r . e [ 3 * j + i ] = a . e [ 3 * j + i ] - b . e [ 3 * j + i ] ;
}
return r ;
}
ZPL_INLINE zpl_mat3 operator * ( zpl_mat3 const & a , zpl_mat3 const & b ) { zpl_mat3 r ; zpl_mat3_mul ( & r , ( zpl_mat3 * ) & a , ( zpl_mat3 * ) & b ) ; return r ; }
ZPL_INLINE zpl_vec3 operator * ( zpl_mat3 const & a , zpl_vec3 v ) { zpl_vec3 r ; zpl_mat3_mul_vec3 ( & r , ( zpl_mat3 * ) & a , v ) ; return r ; }
ZPL_INLINE zpl_mat3 operator * ( zpl_mat3 const & a , float scalar ) {
zpl_mat3 r = { 0 } ;
int i ;
for ( i = 0 ; i < 3 * 3 ; i + + ) r . e [ i ] = a . e [ i ] * scalar ;
return r ;
}
ZPL_INLINE zpl_mat3 operator * ( float scalar , zpl_mat3 const & a ) { return operator * ( a , scalar ) ; }
ZPL_INLINE zpl_mat3 operator / ( zpl_mat3 const & a , float scalar ) { return operator * ( a , 1.0f / scalar ) ; }
ZPL_INLINE zpl_mat3 & operator + = ( zpl_mat3 & a , zpl_mat3 const & b ) { return ( a = a + b ) ; }
ZPL_INLINE zpl_mat3 & operator - = ( zpl_mat3 & a , zpl_mat3 const & b ) { return ( a = a - b ) ; }
ZPL_INLINE zpl_mat3 & operator * = ( zpl_mat3 & a , zpl_mat3 const & b ) { return ( a = a * b ) ; }
ZPL_INLINE zpl_mat4 operator + ( zpl_mat4 const & a , zpl_mat4 const & b ) {
int i , j ;
zpl_mat4 r = { 0 } ;
for ( j = 0 ; j < 4 ; j + + ) {
for ( i = 0 ; i < 4 ; i + + )
r . e [ 4 * j + i ] = a . e [ 4 * j + i ] + b . e [ 4 * j + i ] ;
}
return r ;
}
ZPL_INLINE zpl_mat4 operator - ( zpl_mat4 const & a , zpl_mat4 const & b ) {
int i , j ;
zpl_mat4 r = { 0 } ;
for ( j = 0 ; j < 4 ; j + + ) {
for ( i = 0 ; i < 4 ; i + + )
r . e [ 4 * j + i ] = a . e [ 4 * j + i ] - b . e [ 4 * j + i ] ;
}
return r ;
}
ZPL_INLINE zpl_mat4 operator * ( zpl_mat4 const & a , zpl_mat4 const & b ) { zpl_mat4 r ; zpl_mat4_mul ( & r , ( zpl_mat4 * ) & a , ( zpl_mat4 * ) & b ) ; return r ; }
ZPL_INLINE zpl_vec4 operator * ( zpl_mat4 const & a , zpl_vec4 v ) { zpl_vec4 r ; zpl_mat4_mul_vec4 ( & r , ( zpl_mat4 * ) & a , v ) ; return r ; }
ZPL_INLINE zpl_mat4 operator * ( zpl_mat4 const & a , float scalar ) {
zpl_mat4 r = { 0 } ;
int i ;
for ( i = 0 ; i < 4 * 4 ; i + + ) r . e [ i ] = a . e [ i ] * scalar ;
return r ;
}
ZPL_INLINE zpl_mat4 operator * ( float scalar , zpl_mat4 const & a ) { return operator * ( a , scalar ) ; }
ZPL_INLINE zpl_mat4 operator / ( zpl_mat4 const & a , float scalar ) { return operator * ( a , 1.0f / scalar ) ; }
ZPL_INLINE zpl_mat4 & operator + = ( zpl_mat4 & a , zpl_mat4 const & b ) { return ( a = a + b ) ; }
ZPL_INLINE zpl_mat4 & operator - = ( zpl_mat4 & a , zpl_mat4 const & b ) { return ( a = a - b ) ; }
ZPL_INLINE zpl_mat4 & operator * = ( zpl_mat4 & a , zpl_mat4 const & b ) { return ( a = a * b ) ; }
ZPL_INLINE bool operator = = ( zpl_quat a , zpl_quat b ) { return a . xyzw = = b . xyzw ; }
ZPL_INLINE bool operator ! = ( zpl_quat a , zpl_quat b ) { return ! operator = = ( a , b ) ; }
ZPL_INLINE zpl_quat operator + ( zpl_quat q ) { return q ; }
ZPL_INLINE zpl_quat operator - ( zpl_quat q ) { return zpl_quatf ( - q . x , - q . y , - q . z , - q . w ) ; }
ZPL_INLINE zpl_quat operator + ( zpl_quat a , zpl_quat b ) { zpl_quat r ; zpl_quat_add ( & r , a , b ) ; return r ; }
ZPL_INLINE zpl_quat operator - ( zpl_quat a , zpl_quat b ) { zpl_quat r ; zpl_quat_sub ( & r , a , b ) ; return r ; }
ZPL_INLINE zpl_quat operator * ( zpl_quat a , zpl_quat b ) { zpl_quat r ; zpl_quat_mul ( & r , a , b ) ; return r ; }
ZPL_INLINE zpl_quat operator * ( zpl_quat q , float s ) { zpl_quat r ; zpl_quat_mulf ( & r , q , s ) ; return r ; }
ZPL_INLINE zpl_quat operator * ( float s , zpl_quat q ) { return operator * ( q , s ) ; }
ZPL_INLINE zpl_quat operator / ( zpl_quat q , float s ) { zpl_quat r ; zpl_quat_divf ( & r , q , s ) ; return r ; }
ZPL_INLINE zpl_quat & operator + = ( zpl_quat & a , zpl_quat b ) { zpl_quat_addeq ( & a , b ) ; return a ; }
ZPL_INLINE zpl_quat & operator - = ( zpl_quat & a , zpl_quat b ) { zpl_quat_subeq ( & a , b ) ; return a ; }
ZPL_INLINE zpl_quat & operator * = ( zpl_quat & a , zpl_quat b ) { zpl_quat_muleq ( & a , b ) ; return a ; }
ZPL_INLINE zpl_quat & operator / = ( zpl_quat & a , zpl_quat b ) { zpl_quat_diveq ( & a , b ) ; return a ; }
ZPL_INLINE zpl_quat & operator * = ( zpl_quat & a , float b ) { zpl_quat_muleqf ( & a , b ) ; return a ; }
ZPL_INLINE zpl_quat & operator / = ( zpl_quat & a , float b ) { zpl_quat_diveqf ( & a , b ) ; return a ; }
/* Rotate v by a */
ZPL_INLINE zpl_vec3 operator * ( zpl_quat q , zpl_vec3 v ) { zpl_vec3 r ; zpl_quat_rotate_vec3 ( & r , q , v ) ; return r ; }
2022-09-11 17:42:06 +00:00
# endif
2021-11-29 08:23:08 +00:00
# endif
2022-09-11 17:42:06 +00:00
# if defined(ZPL_MODULE_PARSER)
// file: header/adt.h
ZPL_BEGIN_C_DECLS
typedef enum zpl_adt_type {
ZPL_ADT_TYPE_UNINITIALISED , /* node was not initialised, this is a programming error! */
ZPL_ADT_TYPE_ARRAY ,
ZPL_ADT_TYPE_OBJECT ,
ZPL_ADT_TYPE_STRING ,
ZPL_ADT_TYPE_MULTISTRING ,
ZPL_ADT_TYPE_INTEGER ,
ZPL_ADT_TYPE_REAL ,
} zpl_adt_type ;
typedef enum zpl_adt_props {
ZPL_ADT_PROPS_NONE ,
ZPL_ADT_PROPS_NAN ,
ZPL_ADT_PROPS_NAN_NEG ,
ZPL_ADT_PROPS_INFINITY ,
ZPL_ADT_PROPS_INFINITY_NEG ,
ZPL_ADT_PROPS_FALSE ,
ZPL_ADT_PROPS_TRUE ,
ZPL_ADT_PROPS_NULL ,
ZPL_ADT_PROPS_IS_EXP ,
ZPL_ADT_PROPS_IS_HEX ,
// Used internally so that people can fill in real numbers they plan to write.
ZPL_ADT_PROPS_IS_PARSED_REAL ,
} zpl_adt_props ;
typedef enum zpl_adt_naming_style {
ZPL_ADT_NAME_STYLE_DOUBLE_QUOTE ,
ZPL_ADT_NAME_STYLE_SINGLE_QUOTE ,
ZPL_ADT_NAME_STYLE_NO_QUOTES ,
} zpl_adt_naming_style ;
typedef enum zpl_adt_assign_style {
ZPL_ADT_ASSIGN_STYLE_COLON ,
ZPL_ADT_ASSIGN_STYLE_EQUALS ,
ZPL_ADT_ASSIGN_STYLE_LINE ,
} zpl_adt_assign_style ;
typedef enum zpl_adt_delim_style {
ZPL_ADT_DELIM_STYLE_COMMA ,
ZPL_ADT_DELIM_STYLE_LINE ,
ZPL_ADT_DELIM_STYLE_NEWLINE ,
} zpl_adt_delim_style ;
typedef enum zpl_adt_error {
ZPL_ADT_ERROR_NONE ,
ZPL_ADT_ERROR_INTERNAL ,
ZPL_ADT_ERROR_ALREADY_CONVERTED ,
ZPL_ADT_ERROR_INVALID_TYPE ,
} zpl_adt_error ;
typedef struct zpl_adt_node {
char const * name ;
struct zpl_adt_node * parent ;
/* properties */
zpl_u8 type : 4 ;
zpl_u8 props : 4 ;
# ifndef ZPL_PARSER_DISABLE_ANALYSIS
zpl_u8 cfg_mode : 1 ;
zpl_u8 name_style : 2 ;
zpl_u8 assign_style : 2 ;
zpl_u8 delim_style : 2 ;
zpl_u8 delim_line_width : 4 ;
zpl_u8 assign_line_width : 4 ;
# endif
/* adt data */
union {
char const * string ;
struct zpl_adt_node * nodes ; ///< zpl_array
struct {
union {
zpl_f64 real ;
zpl_i64 integer ;
} ;
# ifndef ZPL_PARSER_DISABLE_ANALYSIS
/* number analysis */
zpl_i32 base ;
zpl_i32 base2 ;
zpl_u8 base2_offset : 4 ;
zpl_i8 exp : 4 ;
zpl_u8 neg_zero : 1 ;
zpl_u8 lead_digit : 1 ;
# endif
} ;
} ;
} zpl_adt_node ;
/* 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
*/
ZPL_DEF zpl_u8 zpl_adt_make_branch ( zpl_adt_node * node , zpl_allocator backing , char const * name , zpl_b32 is_array ) ;
/**
* @ brief Destroy an ADT branch and its descendants
*
* @ param node
* @ return error code
*/
ZPL_DEF zpl_u8 zpl_adt_destroy_branch ( zpl_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
*/
ZPL_DEF zpl_u8 zpl_adt_make_leaf ( zpl_adt_node * node , char const * name , zpl_u8 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 4 th 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
*/
ZPL_DEF zpl_adt_node * zpl_adt_query ( zpl_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
*/
ZPL_DEF zpl_adt_node * zpl_adt_find ( zpl_adt_node * node , char const * name , zpl_b32 deep_search ) ;
/**
* @ brief Allocate an unitialised node within a container at a specified index .
*
* @ param parent
* @ param index
* @ return zpl_adt_node * node
*/
ZPL_DEF zpl_adt_node * zpl_adt_alloc_at ( zpl_adt_node * parent , zpl_isize index ) ;
/**
* @ brief Allocate an unitialised node within a container .
*
* @ param parent
* @ return zpl_adt_node * node
*/
ZPL_DEF zpl_adt_node * zpl_adt_alloc ( zpl_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
*/
ZPL_DEF zpl_adt_node * zpl_adt_move_node_at ( zpl_adt_node * node , zpl_adt_node * new_parent , zpl_isize index ) ;
/**
* @ brief Move an existing node to a new container .
*
* @ param node
* @ param new_parent
* @ return zpl_adt_node * node
*/
ZPL_DEF zpl_adt_node * zpl_adt_move_node ( zpl_adt_node * node , zpl_adt_node * new_parent ) ;
/**
* @ brief Swap two nodes .
*
* @ param node
* @ param other_node
* @ return
*/
ZPL_DEF void zpl_adt_swap_nodes ( zpl_adt_node * node , zpl_adt_node * other_node ) ;
/**
* @ brief Remove node from container .
*
* @ param node
* @ return
*/
ZPL_DEF void zpl_adt_remove_node ( zpl_adt_node * node ) ;
/**
* @ brief Initialise a node as an object
*
* @ param obj
* @ param name
* @ param backing
* @ return
*/
ZPL_DEF void zpl_adt_set_obj ( zpl_adt_node * obj , char const * name , zpl_allocator backing ) ;
/**
* @ brief Initialise a node as an array
*
* @ param obj
* @ param name
* @ param backing
* @ return
*/
ZPL_DEF void zpl_adt_set_arr ( zpl_adt_node * obj , char const * name , zpl_allocator backing ) ;
/**
* @ brief Initialise a node as a string
*
* @ param obj
* @ param name
* @ param value
* @ return
*/
ZPL_DEF void zpl_adt_set_str ( zpl_adt_node * obj , char const * name , char const * value ) ;
/**
* @ brief Initialise a node as a float
*
* @ param obj
* @ param name
* @ param value
* @ return
*/
ZPL_DEF void zpl_adt_set_flt ( zpl_adt_node * obj , char const * name , zpl_f64 value ) ;
/**
* @ brief Initialise a node as a signed integer
*
* @ param obj
* @ param name
* @ param value
* @ return
*/
ZPL_DEF void zpl_adt_set_int ( zpl_adt_node * obj , char const * name , zpl_i64 value ) ;
/**
* @ brief Append a new node to a container as an object
*
* @ param parent
* @ param name
* @ return *
*/
ZPL_DEF zpl_adt_node * zpl_adt_append_obj ( zpl_adt_node * parent , char const * name ) ;
/**
* @ brief Append a new node to a container as an array
*
* @ param parent
* @ param name
* @ return *
*/
ZPL_DEF zpl_adt_node * zpl_adt_append_arr ( zpl_adt_node * parent , char const * name ) ;
/**
* @ brief Append a new node to a container as a string
*
* @ param parent
* @ param name
* @ param value
* @ return *
*/
ZPL_DEF zpl_adt_node * zpl_adt_append_str ( zpl_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 *
*/
ZPL_DEF zpl_adt_node * zpl_adt_append_flt ( zpl_adt_node * parent , char const * name , zpl_f64 value ) ;
/**
* @ brief Append a new node to a container as a signed integer
*
* @ param parent
* @ param name
* @ param value
* @ return *
*/
ZPL_DEF zpl_adt_node * zpl_adt_append_int ( zpl_adt_node * parent , char const * name , zpl_i64 value ) ;
/* parser helpers */
/**
* @ brief Parses a text and stores the result into an unitialised node .
*
* @ param node
* @ param base
* @ return *
*/
ZPL_DEF char * zpl_adt_parse_number ( zpl_adt_node * node , char * base ) ;
/**
* @ brief Parses and converts an existing string node into a number .
*
* @ param node
* @ return
*/
ZPL_DEF zpl_adt_error zpl_adt_str_to_number ( zpl_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
*/
ZPL_DEF zpl_adt_error zpl_adt_print_number ( zpl_file * file , zpl_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
*/
ZPL_DEF zpl_adt_error zpl_adt_print_string ( zpl_file * file , zpl_adt_node * node , char const * escaped_chars , char const * escape_symbol ) ;
/* extensions */
# if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
# define zpl_adt_append(parent, name, value) _Generic((value), \
char * : zpl_adt_append_str , \
char const * : zpl_adt_append_str , \
zpl_f64 : zpl_adt_append_flt , \
default : zpl_adt_append_int ) ( parent , name , value )
# define zpl_adt_set(obj, name, value) _Generic((value), \
char * : zpl_adt_set_str , \
char const * : zpl_adt_set_str , \
zpl_f64 : zpl_adt_set_flt , \
default : zpl_adt_set_int ) ( obj , name , value )
# endif
/* deprecated */
ZPL_DEPRECATED_FOR ( 18.0 .0 , zpl_adt_query )
ZPL_IMPL_INLINE zpl_adt_node * zpl_adt_get ( zpl_adt_node * node , char const * uri ) {
return zpl_adt_query ( node , uri ) ;
}
ZPL_DEPRECATED_FOR ( 13.3 .0 , zpl_adt_str_to_number )
ZPL_IMPL_INLINE void zpl_adt_str_to_flt ( zpl_adt_node * node ) {
( void ) zpl_adt_str_to_number ( node ) ;
}
ZPL_DEPRECATED_FOR ( 17.0 .0 , zpl_adt_append_obj )
ZPL_IMPL_INLINE zpl_adt_node * zpl_adt_inset_obj ( zpl_adt_node * parent , char const * name ) {
return zpl_adt_append_obj ( parent , name ) ;
}
ZPL_DEPRECATED_FOR ( 17.0 .0 , zpl_adt_append_arr )
ZPL_IMPL_INLINE zpl_adt_node * zpl_adt_inset_arr ( zpl_adt_node * parent , char const * name ) {
return zpl_adt_append_arr ( parent , name ) ;
}
ZPL_DEPRECATED_FOR ( 17.0 .0 , zpl_adt_append_str )
ZPL_IMPL_INLINE zpl_adt_node * zpl_adt_inset_str ( zpl_adt_node * parent , char const * name , char const * value ) {
return zpl_adt_append_str ( parent , name , value ) ;
}
ZPL_DEPRECATED_FOR ( 17.0 .0 , zpl_adt_append_flt )
ZPL_IMPL_INLINE zpl_adt_node * zpl_adt_inset_flt ( zpl_adt_node * parent , char const * name , zpl_f64 value ) {
return zpl_adt_append_flt ( parent , name , value ) ;
}
ZPL_DEPRECATED_FOR ( 17.0 .0 , zpl_adt_append_int )
ZPL_IMPL_INLINE zpl_adt_node * zpl_adt_inset_int ( zpl_adt_node * parent , char const * name , zpl_i64 value ) {
return zpl_adt_append_int ( parent , name , value ) ;
}
ZPL_END_C_DECLS
/* parsers */
// file: header/parsers/json.h
ZPL_BEGIN_C_DECLS
typedef enum zpl_json_error {
ZPL_JSON_ERROR_NONE ,
ZPL_JSON_ERROR_INTERNAL ,
ZPL_JSON_ERROR_INVALID_NAME ,
ZPL_JSON_ERROR_INVALID_VALUE ,
ZPL_JSON_ERROR_INVALID_ASSIGNMENT ,
ZPL_JSON_ERROR_UNKNOWN_KEYWORD ,
ZPL_JSON_ERROR_ARRAY_LEFT_OPEN ,
ZPL_JSON_ERROR_OBJECT_END_PAIR_MISMATCHED ,
} zpl_json_error ;
typedef zpl_adt_node zpl_json_object ;
ZPL_DEF zpl_u8 zpl_json_parse ( zpl_json_object * root , char * text , zpl_allocator allocator ) ;
ZPL_DEF void zpl_json_free ( zpl_json_object * obj ) ;
ZPL_DEF void zpl_json_write ( zpl_file * file , zpl_json_object * obj , zpl_isize indent ) ;
ZPL_DEF zpl_string zpl_json_write_string ( zpl_allocator a , zpl_json_object * obj , zpl_isize indent ) ;
ZPL_END_C_DECLS
// file: header/parsers/csv.h
ZPL_BEGIN_C_DECLS
typedef enum zpl_csv_error {
ZPL_CSV_ERROR_NONE ,
ZPL_CSV_ERROR_INTERNAL ,
ZPL_CSV_ERROR_UNEXPECTED_END_OF_INPUT ,
ZPL_CSV_ERROR_MISMATCHED_ROWS ,
} zpl_csv_error ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
typedef zpl_adt_node zpl_csv_object ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_DEF_INLINE zpl_u8 zpl_csv_parse ( zpl_csv_object * root , char * text , zpl_allocator allocator , zpl_b32 has_header ) ;
ZPL_DEF zpl_u8 zpl_csv_parse_delimiter ( zpl_csv_object * root , char * text , zpl_allocator allocator , zpl_b32 has_header , char delim ) ;
ZPL_DEF void zpl_csv_free ( zpl_csv_object * obj ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_DEF_INLINE void zpl_csv_write ( zpl_file * file , zpl_csv_object * obj ) ;
ZPL_DEF_INLINE zpl_string zpl_csv_write_string ( zpl_allocator a , zpl_csv_object * obj ) ;
ZPL_DEF void zpl_csv_write_delimiter ( zpl_file * file , zpl_csv_object * obj , char delim ) ;
ZPL_DEF zpl_string zpl_csv_write_string_delimiter ( zpl_allocator a , zpl_csv_object * obj , char delim ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
/* inline */
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_IMPL_INLINE zpl_u8 zpl_csv_parse ( zpl_csv_object * root , char * text , zpl_allocator allocator , zpl_b32 has_header ) {
return zpl_csv_parse_delimiter ( root , text , allocator , has_header , ' , ' ) ;
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_IMPL_INLINE void zpl_csv_write ( zpl_file * file , zpl_csv_object * obj ) {
zpl_csv_write_delimiter ( file , obj , ' , ' ) ;
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_IMPL_INLINE zpl_string zpl_csv_write_string ( zpl_allocator a , zpl_csv_object * obj ) {
return zpl_csv_write_string_delimiter ( a , obj , ' , ' ) ;
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_END_C_DECLS
2021-11-29 08:23:08 +00:00
# endif
2022-09-11 17:42:06 +00:00
# if defined(ZPL_MODULE_THREADING)
# if defined(ZPL_SYSTEM_UNIX) || defined(ZPL_SYSTEM_MACOS)
# include <pthread.h>
# endif
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
# if !defined(zpl_thread_local)
# if defined(_MSC_VER) && _MSC_VER >= 1300
# define zpl_thread_local __declspec(thread)
# elif defined(__GNUC__)
# define zpl_thread_local __thread
# elif defined(__TINYC__)
# define zpl_thread_local
# else
# define zpl_thread_local thread_local
# endif
# endif
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
// file: header/threading/atomic.h
// Atomics
// TODO: Be specific with memory order?
// e.g. relaxed, acquire, release, acquire_release
# if !defined(__STDC_NO_ATOMICS__) && !defined(__cplusplus) && !defined(ZPL_COMPILER_MSVC) && !defined(ZPL_COMPILER_TINYC)
# define zpl_atomic(X) volatile _Atomic(X)
# else
// TODO: Fix once C++ guys bother to add C atomics to std.
//# include <atomic>
# define zpl_atomic(X) volatile X /*std::atomic<X>*/
# endif
# if defined(__STDC_NO_ATOMICS__) || defined(__cplusplus) || defined(ZPL_COMPILER_MSVC)
# define zpl_atomicarg(X) volatile X
# else
# define zpl_atomicarg(X) X
# endif
ZPL_BEGIN_C_DECLS
# if defined(ZPL_COMPILER_MSVC)
typedef struct zpl_atomic32 { zpl_atomic ( zpl_i32 ) value ; } zpl_atomic32 ;
typedef struct zpl_atomic64 { zpl_atomic ( zpl_i64 ) value ; } zpl_atomic64 ;
typedef struct zpl_atomic_ptr { zpl_atomic ( void * ) value ; } zpl_atomic_ptr ;
# else
# if defined(ZPL_ARCH_32_BIT)
# define ZPL_ATOMIC_PTR_ALIGNMENT 4
# elif defined(ZPL_ARCH_64_BIT)
# define ZPL_ATOMIC_PTR_ALIGNMENT 8
# else
# error Unknown architecture
# endif
typedef struct zpl_atomic32 { zpl_atomic ( zpl_i32 ) value ; } __attribute__ ( ( aligned ( 4 ) ) ) zpl_atomic32 ;
typedef struct zpl_atomic64 { zpl_atomic ( zpl_i64 ) value ; } __attribute__ ( ( aligned ( 8 ) ) ) zpl_atomic64 ;
typedef struct zpl_atomic_ptr { zpl_atomic ( void * ) value ; } __attribute__ ( ( aligned ( ZPL_ATOMIC_PTR_ALIGNMENT ) ) ) zpl_atomic_ptr ;
# endif
ZPL_DEF zpl_i32 zpl_atomic32_load ( zpl_atomic32 const * a ) ;
ZPL_DEF void zpl_atomic32_store ( zpl_atomic32 * a , zpl_atomicarg ( zpl_i32 ) value ) ;
ZPL_DEF zpl_i32 zpl_atomic32_compare_exchange ( zpl_atomic32 * a , zpl_atomicarg ( zpl_i32 ) expected , zpl_atomicarg ( zpl_i32 ) desired ) ;
ZPL_DEF zpl_i32 zpl_atomic32_exchange ( zpl_atomic32 * a , zpl_atomicarg ( zpl_i32 ) desired ) ;
ZPL_DEF zpl_i32 zpl_atomic32_fetch_add ( zpl_atomic32 * a , zpl_atomicarg ( zpl_i32 ) operand ) ;
ZPL_DEF zpl_i32 zpl_atomic32_fetch_and ( zpl_atomic32 * a , zpl_atomicarg ( zpl_i32 ) operand ) ;
ZPL_DEF zpl_i32 zpl_atomic32_fetch_or ( zpl_atomic32 * a , zpl_atomicarg ( zpl_i32 ) operand ) ;
ZPL_DEF zpl_b32 zpl_atomic32_spin_lock ( zpl_atomic32 * a , zpl_isize time_out ) ; // NOTE: time_out = -1 as default
ZPL_DEF void zpl_atomic32_spin_unlock ( zpl_atomic32 * a ) ;
ZPL_DEF zpl_b32 zpl_atomic32_try_acquire_lock ( zpl_atomic32 * a ) ;
ZPL_DEF zpl_i64 zpl_atomic64_load ( zpl_atomic64 const * a ) ;
ZPL_DEF void zpl_atomic64_store ( zpl_atomic64 * a , zpl_atomicarg ( zpl_i64 ) value ) ;
ZPL_DEF zpl_i64 zpl_atomic64_compare_exchange ( zpl_atomic64 * a , zpl_atomicarg ( zpl_i64 ) expected , zpl_atomicarg ( zpl_i64 ) desired ) ;
ZPL_DEF zpl_i64 zpl_atomic64_exchange ( zpl_atomic64 * a , zpl_atomicarg ( zpl_i64 ) desired ) ;
ZPL_DEF zpl_i64 zpl_atomic64_fetch_add ( zpl_atomic64 * a , zpl_atomicarg ( zpl_i64 ) operand ) ;
ZPL_DEF zpl_i64 zpl_atomic64_fetch_and ( zpl_atomic64 * a , zpl_atomicarg ( zpl_i64 ) operand ) ;
ZPL_DEF zpl_i64 zpl_atomic64_fetch_or ( zpl_atomic64 * a , zpl_atomicarg ( zpl_i64 ) operand ) ;
ZPL_DEF zpl_b32 zpl_atomic64_spin_lock ( zpl_atomic64 * a , zpl_isize time_out ) ; // NOTE: time_out = -1 as default
ZPL_DEF void zpl_atomic64_spin_unlock ( zpl_atomic64 * a ) ;
ZPL_DEF zpl_b32 zpl_atomic64_try_acquire_lock ( zpl_atomic64 * a ) ;
ZPL_DEF void * zpl_atomic_ptr_load ( zpl_atomic_ptr const * a ) ;
ZPL_DEF void zpl_atomic_ptr_store ( zpl_atomic_ptr * a , zpl_atomicarg ( void * ) value ) ;
ZPL_DEF void * zpl_atomic_ptr_compare_exchange ( zpl_atomic_ptr * a , zpl_atomicarg ( void * ) expected , zpl_atomicarg ( void * ) desired ) ;
ZPL_DEF void * zpl_atomic_ptr_exchange ( zpl_atomic_ptr * a , zpl_atomicarg ( void * ) desired ) ;
ZPL_DEF void * zpl_atomic_ptr_fetch_add ( zpl_atomic_ptr * a , zpl_atomicarg ( void * ) operand ) ;
ZPL_DEF void * zpl_atomic_ptr_fetch_and ( zpl_atomic_ptr * a , zpl_atomicarg ( void * ) operand ) ;
ZPL_DEF void * zpl_atomic_ptr_fetch_or ( zpl_atomic_ptr * a , zpl_atomicarg ( void * ) operand ) ;
ZPL_DEF zpl_b32 zpl_atomic_ptr_spin_lock ( zpl_atomic_ptr * a , zpl_isize time_out ) ; // NOTE: time_out = -1 as default
ZPL_DEF void zpl_atomic_ptr_spin_unlock ( zpl_atomic_ptr * a ) ;
ZPL_DEF zpl_b32 zpl_atomic_ptr_try_acquire_lock ( zpl_atomic_ptr * a ) ;
ZPL_END_C_DECLS
// file: header/threading/fence.h
// Fences
ZPL_BEGIN_C_DECLS
ZPL_DEF void zpl_yield_thread ( void ) ;
ZPL_DEF void zpl_mfence ( void ) ;
ZPL_DEF void zpl_sfence ( void ) ;
ZPL_DEF void zpl_lfence ( void ) ;
ZPL_END_C_DECLS
// file: header/threading/sem.h
ZPL_BEGIN_C_DECLS
# if defined(ZPL_SYSTEM_MACOS)
# include <mach / thread_act.h>
# elif defined(ZPL_SYSTEM_UNIX)
# include <semaphore.h>
# endif
# if defined(ZPL_SYSTEM_WINDOWS)
typedef struct zpl_semaphore { void * win32_handle ; } zpl_semaphore ;
# elif defined(ZPL_SYSTEM_MACOS)
typedef struct zpl_semaphore { semaphore_t osx_handle ; } zpl_semaphore ;
# elif defined(ZPL_SYSTEM_UNIX)
typedef struct zpl_semaphore { sem_t unix_handle ; } zpl_semaphore ;
# else
# error
# endif
ZPL_DEF void zpl_semaphore_init ( zpl_semaphore * s ) ;
ZPL_DEF void zpl_semaphore_destroy ( zpl_semaphore * s ) ;
ZPL_DEF void zpl_semaphore_post ( zpl_semaphore * s , zpl_i32 count ) ;
ZPL_DEF void zpl_semaphore_release ( zpl_semaphore * s ) ; // NOTE: zpl_semaphore_post(s, 1)
ZPL_DEF void zpl_semaphore_wait ( zpl_semaphore * s ) ;
ZPL_DEF zpl_i32 zpl_semaphore_trywait ( zpl_semaphore * s ) ;
ZPL_END_C_DECLS
// file: header/threading/mutex.h
ZPL_BEGIN_C_DECLS
typedef struct zpl_mutex {
# if defined(ZPL_SYSTEM_WINDOWS)
zpl_u64 win32_critical_section [ sizeof ( zpl_usize ) / 2 + 1 ] ;
# else
pthread_mutex_t pthread_mutex ;
# endif
} zpl_mutex ;
ZPL_DEF void zpl_mutex_init ( zpl_mutex * m ) ;
ZPL_DEF void zpl_mutex_destroy ( zpl_mutex * m ) ;
ZPL_DEF void zpl_mutex_lock ( zpl_mutex * m ) ;
ZPL_DEF zpl_b32 zpl_mutex_try_lock ( zpl_mutex * m ) ;
ZPL_DEF void zpl_mutex_unlock ( zpl_mutex * m ) ;
ZPL_END_C_DECLS
// file: header/threading/thread.h
# ifdef ZPL_EDITOR
# include <zpl.h>
# else
struct zpl_thread ;
# endif
ZPL_BEGIN_C_DECLS
typedef zpl_isize ( * zpl_thread_proc ) ( struct zpl_thread * thread ) ;
typedef struct zpl_thread {
# if defined(ZPL_SYSTEM_WINDOWS)
void * win32_handle ;
# else
pthread_t posix_handle ;
# endif
zpl_thread_proc proc ;
void * user_data ;
zpl_isize user_index ;
zpl_isize return_value ;
zpl_semaphore semaphore ;
zpl_isize stack_size ;
zpl_b32 is_running ;
zpl_b32 nowait ;
} zpl_thread ;
ZPL_DEF void zpl_thread_init ( zpl_thread * t ) ;
ZPL_DEF void zpl_thread_init_nowait ( zpl_thread * t ) ;
ZPL_DEF void zpl_thread_destroy ( zpl_thread * t ) ;
ZPL_DEF void zpl_thread_start ( zpl_thread * t , zpl_thread_proc proc , void * data ) ;
ZPL_DEF void zpl_thread_start_with_stack ( zpl_thread * t , zpl_thread_proc proc , void * data , zpl_isize stack_size ) ;
ZPL_DEF void zpl_thread_join ( zpl_thread * t ) ;
ZPL_DEF zpl_b32 zpl_thread_is_running ( zpl_thread const * t ) ;
ZPL_DEF zpl_u32 zpl_thread_current_id ( void ) ;
ZPL_DEF void zpl_thread_set_name ( zpl_thread * t , char const * name ) ;
ZPL_END_C_DECLS
// file: header/threading/sync.h
// NOTE: Thread Merge Operation
// Based on Sean Barrett's stb_sync
ZPL_BEGIN_C_DECLS
typedef struct zpl_sync {
zpl_i32 target ; // Target Number of threads
zpl_i32 current ; // Threads to hit
zpl_i32 waiting ; // Threads waiting
zpl_mutex start ;
zpl_mutex mutex ;
zpl_semaphore release ;
} zpl_sync ;
ZPL_DEF void zpl_sync_init ( zpl_sync * s ) ;
ZPL_DEF void zpl_sync_destroy ( zpl_sync * s ) ;
ZPL_DEF void zpl_sync_set_target ( zpl_sync * s , zpl_i32 count ) ;
ZPL_DEF void zpl_sync_release ( zpl_sync * s ) ;
ZPL_DEF zpl_i32 zpl_sync_reach ( zpl_sync * s ) ;
ZPL_DEF void zpl_sync_reach_and_wait ( zpl_sync * s ) ;
ZPL_END_C_DECLS
// file: header/threading/affinity.h
ZPL_BEGIN_C_DECLS
# if defined(ZPL_SYSTEM_WINDOWS) || defined (ZPL_SYSTEM_CYGWIN)
typedef struct zpl_affinity {
zpl_b32 is_accurate ;
zpl_isize core_count ;
zpl_isize thread_count ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
# define ZPL_WIN32_MAX_THREADS (8 * zpl_size_of(zpl_usize))
zpl_usize core_masks [ ZPL_WIN32_MAX_THREADS ] ;
} zpl_affinity ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
# elif defined(ZPL_SYSTEM_OSX)
typedef struct zpl_affinity {
zpl_b32 is_accurate ;
zpl_isize core_count ;
zpl_isize thread_count ;
zpl_isize threads_per_core ;
} zpl_affinity ;
# elif defined(ZPL_SYSTEM_LINUX) || defined(ZPL_SYSTEM_FREEBSD) || defined(ZPL_SYSTEM_EMSCRIPTEN) || defined(ZPL_SYSTEM_OPENBSD)
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
typedef struct zpl_affinity {
zpl_b32 is_accurate ;
zpl_isize core_count ;
zpl_isize thread_count ;
zpl_isize threads_per_core ;
} zpl_affinity ;
# else
# error TODO: Unknown system
# endif
ZPL_DEF void zpl_affinity_init ( zpl_affinity * a ) ;
ZPL_DEF void zpl_affinity_destroy ( zpl_affinity * a ) ;
ZPL_DEF zpl_b32 zpl_affinity_set ( zpl_affinity * a , zpl_isize core , zpl_isize thread ) ;
ZPL_DEF zpl_isize zpl_affinity_thread_count_for_core ( zpl_affinity * a , zpl_isize core ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_END_C_DECLS
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
# if defined(ZPL_MODULE_JOBS)
// file: header/jobs.h
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
/** @file threadpool.c
@ brief Job system
@ defgroup jobs Job system
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
This job system follows thread pool pattern to minimize the costs of thread initialization .
It reuses fixed number of threads to process variable number of jobs .
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
@ {
*/
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_BEGIN_C_DECLS
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
typedef void ( * zpl_jobs_proc ) ( void * data ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
# define ZPL_INVALID_JOB ZPL_U32_MAX
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
# ifndef ZPL_JOBS_MAX_QUEUE
# define ZPL_JOBS_MAX_QUEUE 100
# endif
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
# ifdef ZPL_JOBS_ENABLE_DEBUG
# define ZPL_JOBS_DEBUG
# endif
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
typedef enum {
ZPL_JOBS_STATUS_READY ,
ZPL_JOBS_STATUS_BUSY ,
ZPL_JOBS_STATUS_WAITING ,
ZPL_JOBS_STATUS_TERM ,
} zpl_jobs_status ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
typedef enum {
ZPL_JOBS_PRIORITY_REALTIME ,
ZPL_JOBS_PRIORITY_HIGH ,
ZPL_JOBS_PRIORITY_NORMAL ,
ZPL_JOBS_PRIORITY_LOW ,
ZPL_JOBS_PRIORITY_IDLE ,
ZPL_JOBS_MAX_PRIORITIES ,
} zpl_jobs_priority ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
typedef struct {
zpl_jobs_proc proc ;
void * data ;
} zpl_thread_job ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_RING_DECLARE ( extern , zpl__jobs_ring_ , zpl_thread_job ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
typedef struct {
zpl_thread thread ;
zpl_atomic32 status ;
zpl_thread_job job ;
# ifdef ZPL_JOBS_DEBUG
zpl_u32 hits ;
zpl_u32 idle ;
# endif
} zpl_thread_worker ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
typedef struct {
zpl__jobs_ring_zpl_thread_job jobs ; ///< zpl_ring
zpl_u32 chance ;
# ifdef ZPL_JOBS_DEBUG
zpl_u32 hits ;
# endif
} zpl_thread_queue ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
typedef struct {
zpl_allocator alloc ;
zpl_u32 max_threads , max_jobs , counter ;
zpl_thread_worker * workers ; ///< zpl_buffer
zpl_thread_queue queues [ ZPL_JOBS_MAX_PRIORITIES ] ;
} zpl_jobs_system ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Initialize thread pool with specified amount of fixed threads.
ZPL_DEF void zpl_jobs_init ( zpl_jobs_system * pool , zpl_allocator a , zpl_u32 max_threads ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Initialize thread pool with specified amount of fixed threads and custom job limit.
ZPL_DEF void zpl_jobs_init_with_limit ( zpl_jobs_system * pool , zpl_allocator a , zpl_u32 max_threads , zpl_u32 max_jobs ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Release the resources use by thread pool.
ZPL_DEF void zpl_jobs_free ( zpl_jobs_system * pool ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Enqueue a job with specified data and custom priority.
ZPL_DEF zpl_b32 zpl_jobs_enqueue_with_priority ( zpl_jobs_system * pool , zpl_jobs_proc proc , void * data , zpl_jobs_priority priority ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Enqueue a job with specified data.
ZPL_DEF zpl_b32 zpl_jobs_enqueue ( zpl_jobs_system * pool , zpl_jobs_proc proc , void * data ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Check if the work queue is empty.
ZPL_DEF zpl_b32 zpl_jobs_empty ( zpl_jobs_system * pool , zpl_jobs_priority priority ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_DEF zpl_b32 zpl_jobs_empty_all ( zpl_jobs_system * pool ) ;
ZPL_DEF zpl_b32 zpl_jobs_full_all ( zpl_jobs_system * pool ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Check if the work queue is full.
ZPL_DEF zpl_b32 zpl_jobs_full ( zpl_jobs_system * pool , zpl_jobs_priority priority ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Check if all workers are done.
ZPL_DEF zpl_b32 zpl_jobs_done ( zpl_jobs_system * pool ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
//! Process all jobs and check all threads. Should be called by Main Thread in a tight loop.
ZPL_DEF zpl_b32 zpl_jobs_process ( zpl_jobs_system * pool ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_END_C_DECLS
2021-11-29 08:23:08 +00:00
# endif
# else
2022-09-11 17:42:06 +00:00
# if !defined(zpl_thread_local)
# define zpl_thread_local
2021-11-29 08:23:08 +00:00
# endif
# endif
2022-09-11 17:42:06 +00:00
# if defined(ZPL_COMPILER_MSVC)
# pragma warning(pop)
2021-11-29 08:23:08 +00:00
# endif
2022-09-11 17:42:06 +00:00
# if defined(__GCC__) || defined(__GNUC__) || defined(__clang__)
# pragma GCC diagnostic pop
2021-11-29 08:23:08 +00:00
# endif
2022-09-11 17:42:06 +00:00
# if defined(ZPL_IMPLEMENTATION) && !defined(ZPL_IMPLEMENTATION_DONE)
# define ZPL_IMPLEMENTATION_DONE
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
# if defined(__GCC__) || defined(__GNUC__) || defined(__clang__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wattributes"
# pragma GCC diagnostic ignored "-Wunused-value"
# pragma GCC diagnostic ignored "-Wunused-function"
# pragma GCC diagnostic ignored "-Wwrite-strings"
# pragma GCC diagnostic ignored "-Wunused-parameter"
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
# pragma GCC diagnostic ignored "-Wmissing-braces"
# pragma GCC diagnostic ignored "-Wmissing-field-initializers"
# pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
# pragma GCC diagnostic ignored "-Wignored-qualifiers"
2021-11-29 08:23:08 +00:00
# endif
2022-09-11 17:42:06 +00:00
# if defined(_MSC_VER)
# pragma warning(push)
# pragma warning(disable : 4201)
# pragma warning(disable : 4996) // Disable deprecated POSIX functions warning
# pragma warning(disable : 4127) // Conditional expression is constant
# pragma warning(disable : 4204) // non-constant field initializer
# pragma warning(disable : 4756) // -INFINITY
# pragma warning(disable : 4056) // -INFINITY
# pragma warning(disable : 4702) // unreachable code
2021-11-29 08:23:08 +00:00
# endif
2022-09-11 17:42:06 +00:00
/* general purpose includes */
# include <stdio.h>
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
// NOTE: Ensure we use standard methods for these calls if we use ZPL_PICO
# if !defined(ZPL_PICO_CUSTOM_ROUTINES)
# if !defined(ZPL_MODULE_CORE)
# define zpl__strlen strlen
# define zpl__printf_err(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__)
# define zpl__printf_err_va(fmt, va) vfprintf(stderr, fmt, va)
# else
# define zpl__strlen zpl_strlen
# define zpl__printf_err(fmt, ...) zpl_printf_err(fmt, __VA_ARGS__)
# define zpl__printf_err_va(fmt, va) zpl_printf_err_va(fmt, va)
# endif
# endif
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
# include <errno.h>
2021-11-29 08:23:08 +00:00
# if defined(ZPL_SYSTEM_UNIX) || defined(ZPL_SYSTEM_MACOS)
2022-09-11 17:42:06 +00:00
# include <unistd.h>
# elif defined(ZPL_SYSTEM_WINDOWS)
# if !defined(ZPL_NO_WINDOWS_H)
# ifndef WIN32_LEAN_AND_MEAN
# ifndef NOMINMAX
# define NOMINMAX
# endif
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
# define WIN32_LEAN_AND_MEAN
# define WIN32_MEAN_AND_LEAN
# define VC_EXTRALEAN
# endif
# include <windows.h>
# undef NOMINMAX
# undef WIN32_LEAN_AND_MEAN
# undef WIN32_MEAN_AND_LEAN
# undef VC_EXTRALEAN
# endif
2021-11-29 08:23:08 +00:00
# endif
2022-09-11 17:42:06 +00:00
# if defined(ZPL_MODULE_ESSENTIALS)
// file: source/essentials/debug.c
ZPL_BEGIN_C_DECLS
void zpl_assert_handler ( char const * condition , char const * file , zpl_i32 line , char const * msg , . . . ) {
zpl__printf_err ( " %s:(%d): Assert Failure: " , file , line ) ;
if ( condition ) zpl__printf_err ( " `%s` " , condition ) ;
if ( msg ) {
va_list va ;
va_start ( va , msg ) ;
zpl__printf_err_va ( msg , va ) ;
va_end ( va ) ;
}
zpl__printf_err ( " %s " , " \n " ) ;
}
zpl_i32 zpl_assert_crash ( char const * condition ) {
ZPL_PANIC ( condition ) ;
return 0 ;
}
# if defined(ZPL_SYSTEM_UNIX) || defined(ZPL_SYSTEM_MACOS)
# include <sched.h>
# endif
# if defined(ZPL_SYSTEM_WINDOWS)
void zpl_exit ( zpl_u32 code ) { ExitProcess ( code ) ; }
# else
# include <stdlib.h>
void zpl_exit ( zpl_u32 code ) { exit ( code ) ; }
# endif
ZPL_END_C_DECLS
// file: source/essentials/memory.c
# include <string.h>
ZPL_BEGIN_C_DECLS
void zpl_memswap ( void * i , void * j , zpl_isize size ) {
if ( i = = j ) return ;
if ( size = = 4 ) {
zpl_swap ( zpl_u32 , * cast ( zpl_u32 * ) i , * cast ( zpl_u32 * ) j ) ;
} else if ( size = = 8 ) {
zpl_swap ( zpl_u64 , * cast ( zpl_u64 * ) i , * cast ( zpl_u64 * ) j ) ;
} else if ( size < 8 ) {
zpl_u8 * a = cast ( zpl_u8 * ) i ;
zpl_u8 * b = cast ( zpl_u8 * ) j ;
if ( a ! = b ) {
while ( size - - ) { zpl_swap ( zpl_u8 , * a + + , * b + + ) ; }
}
} else {
char buffer [ 256 ] ;
while ( size > zpl_size_of ( buffer ) ) {
zpl_memswap ( i , j , zpl_size_of ( buffer ) ) ;
i = zpl_pointer_add ( i , zpl_size_of ( buffer ) ) ;
j = zpl_pointer_add ( j , zpl_size_of ( buffer ) ) ;
size - = zpl_size_of ( buffer ) ;
}
zpl_memcopy ( buffer , i , size ) ;
zpl_memcopy ( i , j , size ) ;
zpl_memcopy ( j , buffer , size ) ;
}
}
void const * zpl_memchr ( void const * data , zpl_u8 c , zpl_isize n ) {
zpl_u8 const * s = cast ( zpl_u8 const * ) data ;
while ( ( cast ( zpl_uintptr ) s & ( sizeof ( zpl_usize ) - 1 ) ) & & n & & * s ! = c ) {
s + + ;
n - - ;
}
if ( n & & * s ! = c ) {
zpl_isize const * w ;
zpl_isize k = ZPL__ONES * c ;
w = cast ( zpl_isize const * ) s ;
while ( n > = zpl_size_of ( zpl_isize ) & & ! ZPL__HAS_ZERO ( * w ^ k ) ) {
w + + ;
n - = zpl_size_of ( zpl_isize ) ;
}
s = cast ( zpl_u8 const * ) w ;
while ( n & & * s ! = c ) {
s + + ;
n - - ;
}
}
return n ? cast ( void const * ) s : NULL ;
}
void const * zpl_memrchr ( void const * data , zpl_u8 c , zpl_isize n ) {
zpl_u8 const * s = cast ( zpl_u8 const * ) data ;
while ( n - - ) {
if ( s [ n ] = = c ) return cast ( void const * ) ( s + n ) ;
}
return NULL ;
}
void * zpl_memcopy ( void * dest , void const * source , zpl_isize n ) {
if ( dest = = NULL ) { return NULL ; }
return memcpy ( dest , source , n ) ;
// TODO: Re-work the whole method
#if 0
# if defined(_MSC_VER)
__movsb ( cast ( zpl_u8 * ) dest , cast ( zpl_u8 * ) source , n ) ;
# elif defined(ZPL_CPU_X86) && !defined(ZPL_SYSTEM_EMSCRIPTEN)
zpl_u8 * __dest8 = cast ( zpl_u8 * ) dest ;
zpl_u8 * __source8 = cast ( zpl_u8 * ) source ;
__asm__ __volatile__ ( " rep movsb " : " +D " ( __dest8 ) , " +S " ( __source8 ) , " +c " ( n ) : : " memory " ) ;
# elif defined(ZPL_CPU_ARM)
return memcpy ( dest , source , n ) ;
# else
zpl_u8 * d = cast ( zpl_u8 * ) dest ;
zpl_u8 const * s = cast ( zpl_u8 const * ) source ;
zpl_u32 w , x ;
for ( ; cast ( zpl_uintptr ) s % 4 & & n ; n - - ) * d + + = * s + + ;
if ( cast ( zpl_uintptr ) d % 4 = = 0 ) {
for ( ; n > = 16 ; s + = 16 , d + = 16 , n - = 16 ) {
* cast ( zpl_u32 * ) ( d + 0 ) = * cast ( zpl_u32 * ) ( s + 0 ) ;
* cast ( zpl_u32 * ) ( d + 4 ) = * cast ( zpl_u32 * ) ( s + 4 ) ;
* cast ( zpl_u32 * ) ( d + 8 ) = * cast ( zpl_u32 * ) ( s + 8 ) ;
* cast ( zpl_u32 * ) ( d + 12 ) = * cast ( zpl_u32 * ) ( s + 12 ) ;
}
if ( n & 8 ) {
* cast ( zpl_u32 * ) ( d + 0 ) = * cast ( zpl_u32 * ) ( s + 0 ) ;
* cast ( zpl_u32 * ) ( d + 4 ) = * cast ( zpl_u32 * ) ( s + 4 ) ;
d + = 8 ;
s + = 8 ;
}
if ( n & 4 ) {
* cast ( zpl_u32 * ) ( d + 0 ) = * cast ( zpl_u32 * ) ( s + 0 ) ;
d + = 4 ;
s + = 4 ;
}
if ( n & 2 ) {
* d + + = * s + + ;
* d + + = * s + + ;
}
if ( n & 1 ) { * d = * s ; }
return dest ;
}
if ( n > = 32 ) {
# if __BYTE_ORDER == __BIG_ENDIAN
# define LS <<
# define RS >>
# else
# define LS >>
# define RS <<
# endif
switch ( cast ( zpl_uintptr ) d % 4 ) {
case 1 : {
w = * cast ( zpl_u32 * ) s ;
* d + + = * s + + ;
* d + + = * s + + ;
* d + + = * s + + ;
n - = 3 ;
while ( n > 16 ) {
x = * cast ( zpl_u32 * ) ( s + 1 ) ;
* cast ( zpl_u32 * ) ( d + 0 ) = ( w LS 24 ) | ( x RS 8 ) ;
w = * cast ( zpl_u32 * ) ( s + 5 ) ;
* cast ( zpl_u32 * ) ( d + 4 ) = ( x LS 24 ) | ( w RS 8 ) ;
x = * cast ( zpl_u32 * ) ( s + 9 ) ;
* cast ( zpl_u32 * ) ( d + 8 ) = ( w LS 24 ) | ( x RS 8 ) ;
w = * cast ( zpl_u32 * ) ( s + 13 ) ;
* cast ( zpl_u32 * ) ( d + 12 ) = ( x LS 24 ) | ( w RS 8 ) ;
s + = 16 ;
d + = 16 ;
n - = 16 ;
}
} break ;
case 2 : {
w = * cast ( zpl_u32 * ) s ;
* d + + = * s + + ;
* d + + = * s + + ;
n - = 2 ;
while ( n > 17 ) {
x = * cast ( zpl_u32 * ) ( s + 2 ) ;
* cast ( zpl_u32 * ) ( d + 0 ) = ( w LS 16 ) | ( x RS 16 ) ;
w = * cast ( zpl_u32 * ) ( s + 6 ) ;
* cast ( zpl_u32 * ) ( d + 4 ) = ( x LS 16 ) | ( w RS 16 ) ;
x = * cast ( zpl_u32 * ) ( s + 10 ) ;
* cast ( zpl_u32 * ) ( d + 8 ) = ( w LS 16 ) | ( x RS 16 ) ;
w = * cast ( zpl_u32 * ) ( s + 14 ) ;
* cast ( zpl_u32 * ) ( d + 12 ) = ( x LS 16 ) | ( w RS 16 ) ;
s + = 16 ;
d + = 16 ;
n - = 16 ;
}
} break ;
case 3 : {
w = * cast ( zpl_u32 * ) s ;
* d + + = * s + + ;
n - = 1 ;
while ( n > 18 ) {
x = * cast ( zpl_u32 * ) ( s + 3 ) ;
* cast ( zpl_u32 * ) ( d + 0 ) = ( w LS 8 ) | ( x RS 24 ) ;
w = * cast ( zpl_u32 * ) ( s + 7 ) ;
* cast ( zpl_u32 * ) ( d + 4 ) = ( x LS 8 ) | ( w RS 24 ) ;
x = * cast ( zpl_u32 * ) ( s + 11 ) ;
* cast ( zpl_u32 * ) ( d + 8 ) = ( w LS 8 ) | ( x RS 24 ) ;
w = * cast ( zpl_u32 * ) ( s + 15 ) ;
* cast ( zpl_u32 * ) ( d + 12 ) = ( x LS 8 ) | ( w RS 24 ) ;
s + = 16 ;
d + = 16 ;
n - = 16 ;
}
} break ;
default : break ; // NOTE: Do nowt!
}
# undef LS
# undef RS
if ( n & 16 ) {
* d + + = * s + + ;
* d + + = * s + + ;
* d + + = * s + + ;
* d + + = * s + + ;
* d + + = * s + + ;
* d + + = * s + + ;
* d + + = * s + + ;
* d + + = * s + + ;
* d + + = * s + + ;
* d + + = * s + + ;
* d + + = * s + + ;
* d + + = * s + + ;
* d + + = * s + + ;
* d + + = * s + + ;
* d + + = * s + + ;
* d + + = * s + + ;
}
if ( n & 8 ) {
* d + + = * s + + ;
* d + + = * s + + ;
* d + + = * s + + ;
* d + + = * s + + ;
* d + + = * s + + ;
* d + + = * s + + ;
* d + + = * s + + ;
* d + + = * s + + ;
}
if ( n & 4 ) {
* d + + = * s + + ;
* d + + = * s + + ;
* d + + = * s + + ;
* d + + = * s + + ;
}
if ( n & 2 ) {
* d + + = * s + + ;
* d + + = * s + + ;
}
if ( n & 1 ) { * d = * s ; }
}
# endif
# endif
return dest ;
}
ZPL_END_C_DECLS
// file: source/essentials/memory_custom.c
# ifndef _IOSC11_SOURCE
# define _IOSC11_SOURCE
# endif
# include <stdlib.h>
# if defined(ZPL_SYSTEM_WINDOWS)
# include <malloc.h>
# endif
// include errno.h for MinGW
# if defined(ZPL_COMPILER_GCC) || (defined(ZPL_COMPILER_TINYC) && defined(ZPL_SYSTEM_WINDOWS))
# include <errno.h>
# endif
# if defined(ZPL_COMPILER_MINGW)
# ifdef __MINGW32__
# define _aligned_malloc __mingw_aligned_malloc
# define _aligned_free __mingw_aligned_free
# endif //MINGW
# endif
ZPL_BEGIN_C_DECLS
char * zpl_alloc_str ( zpl_allocator a , char const * str ) {
return zpl_alloc_str_len ( a , str , zpl__strlen ( str ) ) ;
}
////////////////////////////////////////////////////////////////
//
// Custom Allocation
//
//
//
// Heap Allocator
//
# define ZPL_HEAP_STATS_MAGIC 0xDEADC0DE
typedef struct zpl__heap_stats {
zpl_u32 magic ;
zpl_isize used_memory ;
zpl_isize alloc_count ;
} zpl__heap_stats ;
zpl_global zpl__heap_stats zpl__heap_stats_info ;
void zpl_heap_stats_init ( void ) {
zpl_zero_item ( & zpl__heap_stats_info ) ;
zpl__heap_stats_info . magic = ZPL_HEAP_STATS_MAGIC ;
}
zpl_isize zpl_heap_stats_used_memory ( void ) {
ZPL_ASSERT_MSG ( zpl__heap_stats_info . magic = = ZPL_HEAP_STATS_MAGIC , " zpl_heap_stats is not initialised yet, call zpl_heap_stats_init first! " ) ;
return zpl__heap_stats_info . used_memory ;
}
zpl_isize zpl_heap_stats_alloc_count ( void ) {
ZPL_ASSERT_MSG ( zpl__heap_stats_info . magic = = ZPL_HEAP_STATS_MAGIC , " zpl_heap_stats is not initialised yet, call zpl_heap_stats_init first! " ) ;
return zpl__heap_stats_info . alloc_count ;
}
void zpl_heap_stats_check ( void ) {
ZPL_ASSERT_MSG ( zpl__heap_stats_info . magic = = ZPL_HEAP_STATS_MAGIC , " zpl_heap_stats is not initialised yet, call zpl_heap_stats_init first! " ) ;
ZPL_ASSERT ( zpl__heap_stats_info . used_memory = = 0 ) ;
ZPL_ASSERT ( zpl__heap_stats_info . alloc_count = = 0 ) ;
}
typedef struct zpl__heap_alloc_info {
zpl_isize size ;
void * physical_start ;
} zpl__heap_alloc_info ;
ZPL_ALLOCATOR_PROC ( zpl_heap_allocator_proc ) {
void * ptr = NULL ;
zpl_unused ( allocator_data ) ;
zpl_unused ( old_size ) ;
if ( ! alignment ) alignment = ZPL_DEFAULT_MEMORY_ALIGNMENT ;
# ifdef ZPL_HEAP_ANALYSIS
zpl_isize alloc_info_size = zpl_size_of ( zpl__heap_alloc_info ) ;
zpl_isize alloc_info_remainder = ( alloc_info_size % alignment ) ;
zpl_isize track_size = zpl_max ( alloc_info_size , alignment ) + alloc_info_remainder ;
switch ( type ) {
case ZPL_ALLOCATION_FREE : {
if ( ! old_memory ) break ;
zpl__heap_alloc_info * alloc_info = cast ( zpl__heap_alloc_info * ) old_memory - 1 ;
zpl__heap_stats_info . used_memory - = alloc_info - > size ;
zpl__heap_stats_info . alloc_count - - ;
old_memory = alloc_info - > physical_start ;
} break ;
case ZPL_ALLOCATION_ALLOC : {
size + = track_size ;
} break ;
default : break ;
}
# endif
switch ( type ) {
# if defined(ZPL_COMPILER_MSVC) || (defined(ZPL_COMPILER_GCC) && defined(ZPL_SYSTEM_WINDOWS)) || (defined(ZPL_COMPILER_TINYC) && defined(ZPL_SYSTEM_WINDOWS))
case ZPL_ALLOCATION_ALLOC :
ptr = _aligned_malloc ( size , alignment ) ;
if ( flags & ZPL_ALLOCATOR_FLAG_CLEAR_TO_ZERO ) zpl_zero_size ( ptr , size ) ;
break ;
case ZPL_ALLOCATION_FREE : _aligned_free ( old_memory ) ; break ;
case ZPL_ALLOCATION_RESIZE : {
zpl_allocator a = zpl_heap_allocator ( ) ;
ptr = zpl_default_resize_align ( a , old_memory , old_size , size , alignment ) ;
} break ;
# elif defined(ZPL_SYSTEM_LINUX) && !defined(ZPL_CPU_ARM) && !defined(ZPL_COMPILER_TINYC)
case ZPL_ALLOCATION_ALLOC : {
ptr = aligned_alloc ( alignment , ( size + alignment - 1 ) & ~ ( alignment - 1 ) ) ;
if ( flags & ZPL_ALLOCATOR_FLAG_CLEAR_TO_ZERO ) { zpl_zero_size ( ptr , size ) ; }
} break ;
case ZPL_ALLOCATION_FREE : {
free ( old_memory ) ;
} break ;
case ZPL_ALLOCATION_RESIZE : {
zpl_allocator a = zpl_heap_allocator ( ) ;
ptr = zpl_default_resize_align ( a , old_memory , old_size , size , alignment ) ;
} break ;
# else
case ZPL_ALLOCATION_ALLOC : {
posix_memalign ( & ptr , alignment , size ) ;
if ( flags & ZPL_ALLOCATOR_FLAG_CLEAR_TO_ZERO ) { zpl_zero_size ( ptr , size ) ; }
} break ;
case ZPL_ALLOCATION_FREE : {
free ( old_memory ) ;
} break ;
case ZPL_ALLOCATION_RESIZE : {
zpl_allocator a = zpl_heap_allocator ( ) ;
ptr = zpl_default_resize_align ( a , old_memory , old_size , size , alignment ) ;
} break ;
# endif
case ZPL_ALLOCATION_FREE_ALL : break ;
}
# ifdef ZPL_HEAP_ANALYSIS
if ( type = = ZPL_ALLOCATION_ALLOC ) {
zpl__heap_alloc_info * alloc_info = cast ( zpl__heap_alloc_info * ) ( cast ( char * ) ptr + alloc_info_remainder ) ;
zpl_zero_item ( alloc_info ) ;
alloc_info - > size = size - track_size ;
alloc_info - > physical_start = ptr ;
ptr = cast ( void * ) ( alloc_info + 1 ) ;
zpl__heap_stats_info . used_memory + = alloc_info - > size ;
zpl__heap_stats_info . alloc_count + + ;
}
# endif
return ptr ;
}
//
// Arena Allocator
//
ZPL_ALLOCATOR_PROC ( zpl_arena_allocator_proc ) {
zpl_arena * arena = cast ( zpl_arena * ) allocator_data ;
void * ptr = NULL ;
zpl_unused ( old_size ) ;
switch ( type ) {
case ZPL_ALLOCATION_ALLOC : {
void * end = zpl_pointer_add ( arena - > physical_start , arena - > total_allocated ) ;
2022-09-18 15:35:53 +00:00
zpl_isize total_size = zpl_align_forward_i64 ( size , alignment ) ;
2022-09-11 17:42:06 +00:00
// NOTE: Out of memory
if ( arena - > total_allocated + total_size > cast ( zpl_isize ) arena - > total_size ) {
2022-09-18 15:35:53 +00:00
// zpl__printf_err("%s", "Arena out of memory\n");
2022-09-11 17:42:06 +00:00
return NULL ;
}
ptr = zpl_align_forward ( end , alignment ) ;
arena - > total_allocated + = total_size ;
if ( flags & ZPL_ALLOCATOR_FLAG_CLEAR_TO_ZERO ) zpl_zero_size ( ptr , size ) ;
} break ;
case ZPL_ALLOCATION_FREE :
// NOTE: Free all at once
// Use Temp_Arena_Memory if you want to free a block
break ;
case ZPL_ALLOCATION_FREE_ALL : arena - > total_allocated = 0 ; break ;
case ZPL_ALLOCATION_RESIZE : {
// TODO: Check if ptr is on top of stack and just extend
zpl_allocator a = zpl_arena_allocator ( arena ) ;
ptr = zpl_default_resize_align ( a , old_memory , old_size , size , alignment ) ;
} break ;
}
return ptr ;
}
//
// Pool Allocator
//
void zpl_pool_init_align ( zpl_pool * pool , zpl_allocator backing , zpl_isize num_blocks , zpl_isize block_size , zpl_isize block_align ) {
zpl_isize actual_block_size , pool_size , block_index ;
void * data , * curr ;
zpl_uintptr * end ;
zpl_zero_item ( pool ) ;
pool - > backing = backing ;
pool - > block_size = block_size ;
pool - > block_align = block_align ;
pool - > num_blocks = num_blocks ;
actual_block_size = block_size + block_align ;
pool_size = num_blocks * actual_block_size ;
data = zpl_alloc_align ( backing , pool_size , block_align ) ;
// NOTE: Init intrusive freelist
curr = data ;
for ( block_index = 0 ; block_index < num_blocks - 1 ; block_index + + ) {
zpl_uintptr * next = cast ( zpl_uintptr * ) curr ;
* next = cast ( zpl_uintptr ) curr + actual_block_size ;
curr = zpl_pointer_add ( curr , actual_block_size ) ;
}
end = cast ( zpl_uintptr * ) curr ;
* end = cast ( zpl_uintptr ) NULL ;
pool - > physical_start = data ;
pool - > free_list = data ;
}
ZPL_ALLOCATOR_PROC ( zpl_pool_allocator_proc ) {
zpl_pool * pool = cast ( zpl_pool * ) allocator_data ;
void * ptr = NULL ;
zpl_unused ( old_size ) ;
switch ( type ) {
case ZPL_ALLOCATION_ALLOC : {
zpl_uintptr next_free ;
ZPL_ASSERT ( size = = pool - > block_size ) ;
ZPL_ASSERT ( alignment = = pool - > block_align ) ;
ZPL_ASSERT ( pool - > free_list ! = NULL ) ;
next_free = * cast ( zpl_uintptr * ) pool - > free_list ;
ptr = pool - > free_list ;
pool - > free_list = cast ( void * ) next_free ;
pool - > total_size + = pool - > block_size ;
if ( flags & ZPL_ALLOCATOR_FLAG_CLEAR_TO_ZERO ) zpl_zero_size ( ptr , size ) ;
} break ;
case ZPL_ALLOCATION_FREE : {
zpl_uintptr * next ;
if ( old_memory = = NULL ) return NULL ;
next = cast ( zpl_uintptr * ) old_memory ;
* next = cast ( zpl_uintptr ) pool - > free_list ;
pool - > free_list = old_memory ;
pool - > total_size - = pool - > block_size ;
} break ;
case ZPL_ALLOCATION_FREE_ALL : {
zpl_isize actual_block_size , block_index ;
void * curr ;
zpl_uintptr * end ;
actual_block_size = pool - > block_size + pool - > block_align ;
pool - > total_size = 0 ;
// NOTE: Init intrusive freelist
curr = pool - > physical_start ;
for ( block_index = 0 ; block_index < pool - > num_blocks - 1 ; block_index + + ) {
zpl_uintptr * next = cast ( zpl_uintptr * ) curr ;
* next = cast ( zpl_uintptr ) curr + actual_block_size ;
curr = zpl_pointer_add ( curr , actual_block_size ) ;
}
end = cast ( zpl_uintptr * ) curr ;
* end = cast ( zpl_uintptr ) NULL ;
pool - > free_list = pool - > physical_start ;
} break ;
case ZPL_ALLOCATION_RESIZE :
// NOTE: Cannot resize
ZPL_PANIC ( " You cannot resize something allocated by with a pool. " ) ;
break ;
}
return ptr ;
}
//
// Scratch Memory Allocator
//
void zpl_scratch_memory_init ( zpl_scratch_memory * s , void * start , zpl_isize size ) {
s - > physical_start = start ;
s - > total_size = size ;
s - > alloc_point = start ;
s - > free_point = start ;
}
zpl_b32 zpl_scratch_memory_is_in_use ( zpl_scratch_memory * s , void * ptr ) {
if ( s - > free_point = = s - > alloc_point ) return false ;
if ( s - > alloc_point > s - > free_point ) return ptr > = s - > free_point & & ptr < s - > alloc_point ;
return ptr > = s - > free_point | | ptr < s - > alloc_point ;
}
zpl_allocator zpl_scratch_allocator ( zpl_scratch_memory * s ) {
zpl_allocator a ;
a . proc = zpl_scratch_allocator_proc ;
a . data = s ;
return a ;
}
ZPL_ALLOCATOR_PROC ( zpl_scratch_allocator_proc ) {
zpl_scratch_memory * s = cast ( zpl_scratch_memory * ) allocator_data ;
void * ptr = NULL ;
ZPL_ASSERT_NOT_NULL ( s ) ;
switch ( type ) {
case ZPL_ALLOCATION_ALLOC : {
void * pt = s - > alloc_point ;
zpl_allocation_header_ev * header = cast ( zpl_allocation_header_ev * ) pt ;
void * data = zpl_align_forward ( header + 1 , alignment ) ;
void * end = zpl_pointer_add ( s - > physical_start , s - > total_size ) ;
ZPL_ASSERT ( alignment % 4 = = 0 ) ;
size = ( ( size + 3 ) / 4 ) * 4 ;
pt = zpl_pointer_add ( pt , size ) ;
// NOTE: Wrap around
if ( pt > end ) {
header - > size = zpl_pointer_diff ( header , end ) | ZPL_ISIZE_HIGH_BIT ;
pt = s - > physical_start ;
header = cast ( zpl_allocation_header_ev * ) pt ;
data = zpl_align_forward ( header + 1 , alignment ) ;
pt = zpl_pointer_add ( pt , size ) ;
}
if ( ! zpl_scratch_memory_is_in_use ( s , pt ) ) {
zpl_allocation_header_fill ( header , pt , zpl_pointer_diff ( header , pt ) ) ;
s - > alloc_point = cast ( zpl_u8 * ) pt ;
ptr = data ;
}
if ( flags & ZPL_ALLOCATOR_FLAG_CLEAR_TO_ZERO ) zpl_zero_size ( ptr , size ) ;
} break ;
case ZPL_ALLOCATION_FREE : {
if ( old_memory ) {
void * end = zpl_pointer_add ( s - > physical_start , s - > total_size ) ;
if ( old_memory < s - > physical_start | | old_memory > = end ) {
ZPL_ASSERT ( false ) ;
} else {
// NOTE: Mark as free
zpl_allocation_header_ev * h = zpl_allocation_header ( old_memory ) ;
ZPL_ASSERT ( ( h - > size & ZPL_ISIZE_HIGH_BIT ) = = 0 ) ;
h - > size = h - > size | ZPL_ISIZE_HIGH_BIT ;
while ( s - > free_point ! = s - > alloc_point ) {
zpl_allocation_header_ev * header = cast ( zpl_allocation_header_ev * ) s - > free_point ;
if ( ( header - > size & ZPL_ISIZE_HIGH_BIT ) = = 0 ) break ;
s - > free_point = zpl_pointer_add ( s - > free_point , h - > size & ( ~ ZPL_ISIZE_HIGH_BIT ) ) ;
if ( s - > free_point = = end ) s - > free_point = s - > physical_start ;
}
}
}
} break ;
case ZPL_ALLOCATION_FREE_ALL :
s - > alloc_point = s - > physical_start ;
s - > free_point = s - > physical_start ;
break ;
case ZPL_ALLOCATION_RESIZE :
ptr = zpl_default_resize_align ( zpl_scratch_allocator ( s ) , old_memory , old_size , size , alignment ) ;
break ;
}
return ptr ;
}
//
// Stack Memory Allocator
//
ZPL_ALLOCATOR_PROC ( zpl_stack_allocator_proc ) {
zpl_stack_memory * s = cast ( zpl_stack_memory * ) allocator_data ;
void * ptr = NULL ;
ZPL_ASSERT_NOT_NULL ( s ) ;
zpl_unused ( old_size ) ;
zpl_unused ( flags ) ;
switch ( type ) {
case ZPL_ALLOCATION_ALLOC : {
size + = ZPL_STACK_ALLOC_OFFSET ;
zpl_u64 alloc_offset = s - > allocated ;
void * curr =
cast ( zpl_u64 * ) zpl_align_forward ( cast ( zpl_u64 * ) zpl_pointer_add ( s - > physical_start , s - > allocated ) , alignment ) ;
if ( cast ( zpl_u64 * ) zpl_pointer_add ( curr , size ) > cast ( zpl_u64 * ) zpl_pointer_add ( s - > physical_start , s - > total_size ) ) {
if ( s - > backing . proc ) {
void * old_start = s - > physical_start ;
s - > physical_start =
zpl_resize_align ( s - > backing , s - > physical_start , s - > total_size , s - > total_size + size , alignment ) ;
curr = cast ( zpl_u64 * )
zpl_align_forward ( cast ( zpl_u64 * ) zpl_pointer_add ( s - > physical_start , s - > allocated ) , alignment ) ;
s - > total_size = zpl_pointer_diff ( old_start , s - > physical_start ) ;
} else {
ZPL_PANIC ( " Can not resize stack's memory! Allocator not defined! " ) ;
}
}
s - > allocated = zpl_pointer_diff ( s - > physical_start , curr ) + size ;
* ( zpl_u64 * ) curr = alloc_offset ;
curr = zpl_pointer_add ( curr , ZPL_STACK_ALLOC_OFFSET ) ;
ptr = curr ;
} break ;
case ZPL_ALLOCATION_FREE : {
if ( old_memory ) {
void * curr = old_memory ;
curr = zpl_pointer_sub ( curr , ZPL_STACK_ALLOC_OFFSET ) ;
zpl_u64 alloc_offset = * ( zpl_u64 * ) curr ;
s - > allocated = ( zpl_usize ) alloc_offset ;
}
} break ;
case ZPL_ALLOCATION_FREE_ALL : {
s - > allocated = 0 ;
} break ;
case ZPL_ALLOCATION_RESIZE : {
ZPL_PANIC ( " You cannot resize something allocated by a stack. " ) ;
} break ;
}
return ptr ;
}
ZPL_END_C_DECLS
// file: source/essentials/array.c
ZPL_BEGIN_C_DECLS
ZPL_NEVER_INLINE void * zpl__array_set_capacity ( void * array , zpl_isize capacity , zpl_isize element_size ) {
zpl_array_header * h = ZPL_ARRAY_HEADER ( array ) ;
ZPL_ASSERT ( element_size > 0 ) ;
if ( capacity = = h - > capacity ) return array ;
if ( capacity < h - > count ) {
if ( h - > capacity < capacity ) {
zpl_isize new_capacity = ZPL_ARRAY_GROW_FORMULA ( h - > capacity ) ;
if ( new_capacity < capacity ) new_capacity = capacity ;
zpl__array_set_capacity ( array , new_capacity , element_size ) ;
}
h - > count = capacity ;
}
{
zpl_isize size = zpl_size_of ( zpl_array_header ) + element_size * capacity ;
zpl_array_header * nh = cast ( zpl_array_header * ) zpl_alloc ( h - > allocator , size ) ;
zpl_memmove ( nh , h , zpl_size_of ( zpl_array_header ) + element_size * h - > count ) ;
nh - > allocator = h - > allocator ;
nh - > count = h - > count ;
nh - > data = ( char * ) nh + 1 ;
nh - > capacity = capacity ;
zpl_free ( h - > allocator , h ) ;
return nh + 1 ;
}
}
ZPL_END_C_DECLS
# if defined(ZPL_MODULE_CORE)
// file: source/core/memory_virtual.c
////////////////////////////////////////////////////////////////
//
// Virtual Memory
//
//
ZPL_BEGIN_C_DECLS
zpl_virtual_memory zpl_vm ( void * data , zpl_isize size ) {
zpl_virtual_memory vm ;
vm . data = data ;
vm . size = size ;
return vm ;
}
# if defined(ZPL_SYSTEM_WINDOWS)
zpl_virtual_memory zpl_vm_alloc ( void * addr , zpl_isize size ) {
zpl_virtual_memory vm ;
ZPL_ASSERT ( size > 0 ) ;
vm . data = VirtualAlloc ( addr , size , MEM_COMMIT | MEM_RESERVE , PAGE_READWRITE ) ;
vm . size = size ;
return vm ;
}
zpl_b32 zpl_vm_free ( zpl_virtual_memory vm ) {
MEMORY_BASIC_INFORMATION info ;
while ( vm . size > 0 ) {
if ( VirtualQuery ( vm . data , & info , zpl_size_of ( info ) ) = = 0 ) return false ;
if ( info . BaseAddress ! = vm . data | | info . AllocationBase ! = vm . data | | info . State ! = MEM_COMMIT | |
info . RegionSize > cast ( zpl_usize ) vm . size ) {
return false ;
}
if ( VirtualFree ( vm . data , 0 , MEM_RELEASE ) = = 0 ) return false ;
vm . data = zpl_pointer_add ( vm . data , info . RegionSize ) ;
vm . size - = info . RegionSize ;
}
return true ;
}
zpl_virtual_memory zpl_vm_trim ( zpl_virtual_memory vm , zpl_isize lead_size , zpl_isize size ) {
zpl_virtual_memory new_vm = { 0 } ;
void * ptr ;
ZPL_ASSERT ( vm . size > = lead_size + size ) ;
ptr = zpl_pointer_add ( vm . data , lead_size ) ;
zpl_vm_free ( vm ) ;
new_vm = zpl_vm_alloc ( ptr , size ) ;
if ( new_vm . data = = ptr ) return new_vm ;
if ( new_vm . data ) zpl_vm_free ( new_vm ) ;
return new_vm ;
}
zpl_b32 zpl_vm_purge ( zpl_virtual_memory vm ) {
VirtualAlloc ( vm . data , vm . size , MEM_RESET , PAGE_READWRITE ) ;
// NOTE: Can this really fail?
return true ;
}
zpl_isize zpl_virtual_memory_page_size ( zpl_isize * alignment_out ) {
SYSTEM_INFO info ;
GetSystemInfo ( & info ) ;
if ( alignment_out ) * alignment_out = info . dwAllocationGranularity ;
return info . dwPageSize ;
}
# else
# include <sys / mman.h>
# ifndef MAP_ANONYMOUS
# define MAP_ANONYMOUS MAP_ANON
# endif
zpl_virtual_memory zpl_vm_alloc ( void * addr , zpl_isize size ) {
zpl_virtual_memory vm ;
ZPL_ASSERT ( size > 0 ) ;
vm . data = mmap ( addr , size , PROT_READ | PROT_WRITE , MAP_ANONYMOUS | MAP_PRIVATE , - 1 , 0 ) ;
vm . size = size ;
return vm ;
}
zpl_b32 zpl_vm_free ( zpl_virtual_memory vm ) {
munmap ( vm . data , vm . size ) ;
return true ;
}
zpl_virtual_memory zpl_vm_trim ( zpl_virtual_memory vm , zpl_isize lead_size , zpl_isize size ) {
void * ptr ;
zpl_isize trail_size ;
ZPL_ASSERT ( vm . size > = lead_size + size ) ;
ptr = zpl_pointer_add ( vm . data , lead_size ) ;
trail_size = vm . size - lead_size - size ;
if ( lead_size ! = 0 ) zpl_vm_free ( zpl_vm ( vm . data , lead_size ) ) ;
if ( trail_size ! = 0 ) zpl_vm_free ( zpl_vm ( ptr , trail_size ) ) ;
return zpl_vm ( ptr , size ) ;
}
zpl_b32 zpl_vm_purge ( zpl_virtual_memory vm ) {
int err = madvise ( vm . data , vm . size , MADV_DONTNEED ) ;
return err ! = 0 ;
}
zpl_isize zpl_virtual_memory_page_size ( zpl_isize * alignment_out ) {
// TODO: Is this always true?
zpl_isize result = cast ( zpl_isize ) sysconf ( _SC_PAGE_SIZE ) ;
if ( alignment_out ) * alignment_out = result ;
return result ;
}
# endif
ZPL_END_C_DECLS
// file: source/core/string.c
////////////////////////////////////////////////////////////////
//
// Char things
//
//
ZPL_BEGIN_C_DECLS
zpl_internal zpl_isize zpl__scan_zpl_i64 ( const char * text , zpl_i32 base , zpl_i64 * value ) {
const char * text_begin = text ;
zpl_i64 result = 0 ;
zpl_b32 negative = false ;
if ( * text = = ' - ' ) {
negative = true ;
text + + ;
}
if ( base = = 16 & & zpl_strncmp ( text , " 0x " , 2 ) = = 0 ) text + = 2 ;
for ( ; ; ) {
zpl_i64 v ;
if ( zpl_char_is_digit ( * text ) )
v = * text - ' 0 ' ;
else if ( base = = 16 & & zpl_char_is_hex_digit ( * text ) )
v = zpl_hex_digit_to_int ( * text ) ;
else
break ;
result * = base ;
result + = v ;
text + + ;
}
if ( value ) {
if ( negative ) result = - result ;
* value = result ;
}
return ( text - text_begin ) ;
}
zpl_internal zpl_isize zpl__scan_zpl_u64 ( const char * text , zpl_i32 base , zpl_u64 * value ) {
const char * text_begin = text ;
zpl_u64 result = 0 ;
if ( base = = 16 & & zpl_strncmp ( text , " 0x " , 2 ) = = 0 ) text + = 2 ;
for ( ; ; ) {
zpl_u64 v ;
if ( zpl_char_is_digit ( * text ) )
v = * text - ' 0 ' ;
else if ( base = = 16 & & zpl_char_is_hex_digit ( * text ) )
v = zpl_hex_digit_to_int ( * text ) ;
else {
break ;
}
result * = base ;
result + = v ;
text + + ;
}
if ( value ) * value = result ;
return ( text - text_begin ) ;
}
// TODO: Make better
zpl_u64 zpl_str_to_u64 ( const char * str , char * * end_ptr , zpl_i32 base ) {
zpl_isize len ;
zpl_u64 value = 0 ;
if ( ! base ) {
if ( ( zpl_strlen ( str ) > 2 ) & & ( zpl_strncmp ( str , " 0x " , 2 ) = = 0 ) )
base = 16 ;
else
base = 10 ;
}
len = zpl__scan_zpl_u64 ( str , base , & value ) ;
if ( end_ptr ) * end_ptr = ( char * ) str + len ;
return value ;
}
zpl_i64 zpl_str_to_i64 ( const char * str , char * * end_ptr , zpl_i32 base ) {
zpl_isize len ;
zpl_i64 value ;
if ( ! base ) {
if ( ( zpl_strlen ( str ) > 2 ) & & ( zpl_strncmp ( str , " 0x " , 2 ) = = 0 ) )
base = 16 ;
else
base = 10 ;
}
len = zpl__scan_zpl_i64 ( str , base , & value ) ;
if ( end_ptr ) * end_ptr = ( char * ) str + len ;
return value ;
}
// TODO: Are these good enough for characters?
zpl_global const char zpl__num_to_char_table [ ] = " 0123456789 "
" ABCDEFGHIJKLMNOPQRSTUVWXYZ "
" abcdefghijklmnopqrstuvwxyz "
" @$ " ;
void zpl_i64_to_str ( zpl_i64 value , char * string , zpl_i32 base ) {
char * buf = string ;
zpl_b32 negative = false ;
zpl_u64 v ;
if ( value < 0 ) {
negative = true ;
value = - value ;
}
v = cast ( zpl_u64 ) value ;
if ( v ! = 0 ) {
while ( v > 0 ) {
* buf + + = zpl__num_to_char_table [ v % base ] ;
v / = base ;
}
} else {
* buf + + = ' 0 ' ;
}
if ( negative ) * buf + + = ' - ' ;
* buf = ' \0 ' ;
zpl_strrev ( string ) ;
}
void zpl_u64_to_str ( zpl_u64 value , char * string , zpl_i32 base ) {
char * buf = string ;
if ( value ) {
while ( value > 0 ) {
* buf + + = zpl__num_to_char_table [ value % base ] ;
value / = base ;
}
} else {
* buf + + = ' 0 ' ;
}
* buf = ' \0 ' ;
zpl_strrev ( string ) ;
}
zpl_f64 zpl_str_to_f64 ( const char * str , char * * end_ptr ) {
zpl_f64 result , value , sign , scale ;
zpl_i32 frac ;
while ( zpl_char_is_space ( * str ) ) { str + + ; }
sign = 1.0 ;
if ( * str = = ' - ' ) {
sign = - 1.0 ;
str + + ;
} else if ( * str = = ' + ' ) {
str + + ;
}
for ( value = 0.0 ; zpl_char_is_digit ( * str ) ; str + + ) { value = value * 10.0 + ( * str - ' 0 ' ) ; }
if ( * str = = ' . ' ) {
zpl_f64 pow10 = 10.0 ;
str + + ;
while ( zpl_char_is_digit ( * str ) ) {
value + = ( * str - ' 0 ' ) / pow10 ;
pow10 * = 10.0 ;
str + + ;
}
}
frac = 0 ;
scale = 1.0 ;
if ( ( * str = = ' e ' ) | | ( * str = = ' E ' ) ) {
zpl_u32 exp ;
str + + ;
if ( * str = = ' - ' ) {
frac = 1 ;
str + + ;
} else if ( * str = = ' + ' ) {
str + + ;
}
for ( exp = 0 ; zpl_char_is_digit ( * str ) ; str + + ) { exp = exp * 10 + ( * str - ' 0 ' ) ; }
if ( exp > 308 ) exp = 308 ;
while ( exp > = 50 ) {
scale * = 1e50 ;
exp - = 50 ;
}
while ( exp > = 8 ) {
scale * = 1e8 ;
exp - = 8 ;
}
while ( exp > 0 ) {
scale * = 10.0 ;
exp - = 1 ;
}
}
result = sign * ( frac ? ( value / scale ) : ( value * scale ) ) ;
if ( end_ptr ) * end_ptr = cast ( char * ) str ;
return result ;
}
////////////////////////////////////////////////////////////////
//
// Windows UTF-8 Handling
//
//
zpl_u16 * zpl_utf8_to_ucs2 ( zpl_u16 * buffer , zpl_isize len , zpl_u8 const * str ) {
zpl_rune c ;
zpl_isize i = 0 ;
len - - ;
while ( * str ) {
if ( i > = len ) return NULL ;
if ( ! ( * str & 0x80 ) ) {
buffer [ i + + ] = * str + + ;
} else if ( ( * str & 0xe0 ) = = 0xc0 ) {
if ( * str < 0xc2 ) return NULL ;
c = ( * str + + & 0x1f ) < < 6 ;
if ( ( * str & 0xc0 ) ! = 0x80 ) return NULL ;
buffer [ i + + ] = cast ( zpl_u16 ) ( c + ( * str + + & 0x3f ) ) ;
} else if ( ( * str & 0xf0 ) = = 0xe0 ) {
if ( * str = = 0xe0 & & ( str [ 1 ] < 0xa0 | | str [ 1 ] > 0xbf ) ) return NULL ;
if ( * str = = 0xed & & str [ 1 ] > 0x9f ) // str[1] < 0x80 is checked below
return NULL ;
c = ( * str + + & 0x0f ) < < 12 ;
if ( ( * str & 0xc0 ) ! = 0x80 ) return NULL ;
c + = ( * str + + & 0x3f ) < < 6 ;
if ( ( * str & 0xc0 ) ! = 0x80 ) return NULL ;
buffer [ i + + ] = cast ( zpl_u16 ) ( c + ( * str + + & 0x3f ) ) ;
} else if ( ( * str & 0xf8 ) = = 0xf0 ) {
if ( * str > 0xf4 ) return NULL ;
if ( * str = = 0xf0 & & ( str [ 1 ] < 0x90 | | str [ 1 ] > 0xbf ) ) return NULL ;
if ( * str = = 0xf4 & & str [ 1 ] > 0x8f ) // str[1] < 0x80 is checked below
return NULL ;
c = ( * str + + & 0x07 ) < < 18 ;
if ( ( * str & 0xc0 ) ! = 0x80 ) return NULL ;
c + = ( * str + + & 0x3f ) < < 12 ;
if ( ( * str & 0xc0 ) ! = 0x80 ) return NULL ;
c + = ( * str + + & 0x3f ) < < 6 ;
if ( ( * str & 0xc0 ) ! = 0x80 ) return NULL ;
c + = ( * str + + & 0x3f ) ;
// UTF-8 encodings of values used in surrogate pairs are invalid
if ( ( c & 0xfffff800 ) = = 0xd800 ) return NULL ;
if ( c > = 0x10000 ) {
c - = 0x10000 ;
if ( i + 2 > len ) return NULL ;
buffer [ i + + ] = 0xd800 | ( 0x3ff & ( c > > 10 ) ) ;
buffer [ i + + ] = 0xdc00 | ( 0x3ff & ( c ) ) ;
}
} else {
return NULL ;
}
}
buffer [ i ] = 0 ;
return buffer ;
}
zpl_u8 * zpl_ucs2_to_utf8 ( zpl_u8 * buffer , zpl_isize len , zpl_u16 const * str ) {
zpl_isize i = 0 ;
len - - ;
while ( * str ) {
if ( * str < 0x80 ) {
if ( i + 1 > len ) return NULL ;
buffer [ i + + ] = ( char ) * str + + ;
} else if ( * str < 0x800 ) {
if ( i + 2 > len ) return NULL ;
buffer [ i + + ] = cast ( char ) ( 0xc0 + ( * str > > 6 ) ) ;
buffer [ i + + ] = cast ( char ) ( 0x80 + ( * str & 0x3f ) ) ;
str + = 1 ;
} else if ( * str > = 0xd800 & & * str < 0xdc00 ) {
zpl_rune c ;
if ( i + 4 > len ) return NULL ;
c = ( ( str [ 0 ] - 0xd800 ) < < 10 ) + ( ( str [ 1 ] ) - 0xdc00 ) + 0x10000 ;
buffer [ i + + ] = cast ( char ) ( 0xf0 + ( c > > 18 ) ) ;
buffer [ i + + ] = cast ( char ) ( 0x80 + ( ( c > > 12 ) & 0x3f ) ) ;
buffer [ i + + ] = cast ( char ) ( 0x80 + ( ( c > > 6 ) & 0x3f ) ) ;
buffer [ i + + ] = cast ( char ) ( 0x80 + ( ( c ) & 0x3f ) ) ;
str + = 2 ;
} else if ( * str > = 0xdc00 & & * str < 0xe000 ) {
return NULL ;
} else {
if ( i + 3 > len ) return NULL ;
buffer [ i + + ] = 0xe0 + ( * str > > 12 ) ;
buffer [ i + + ] = 0x80 + ( ( * str > > 6 ) & 0x3f ) ;
buffer [ i + + ] = 0x80 + ( ( * str ) & 0x3f ) ;
str + = 1 ;
}
}
buffer [ i ] = 0 ;
return buffer ;
}
zpl_u16 * zpl_utf8_to_ucs2_buf ( zpl_u8 const * str ) { // NOTE: Uses locally persisting buffer
zpl_local_persist zpl_u16 buf [ 4096 ] ;
return zpl_utf8_to_ucs2 ( buf , zpl_count_of ( buf ) , str ) ;
}
zpl_u8 * zpl_ucs2_to_utf8_buf ( zpl_u16 const * str ) { // NOTE: Uses locally persisting buffer
zpl_local_persist zpl_u8 buf [ 4096 ] ;
return zpl_ucs2_to_utf8 ( buf , zpl_count_of ( buf ) , str ) ;
}
zpl_global zpl_u8 const zpl__utf8_first [ 256 ] = {
0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , // 0x00-0x0F
0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , // 0x10-0x1F
0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , // 0x20-0x2F
0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , // 0x30-0x3F
0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , // 0x40-0x4F
0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , // 0x50-0x5F
0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , // 0x60-0x6F
0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , 0xf0 , // 0x70-0x7F
0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , // 0x80-0x8F
0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , // 0x90-0x9F
0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , // 0xA0-0xAF
0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , // 0xB0-0xBF
0xf1 , 0xf1 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , // 0xC0-0xCF
0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , // 0xD0-0xDF
0x13 , 0x03 , 0x03 , 0x03 , 0x03 , 0x03 , 0x03 , 0x03 , 0x03 , 0x03 , 0x03 , 0x03 , 0x03 , 0x23 , 0x03 , 0x03 , // 0xE0-0xEF
0x34 , 0x04 , 0x04 , 0x04 , 0x44 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , // 0xF0-0xFF
} ;
typedef struct zpl_utf8_accept_range {
zpl_u8 lo , hi ;
} zpl_utf8_accept_range ;
zpl_global zpl_utf8_accept_range const zpl__utf8_accept_ranges [ ] = {
{ 0x80 , 0xbf } , { 0xa0 , 0xbf } , { 0x80 , 0x9f } , { 0x90 , 0xbf } , { 0x80 , 0x8f } ,
} ;
zpl_isize zpl_utf8_decode ( zpl_u8 const * str , zpl_isize str_len , zpl_rune * codepoint_out ) {
zpl_isize width = 0 ;
zpl_rune codepoint = ZPL_RUNE_INVALID ;
if ( str_len > 0 ) {
zpl_u8 s0 = str [ 0 ] ;
zpl_u8 x = zpl__utf8_first [ s0 ] , sz ;
zpl_u8 b1 , b2 , b3 ;
zpl_utf8_accept_range accept ;
if ( x > = 0xf0 ) {
zpl_rune mask = ( cast ( zpl_rune ) x < < 31 ) > > 31 ;
codepoint = ( cast ( zpl_rune ) s0 & ( ~ mask ) ) | ( ZPL_RUNE_INVALID & mask ) ;
width = 1 ;
goto end ;
}
if ( s0 < 0x80 ) {
codepoint = s0 ;
width = 1 ;
goto end ;
}
sz = x & 7 ;
accept = zpl__utf8_accept_ranges [ x > > 4 ] ;
if ( str_len < sz ) goto invalid_codepoint ;
b1 = str [ 1 ] ;
if ( b1 < accept . lo | | accept . hi < b1 ) goto invalid_codepoint ;
if ( sz = = 2 ) {
codepoint = ( cast ( zpl_rune ) s0 & 0x1f ) < < 6 | ( cast ( zpl_rune ) b1 & 0x3f ) ;
width = 2 ;
goto end ;
}
b2 = str [ 2 ] ;
if ( ! zpl_is_between ( b2 , 0x80 , 0xbf ) ) goto invalid_codepoint ;
if ( sz = = 3 ) {
codepoint = ( cast ( zpl_rune ) s0 & 0x1f ) < < 12 | ( cast ( zpl_rune ) b1 & 0x3f ) < < 6 | ( cast ( zpl_rune ) b2 & 0x3f ) ;
width = 3 ;
goto end ;
}
b3 = str [ 3 ] ;
if ( ! zpl_is_between ( b3 , 0x80 , 0xbf ) ) goto invalid_codepoint ;
codepoint = ( cast ( zpl_rune ) s0 & 0x07 ) < < 18 | ( cast ( zpl_rune ) b1 & 0x3f ) < < 12 | ( cast ( zpl_rune ) b2 & 0x3f ) < < 6 |
( cast ( zpl_rune ) b3 & 0x3f ) ;
width = 4 ;
goto end ;
invalid_codepoint :
codepoint = ZPL_RUNE_INVALID ;
width = 1 ;
}
end :
if ( codepoint_out ) * codepoint_out = codepoint ;
return width ;
}
zpl_isize zpl_utf8_codepoint_size ( zpl_u8 const * str , zpl_isize str_len ) {
zpl_isize i = 0 ;
for ( ; i < str_len & & str [ i ] ; i + + ) {
if ( ( str [ i ] & 0xc0 ) ! = 0x80 ) break ;
}
return i + 1 ;
}
zpl_isize zpl_utf8_encode_rune ( zpl_u8 buf [ 4 ] , zpl_rune r ) {
zpl_u32 i = cast ( zpl_u32 ) r ;
zpl_u8 mask = 0x3f ;
if ( i < = ( 1 < < 7 ) - 1 ) {
buf [ 0 ] = cast ( zpl_u8 ) r ;
return 1 ;
}
if ( i < = ( 1 < < 11 ) - 1 ) {
buf [ 0 ] = 0xc0 | cast ( zpl_u8 ) ( r > > 6 ) ;
buf [ 1 ] = 0x80 | ( cast ( zpl_u8 ) ( r ) & mask ) ;
return 2 ;
}
// Invalid or Surrogate range
if ( i > ZPL_RUNE_MAX | | zpl_is_between ( i , 0xd800 , 0xdfff ) ) {
r = ZPL_RUNE_INVALID ;
buf [ 0 ] = 0xe0 | cast ( zpl_u8 ) ( r > > 12 ) ;
buf [ 1 ] = 0x80 | ( cast ( zpl_u8 ) ( r > > 6 ) & mask ) ;
buf [ 2 ] = 0x80 | ( cast ( zpl_u8 ) ( r ) & mask ) ;
return 3 ;
}
if ( i < = ( 1 < < 16 ) - 1 ) {
buf [ 0 ] = 0xe0 | cast ( zpl_u8 ) ( r > > 12 ) ;
buf [ 1 ] = 0x80 | ( cast ( zpl_u8 ) ( r > > 6 ) & mask ) ;
buf [ 2 ] = 0x80 | ( cast ( zpl_u8 ) ( r ) & mask ) ;
return 3 ;
}
buf [ 0 ] = 0xf0 | cast ( zpl_u8 ) ( r > > 18 ) ;
buf [ 1 ] = 0x80 | ( cast ( zpl_u8 ) ( r > > 12 ) & mask ) ;
buf [ 2 ] = 0x80 | ( cast ( zpl_u8 ) ( r > > 6 ) & mask ) ;
buf [ 3 ] = 0x80 | ( cast ( zpl_u8 ) ( r ) & mask ) ;
return 4 ;
}
ZPL_END_C_DECLS
// file: source/core/stringlib.c
ZPL_BEGIN_C_DECLS
zpl_string zpl_string_make_reserve ( zpl_allocator a , zpl_isize capacity ) {
zpl_isize header_size = zpl_size_of ( zpl_string_header ) ;
void * ptr = zpl_alloc ( a , header_size + capacity + 1 ) ;
zpl_string str ;
zpl_string_header * header ;
if ( ptr = = NULL ) return NULL ;
zpl_zero_size ( ptr , header_size + capacity + 1 ) ;
str = cast ( char * ) ptr + header_size ;
header = ZPL_STRING_HEADER ( str ) ;
header - > allocator = a ;
header - > length = 0 ;
header - > capacity = capacity ;
str [ capacity ] = ' \0 ' ;
return str ;
}
zpl_string zpl_string_make_length ( zpl_allocator a , void const * init_str , zpl_isize num_bytes ) {
zpl_isize header_size = zpl_size_of ( zpl_string_header ) ;
void * ptr = zpl_alloc ( a , header_size + num_bytes + 1 ) ;
zpl_string str ;
zpl_string_header * header ;
if ( ptr = = NULL ) return NULL ;
if ( ! init_str ) zpl_zero_size ( ptr , header_size + num_bytes + 1 ) ;
str = cast ( char * ) ptr + header_size ;
header = ZPL_STRING_HEADER ( str ) ;
header - > allocator = a ;
header - > length = num_bytes ;
header - > capacity = num_bytes ;
if ( num_bytes & & init_str ) zpl_memcopy ( str , init_str , num_bytes ) ;
str [ num_bytes ] = ' \0 ' ;
return str ;
}
zpl_string zpl_string_sprintf_buf ( zpl_allocator a , const char * fmt , . . . ) {
zpl_local_persist zpl_thread_local char buf [ ZPL_PRINTF_MAXLEN ] = { 0 } ;
va_list va ;
va_start ( va , fmt ) ;
zpl_snprintf_va ( buf , ZPL_PRINTF_MAXLEN , fmt , va ) ;
va_end ( va ) ;
return zpl_string_make ( a , buf ) ;
}
zpl_string zpl_string_sprintf ( zpl_allocator a , char * buf , zpl_isize num_bytes , const char * fmt , . . . ) {
va_list va ;
va_start ( va , fmt ) ;
zpl_snprintf_va ( buf , num_bytes , fmt , va ) ;
va_end ( va ) ;
return zpl_string_make ( a , buf ) ;
}
zpl_string zpl_string_append_length ( zpl_string str , void const * other , zpl_isize other_len ) {
if ( other_len > 0 ) {
zpl_isize curr_len = zpl_string_length ( str ) ;
str = zpl_string_make_space_for ( str , other_len ) ;
if ( str = = NULL ) return NULL ;
zpl_memcopy ( str + curr_len , other , other_len ) ;
str [ curr_len + other_len ] = ' \0 ' ;
zpl__set_string_length ( str , curr_len + other_len ) ;
}
return str ;
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_ALWAYS_INLINE zpl_string zpl_string_appendc ( zpl_string str , const char * other ) {
return zpl_string_append_length ( str , other , zpl_strlen ( other ) ) ;
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_ALWAYS_INLINE zpl_string zpl_string_join ( zpl_allocator a , const char * * parts , zpl_isize count , const char * glue ) {
zpl_string ret ;
zpl_isize i ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ret = zpl_string_make ( a , NULL ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
for ( i = 0 ; i < count ; + + i ) {
ret = zpl_string_appendc ( ret , parts [ i ] ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
if ( ( i + 1 ) < count ) {
ret = zpl_string_appendc ( ret , glue ) ;
}
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
return ret ;
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
zpl_string zpl_string_set ( zpl_string str , const char * cstr ) {
zpl_isize len = zpl_strlen ( cstr ) ;
if ( zpl_string_capacity ( str ) < len ) {
str = zpl_string_make_space_for ( str , len - zpl_string_length ( str ) ) ;
if ( str = = NULL ) return NULL ;
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
zpl_memcopy ( str , cstr , len ) ;
str [ len ] = ' \0 ' ;
zpl__set_string_length ( str , len ) ;
return str ;
}
zpl_string zpl_string_make_space_for ( zpl_string str , zpl_isize add_len ) {
zpl_isize available = zpl_string_available_space ( str ) ;
// NOTE: Return if there is enough space left
if ( available > = add_len ) {
return str ;
} else {
zpl_isize new_len , old_size , new_size ;
void * ptr , * new_ptr ;
zpl_allocator a = ZPL_STRING_HEADER ( str ) - > allocator ;
zpl_string_header * header ;
new_len = zpl_string_length ( str ) + add_len ;
ptr = ZPL_STRING_HEADER ( str ) ;
old_size = zpl_size_of ( zpl_string_header ) + zpl_string_length ( str ) + 1 ;
new_size = zpl_size_of ( zpl_string_header ) + new_len + 1 ;
new_ptr = zpl_resize ( a , ptr , old_size , new_size ) ;
if ( new_ptr = = NULL ) return NULL ;
header = cast ( zpl_string_header * ) new_ptr ;
header - > allocator = a ;
str = cast ( zpl_string ) ( header + 1 ) ;
zpl__set_string_capacity ( str , new_len ) ;
return str ;
}
}
zpl_isize zpl_string_allocation_size ( zpl_string const str ) {
zpl_isize cap = zpl_string_capacity ( str ) ;
return zpl_size_of ( zpl_string_header ) + cap ;
}
zpl_b32 zpl_string_are_equal ( zpl_string const lhs , zpl_string const rhs ) {
zpl_isize lhs_len , rhs_len , i ;
lhs_len = zpl_string_length ( lhs ) ;
rhs_len = zpl_string_length ( rhs ) ;
if ( lhs_len ! = rhs_len ) return false ;
for ( i = 0 ; i < lhs_len ; i + + ) {
if ( lhs [ i ] ! = rhs [ i ] ) return false ;
}
return true ;
}
zpl_string zpl_string_trim ( zpl_string str , const char * cut_set ) {
char * start , * end , * start_pos , * end_pos ;
zpl_isize len ;
start_pos = start = str ;
end_pos = end = str + zpl_string_length ( str ) - 1 ;
while ( start_pos < = end & & zpl_char_first_occurence ( cut_set , * start_pos ) ) start_pos + + ;
while ( end_pos > start_pos & & zpl_char_first_occurence ( cut_set , * end_pos ) ) end_pos - - ;
len = cast ( zpl_isize ) ( ( start_pos > end_pos ) ? 0 : ( ( end_pos - start_pos ) + 1 ) ) ;
if ( str ! = start_pos ) zpl_memmove ( str , start_pos , len ) ;
str [ len ] = ' \0 ' ;
zpl__set_string_length ( str , len ) ;
return str ;
}
zpl_string zpl_string_append_rune ( zpl_string str , zpl_rune r ) {
if ( r > = 0 ) {
zpl_u8 buf [ 8 ] = { 0 } ;
zpl_isize len = zpl_utf8_encode_rune ( buf , r ) ;
return zpl_string_append_length ( str , buf , len ) ;
}
return str ;
}
zpl_string zpl_string_append_fmt ( zpl_string str , const char * fmt , . . . ) {
zpl_isize res ;
char buf [ ZPL_PRINTF_MAXLEN ] = { 0 } ;
va_list va ;
va_start ( va , fmt ) ;
res = zpl_snprintf_va ( buf , zpl_count_of ( buf ) - 1 , fmt , va ) - 1 ;
va_end ( va ) ;
return zpl_string_append_length ( str , buf , res ) ;
}
ZPL_END_C_DECLS
// file: source/core/file.c
////////////////////////////////////////////////////////////////
//
// File Handling
//
//
# include <sys/stat.h>
# ifdef ZPL_SYSTEM_MACOS
# include <copyfile.h>
# endif
# ifdef ZPL_SYSTEM_CYGWIN
# include <windows.h>
# endif
# if defined(ZPL_SYSTEM_WINDOWS) && !defined(ZPL_COMPILER_GCC)
# include <io.h>
# endif
ZPL_BEGIN_C_DECLS
# if defined(ZPL_SYSTEM_WINDOWS) || defined (ZPL_SYSTEM_CYGWIN)
zpl_internal wchar_t * zpl__alloc_utf8_to_ucs2 ( zpl_allocator a , char const * text , zpl_isize * w_len_ ) {
wchar_t * w_text = NULL ;
zpl_isize len = 0 , w_len = 0 , w_len1 = 0 ;
if ( text = = NULL ) {
if ( w_len_ ) * w_len_ = w_len ;
return NULL ;
}
len = zpl_strlen ( text ) ;
if ( len = = 0 ) {
if ( w_len_ ) * w_len_ = w_len ;
return NULL ;
}
w_len = MultiByteToWideChar ( CP_UTF8 , MB_ERR_INVALID_CHARS , text , cast ( int ) len , NULL , 0 ) ;
if ( w_len = = 0 ) {
if ( w_len_ ) * w_len_ = w_len ;
return NULL ;
}
w_text = zpl_alloc_array ( a , wchar_t , w_len + 1 ) ;
w_len1 = MultiByteToWideChar ( CP_UTF8 , MB_ERR_INVALID_CHARS , text , cast ( int ) len , w_text , cast ( int ) w_len ) ;
if ( w_len1 = = 0 ) {
zpl_free ( a , w_text ) ;
if ( w_len_ ) * w_len_ = 0 ;
return NULL ;
}
w_text [ w_len ] = 0 ;
if ( w_len_ ) * w_len_ = w_len ;
return w_text ;
}
zpl_internal ZPL_FILE_SEEK_PROC ( zpl__win32_file_seek ) {
LARGE_INTEGER li_offset ;
li_offset . QuadPart = offset ;
if ( ! SetFilePointerEx ( fd . p , li_offset , & li_offset , whence ) ) { return false ; }
if ( new_offset ) * new_offset = li_offset . QuadPart ;
return true ;
}
zpl_internal ZPL_FILE_READ_AT_PROC ( zpl__win32_file_read ) {
zpl_unused ( stop_at_newline ) ;
zpl_b32 result = false ;
zpl__win32_file_seek ( fd , offset , ZPL_SEEK_WHENCE_BEGIN , NULL ) ;
DWORD size_ = cast ( DWORD ) ( size > ZPL_I32_MAX ? ZPL_I32_MAX : size ) ;
DWORD bytes_read_ ;
if ( ReadFile ( fd . p , buffer , size_ , & bytes_read_ , NULL ) ) {
if ( bytes_read ) * bytes_read = bytes_read_ ;
result = true ;
}
return result ;
}
zpl_internal ZPL_FILE_WRITE_AT_PROC ( zpl__win32_file_write ) {
DWORD size_ = cast ( DWORD ) ( size > ZPL_I32_MAX ? ZPL_I32_MAX : size ) ;
DWORD bytes_written_ ;
zpl__win32_file_seek ( fd , offset , ZPL_SEEK_WHENCE_BEGIN , NULL ) ;
if ( WriteFile ( fd . p , buffer , size_ , & bytes_written_ , NULL ) ) {
if ( bytes_written ) * bytes_written = bytes_written_ ;
return true ;
}
return false ;
}
zpl_internal ZPL_FILE_CLOSE_PROC ( zpl__win32_file_close ) { CloseHandle ( fd . p ) ; }
zpl_file_operations const zpl_default_file_operations = { zpl__win32_file_read , zpl__win32_file_write ,
zpl__win32_file_seek , zpl__win32_file_close } ;
ZPL_NEVER_INLINE ZPL_FILE_OPEN_PROC ( zpl__win32_file_open ) {
DWORD desired_access ;
DWORD creation_disposition ;
void * handle ;
wchar_t * w_text ;
switch ( mode & ZPL_FILE_MODES ) {
case ZPL_FILE_MODE_READ :
desired_access = GENERIC_READ ;
creation_disposition = OPEN_EXISTING ;
break ;
case ZPL_FILE_MODE_WRITE :
desired_access = GENERIC_WRITE ;
creation_disposition = CREATE_ALWAYS ;
break ;
case ZPL_FILE_MODE_APPEND :
desired_access = GENERIC_WRITE ;
creation_disposition = OPEN_ALWAYS ;
break ;
case ZPL_FILE_MODE_READ | ZPL_FILE_MODE_RW :
desired_access = GENERIC_READ | GENERIC_WRITE ;
creation_disposition = OPEN_EXISTING ;
break ;
case ZPL_FILE_MODE_WRITE | ZPL_FILE_MODE_RW :
desired_access = GENERIC_READ | GENERIC_WRITE ;
creation_disposition = CREATE_ALWAYS ;
break ;
case ZPL_FILE_MODE_APPEND | ZPL_FILE_MODE_RW :
desired_access = GENERIC_READ | GENERIC_WRITE ;
creation_disposition = OPEN_ALWAYS ;
break ;
default : ZPL_PANIC ( " Invalid file mode " ) ; return ZPL_FILE_ERROR_INVALID ;
}
w_text = zpl__alloc_utf8_to_ucs2 ( zpl_heap_allocator ( ) , filename , NULL ) ;
handle = CreateFileW ( w_text , desired_access , FILE_SHARE_READ | FILE_SHARE_DELETE , NULL , creation_disposition ,
FILE_ATTRIBUTE_NORMAL , NULL ) ;
zpl_free ( zpl_heap_allocator ( ) , w_text ) ;
if ( handle = = INVALID_HANDLE_VALUE ) {
DWORD err = GetLastError ( ) ;
switch ( err ) {
case ERROR_FILE_NOT_FOUND : return ZPL_FILE_ERROR_NOT_EXISTS ;
case ERROR_FILE_EXISTS : return ZPL_FILE_ERROR_EXISTS ;
case ERROR_ALREADY_EXISTS : return ZPL_FILE_ERROR_EXISTS ;
case ERROR_ACCESS_DENIED : return ZPL_FILE_ERROR_PERMISSION ;
}
return ZPL_FILE_ERROR_INVALID ;
}
if ( mode & ZPL_FILE_MODE_APPEND ) {
LARGE_INTEGER offset = { 0 } ;
if ( ! SetFilePointerEx ( handle , offset , NULL , ZPL_SEEK_WHENCE_END ) ) {
CloseHandle ( handle ) ;
return ZPL_FILE_ERROR_INVALID ;
}
}
fd - > p = handle ;
* ops = zpl_default_file_operations ;
return ZPL_FILE_ERROR_NONE ;
}
# else // POSIX
# include <fcntl.h>
zpl_internal ZPL_FILE_SEEK_PROC ( zpl__posix_file_seek ) {
# if defined(ZPL_SYSTEM_OSX)
zpl_i64 res = lseek ( fd . i , offset , whence ) ;
# else // TODO(ZaKlaus): @fixme lseek64
zpl_i64 res = lseek ( fd . i , offset , whence ) ;
# endif
if ( res < 0 ) return false ;
if ( new_offset ) * new_offset = res ;
return true ;
}
zpl_internal ZPL_FILE_READ_AT_PROC ( zpl__posix_file_read ) {
zpl_unused ( stop_at_newline ) ;
zpl_isize res = pread ( fd . i , buffer , size , offset ) ;
if ( res < 0 ) return false ;
if ( bytes_read ) * bytes_read = res ;
return true ;
}
zpl_internal ZPL_FILE_WRITE_AT_PROC ( zpl__posix_file_write ) {
zpl_isize res ;
zpl_i64 curr_offset = 0 ;
zpl__posix_file_seek ( fd , 0 , ZPL_SEEK_WHENCE_CURRENT , & curr_offset ) ;
if ( curr_offset = = offset ) {
// NOTE: Writing to stdout et al. doesn't like pwrite for numerous reasons
res = write ( cast ( int ) fd . i , buffer , size ) ;
} else {
res = pwrite ( cast ( int ) fd . i , buffer , size , offset ) ;
}
if ( res < 0 ) return false ;
if ( bytes_written ) * bytes_written = res ;
return true ;
}
zpl_internal ZPL_FILE_CLOSE_PROC ( zpl__posix_file_close ) { close ( fd . i ) ; }
zpl_file_operations const zpl_default_file_operations = { zpl__posix_file_read , zpl__posix_file_write ,
zpl__posix_file_seek , zpl__posix_file_close } ;
ZPL_NEVER_INLINE ZPL_FILE_OPEN_PROC ( zpl__posix_file_open ) {
zpl_i32 os_mode ;
switch ( mode & ZPL_FILE_MODES ) {
case ZPL_FILE_MODE_READ : os_mode = O_RDONLY ; break ;
case ZPL_FILE_MODE_WRITE : os_mode = O_WRONLY | O_CREAT | O_TRUNC ; break ;
case ZPL_FILE_MODE_APPEND : os_mode = O_WRONLY | O_APPEND | O_CREAT ; break ;
case ZPL_FILE_MODE_READ | ZPL_FILE_MODE_RW : os_mode = O_RDWR ; break ;
case ZPL_FILE_MODE_WRITE | ZPL_FILE_MODE_RW : os_mode = O_RDWR | O_CREAT | O_TRUNC ; break ;
case ZPL_FILE_MODE_APPEND | ZPL_FILE_MODE_RW : os_mode = O_RDWR | O_APPEND | O_CREAT ; break ;
default : ZPL_PANIC ( " Invalid file mode " ) ; return ZPL_FILE_ERROR_INVALID ;
}
fd - > i = open ( filename , os_mode , S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH ) ;
if ( fd - > i < 0 ) {
// TODO: More file errors
return ZPL_FILE_ERROR_INVALID ;
}
* ops = zpl_default_file_operations ;
return ZPL_FILE_ERROR_NONE ;
}
# endif
zpl_file_error zpl_file_new ( zpl_file * f , zpl_file_descriptor fd , zpl_file_operations ops , char const * filename ) {
zpl_file_error err = ZPL_FILE_ERROR_NONE ;
zpl_isize len = zpl_strlen ( filename ) ;
f - > ops = ops ;
f - > fd = fd ;
f - > dir = NULL ;
f - > last_write_time = 0 ;
f - > filename = zpl_alloc_array ( zpl_heap_allocator ( ) , char , len + 1 ) ;
zpl_memcopy ( cast ( char * ) f - > filename , cast ( char * ) filename , len + 1 ) ;
return err ;
}
zpl_file_error zpl_file_open_mode ( zpl_file * f , zpl_file_mode mode , char const * filename ) {
zpl_file file_ = { 0 } ;
* f = file_ ;
zpl_file_error err ;
# if defined(ZPL_SYSTEM_WINDOWS) || defined(ZPL_SYSTEM_CYGWIN)
err = zpl__win32_file_open ( & f - > fd , & f - > ops , mode , filename ) ;
# else
err = zpl__posix_file_open ( & f - > fd , & f - > ops , mode , filename ) ;
# endif
if ( err = = ZPL_FILE_ERROR_NONE ) return zpl_file_new ( f , f - > fd , f - > ops , filename ) ;
return err ;
}
zpl_internal void zpl__dirinfo_free_entry ( zpl_dir_entry * entry ) ;
zpl_file_error zpl_file_close ( zpl_file * f ) {
if ( ! f ) return ZPL_FILE_ERROR_INVALID ;
if ( f - > filename ) zpl_free ( zpl_heap_allocator ( ) , cast ( char * ) f - > filename ) ;
# if defined(ZPL_SYSTEM_WINDOWS)
if ( f - > fd . p = = INVALID_HANDLE_VALUE ) return ZPL_FILE_ERROR_INVALID ;
# else
if ( f - > fd . i < 0 ) return ZPL_FILE_ERROR_INVALID ;
# endif
if ( f - > is_temp )
{
f - > ops . close ( f - > fd ) ;
return ZPL_FILE_ERROR_NONE ;
}
if ( ! f - > ops . read_at ) f - > ops = zpl_default_file_operations ;
f - > ops . close ( f - > fd ) ;
if ( f - > dir ) {
zpl__dirinfo_free_entry ( f - > dir ) ;
zpl_mfree ( f - > dir ) ;
f - > dir = NULL ;
}
return ZPL_FILE_ERROR_NONE ;
}
zpl_file_error zpl_file_create ( zpl_file * f , char const * filename ) {
return zpl_file_open_mode ( f , ZPL_FILE_MODE_WRITE | ZPL_FILE_MODE_RW , filename ) ;
}
zpl_file_error zpl_file_open ( zpl_file * f , char const * filename ) {
return zpl_file_open_mode ( f , ZPL_FILE_MODE_READ , filename ) ;
}
char const * zpl_file_name ( zpl_file * f ) { return f - > filename ? f - > filename : " " ; }
zpl_b32 zpl_file_has_changed ( zpl_file * f ) {
if ( f - > is_temp )
return false ;
zpl_b32 result = false ;
zpl_file_time last_write_time = zpl_fs_last_write_time ( f - > filename ) ;
if ( f - > last_write_time ! = last_write_time ) {
result = true ;
f - > last_write_time = last_write_time ;
}
return result ;
}
// TODO: Is this a bad idea?
zpl_global zpl_b32 zpl__std_file_set = false ;
zpl_global zpl_file zpl__std_files [ ZPL_FILE_STANDARD_COUNT ] = { { 0 } } ;
# if defined(ZPL_SYSTEM_WINDOWS) || defined(ZPL_SYSTEM_CYGWIN)
zpl_file * zpl_file_get_standard ( zpl_file_standard_type std ) {
if ( ! zpl__std_file_set ) {
# define ZPL__SET_STD_FILE(type, v) \
zpl__std_files [ type ] . fd . p = v ; \
zpl__std_files [ type ] . ops = zpl_default_file_operations
ZPL__SET_STD_FILE ( ZPL_FILE_STANDARD_INPUT , GetStdHandle ( STD_INPUT_HANDLE ) ) ;
ZPL__SET_STD_FILE ( ZPL_FILE_STANDARD_OUTPUT , GetStdHandle ( STD_OUTPUT_HANDLE ) ) ;
ZPL__SET_STD_FILE ( ZPL_FILE_STANDARD_ERROR , GetStdHandle ( STD_ERROR_HANDLE ) ) ;
# undef ZPL__SET_STD_FILE
zpl__std_file_set = true ;
}
return & zpl__std_files [ std ] ;
}
void zpl_file_connect_handle ( zpl_file * file , void * handle ) {
ZPL_ASSERT_NOT_NULL ( file ) ;
ZPL_ASSERT_NOT_NULL ( handle ) ;
if ( file - > is_temp )
return ;
zpl_zero_item ( file ) ;
file - > fd . p = handle ;
file - > ops = zpl_default_file_operations ;
}
zpl_file_error zpl_file_truncate ( zpl_file * f , zpl_i64 size ) {
zpl_file_error err = ZPL_FILE_ERROR_NONE ;
zpl_i64 prev_offset = zpl_file_tell ( f ) ;
zpl_file_seek ( f , size ) ;
if ( ! SetEndOfFile ( f ) ) err = ZPL_FILE_ERROR_TRUNCATION_FAILURE ;
zpl_file_seek ( f , prev_offset ) ;
return err ;
}
zpl_b32 zpl_fs_exists ( char const * name ) {
WIN32_FIND_DATAW data ;
wchar_t * w_text ;
void * handle ;
zpl_b32 found = false ;
zpl_allocator a = zpl_heap_allocator ( ) ;
w_text = zpl__alloc_utf8_to_ucs2 ( a , name , NULL ) ;
if ( w_text = = NULL ) { return false ; }
handle = FindFirstFileW ( w_text , & data ) ;
zpl_free ( a , w_text ) ;
found = handle ! = INVALID_HANDLE_VALUE ;
if ( found ) FindClose ( handle ) ;
return found ;
}
# else // POSIX
zpl_file * zpl_file_get_standard ( zpl_file_standard_type std ) {
if ( ! zpl__std_file_set ) {
# define ZPL__SET_STD_FILE(type, v) \
zpl__std_files [ type ] . fd . i = v ; \
zpl__std_files [ type ] . ops = zpl_default_file_operations
ZPL__SET_STD_FILE ( ZPL_FILE_STANDARD_INPUT , 0 ) ;
ZPL__SET_STD_FILE ( ZPL_FILE_STANDARD_OUTPUT , 1 ) ;
ZPL__SET_STD_FILE ( ZPL_FILE_STANDARD_ERROR , 2 ) ;
# undef ZPL__SET_STD_FILE
zpl__std_file_set = true ;
}
return & zpl__std_files [ std ] ;
}
zpl_file_error zpl_file_truncate ( zpl_file * f , zpl_i64 size ) {
zpl_file_error err = ZPL_FILE_ERROR_NONE ;
int i = ftruncate ( f - > fd . i , size ) ;
if ( i ! = 0 ) err = ZPL_FILE_ERROR_TRUNCATION_FAILURE ;
return err ;
}
zpl_b32 zpl_fs_exists ( char const * name ) { return access ( name , F_OK ) ! = - 1 ; }
# endif
zpl_i64 zpl_file_size ( zpl_file * f ) {
zpl_i64 size = 0 ;
zpl_i64 prev_offset = zpl_file_tell ( f ) ;
zpl_file_seek_to_end ( f ) ;
size = zpl_file_tell ( f ) ;
zpl_file_seek ( f , prev_offset ) ;
return size ;
}
zpl_file_error zpl_file_temp ( zpl_file * file ) {
zpl_zero_item ( file ) ;
FILE * fd = NULL ;
# if (defined(ZPL_SYSTEM_WINDOWS) && !defined(ZPL_SYSTEM_TINYC)) && !defined(ZPL_COMPILER_GCC)
errno_t errcode = tmpfile_s ( & fd ) ;
if ( errcode ! = 0 ) {
fd = NULL ;
}
# else
fd = tmpfile ( ) ;
# endif
if ( fd = = NULL ) { return ZPL_FILE_ERROR_INVALID ; }
# if defined(ZPL_SYSTEM_WINDOWS) && !defined(ZPL_COMPILER_GCC)
file - > fd . i = _get_osfhandle ( _fileno ( fd ) ) ;
# else
file - > fd . i = fileno ( fd ) ;
# endif
file - > ops = zpl_default_file_operations ;
file - > is_temp = true ;
return ZPL_FILE_ERROR_NONE ;
}
zpl_file_contents zpl_file_read_contents ( zpl_allocator a , zpl_b32 zero_terminate , char const * filepath ) {
zpl_file_contents result = { 0 } ;
zpl_file file = { 0 } ;
result . allocator = a ;
if ( zpl_file_open ( & file , filepath ) = = ZPL_FILE_ERROR_NONE ) {
zpl_isize file_size = cast ( zpl_isize ) zpl_file_size ( & file ) ;
if ( file_size > 0 ) {
result . data = zpl_alloc ( a , zero_terminate ? file_size + 1 : file_size ) ;
result . size = file_size ;
zpl_file_read_at ( & file , result . data , result . size , 0 ) ;
if ( zero_terminate ) {
zpl_u8 * str = cast ( zpl_u8 * ) result . data ;
str [ file_size ] = ' \0 ' ;
}
}
zpl_file_close ( & file ) ;
}
return result ;
}
void zpl_file_free_contents ( zpl_file_contents * fc ) {
ZPL_ASSERT_NOT_NULL ( fc - > data ) ;
zpl_free ( fc - > allocator , fc - > data ) ;
fc - > data = NULL ;
fc - > size = 0 ;
}
zpl_b32 zpl_file_write_contents ( char const * filepath , void const * buffer , zpl_isize size , zpl_file_error * err ) {
zpl_file f = { 0 } ;
zpl_file_error open_err ;
zpl_b32 write_ok ;
open_err = zpl_file_open_mode ( & f , ZPL_FILE_MODE_WRITE , filepath ) ;
if ( open_err ! = ZPL_FILE_ERROR_NONE )
{
if ( err )
* err = open_err ;
return false ;
}
write_ok = zpl_file_write ( & f , buffer , size ) ;
zpl_file_close ( & f ) ;
return write_ok ;
}
char * zpl_file_read_lines ( zpl_allocator alloc , zpl_array ( char * ) * lines , char const * filename , zpl_b32 strip_whitespace ) {
zpl_file f = { 0 } ;
zpl_file_open ( & f , filename ) ;
zpl_isize fsize = ( zpl_isize ) zpl_file_size ( & f ) ;
char * contents = ( char * ) zpl_alloc ( alloc , fsize + 1 ) ;
zpl_file_read ( & f , contents , fsize ) ;
contents [ fsize ] = 0 ;
* lines = zpl_str_split_lines ( alloc , contents , strip_whitespace ) ;
zpl_file_close ( & f ) ;
return contents ;
}
# if !defined(_WINDOWS_) && defined(ZPL_SYSTEM_WINDOWS)
ZPL_IMPORT DWORD WINAPI GetFullPathNameA ( char const * lpFileName , DWORD nBufferLength , char * lpBuffer , char * * lpFilePart ) ;
ZPL_IMPORT DWORD WINAPI GetFullPathNameW ( wchar_t const * lpFileName , DWORD nBufferLength , wchar_t * lpBuffer , wchar_t * * lpFilePart ) ;
# endif
ZPL_END_C_DECLS
// file: source/core/file_stream.c
////////////////////////////////////////////////////////////////
//
// Memory streaming
//
//
ZPL_BEGIN_C_DECLS
typedef struct {
zpl_u8 magic ;
zpl_u8 * buf ; //< zpl_array OR plain buffer if we can't write
zpl_isize cursor ;
zpl_allocator alloc ;
zpl_file_stream_flags flags ;
zpl_isize cap ;
} zpl__memory_fd ;
# define ZPL__FILE_STREAM_FD_MAGIC 37
ZPL_DEF_INLINE zpl_file_descriptor zpl__file_stream_fd_make ( zpl__memory_fd * d ) ;
ZPL_DEF_INLINE zpl__memory_fd * zpl__file_stream_from_fd ( zpl_file_descriptor fd ) ;
ZPL_IMPL_INLINE zpl_file_descriptor zpl__file_stream_fd_make ( zpl__memory_fd * d ) {
zpl_file_descriptor fd = { 0 } ;
fd . p = ( void * ) d ;
return fd ;
}
ZPL_IMPL_INLINE zpl__memory_fd * zpl__file_stream_from_fd ( zpl_file_descriptor fd ) {
zpl__memory_fd * d = ( zpl__memory_fd * ) fd . p ;
ZPL_ASSERT ( d - > magic = = ZPL__FILE_STREAM_FD_MAGIC ) ;
return d ;
}
void zpl_file_stream_new ( zpl_file * file , zpl_allocator allocator ) {
ZPL_ASSERT_NOT_NULL ( file ) ;
zpl__memory_fd * d = ( zpl__memory_fd * ) zpl_alloc ( allocator , zpl_size_of ( zpl__memory_fd ) ) ;
zpl_zero_item ( file ) ;
d - > magic = ZPL__FILE_STREAM_FD_MAGIC ;
d - > alloc = allocator ;
d - > flags = ZPL_FILE_STREAM_CLONE_WRITABLE ;
d - > cap = 0 ;
zpl_array_init ( d - > buf , allocator ) ;
file - > ops = zpl_memory_file_operations ;
file - > fd = zpl__file_stream_fd_make ( d ) ;
file - > dir = NULL ;
file - > last_write_time = 0 ;
file - > filename = NULL ;
file - > is_temp = true ;
}
void zpl_file_stream_open ( zpl_file * file , zpl_allocator allocator , zpl_u8 * buffer , zpl_isize size , zpl_file_stream_flags flags ) {
ZPL_ASSERT_NOT_NULL ( file ) ;
zpl__memory_fd * d = ( zpl__memory_fd * ) zpl_alloc ( allocator , zpl_size_of ( zpl__memory_fd ) ) ;
zpl_zero_item ( file ) ;
d - > magic = ZPL__FILE_STREAM_FD_MAGIC ;
d - > alloc = allocator ;
d - > flags = flags ;
if ( d - > flags & ZPL_FILE_STREAM_CLONE_WRITABLE ) {
zpl_array_init_reserve ( d - > buf , allocator , size ) ;
zpl_memcopy ( d - > buf , buffer , size ) ;
d - > cap = zpl_array_count ( d - > buf ) = size ;
} else {
d - > buf = buffer ;
d - > cap = size ;
}
file - > ops = zpl_memory_file_operations ;
file - > fd = zpl__file_stream_fd_make ( d ) ;
file - > dir = NULL ;
file - > last_write_time = 0 ;
file - > filename = NULL ;
file - > is_temp = true ;
}
zpl_u8 * zpl_file_stream_buf ( zpl_file * file , zpl_isize * size ) {
ZPL_ASSERT_NOT_NULL ( file ) ;
zpl__memory_fd * d = zpl__file_stream_from_fd ( file - > fd ) ;
if ( size ) * size = d - > cap ;
return d - > buf ;
}
zpl_internal ZPL_FILE_SEEK_PROC ( zpl__memory_file_seek ) {
zpl__memory_fd * d = zpl__file_stream_from_fd ( fd ) ;
zpl_isize buflen = d - > cap ;
if ( whence = = ZPL_SEEK_WHENCE_BEGIN )
d - > cursor = 0 ;
else if ( whence = = ZPL_SEEK_WHENCE_END )
d - > cursor = buflen ;
d - > cursor = zpl_max ( 0 , zpl_clamp ( d - > cursor + offset , 0 , buflen ) ) ;
if ( new_offset ) * new_offset = d - > cursor ;
return true ;
}
zpl_internal ZPL_FILE_READ_AT_PROC ( zpl__memory_file_read ) {
zpl_unused ( stop_at_newline ) ;
zpl__memory_fd * d = zpl__file_stream_from_fd ( fd ) ;
zpl_memcopy ( buffer , d - > buf + offset , size ) ;
if ( bytes_read ) * bytes_read = size ;
return true ;
}
zpl_internal ZPL_FILE_WRITE_AT_PROC ( zpl__memory_file_write ) {
zpl__memory_fd * d = zpl__file_stream_from_fd ( fd ) ;
if ( ! ( d - > flags & ( ZPL_FILE_STREAM_CLONE_WRITABLE | ZPL_FILE_STREAM_WRITABLE ) ) )
return false ;
zpl_isize buflen = d - > cap ;
zpl_isize extralen = zpl_max ( 0 , size - ( buflen - offset ) ) ;
zpl_isize rwlen = size - extralen ;
zpl_isize new_cap = buflen + extralen ;
if ( d - > flags & ZPL_FILE_STREAM_CLONE_WRITABLE ) {
if ( zpl_array_capacity ( d - > buf ) < new_cap ) {
zpl_array_grow ( d - > buf , ( zpl_i64 ) ( new_cap ) ) ;
}
}
zpl_memcopy ( d - > buf + offset , buffer , rwlen ) ;
if ( ( d - > flags & ZPL_FILE_STREAM_CLONE_WRITABLE ) & & extralen > 0 ) {
zpl_memcopy ( d - > buf + offset + rwlen , zpl_ptr_add_const ( buffer , rwlen ) , extralen ) ;
d - > cap = zpl_array_count ( d - > buf ) = new_cap ;
} else {
extralen = 0 ;
}
if ( bytes_written ) * bytes_written = ( rwlen + extralen ) ;
return true ;
}
zpl_internal ZPL_FILE_CLOSE_PROC ( zpl__memory_file_close ) {
zpl__memory_fd * d = zpl__file_stream_from_fd ( fd ) ;
zpl_allocator alloc = d - > alloc ;
if ( d - > flags & ZPL_FILE_STREAM_CLONE_WRITABLE )
zpl_array_free ( d - > buf ) ;
zpl_free ( alloc , d ) ;
}
zpl_file_operations const zpl_memory_file_operations = { zpl__memory_file_read , zpl__memory_file_write ,
zpl__memory_file_seek , zpl__memory_file_close } ;
ZPL_END_C_DECLS
// file: source/core/file_misc.c
# if defined(ZPL_SYSTEM_UNIX) || defined(ZPL_SYSTEM_MACOS)
# include <dirent.h>
# endif
# if defined(ZPL_SYSTEM_UNIX) && !defined(ZPL_SYSTEM_FREEBSD) && !defined(ZPL_SYSTEM_OPENBSD) && !defined(ZPL_SYSTEM_CYGWIN) && !defined(ZPL_SYSTEM_EMSCRIPTEN)
# include <sys / sendfile.h>
# endif
# if defined(ZPL_SYSTEM_WINDOWS)
# include <io.h>
# include <direct.h>
# endif
# if defined(ZPL_SYSTEM_CYGWIN)
# include <io.h>
# include <dirent.h>
# include <windows.h>
# endif
ZPL_BEGIN_C_DECLS
# if defined(ZPL_SYSTEM_WINDOWS) || defined(ZPL_SYSTEM_CYGWIN)
zpl_file_time zpl_fs_last_write_time ( char const * filepath ) {
ULARGE_INTEGER li = { 0 } ;
FILETIME last_write_time = { 0 } ;
WIN32_FILE_ATTRIBUTE_DATA data = { 0 } ;
zpl_allocator a = zpl_heap_allocator ( ) ;
wchar_t * w_text = zpl__alloc_utf8_to_ucs2 ( a , filepath , NULL ) ;
if ( w_text = = NULL ) { return 0 ; }
if ( GetFileAttributesExW ( w_text , GetFileExInfoStandard , & data ) ) last_write_time = data . ftLastWriteTime ;
zpl_free ( a , w_text ) ;
li . LowPart = last_write_time . dwLowDateTime ;
li . HighPart = last_write_time . dwHighDateTime ;
return cast ( zpl_file_time ) li . QuadPart ;
}
zpl_b32 zpl_fs_copy ( char const * existing_filename , char const * new_filename , zpl_b32 fail_if_exists ) {
zpl_b32 result = false ;
zpl_allocator a = zpl_heap_allocator ( ) ;
wchar_t * w_old = zpl__alloc_utf8_to_ucs2 ( a , existing_filename , NULL ) ;
if ( w_old = = NULL ) { return false ; }
wchar_t * w_new = zpl__alloc_utf8_to_ucs2 ( a , new_filename , NULL ) ;
if ( w_new ! = NULL ) { result = CopyFileW ( w_old , w_new , fail_if_exists ) ; }
zpl_free ( a , w_old ) ;
zpl_free ( a , w_new ) ;
return result ;
}
zpl_b32 zpl_fs_move ( char const * existing_filename , char const * new_filename ) {
zpl_b32 result = false ;
zpl_allocator a = zpl_heap_allocator ( ) ;
wchar_t * w_old = zpl__alloc_utf8_to_ucs2 ( a , existing_filename , NULL ) ;
if ( w_old = = NULL ) { return false ; }
wchar_t * w_new = zpl__alloc_utf8_to_ucs2 ( a , new_filename , NULL ) ;
if ( w_new ! = NULL ) { result = MoveFileW ( w_old , w_new ) ; }
zpl_free ( a , w_old ) ;
zpl_free ( a , w_new ) ;
return result ;
}
zpl_b32 zpl_fs_remove ( char const * filename ) {
zpl_b32 result = false ;
zpl_allocator a = zpl_heap_allocator ( ) ;
wchar_t * w_filename = zpl__alloc_utf8_to_ucs2 ( a , filename , NULL ) ;
if ( w_filename = = NULL ) { return false ; }
result = DeleteFileW ( w_filename ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
zpl_free ( a , w_filename ) ;
return result ;
}
# else
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
zpl_file_time zpl_fs_last_write_time ( char const * filepath ) {
time_t result = 0 ;
struct stat file_stat ;
if ( stat ( filepath , & file_stat ) ) result = file_stat . st_mtime ;
return cast ( zpl_file_time ) result ;
}
# if defined(ZPL_SYSTEM_FREEBSD)
# include <sys / types.h>
# include <sys / socket.h>
# include <sys / uio.h>
# endif
zpl_b32 zpl_fs_copy ( char const * existing_filename , char const * new_filename , zpl_b32 fail_if_exists ) {
zpl_unused ( fail_if_exists ) ;
# if defined(ZPL_SYSTEM_OSX)
return copyfile ( existing_filename , new_filename , NULL , COPYFILE_DATA ) = = 0 ;
# elif defined(ZPL_SYSTEM_OPENBSD)
ZPL_NOT_IMPLEMENTED ;
return 0 ;
# elif defined(ZPL_SYSTEM_EMSCRIPTEN)
ZPL_NOT_IMPLEMENTED ;
return 0 ;
# else
int existing_fd = open ( existing_filename , O_RDONLY , 0 ) ;
struct stat stat_existing ;
fstat ( existing_fd , & stat_existing ) ;
zpl_isize size ;
int new_fd = open ( new_filename , O_WRONLY | O_CREAT , stat_existing . st_mode ) ;
# if defined(ZPL_SYSTEM_FREEBSD)
size = sendfile ( new_fd , existing_fd , 0 , stat_existing . st_size , NULL , 0 , 0 ) ;
# else
size = sendfile ( new_fd , existing_fd , 0 , stat_existing . st_size ) ;
# endif
close ( new_fd ) ;
close ( existing_fd ) ;
return size = = stat_existing . st_size ;
# endif
}
zpl_b32 zpl_fs_move ( char const * existing_filename , char const * new_filename ) {
if ( link ( existing_filename , new_filename ) = = 0 ) { return ( unlink ( existing_filename ) ! = - 1 ) ; }
return false ;
}
zpl_b32 zpl_fs_remove ( char const * filename ) {
# if defined(ZPL_SYSTEM_OSX) || defined(ZPL_SYSTEM_EMSCRIPTEN)
return ( unlink ( filename ) ! = - 1 ) ;
# else
return ( remove ( filename ) = = 0 ) ;
# endif
}
# endif
char * zpl_path_get_full_name ( zpl_allocator a , char const * path ) {
# if defined(ZPL_SYSTEM_WINDOWS)
wchar_t * w_path = NULL ;
wchar_t * w_fullpath = NULL ;
zpl_isize w_len = 0 ;
zpl_isize new_len = 0 ;
zpl_isize new_len1 = 0 ;
char * new_path = 0 ;
w_path = zpl__alloc_utf8_to_ucs2 ( zpl_heap_allocator ( ) , path , NULL ) ;
if ( w_path = = NULL ) { return NULL ; }
w_len = GetFullPathNameW ( w_path , 0 , NULL , NULL ) ;
if ( w_len = = 0 ) { return NULL ; }
w_fullpath = zpl_alloc_array ( zpl_heap_allocator ( ) , wchar_t , w_len + 1 ) ;
GetFullPathNameW ( w_path , cast ( int ) w_len , w_fullpath , NULL ) ;
w_fullpath [ w_len ] = 0 ;
zpl_free ( zpl_heap_allocator ( ) , w_path ) ;
new_len = WideCharToMultiByte ( CP_UTF8 , WC_ERR_INVALID_CHARS , w_fullpath , cast ( int ) w_len , NULL , 0 , NULL , NULL ) ;
if ( new_len = = 0 ) {
zpl_free ( zpl_heap_allocator ( ) , w_fullpath ) ;
return NULL ;
}
new_path = zpl_alloc_array ( a , char , new_len ) ;
new_len1 = WideCharToMultiByte ( CP_UTF8 , WC_ERR_INVALID_CHARS , w_fullpath , cast ( int ) w_len , new_path ,
cast ( int ) new_len , NULL , NULL ) ;
if ( new_len1 = = 0 ) {
zpl_free ( zpl_heap_allocator ( ) , w_fullpath ) ;
zpl_free ( a , new_path ) ;
return NULL ;
}
new_path [ new_len ] = 0 ;
return new_path ;
# else
char * p , * result , * fullpath = NULL ;
zpl_isize len ;
p = realpath ( path , NULL ) ;
fullpath = p ;
if ( p = = NULL ) {
// NOTE(bill): File does not exist
fullpath = cast ( char * ) path ;
}
len = zpl_strlen ( fullpath ) ;
result = zpl_alloc_array ( a , char , len + 1 ) ;
zpl_memmove ( result , fullpath , len ) ;
result [ len ] = 0 ;
zpl_free ( a , p ) ;
return result ;
# endif
}
zpl_file_error zpl_path_mkdir ( char const * path , zpl_i32 mode ) {
zpl_i32 error = 0 ;
# if defined(ZPL_SYSTEM_WINDOWS)
error = _wmkdir ( ( const wchar_t * ) zpl_utf8_to_ucs2_buf ( ( const zpl_u8 * ) path ) ) ;
# else
error = mkdir ( path , ( mode_t ) mode ) ;
# endif
if ( error = = 0 ) { return ZPL_FILE_ERROR_NONE ; }
switch ( errno ) {
case EPERM :
case EACCES : return ZPL_FILE_ERROR_PERMISSION ;
case EEXIST : return ZPL_FILE_ERROR_EXISTS ;
case ENAMETOOLONG : return ZPL_FILE_ERROR_NAME_TOO_LONG ;
}
return ZPL_FILE_ERROR_UNKNOWN ;
}
zpl_isize zpl_path_mkdir_recursive ( char const * path , zpl_i32 mode ) {
char tmp [ ZPL_MAX_PATH ] = { 0 } ;
char * p = 0 ;
zpl_isize len = zpl_strlen ( path ) ;
if ( len > zpl_size_of ( tmp ) - 1 ) {
return - 1 ;
}
zpl_strcpy ( tmp , path ) ;
zpl_path_fix_slashes ( tmp ) ;
for ( p = tmp + 1 ; * p ; p + + ) {
if ( * p = = ZPL_PATH_SEPARATOR ) {
* p = 0 ;
zpl_path_mkdir ( tmp , mode ) ;
* p = ZPL_PATH_SEPARATOR ;
}
}
zpl_path_mkdir ( tmp , mode ) ;
return 0 ;
}
zpl_file_error zpl_path_rmdir ( char const * path ) {
zpl_i32 error = 0 ;
# if defined(ZPL_SYSTEM_WINDOWS)
error = _wrmdir ( ( const wchar_t * ) zpl_utf8_to_ucs2_buf ( ( const zpl_u8 * ) path ) ) ;
# else
error = rmdir ( path ) ;
# endif
if ( error = = 0 ) { return ZPL_FILE_ERROR_NONE ; }
switch ( errno ) {
case EPERM :
case EACCES : return ZPL_FILE_ERROR_PERMISSION ;
case ENOENT : return ZPL_FILE_ERROR_NOT_EXISTS ;
case ENOTEMPTY : return ZPL_FILE_ERROR_NOT_EMPTY ;
case ENAMETOOLONG : return ZPL_FILE_ERROR_NAME_TOO_LONG ;
}
return ZPL_FILE_ERROR_UNKNOWN ;
}
void zpl__file_direntry ( zpl_allocator alloc , char const * dirname , zpl_string * output , zpl_b32 recurse ) {
# if defined(ZPL_SYSTEM_UNIX) || defined(ZPL_SYSTEM_OSX)
DIR * d , * cd ;
struct dirent * dir ;
d = opendir ( dirname ) ;
if ( d ) {
while ( ( dir = readdir ( d ) ) ) {
if ( dir = = 0 ) break ;
if ( ! zpl_strncmp ( dir - > d_name , " .. " , 2 ) ) continue ;
if ( dir - > d_name [ 0 ] = = ' . ' & & dir - > d_name [ 1 ] = = 0 ) continue ;
zpl_string dirpath = zpl_string_make ( alloc , dirname ) ;
dirpath = zpl_string_appendc ( dirpath , " / " ) ;
dirpath = zpl_string_appendc ( dirpath , dir - > d_name ) ;
* output = zpl_string_appendc ( * output , dirpath ) ;
* output = zpl_string_appendc ( * output , " \n " ) ;
if ( recurse & & ( cd = opendir ( dirpath ) ) ! = NULL & & dir - > d_type = = DT_DIR ) { zpl__file_direntry ( alloc , dirpath , output , recurse ) ; }
zpl_string_free ( dirpath ) ;
}
}
# elif defined(ZPL_SYSTEM_WINDOWS)
zpl_usize length = zpl_strlen ( dirname ) ;
struct _wfinddata_t data ;
zpl_intptr findhandle ;
char directory [ MAX_PATH ] = { 0 } ;
zpl_strncpy ( directory , dirname , length ) ;
// keeping it native
for ( zpl_usize i = 0 ; i < length ; i + + ) {
if ( directory [ i ] = = ' / ' ) directory [ i ] = ' \\ ' ;
}
// remove trailing slashses
if ( directory [ length - 1 ] = = ' \\ ' ) { directory [ length - 1 ] = ' \0 ' ; }
// attach search pattern
zpl_string findpath = zpl_string_make ( alloc , directory ) ;
findpath = zpl_string_appendc ( findpath , " \\ " ) ;
findpath = zpl_string_appendc ( findpath , " * " ) ;
findhandle = _wfindfirst ( ( const wchar_t * ) zpl_utf8_to_ucs2_buf ( ( const zpl_u8 * ) findpath ) , & data ) ;
zpl_string_free ( findpath ) ;
if ( findhandle ! = - 1 ) {
do {
char * filename = ( char * ) zpl_ucs2_to_utf8_buf ( ( const zpl_u16 * ) data . name ) ;
if ( ! zpl_strncmp ( filename , " .. " , 2 ) ) continue ;
if ( filename [ 0 ] = = ' . ' & & filename [ 1 ] = = 0 ) continue ;
zpl_string dirpath = zpl_string_make ( alloc , directory ) ;
dirpath = zpl_string_appendc ( dirpath , " \\ " ) ;
dirpath = zpl_string_appendc ( dirpath , filename ) ;
DWORD attrs = GetFileAttributesW ( ( const wchar_t * ) zpl_utf8_to_ucs2_buf ( ( const zpl_u8 * ) dirpath ) ) ;
* output = zpl_string_appendc ( * output , dirpath ) ;
* output = zpl_string_appendc ( * output , " \n " ) ;
if ( recurse & & ( data . attrib & _A_SUBDIR ) & & ! ( attrs & FILE_ATTRIBUTE_REPARSE_POINT ) ) { zpl__file_direntry ( alloc , dirpath , output , recurse ) ; }
zpl_string_free ( dirpath ) ;
} while ( _wfindnext ( findhandle , & data ) ! = - 1 ) ;
_findclose ( findhandle ) ;
}
# else
// TODO: Implement other OSes
# endif
}
zpl_string zpl_path_dirlist ( zpl_allocator alloc , char const * dirname , zpl_b32 recurse ) {
zpl_string buf = zpl_string_make_reserve ( alloc , 4 ) ;
zpl__file_direntry ( alloc , dirname , & buf , recurse ) ;
return buf ;
}
void zpl_dirinfo_init ( zpl_dir_info * dir , char const * path ) {
ZPL_ASSERT_NOT_NULL ( dir ) ;
zpl_dir_info dir_ = { 0 } ;
* dir = dir_ ;
dir - > fullpath = ( char const * ) zpl_malloc ( zpl_strlen ( path ) ) ;
zpl_strcpy ( ( char * ) dir - > fullpath , path ) ;
zpl_string dirlist = zpl_path_dirlist ( zpl_heap ( ) , path , false ) ;
char * * files = zpl_str_split_lines ( zpl_heap ( ) , dirlist , false ) ;
dir - > filenames = files ;
dir - > buf = dirlist ;
zpl_array_init ( dir - > entries , zpl_heap ( ) ) ;
for ( zpl_i32 i = 0 ; i < zpl_array_count ( files ) ; + + i ) {
zpl_dir_entry entry = { 0 } ;
entry . filename = files [ i ] ;
entry . type = zpl_fs_get_type ( entry . filename ) ;
zpl_array_append ( dir - > entries , entry ) ;
}
}
zpl_internal void zpl__dirinfo_free_entry ( zpl_dir_entry * entry ) {
if ( entry - > dir_info ) {
zpl_dirinfo_free ( entry - > dir_info ) ;
zpl_mfree ( entry - > dir_info ) ;
entry - > dir_info = NULL ;
}
}
void zpl_dirinfo_free ( zpl_dir_info * dir ) {
ZPL_ASSERT_NOT_NULL ( dir ) ;
for ( zpl_isize i = 0 ; i < zpl_array_count ( dir - > entries ) ; + + i ) {
zpl__dirinfo_free_entry ( dir - > entries + i ) ;
}
zpl_array_free ( dir - > entries ) ;
zpl_array_free ( dir - > filenames ) ;
zpl_string_free ( dir - > buf ) ;
zpl_mfree ( ( void * ) dir - > fullpath ) ;
}
zpl_u8 zpl_fs_get_type ( char const * path ) {
# ifdef ZPL_SYSTEM_WINDOWS
DWORD attrs = GetFileAttributesW ( ( const wchar_t * ) zpl_utf8_to_ucs2_buf ( ( const zpl_u8 * ) path ) ) ;
if ( attrs = = INVALID_FILE_ATTRIBUTES ) {
return ZPL_DIR_TYPE_UNKNOWN ;
}
if ( attrs & FILE_ATTRIBUTE_DIRECTORY )
return ZPL_DIR_TYPE_FOLDER ;
else
return ZPL_DIR_TYPE_FILE ;
# else
struct stat s ;
if ( stat ( path , & s ) = = 0 )
{
if ( s . st_mode & S_IFDIR )
return ZPL_DIR_TYPE_FOLDER ;
else
return ZPL_DIR_TYPE_FILE ;
}
# endif
return ZPL_DIR_TYPE_UNKNOWN ;
}
void zpl_dirinfo_step ( zpl_dir_entry * entry ) {
if ( entry - > dir_info ) {
zpl__dirinfo_free_entry ( entry ) ;
}
entry - > dir_info = ( zpl_dir_info * ) zpl_malloc ( sizeof ( zpl_dir_info ) ) ;
zpl_dir_info dir_ = { 0 } ;
* entry - > dir_info = dir_ ;
zpl_local_persist char buf [ 128 ] = { 0 } ;
char const * path = entry - > filename ;
if ( entry - > type ! = ZPL_DIR_TYPE_FOLDER ) {
zpl_path_fix_slashes ( ( char * ) path ) ;
char const * slash = zpl_char_last_occurence ( path , ZPL_PATH_SEPARATOR ) ;
zpl_strncpy ( buf , path , slash - path ) ;
path = buf ;
}
zpl_dirinfo_init ( entry - > dir_info , path ) ;
}
void zpl_file_dirinfo_refresh ( zpl_file * file ) {
if ( file - > is_temp )
return ;
if ( file - > dir ) {
zpl__dirinfo_free_entry ( file - > dir ) ;
zpl_mfree ( file - > dir ) ;
file - > dir = NULL ;
}
file - > dir = ( zpl_dir_entry * ) zpl_malloc ( sizeof ( zpl_dir_entry ) ) ;
zpl_dir_entry dir_ = { 0 } ;
* file - > dir = dir_ ;
file - > dir - > filename = file - > filename ;
file - > dir - > type = ZPL_DIR_TYPE_FILE ;
zpl_dirinfo_step ( file - > dir ) ;
}
void zpl_path_fix_slashes ( char * path ) {
# ifdef ZPL_SYSTEM_WINDOWS
char * p = path ;
while ( * p ! = ' \0 ' ) {
if ( * p = = ' / ' )
* p = ' \\ ' ;
+ + p ;
}
# endif
}
ZPL_END_C_DECLS
// file: source/core/file_tar.c
typedef struct {
char name [ 100 ] ;
char mode [ 8 ] ;
char owner [ 8 ] ;
char group [ 8 ] ;
char size [ 12 ] ;
char mtime [ 12 ] ;
char checksum [ 8 ] ;
char type ;
char linkname [ 100 ] ;
char _padding [ 255 ] ;
} zpl__tar_header ;
zpl_internal zpl_usize zpl__tar_checksum ( zpl__tar_header * hr ) {
zpl_usize i ;
zpl_usize res = 256 ;
zpl_u8 * p = cast ( zpl_u8 * ) ( hr ) ;
for ( i = 0 ; i < cast ( zpl_usize ) zpl_offset_of ( zpl__tar_header , checksum ) ; i + + )
res + = p [ i ] ;
for ( i = cast ( zpl_usize ) zpl_offset_of ( zpl__tar_header , type ) ; i < cast ( zpl_usize ) zpl_size_of ( zpl__tar_header ) ; i + + )
res + = p [ i ] ;
return res ;
}
zpl_internal zpl_b32 zpl__tar_write_null ( zpl_file * archive , zpl_isize cnt ) {
char * out = zpl_bprintf ( " %*r " , cnt , ' \0 ' ) ;
if ( ! zpl_file_write ( archive , out , cnt ) )
return 0 ;
return 1 ;
}
zpl_isize zpl_tar_pack ( zpl_file * archive , char const * * paths , zpl_isize paths_len ) {
ZPL_ASSERT_NOT_NULL ( archive ) ;
ZPL_ASSERT_NOT_NULL ( paths ) ;
for ( zpl_isize i = 0 ; i < paths_len ; i + + ) {
ZPL_ASSERT_NOT_NULL ( paths [ i ] ) ;
zpl__tar_header hr = { 0 } ;
zpl_file file ;
zpl_file_error ferr = zpl_file_open_mode ( & file , ZPL_FILE_MODE_READ , paths [ i ] ) ;
if ( ferr = = ZPL_FILE_ERROR_NOT_EXISTS ) {
return - ( ZPL_TAR_ERROR_FILE_NOT_FOUND ) ;
} else if ( ferr ! = ZPL_FILE_ERROR_NONE ) {
return - ( ZPL_TAR_ERROR_IO_ERROR ) ;
}
zpl_i64 file_size = zpl_file_size ( & file ) ;
zpl_snprintf ( hr . name , 12 , " %s " , paths [ i ] ) ;
zpl_snprintf ( hr . size , 12 , " %o " , file_size ) ;
zpl_snprintf ( hr . mode , 8 , " %o " , 0664 ) ;
zpl_snprintf ( hr . mtime , 12 , " %o " , zpl_fs_last_write_time ( paths [ i ] ) ) ;
hr . type = ZPL_TAR_TYPE_REGULAR ;
zpl_snprintf ( hr . checksum , 8 , " %o " , zpl__tar_checksum ( & hr ) ) ;
zpl_file_write ( archive , cast ( void * ) ( & hr ) , zpl_size_of ( zpl__tar_header ) ) ;
// write data
{
zpl_i64 remaining_data = file_size ;
zpl_i64 total_data = zpl_align_forward_i64 ( remaining_data , 512 ) ;
zpl_i64 padding = ( total_data - file_size ) ;
char buf [ 4096 ] = { 0 } ;
zpl_i64 pos = 0 ;
zpl_isize bytes_read = 0 ;
do {
if ( ! zpl_file_read_at_check ( & file , buf , 4096 , pos , & bytes_read ) ) {
zpl_file_close ( & file ) ;
return - ( ZPL_TAR_ERROR_IO_ERROR ) ;
} else if ( bytes_read = = 0 ) {
break ;
}
zpl_file_write ( archive , buf , bytes_read ) ;
pos + = bytes_read ;
remaining_data - = bytes_read ;
}
while ( remaining_data > 0 ) ;
if ( padding > 0 ) {
if ( ! zpl__tar_write_null ( archive , padding ) ) {
zpl_file_close ( & file ) ;
return - ( ZPL_TAR_ERROR_IO_ERROR ) ;
}
}
}
zpl_file_close ( & file ) ;
}
if ( ! zpl__tar_write_null ( archive , zpl_size_of ( zpl__tar_header ) * 2 ) ) {
return - ( ZPL_TAR_ERROR_IO_ERROR ) ;
}
return 0 ;
}
zpl_isize zpl_tar_pack_dir ( zpl_file * archive , char const * path , zpl_allocator alloc ) {
zpl_string filelst = zpl_path_dirlist ( alloc , path , true ) ;
char const * * files = cast ( char const * * ) zpl_str_split_lines ( alloc , filelst , false ) ;
zpl_isize err = zpl_tar_pack ( archive , files , zpl_array_count ( files ) ) ;
zpl_string_free ( filelst ) ;
zpl_array_free ( files ) ;
return err ;
}
zpl_isize zpl_tar_unpack ( zpl_file * archive , zpl_tar_unpack_proc * unpack_proc , void * user_data ) {
ZPL_ASSERT_NOT_NULL ( archive ) ;
ZPL_ASSERT_NOT_NULL ( unpack_proc ) ;
zpl_i64 pos = zpl_file_tell ( archive ) ;
zpl__tar_header hr = { 0 } ;
zpl_isize err = ZPL_TAR_ERROR_NONE ;
do {
if ( ! zpl_file_read ( archive , cast ( void * ) & hr , zpl_size_of ( hr ) ) ) {
err = ZPL_TAR_ERROR_IO_ERROR ;
break ;
}
else if ( * hr . checksum = = 0 ) {
break ;
}
pos = zpl_file_tell ( archive ) ;
zpl_tar_record rec = { 0 } ;
rec . type = hr . type ;
rec . path = hr . name ;
rec . offset = pos ;
rec . length = zpl_str_to_i64 ( hr . size , 0 , 8 ) ;
rec . error = ZPL_TAR_ERROR_NONE ;
zpl_usize checksum1 = cast ( zpl_usize ) ( zpl_str_to_i64 ( hr . checksum , 0 , 8 ) ) ;
zpl_usize checksum2 = zpl__tar_checksum ( & hr ) ;
rec . error = ( checksum1 ! = checksum2 ) ? cast ( zpl_isize ) ZPL_TAR_ERROR_BAD_CHECKSUM : rec . error ;
rec . error = unpack_proc ( archive , & rec , user_data ) ;
if ( rec . error > 0 ) {
err = ZPL_TAR_ERROR_INTERRUPTED ;
break ;
}
/* tar rounds files to 512 byte boundary */
zpl_file_seek ( archive , pos + zpl_align_forward_i64 ( rec . length , 512 ) ) ;
}
while ( err = = ZPL_TAR_ERROR_NONE ) ;
return - ( err ) ;
}
ZPL_TAR_UNPACK_PROC ( zpl_tar_default_list_file ) {
( void ) archive ;
( void ) user_data ;
if ( file - > error ! = ZPL_TAR_ERROR_NONE )
return 0 ; /* skip file */
if ( file - > type ! = ZPL_TAR_TYPE_REGULAR )
return 0 ; /* we only care about regular files */
/* proceed as usual */
zpl_printf ( " name: %s, offset: %d, length: %d \n " , file - > path , file - > offset , file - > length ) ;
return 0 ;
}
ZPL_TAR_UNPACK_PROC ( zpl_tar_default_unpack_file ) {
if ( file - > error ! = ZPL_TAR_ERROR_NONE )
return 0 ; /* skip file */
if ( file - > type ! = ZPL_TAR_TYPE_REGULAR )
return 0 ; /* we only care about regular files */
if ( ! zpl_strncmp ( file - > path , " .. " , 2 ) )
return 0 ;
char tmp [ ZPL_MAX_PATH ] = { 0 } ;
char * base_path = cast ( char * ) user_data ;
zpl_isize base_len = zpl_strlen ( base_path ) ;
zpl_isize len = zpl_strlen ( file - > path ) ;
ZPL_ASSERT ( base_len + len - 2 < ZPL_MAX_PATH ) ; /* todo: account for missing leading path sep */
zpl_strcpy ( tmp , base_path ) ;
zpl_path_fix_slashes ( tmp ) ; /* todo: need to do twice as base_path is checked before concat */
if ( * tmp & & tmp [ base_len - 1 ] ! = ZPL_PATH_SEPARATOR ) {
char sep [ 2 ] = { ZPL_PATH_SEPARATOR , 0 } ;
zpl_strcat ( tmp , sep ) ;
}
zpl_strcat ( tmp , file - > path ) ;
zpl_path_fix_slashes ( tmp ) ;
const char * last_slash = zpl_char_last_occurence ( tmp , ZPL_PATH_SEPARATOR ) ;
if ( last_slash ) {
zpl_isize i = cast ( zpl_isize ) ( last_slash - tmp ) ;
tmp [ i ] = 0 ;
zpl_path_mkdir_recursive ( tmp , 0755 ) ;
tmp [ i ] = ZPL_PATH_SEPARATOR ;
}
zpl_file f ;
zpl_file_create ( & f , tmp ) ;
{
char buf [ 4096 ] = { 0 } ;
zpl_isize remaining_data = file - > length ;
zpl_isize bytes_read = 0 ;
zpl_i64 pos = file - > offset ;
do {
if ( ! zpl_file_read_at_check ( archive , buf , zpl_min ( 4096 , remaining_data ) , pos , & bytes_read ) ) {
zpl_file_close ( & f ) ;
return 1 ;
} else if ( bytes_read = = 0 ) {
break ;
}
zpl_file_write ( & f , buf , bytes_read ) ;
pos + = bytes_read ;
remaining_data - = bytes_read ;
}
while ( remaining_data > 0 ) ;
}
zpl_file_close ( & f ) ;
return 0 ;
}
// file: source/core/print.c
ZPL_BEGIN_C_DECLS
zpl_isize zpl_printf_va ( char const * fmt , va_list va ) {
return zpl_fprintf_va ( zpl_file_get_standard ( ZPL_FILE_STANDARD_OUTPUT ) , fmt , va ) ;
}
zpl_isize zpl_printf_err_va ( char const * fmt , va_list va ) {
return zpl_fprintf_va ( zpl_file_get_standard ( ZPL_FILE_STANDARD_ERROR ) , fmt , va ) ;
}
zpl_isize zpl_fprintf_va ( struct zpl_file * f , char const * fmt , va_list va ) {
zpl_local_persist zpl_thread_local char buf [ ZPL_PRINTF_MAXLEN ] ;
zpl_isize len = zpl_snprintf_va ( buf , zpl_size_of ( buf ) , fmt , va ) ;
zpl_file_write ( f , buf , len - 1 ) ; // NOTE: prevent extra whitespace
return len ;
}
char * zpl_bprintf_va ( char const * fmt , va_list va ) {
zpl_local_persist zpl_thread_local char buffer [ ZPL_PRINTF_MAXLEN ] ;
zpl_snprintf_va ( buffer , zpl_size_of ( buffer ) , fmt , va ) ;
return buffer ;
}
zpl_isize zpl_asprintf_va ( zpl_allocator allocator , char * * buffer , char const * fmt , va_list va ) {
zpl_local_persist zpl_thread_local char tmp [ ZPL_PRINTF_MAXLEN ] ;
ZPL_ASSERT_NOT_NULL ( buffer ) ;
zpl_isize res ;
res = zpl_snprintf_va ( tmp , zpl_size_of ( tmp ) , fmt , va ) ;
* buffer = zpl_alloc_str ( allocator , tmp ) ;
return res ;
}
zpl_isize zpl_printf ( char const * fmt , . . . ) {
zpl_isize res ;
va_list va ;
va_start ( va , fmt ) ;
res = zpl_printf_va ( fmt , va ) ;
va_end ( va ) ;
return res ;
}
zpl_isize zpl_printf_err ( char const * fmt , . . . ) {
zpl_isize res ;
va_list va ;
va_start ( va , fmt ) ;
res = zpl_printf_err_va ( fmt , va ) ;
va_end ( va ) ;
return res ;
}
zpl_isize zpl_fprintf ( struct zpl_file * f , char const * fmt , . . . ) {
zpl_isize res ;
va_list va ;
va_start ( va , fmt ) ;
res = zpl_fprintf_va ( f , fmt , va ) ;
va_end ( va ) ;
return res ;
}
char * zpl_bprintf ( char const * fmt , . . . ) {
va_list va ;
char * str ;
va_start ( va , fmt ) ;
str = zpl_bprintf_va ( fmt , va ) ;
va_end ( va ) ;
return str ;
}
zpl_isize zpl_asprintf ( zpl_allocator allocator , char * * buffer , char const * fmt , . . . ) {
zpl_isize res ;
va_list va ;
va_start ( va , fmt ) ;
res = zpl_asprintf_va ( allocator , buffer , fmt , va ) ;
va_end ( va ) ;
return res ;
}
zpl_isize zpl_snprintf ( char * str , zpl_isize n , char const * fmt , . . . ) {
zpl_isize res ;
va_list va ;
va_start ( va , fmt ) ;
res = zpl_snprintf_va ( str , n , fmt , va ) ;
va_end ( va ) ;
return res ;
}
enum {
ZPL_FMT_MINUS = ZPL_BIT ( 0 ) ,
ZPL_FMT_PLUS = ZPL_BIT ( 1 ) ,
ZPL_FMT_ALT = ZPL_BIT ( 2 ) ,
ZPL_FMT_SPACE = ZPL_BIT ( 3 ) ,
ZPL_FMT_ZERO = ZPL_BIT ( 4 ) ,
ZPL_FMT_CHAR = ZPL_BIT ( 5 ) ,
ZPL_FMT_SHORT = ZPL_BIT ( 6 ) ,
ZPL_FMT_INT = ZPL_BIT ( 7 ) ,
ZPL_FMT_LONG = ZPL_BIT ( 8 ) ,
ZPL_FMT_LLONG = ZPL_BIT ( 9 ) ,
ZPL_FMT_SIZE = ZPL_BIT ( 10 ) ,
ZPL_FMT_INTPTR = ZPL_BIT ( 11 ) ,
ZPL_FMT_UNSIGNED = ZPL_BIT ( 12 ) ,
ZPL_FMT_LOWER = ZPL_BIT ( 13 ) ,
ZPL_FMT_UPPER = ZPL_BIT ( 14 ) ,
ZPL_FMT_WIDTH = ZPL_BIT ( 15 ) ,
ZPL_FMT_DONE = ZPL_BIT ( 30 ) ,
ZPL_FMT_INTS =
ZPL_FMT_CHAR | ZPL_FMT_SHORT | ZPL_FMT_INT |
ZPL_FMT_LONG | ZPL_FMT_LLONG | ZPL_FMT_SIZE | ZPL_FMT_INTPTR
} ;
typedef struct {
zpl_i32 base ;
zpl_i32 flags ;
zpl_i32 width ;
zpl_i32 precision ;
} zpl__format_info ;
zpl_internal zpl_isize zpl__print_string ( char * text , zpl_isize max_len , zpl__format_info * info , char const * str ) {
zpl_isize res = 0 , len = 0 ;
zpl_isize remaining = max_len ;
char * begin = text ;
if ( str = = NULL & & max_len > = 6 ) {
res + = zpl_strlcpy ( text , " (null) " , 6 ) ;
return res ;
}
if ( info & & info - > precision > = 0 )
len = zpl_strnlen ( str , info - > precision ) ;
else
len = zpl_strlen ( str ) ;
if ( info & & ( info - > width = = 0 & & info - > flags & ZPL_FMT_WIDTH ) ) {
return res ;
}
if ( info & & ( info - > width = = 0 | | info - > flags & ZPL_FMT_MINUS ) ) {
if ( info - > precision > 0 ) len = info - > precision < len ? info - > precision : len ;
if ( res + len > max_len ) return res ;
res + = zpl_strlcpy ( text , str , len ) ;
text + = res ;
if ( info - > width > res ) {
zpl_isize padding = info - > width - len ;
char pad = ( info - > flags & ZPL_FMT_ZERO ) ? ' 0 ' : ' ' ;
while ( padding - - > 0 & & remaining - - > 0 ) * text + + = pad , res + + ;
}
} else {
if ( info & & ( info - > width > res ) ) {
zpl_isize padding = info - > width - len ;
char pad = ( info - > flags & ZPL_FMT_ZERO ) ? ' 0 ' : ' ' ;
while ( padding - - > 0 & & remaining - - > 0 ) * text + + = pad , res + + ;
}
if ( res + len > max_len ) return res ;
res + = zpl_strlcpy ( text , str , len ) ;
}
if ( info ) {
if ( info - > flags & ZPL_FMT_UPPER )
zpl_str_to_upper ( begin ) ;
else if ( info - > flags & ZPL_FMT_LOWER )
zpl_str_to_lower ( begin ) ;
}
return res ;
}
zpl_internal zpl_isize zpl__print_char ( char * text , zpl_isize max_len , zpl__format_info * info , char arg ) {
char str [ 2 ] = " " ;
str [ 0 ] = arg ;
return zpl__print_string ( text , max_len , info , str ) ;
}
zpl_internal zpl_isize zpl__print_repeated_char ( char * text , zpl_isize max_len , zpl__format_info * info , char arg ) {
zpl_isize res = 0 ;
zpl_i32 rem = ( info ) ? ( info - > width > 0 ) ? info - > width : 1 : 1 ;
res = rem ;
while ( rem - - > 0 ) * text + + = arg ;
return res ;
}
zpl_internal zpl_isize zpl__print_i64 ( char * text , zpl_isize max_len , zpl__format_info * info , zpl_i64 value ) {
char num [ 130 ] ;
zpl_i64_to_str ( value , num , info ? info - > base : 10 ) ;
return zpl__print_string ( text , max_len , info , num ) ;
}
zpl_internal zpl_isize zpl__print_u64 ( char * text , zpl_isize max_len , zpl__format_info * info , zpl_u64 value ) {
char num [ 130 ] ;
zpl_u64_to_str ( value , num , info ? info - > base : 10 ) ;
return zpl__print_string ( text , max_len , info , num ) ;
}
zpl_internal zpl_isize zpl__print_f64 ( char * text , zpl_isize max_len , zpl__format_info * info , zpl_b32 is_hexadecimal , zpl_f64 arg ) {
// TODO: Handle exponent notation
zpl_isize width , len , remaining = max_len ;
char * text_begin = text ;
if ( arg ) {
zpl_u64 value ;
if ( arg < 0 ) {
if ( remaining > 1 ) * text = ' - ' , remaining - - ;
text + + ;
arg = - arg ;
} else if ( info - > flags & ZPL_FMT_MINUS ) {
if ( remaining > 1 ) * text = ' + ' , remaining - - ;
text + + ;
}
value = cast ( zpl_u64 ) arg ;
len = zpl__print_u64 ( text , remaining , NULL , value ) ;
text + = len ;
if ( len > = remaining )
remaining = zpl_min ( remaining , 1 ) ;
else
remaining - = len ;
arg - = value ;
if ( info - > precision < 0 ) info - > precision = 6 ;
if ( ( info - > flags & ZPL_FMT_ALT ) | | info - > precision > 0 ) {
zpl_i64 mult = 10 ;
if ( remaining > 1 ) * text = ' . ' , remaining - - ;
text + + ;
while ( info - > precision - - > 0 ) {
value = cast ( zpl_u64 ) ( arg * mult ) ;
len = zpl__print_u64 ( text , remaining , NULL , value ) ;
text + = len ;
if ( len > = remaining )
remaining = zpl_min ( remaining , 1 ) ;
else
remaining - = len ;
arg - = cast ( zpl_f64 ) value / mult ;
mult * = 10 ;
}
}
} else {
if ( remaining > 1 ) * text = ' 0 ' , remaining - - ;
text + + ;
if ( info - > flags & ZPL_FMT_ALT ) {
if ( remaining > 1 ) * text = ' . ' , remaining - - ;
text + + ;
}
}
width = info - > width - ( text - text_begin ) ;
if ( width > 0 ) {
char fill = ( info - > flags & ZPL_FMT_ZERO ) ? ' 0 ' : ' ' ;
char * end = text + remaining - 1 ;
len = ( text - text_begin ) ;
for ( len = ( text - text_begin ) ; len - - ; ) {
if ( ( text_begin + len + width ) < end ) * ( text_begin + len + width ) = * ( text_begin + len ) ;
}
len = width ;
text + = len ;
if ( len > = remaining )
remaining = zpl_min ( remaining , 1 ) ;
else
remaining - = len ;
while ( len - - ) {
if ( text_begin + len < end ) text_begin [ len ] = fill ;
}
}
return ( text - text_begin ) ;
}
ZPL_NEVER_INLINE zpl_isize zpl_snprintf_va ( char * text , zpl_isize max_len , char const * fmt , va_list va ) {
char const * text_begin = text ;
zpl_isize remaining = max_len , res ;
while ( * fmt ) {
zpl__format_info info = { 0 } ;
zpl_isize len = 0 ;
info . precision = - 1 ;
while ( * fmt & & * fmt ! = ' % ' & & remaining ) * text + + = * fmt + + ;
if ( * fmt = = ' % ' ) {
do {
switch ( * + + fmt ) {
case ' - ' : { info . flags | = ZPL_FMT_MINUS ; break ; }
case ' + ' : { info . flags | = ZPL_FMT_PLUS ; break ; }
case ' # ' : { info . flags | = ZPL_FMT_ALT ; break ; }
case ' ' : { info . flags | = ZPL_FMT_SPACE ; break ; }
case ' 0 ' : { info . flags | = ( ZPL_FMT_ZERO | ZPL_FMT_WIDTH ) ; break ; }
default : { info . flags | = ZPL_FMT_DONE ; break ; }
}
} while ( ! ( info . flags & ZPL_FMT_DONE ) ) ;
}
// NOTE: Optional Width
if ( * fmt = = ' * ' ) {
int width = va_arg ( va , int ) ;
if ( width < 0 ) {
info . flags | = ZPL_FMT_MINUS ;
info . width = - width ;
} else {
info . width = width ;
}
info . flags | = ZPL_FMT_WIDTH ;
fmt + + ;
} else {
info . width = cast ( zpl_i32 ) zpl_str_to_i64 ( fmt , cast ( char * * ) & fmt , 10 ) ;
if ( info . width ! = 0 ) {
info . flags | = ZPL_FMT_WIDTH ;
}
}
// NOTE: Optional Precision
if ( * fmt = = ' . ' ) {
fmt + + ;
if ( * fmt = = ' * ' ) {
info . precision = va_arg ( va , int ) ;
fmt + + ;
} else {
info . precision = cast ( zpl_i32 ) zpl_str_to_i64 ( fmt , cast ( char * * ) & fmt , 10 ) ;
}
info . flags & = ~ ZPL_FMT_ZERO ;
}
switch ( * fmt + + ) {
case ' h ' :
if ( * fmt = = ' h ' ) { // hh => char
info . flags | = ZPL_FMT_CHAR ;
fmt + + ;
} else { // h => short
info . flags | = ZPL_FMT_SHORT ;
}
break ;
case ' l ' :
if ( * fmt = = ' l ' ) { // ll => long long
info . flags | = ZPL_FMT_LLONG ;
fmt + + ;
} else { // l => long
info . flags | = ZPL_FMT_LONG ;
}
break ;
break ;
case ' z ' : // NOTE: zpl_usize
info . flags | = ZPL_FMT_UNSIGNED ;
// fallthrough
case ' t ' : // NOTE: zpl_isize
info . flags | = ZPL_FMT_SIZE ;
break ;
default : fmt - - ; break ;
}
switch ( * fmt ) {
case ' u ' :
info . flags | = ZPL_FMT_UNSIGNED ;
// fallthrough
case ' d ' :
case ' i ' : info . base = 10 ; break ;
case ' o ' : info . base = 8 ; break ;
case ' x ' :
info . base = 16 ;
info . flags | = ( ZPL_FMT_UNSIGNED | ZPL_FMT_LOWER ) ;
break ;
case ' X ' :
info . base = 16 ;
info . flags | = ( ZPL_FMT_UNSIGNED | ZPL_FMT_UPPER ) ;
break ;
case ' f ' :
case ' F ' :
case ' g ' :
case ' G ' : len = zpl__print_f64 ( text , remaining , & info , 0 , va_arg ( va , zpl_f64 ) ) ; break ;
case ' a ' :
case ' A ' :
len = zpl__print_f64 ( text , remaining , & info , 1 , va_arg ( va , zpl_f64 ) ) ; break ;
case ' c ' : len = zpl__print_char ( text , remaining , & info , cast ( char ) va_arg ( va , int ) ) ; break ;
case ' s ' : len = zpl__print_string ( text , remaining , & info , va_arg ( va , char * ) ) ; break ;
case ' r ' : len = zpl__print_repeated_char ( text , remaining , & info , va_arg ( va , int ) ) ; break ;
case ' p ' :
info . base = 16 ;
info . flags | = ( ZPL_FMT_LOWER | ZPL_FMT_UNSIGNED | ZPL_FMT_ALT | ZPL_FMT_INTPTR ) ;
break ;
case ' % ' : len = zpl__print_char ( text , remaining , & info , ' % ' ) ; break ;
default : fmt - - ; break ;
}
fmt + + ;
if ( info . base ! = 0 ) {
if ( info . flags & ZPL_FMT_UNSIGNED ) {
zpl_u64 value = 0 ;
switch ( info . flags & ZPL_FMT_INTS ) {
case ZPL_FMT_CHAR : value = cast ( zpl_u64 ) cast ( zpl_u8 ) va_arg ( va , int ) ; break ;
case ZPL_FMT_SHORT : value = cast ( zpl_u64 ) cast ( zpl_u16 ) va_arg ( va , int ) ; break ;
case ZPL_FMT_LONG : value = cast ( zpl_u64 ) va_arg ( va , unsigned long ) ; break ;
case ZPL_FMT_LLONG : value = cast ( zpl_u64 ) va_arg ( va , unsigned long long ) ; break ;
case ZPL_FMT_SIZE : value = cast ( zpl_u64 ) va_arg ( va , zpl_usize ) ; break ;
case ZPL_FMT_INTPTR : value = cast ( zpl_u64 ) va_arg ( va , zpl_uintptr ) ; break ;
default : value = cast ( zpl_u64 ) va_arg ( va , unsigned int ) ; break ;
}
len = zpl__print_u64 ( text , remaining , & info , value ) ;
} else {
zpl_i64 value = 0 ;
switch ( info . flags & ZPL_FMT_INTS ) {
case ZPL_FMT_CHAR : value = cast ( zpl_i64 ) cast ( zpl_i8 ) va_arg ( va , int ) ; break ;
case ZPL_FMT_SHORT : value = cast ( zpl_i64 ) cast ( zpl_i16 ) va_arg ( va , int ) ; break ;
case ZPL_FMT_LONG : value = cast ( zpl_i64 ) va_arg ( va , long ) ; break ;
case ZPL_FMT_LLONG : value = cast ( zpl_i64 ) va_arg ( va , long long ) ; break ;
case ZPL_FMT_SIZE : value = cast ( zpl_i64 ) va_arg ( va , zpl_usize ) ; break ;
case ZPL_FMT_INTPTR : value = cast ( zpl_i64 ) va_arg ( va , zpl_uintptr ) ; break ;
default : value = cast ( zpl_i64 ) va_arg ( va , int ) ; break ;
}
len = zpl__print_i64 ( text , remaining , & info , value ) ;
}
}
text + = len ;
if ( len > = remaining )
remaining = zpl_min ( remaining , 1 ) ;
else
remaining - = len ;
}
* text + + = ' \0 ' ;
res = ( text - text_begin ) ;
return ( res > = max_len | | res < 0 ) ? - 1 : res ;
}
ZPL_END_C_DECLS
// file: source/core/time.c
# if defined(ZPL_SYSTEM_MACOS) || ZPL_SYSTEM_UNIX
# include <time.h>
# include <sys / time.h>
# endif
# if defined(ZPL_SYSTEM_MACOS)
# include <mach / mach.h>
# include <mach / mach_time.h>
# include <mach / clock.h>
# endif
# if defined(ZPL_SYSTEM_EMSCRIPTEN)
# include <emscripten.h>
# endif
# if defined(ZPL_SYSTEM_WINDOWS)
# include <timezoneapi.h>
# endif
ZPL_BEGIN_C_DECLS
//! @}
//$$
////////////////////////////////////////////////////////////////
//
// Time
//
//
# if defined(ZPL_COMPILER_MSVC) && !defined(__clang__)
zpl_u64 zpl_rdtsc ( void ) { return __rdtsc ( ) ; }
# elif defined(__i386__)
zpl_u64 zpl_rdtsc ( void ) {
zpl_u64 x ;
__asm__ volatile ( " .byte 0x0f, 0x31 " : " =A " ( x ) ) ;
return x ;
}
# elif defined(__x86_64__)
zpl_u64 zpl_rdtsc ( void ) {
zpl_u32 hi , lo ;
__asm__ __volatile__ ( " rdtsc " : " =a " ( lo ) , " =d " ( hi ) ) ;
return ( cast ( zpl_u64 ) lo ) | ( ( cast ( zpl_u64 ) hi ) < < 32 ) ;
}
# elif defined(__powerpc__)
zpl_u64 zpl_rdtsc ( void ) {
zpl_u64 result = 0 ;
zpl_u32 upper , lower , tmp ;
__asm__ volatile ( " 0: \n "
" \t mftbu %0 \n "
" \t mftb %1 \n "
" \t mftbu %2 \n "
" \t cmpw %2,%0 \n "
" \t bne 0b \n "
: " =r " ( upper ) , " =r " ( lower ) , " =r " ( tmp ) ) ;
result = upper ;
result = result < < 32 ;
result = result | lower ;
return result ;
}
# elif defined(ZPL_SYSTEM_EMSCRIPTEN)
zpl_u64 zpl_rdtsc ( void ) {
return ( zpl_u64 ) ( emscripten_get_now ( ) * 1e+6 ) ;
}
# elif defined(ZPL_CPU_ARM) && !defined(ZPL_COMPILER_TINYC)
zpl_u64 zpl_rdtsc ( void ) {
# if defined(__aarch64__)
int64_t r = 0 ;
asm volatile ( " mrs %0, cntvct_el0 " : " =r " ( r ) ) ;
# elif (__ARM_ARCH >= 6)
uint32_t r = 0 ;
uint32_t pmccntr ;
uint32_t pmuseren ;
uint32_t pmcntenset ;
// Read the user mode perf monitor counter access permissions.
asm volatile ( " mrc p15, 0, %0, c9, c14, 0 " : " =r " ( pmuseren ) ) ;
if ( pmuseren & 1 ) { // Allows reading perfmon counters for user mode code.
asm volatile ( " mrc p15, 0, %0, c9, c12, 1 " : " =r " ( pmcntenset ) ) ;
if ( pmcntenset & 0x80000000ul ) { // Is it counting?
asm volatile ( " mrc p15, 0, %0, c9, c13, 0 " : " =r " ( pmccntr ) ) ;
// The counter is set up to count every 64th cycle
return ( ( int64_t ) pmccntr ) * 64 ; // Should optimize to << 6
}
}
# else
# error "No suitable method for zpl_rdtsc for this cpu type"
# endif
return r ;
}
# else
zpl_u64 zpl_rdtsc ( void ) {
ZPL_PANIC ( " zpl_rdtsc is not supported on this particular setup " ) ;
return - 0 ;
}
# endif
# if defined(ZPL_SYSTEM_WINDOWS) || defined(ZPL_SYSTEM_CYGWIN)
zpl_u64 zpl_time_rel_ms ( void ) {
zpl_local_persist LARGE_INTEGER win32_perf_count_freq = { 0 } ;
zpl_u64 result ;
LARGE_INTEGER counter ;
zpl_local_persist LARGE_INTEGER win32_perf_counter = { 0 } ;
if ( ! win32_perf_count_freq . QuadPart ) {
QueryPerformanceFrequency ( & win32_perf_count_freq ) ;
ZPL_ASSERT ( win32_perf_count_freq . QuadPart ! = 0 ) ;
QueryPerformanceCounter ( & win32_perf_counter ) ;
}
QueryPerformanceCounter ( & counter ) ;
result = ( counter . QuadPart - win32_perf_counter . QuadPart ) * 1000 / ( win32_perf_count_freq . QuadPart ) ;
return result ;
}
zpl_u64 zpl_time_utc_ms ( void ) {
FILETIME ft ;
ULARGE_INTEGER li ;
GetSystemTimeAsFileTime ( & ft ) ;
li . LowPart = ft . dwLowDateTime ;
li . HighPart = ft . dwHighDateTime ;
return li . QuadPart / 1000 ;
}
zpl_u64 zpl_time_tz_ms ( void ) {
FILETIME ft ;
SYSTEMTIME st , lst ;
ULARGE_INTEGER li ;
GetSystemTime ( & st ) ;
SystemTimeToTzSpecificLocalTime ( NULL , & st , & lst ) ;
SystemTimeToFileTime ( & lst , & ft ) ;
li . LowPart = ft . dwLowDateTime ;
li . HighPart = ft . dwHighDateTime ;
return li . QuadPart / 1000 ;
}
void zpl_sleep_ms ( zpl_u32 ms ) { Sleep ( ms ) ; }
# else
# if defined(ZPL_SYSTEM_LINUX) || defined(ZPL_SYSTEM_FREEBSD) || defined(ZPL_SYSTEM_OPENBSD) || defined(ZPL_SYSTEM_EMSCRIPTEN)
zpl_u64 zpl__unix_gettime ( void ) {
struct timespec t ;
zpl_u64 result ;
clock_gettime ( 1 /*CLOCK_MONOTONIC*/ , & t ) ;
result = 1000 * t . tv_sec + 1.0e-6 * t . tv_nsec ;
return result ;
}
# endif
zpl_u64 zpl_time_rel_ms ( void ) {
# if defined(ZPL_SYSTEM_OSX)
zpl_u64 result ;
zpl_local_persist zpl_u64 timebase = 0 ;
zpl_local_persist zpl_u64 timestart = 0 ;
if ( ! timestart ) {
mach_timebase_info_data_t tb = { 0 } ;
mach_timebase_info ( & tb ) ;
timebase = tb . numer ;
timebase / = tb . denom ;
timestart = mach_absolute_time ( ) ;
}
// NOTE: mach_absolute_time() returns things in nanoseconds
result = 1.0e-6 * ( mach_absolute_time ( ) - timestart ) * timebase ;
return result ;
# else
zpl_local_persist zpl_u64 unix_timestart = 0.0 ;
if ( ! unix_timestart ) { unix_timestart = zpl__unix_gettime ( ) ; }
zpl_u64 now = zpl__unix_gettime ( ) ;
return ( now - unix_timestart ) ;
# endif
}
zpl_u64 zpl_time_utc_ms ( void ) {
struct timespec t ;
# if defined(ZPL_SYSTEM_OSX)
clock_serv_t cclock ;
mach_timespec_t mts ;
host_get_clock_service ( mach_host_self ( ) , CALENDAR_CLOCK , & cclock ) ;
clock_get_time ( cclock , & mts ) ;
mach_port_deallocate ( mach_task_self ( ) , cclock ) ;
t . tv_sec = mts . tv_sec ;
t . tv_nsec = mts . tv_nsec ;
# else
clock_gettime ( 0 /*CLOCK_REALTIME*/ , & t ) ;
# endif
return ( ( zpl_u64 ) t . tv_sec * 1000 + t . tv_nsec * 1e-6 + ZPL__UNIX_TO_WIN32_EPOCH ) ;
}
void zpl_sleep_ms ( zpl_u32 ms ) {
struct timespec req = { cast ( time_t ) ( ms * 1e-3 ) , cast ( long ) ( ( ms % 1000 ) * 1e6 ) } ;
struct timespec rem = { 0 , 0 } ;
nanosleep ( & req , & rem ) ;
}
zpl_u64 zpl_time_tz_ms ( void ) {
struct tm t ;
zpl_u64 result = zpl_time_utc_ms ( ) - ZPL__UNIX_TO_WIN32_EPOCH ;
zpl_u16 ms = result % 1000 ;
result * = 1e-3 ;
localtime_r ( ( const time_t * ) & result , & t ) ;
result = ( zpl_u64 ) mktime ( & t ) ;
return ( result - timezone + t . tm_isdst * 3600 ) * 1000 + ms + ZPL__UNIX_TO_WIN32_EPOCH ;
}
# endif
zpl_f64 zpl_time_rel ( void ) {
return ( zpl_f64 ) ( zpl_time_rel_ms ( ) * 1e-3 ) ;
}
zpl_f64 zpl_time_utc ( void ) {
return ( zpl_f64 ) ( zpl_time_utc_ms ( ) * 1e-3 ) ;
}
zpl_f64 zpl_time_tz ( void ) {
return ( zpl_f64 ) ( zpl_time_tz_ms ( ) * 1e-3 ) ;
}
ZPL_END_C_DECLS
// file: source/core/random.c
ZPL_BEGIN_C_DECLS
# if defined(ZPL_MODULE_THREADING)
zpl_global zpl_atomic32 zpl__random_shared_counter = { 0 } ;
# else
zpl_global zpl_i32 zpl__random_shared_counter = 0 ;
# endif
zpl_internal zpl_u32 zpl__get_noise_from_time ( void ) {
zpl_u32 accum = 0 ;
zpl_f64 start , remaining , end , curr = 0 ;
zpl_u64 interval = 100000ll ;
start = zpl_time_rel ( ) ;
remaining = ( interval - cast ( zpl_u64 ) ( interval * start ) % interval ) / cast ( zpl_f64 ) interval ;
end = start + remaining ;
do {
curr = zpl_time_rel ( ) ;
accum + = cast ( zpl_u32 ) curr ;
} while ( curr > = end ) ;
return accum ;
}
// NOTE: Partly from http://preshing.com/20121224/how-to-generate-a-sequence-of-unique-random-integers/
// But the generation is even more random-er-est
zpl_internal ZPL_ALWAYS_INLINE zpl_u32 zpl__permute_qpr ( zpl_u32 x ) {
zpl_local_persist zpl_u32 const prime = 4294967291 ; // 2^32 - 5
if ( x > = prime ) {
return x ;
} else {
zpl_u32 residue = cast ( zpl_u32 ) ( cast ( zpl_u64 ) x * x ) % prime ;
if ( x < = prime / 2 )
return residue ;
else
return prime - residue ;
}
}
zpl_internal ZPL_ALWAYS_INLINE zpl_u32 zpl__permute_with_offset ( zpl_u32 x , zpl_u32 offset ) {
return ( zpl__permute_qpr ( x ) + offset ) ^ 0x5bf03635 ;
}
void zpl_random_init ( zpl_random * r ) {
zpl_u64 time , tick ;
zpl_isize i , j ;
zpl_u32 x = 0 ;
r - > value = 0 ;
r - > offsets [ 0 ] = zpl__get_noise_from_time ( ) ;
# ifdef ZPL_MODULE_THREADING
r - > offsets [ 1 ] = zpl_atomic32_fetch_add ( & zpl__random_shared_counter , 1 ) ;
r - > offsets [ 2 ] = zpl_thread_current_id ( ) ;
r - > offsets [ 3 ] = zpl_thread_current_id ( ) * 3 + 1 ;
# else
r - > offsets [ 1 ] = zpl__random_shared_counter + + ;
r - > offsets [ 2 ] = 0 ;
r - > offsets [ 3 ] = 1 ;
# endif
time = zpl_time_tz_ms ( ) ;
r - > offsets [ 4 ] = cast ( zpl_u32 ) ( time > > 32 ) ;
r - > offsets [ 5 ] = cast ( zpl_u32 ) time ;
r - > offsets [ 6 ] = zpl__get_noise_from_time ( ) ;
tick = zpl_rdtsc ( ) ;
r - > offsets [ 7 ] = cast ( zpl_u32 ) ( tick ^ ( tick > > 32 ) ) ;
for ( j = 0 ; j < 4 ; j + + ) {
for ( i = 0 ; i < zpl_count_of ( r - > offsets ) ; i + + ) {
r - > offsets [ i ] = x = zpl__permute_with_offset ( x , r - > offsets [ i ] ) ;
}
}
}
zpl_u32 zpl_random_gen_u32 ( zpl_random * r ) {
zpl_u32 x = r - > value ;
zpl_u32 carry = 1 ;
zpl_isize i ;
for ( i = 0 ; i < zpl_count_of ( r - > offsets ) ; i + + ) {
x = zpl__permute_with_offset ( x , r - > offsets [ i ] ) ;
if ( carry > 0 ) {
carry = + + r - > offsets [ i ] ? 0 : 1 ;
}
}
r - > value = x ;
return x ;
}
zpl_u32 zpl_random_gen_u32_unique ( zpl_random * r ) {
zpl_u32 x = r - > value ;
zpl_isize i ;
r - > value + + ;
for ( i = 0 ; i < zpl_count_of ( r - > offsets ) ; i + + ) {
x = zpl__permute_with_offset ( x , r - > offsets [ i ] ) ;
}
return x ;
}
zpl_u64 zpl_random_gen_u64 ( zpl_random * r ) {
return ( ( cast ( zpl_u64 ) zpl_random_gen_u32 ( r ) ) < < 32 ) | zpl_random_gen_u32 ( r ) ;
}
zpl_isize zpl_random_gen_isize ( zpl_random * r ) {
2023-01-15 15:59:33 +00:00
# if defined(ZPL_ARCH_32_BIT)
zpl_u32 u = zpl_random_gen_u32 ( r ) ;
# else
2022-09-11 17:42:06 +00:00
zpl_u64 u = zpl_random_gen_u64 ( r ) ;
2023-01-15 15:59:33 +00:00
# endif
2022-09-11 17:42:06 +00:00
zpl_isize i ;
zpl_memcopy ( & i , & u , zpl_size_of ( u ) ) ;
return i ;
}
zpl_i64 zpl_random_range_i64 ( zpl_random * r , zpl_i64 lower_inc , zpl_i64 higher_inc ) {
zpl_u64 u = zpl_random_gen_u64 ( r ) ;
zpl_i64 diff = higher_inc - lower_inc + 1 ;
u % = diff ;
zpl_i64 i ;
zpl_memcopy ( & i , & u , zpl_size_of ( u ) ) ;
i + = lower_inc ;
return i ;
}
zpl_isize zpl_random_range_isize ( zpl_random * r , zpl_isize lower_inc , zpl_isize higher_inc ) {
2023-01-15 15:59:33 +00:00
# if defined(ZPL_ARCH_32_BIT)
zpl_u32 u = zpl_random_gen_u32 ( r ) ;
# else
2022-09-11 17:42:06 +00:00
zpl_u64 u = zpl_random_gen_u64 ( r ) ;
2023-01-15 15:59:33 +00:00
# endif
2022-09-11 17:42:06 +00:00
zpl_isize diff = higher_inc - lower_inc + 1 ;
u % = diff ;
zpl_isize i ;
zpl_memcopy ( & i , & u , zpl_size_of ( u ) ) ;
i + = lower_inc ;
return i ;
}
ZPL_ALWAYS_INLINE zpl_f64 zpl__random_copy_sign64 ( zpl_f64 x , zpl_f64 y ) {
zpl_i64 ix = 0 , iy = 0 ;
zpl_memcopy ( & ix , & x , zpl_size_of ( zpl_i64 ) ) ;
zpl_memcopy ( & iy , & y , zpl_size_of ( zpl_i64 ) ) ;
ix & = 0x7fffffffffffffff ;
ix | = iy & 0x8000000000000000 ;
zpl_f64 r = 0.0 ;
zpl_memcopy ( & r , & ix , zpl_size_of ( zpl_f64 ) ) ;
return r ;
}
zpl_f64 zpl_random_range_f64 ( zpl_random * r , zpl_f64 lower_inc , zpl_f64 higher_inc ) {
zpl_f64 f = cast ( zpl_f64 ) zpl_random_gen_u64 ( r ) / cast ( zpl_f64 ) ZPL_U64_MAX ;
zpl_f64 diff = higher_inc - lower_inc ;
f * = diff ;
f + = lower_inc ;
return f ;
}
ZPL_END_C_DECLS
// file: source/core/misc.c
ZPL_BEGIN_C_DECLS
void zpl_yield ( void ) {
# if defined(ZPL_SYSTEM_WINDOWS)
Sleep ( 0 ) ;
# else
sched_yield ( ) ;
# endif
}
const char * zpl_get_env ( const char * name ) {
char * buffer = NULL ;
const char * ptr = zpl_get_env_buf ( name ) ;
if ( ptr = = NULL ) {
return NULL ;
}
zpl_isize ptr_size = zpl_strlen ( ptr ) ;
buffer = ( char * ) zpl_malloc ( ptr_size * sizeof ( char ) + 1 ) ;
zpl_memcopy ( ( char * ) buffer , ptr , ptr_size + 1 ) ;
return buffer ;
}
const char * zpl_get_env_buf ( const char * name ) {
# ifdef ZPL_SYSTEM_WINDOWS
zpl_local_persist wchar_t wbuffer [ 32767 ] = { 0 } ;
zpl_local_persist char buffer [ 32767 ] = { 0 } ;
if ( ! GetEnvironmentVariableW (
cast ( LPCWSTR ) zpl_utf8_to_ucs2_buf ( cast ( const zpl_u8 * ) name ) ,
cast ( LPWSTR ) wbuffer , 32767 ) ) {
return NULL ;
}
zpl_ucs2_to_utf8 ( cast ( zpl_u8 * ) buffer , 32767 , cast ( const zpl_u16 * ) wbuffer ) ;
return ( const char * ) buffer ;
# else
return ( const char * ) getenv ( name ) ;
# endif
}
zpl_string zpl_get_env_str ( const char * name ) {
const char * buf = zpl_get_env_buf ( name ) ;
if ( buf = = NULL ) {
return NULL ;
}
zpl_string str = zpl_string_make ( zpl_heap ( ) , buf ) ;
return str ;
}
void zpl_set_env ( const char * name , const char * value ) {
# if defined(ZPL_SYSTEM_WINDOWS)
SetEnvironmentVariableA ( name , value ) ;
# else
setenv ( name , value , 1 ) ;
# endif
}
void zpl_unset_env ( const char * name ) {
# if defined(ZPL_SYSTEM_WINDOWS)
SetEnvironmentVariableA ( name , NULL ) ;
# else
unsetenv ( name ) ;
# endif
}
# if !defined(ZPL_SYSTEM_WINDOWS)
extern char * * environ ;
# endif
zpl_u32 zpl_system_command ( const char * command , zpl_usize buffer_len , char * buffer ) {
# if defined(ZPL_SYSTEM_EMSCRIPTEN)
ZPL_PANIC ( " zpl_system_command not supported " ) ;
# else
# if defined(ZPL_SYSTEM_WINDOWS)
FILE * handle = _popen ( command , " r " ) ;
# else
FILE * handle = popen ( command , " r " ) ;
# endif
if ( ! handle ) return 0 ;
int c ;
zpl_usize i = 0 ;
while ( ( c = getc ( handle ) ) ! = EOF & & i + + < buffer_len ) {
* buffer + + = c ;
}
# if defined(ZPL_SYSTEM_WINDOWS)
_pclose ( handle ) ;
# else
pclose ( handle ) ;
# endif
# endif
return 1 ;
}
zpl_string zpl_system_command_str ( const char * command , zpl_allocator backing ) {
# if defined(ZPL_SYSTEM_EMSCRIPTEN)
ZPL_PANIC ( " zpl_system_command not supported " ) ;
# else
# if defined(ZPL_SYSTEM_WINDOWS)
FILE * handle = _popen ( command , " r " ) ;
# else
FILE * handle = popen ( command , " r " ) ;
# endif
if ( ! handle ) return NULL ;
zpl_string output = zpl_string_make_reserve ( backing , 4 ) ;
int c ;
while ( ( c = getc ( handle ) ) ! = EOF ) {
char ins [ 2 ] = { ( char ) c , 0 } ;
output = zpl_string_appendc ( output , ins ) ;
}
# if defined(ZPL_SYSTEM_WINDOWS)
_pclose ( handle ) ;
# else
pclose ( handle ) ;
# endif
return output ;
# endif
return NULL ;
}
ZPL_END_C_DECLS
// file: source/core/sort.c
ZPL_BEGIN_C_DECLS
# define ZPL__COMPARE_PROC(Type) \
zpl_global zpl_isize Type # # __cmp_offset ; \
ZPL_COMPARE_PROC ( Type # # __cmp ) { \
Type const p = * cast ( Type const * ) zpl_pointer_add_const ( a , Type # # __cmp_offset ) ; \
Type const q = * cast ( Type const * ) zpl_pointer_add_const ( b , Type # # __cmp_offset ) ; \
return p < q ? - 1 : p > q ; \
} \
ZPL_COMPARE_PROC_PTR ( Type # # _cmp ( zpl_isize offset ) ) { \
Type # # __cmp_offset = offset ; \
return & Type # # __cmp ; \
}
ZPL__COMPARE_PROC ( zpl_u8 ) ;
ZPL__COMPARE_PROC ( zpl_i16 ) ;
ZPL__COMPARE_PROC ( zpl_i32 ) ;
ZPL__COMPARE_PROC ( zpl_i64 ) ;
ZPL__COMPARE_PROC ( zpl_isize ) ;
ZPL__COMPARE_PROC ( zpl_f32 ) ;
ZPL__COMPARE_PROC ( zpl_f64 ) ;
// NOTE: str_cmp is special as it requires a funny type and funny comparison
zpl_global zpl_isize zpl__str_cmp_offset ;
ZPL_COMPARE_PROC ( zpl__str_cmp ) {
char const * p = * cast ( char const * * ) zpl_pointer_add_const ( a , zpl__str_cmp_offset ) ;
char const * q = * cast ( char const * * ) zpl_pointer_add_const ( b , zpl__str_cmp_offset ) ;
return zpl_strcmp ( p , q ) ;
}
ZPL_COMPARE_PROC_PTR ( zpl_str_cmp ( zpl_isize offset ) ) {
zpl__str_cmp_offset = offset ;
return & zpl__str_cmp ;
}
# undef ZPL__COMPARE_PROC
// TODO: Make user definable?
# define ZPL__SORT_STACK_SIZE 64
# define zpl__SORT_INSERT_SORT_TRESHOLD 8
# define ZPL__SORT_PUSH(_base, _limit) \
do { \
stack_ptr [ 0 ] = ( _base ) ; \
stack_ptr [ 1 ] = ( _limit ) ; \
stack_ptr + = 2 ; \
} while ( 0 )
# define ZPL__SORT_POP(_base, _limit) \
do { \
stack_ptr - = 2 ; \
( _base ) = stack_ptr [ 0 ] ; \
( _limit ) = stack_ptr [ 1 ] ; \
} while ( 0 )
void zpl_sort ( void * base_ , zpl_isize count , zpl_isize size , zpl_compare_proc cmp ) {
zpl_u8 * i , * j ;
zpl_u8 * base = cast ( zpl_u8 * ) base_ ;
zpl_u8 * limit = base + count * size ;
zpl_isize threshold = zpl__SORT_INSERT_SORT_TRESHOLD * size ;
// NOTE: Prepare the stack
zpl_u8 * stack [ ZPL__SORT_STACK_SIZE ] = { 0 } ;
zpl_u8 * * stack_ptr = stack ;
for ( ; ; ) {
if ( ( limit - base ) > threshold ) {
// NOTE: Quick sort
i = base + size ;
j = limit - size ;
zpl_memswap ( ( ( limit - base ) / size / 2 ) * size + base , base , size ) ;
if ( cmp ( i , j ) > 0 ) zpl_memswap ( i , j , size ) ;
if ( cmp ( base , j ) > 0 ) zpl_memswap ( base , j , size ) ;
if ( cmp ( i , base ) > 0 ) zpl_memswap ( i , base , size ) ;
for ( ; ; ) {
do
i + = size ;
while ( cmp ( i , base ) < 0 ) ;
do
j - = size ;
while ( cmp ( j , base ) > 0 ) ;
if ( i > j ) break ;
zpl_memswap ( i , j , size ) ;
}
zpl_memswap ( base , j , size ) ;
if ( j - base > limit - i ) {
ZPL__SORT_PUSH ( base , j ) ;
base = i ;
} else {
ZPL__SORT_PUSH ( i , limit ) ;
limit = j ;
}
} else {
// NOTE: Insertion sort
for ( j = base , i = j + size ; i < limit ; j = i , i + = size ) {
for ( ; cmp ( j , j + size ) > 0 ; j - = size ) {
zpl_memswap ( j , j + size , size ) ;
if ( j = = base ) break ;
}
}
if ( stack_ptr = = stack ) break ; // NOTE: Sorting is done!
ZPL__SORT_POP ( base , limit ) ;
}
}
}
# undef ZPL__SORT_PUSH
# undef ZPL__SORT_POP
# define ZPL_RADIX_SORT_PROC_GEN(Type) \
ZPL_RADIX_SORT_PROC ( Type ) { \
zpl_ # # Type * source = items ; \
zpl_ # # Type * dest = temp ; \
zpl_isize byte_index , i , byte_max = 8 * zpl_size_of ( zpl_ # # Type ) ; \
for ( byte_index = 0 ; byte_index < byte_max ; byte_index + = 8 ) { \
zpl_isize offsets [ 256 ] = { 0 } ; \
zpl_isize total = 0 ; \
/* NOTE: First pass - count how many of each key */ \
for ( i = 0 ; i < count ; i + + ) { \
zpl_ # # Type radix_value = source [ i ] ; \
zpl_ # # Type radix_piece = ( radix_value > > byte_index ) & 0xff ; \
offsets [ radix_piece ] + + ; \
} \
/* NOTE: Change counts to offsets */ \
for ( i = 0 ; i < zpl_count_of ( offsets ) ; i + + ) { \
zpl_isize skcount = offsets [ i ] ; \
offsets [ i ] = total ; \
total + = skcount ; \
} \
/* NOTE: Second pass - place elements into the right location */ \
for ( i = 0 ; i < count ; i + + ) { \
zpl_ # # Type radix_value = source [ i ] ; \
zpl_ # # Type radix_piece = ( radix_value > > byte_index ) & 0xff ; \
dest [ offsets [ radix_piece ] + + ] = source [ i ] ; \
} \
zpl_swap ( zpl_ # # Type * , source , dest ) ; \
} \
}
ZPL_RADIX_SORT_PROC_GEN ( u8 ) ;
ZPL_RADIX_SORT_PROC_GEN ( u16 ) ;
ZPL_RADIX_SORT_PROC_GEN ( u32 ) ;
ZPL_RADIX_SORT_PROC_GEN ( u64 ) ;
void zpl_shuffle ( void * base , zpl_isize count , zpl_isize size ) {
zpl_u8 * a ;
zpl_isize i , j ;
zpl_random random ;
zpl_random_init ( & random ) ;
a = cast ( zpl_u8 * ) base + ( count - 1 ) * size ;
for ( i = count ; i > 1 ; i - - ) {
j = zpl_random_gen_isize ( & random ) % i ;
zpl_memswap ( a , cast ( zpl_u8 * ) base + j * size , size ) ;
a - = size ;
}
}
void zpl_reverse ( void * base , zpl_isize count , zpl_isize size ) {
zpl_isize i , j = count - 1 ;
for ( i = 0 ; i < j ; i + + , j + + ) zpl_memswap ( cast ( zpl_u8 * ) base + i * size , cast ( zpl_u8 * ) base + j * size , size ) ;
}
ZPL_END_C_DECLS
# endif
2021-11-29 08:23:08 +00:00
# endif
2022-09-11 17:42:06 +00:00
# if defined(ZPL_MODULE_HASHING)
// file: source/hashing.c
////////////////////////////////////////////////////////////////
//
// Hashing functions
//
//
ZPL_BEGIN_C_DECLS
zpl_u32 zpl_adler32 ( void const * data , zpl_isize len ) {
zpl_u32 const MOD_ALDER = 65521 ;
zpl_u32 a = 1 , b = 0 ;
zpl_isize i , block_len ;
zpl_u8 const * bytes = cast ( zpl_u8 const * ) data ;
block_len = len % 5552 ;
while ( len ) {
for ( i = 0 ; i + 7 < block_len ; i + = 8 ) {
a + = bytes [ 0 ] , b + = a ;
a + = bytes [ 1 ] , b + = a ;
a + = bytes [ 2 ] , b + = a ;
a + = bytes [ 3 ] , b + = a ;
a + = bytes [ 4 ] , b + = a ;
a + = bytes [ 5 ] , b + = a ;
a + = bytes [ 6 ] , b + = a ;
a + = bytes [ 7 ] , b + = a ;
bytes + = 8 ;
}
for ( ; i < block_len ; i + + ) a + = * bytes + + , b + = a ;
a % = MOD_ALDER , b % = MOD_ALDER ;
len - = block_len ;
block_len = 5552 ;
}
return ( b < < 16 ) | a ;
}
zpl_global zpl_u32 const zpl__crc32_table [ 256 ] = {
0x00000000 , 0x77073096 , 0xee0e612c , 0x990951ba , 0x076dc419 , 0x706af48f , 0xe963a535 , 0x9e6495a3 , 0x0edb8832 ,
0x79dcb8a4 , 0xe0d5e91e , 0x97d2d988 , 0x09b64c2b , 0x7eb17cbd , 0xe7b82d07 , 0x90bf1d91 , 0x1db71064 , 0x6ab020f2 ,
0xf3b97148 , 0x84be41de , 0x1adad47d , 0x6ddde4eb , 0xf4d4b551 , 0x83d385c7 , 0x136c9856 , 0x646ba8c0 , 0xfd62f97a ,
0x8a65c9ec , 0x14015c4f , 0x63066cd9 , 0xfa0f3d63 , 0x8d080df5 , 0x3b6e20c8 , 0x4c69105e , 0xd56041e4 , 0xa2677172 ,
0x3c03e4d1 , 0x4b04d447 , 0xd20d85fd , 0xa50ab56b , 0x35b5a8fa , 0x42b2986c , 0xdbbbc9d6 , 0xacbcf940 , 0x32d86ce3 ,
0x45df5c75 , 0xdcd60dcf , 0xabd13d59 , 0x26d930ac , 0x51de003a , 0xc8d75180 , 0xbfd06116 , 0x21b4f4b5 , 0x56b3c423 ,
0xcfba9599 , 0xb8bda50f , 0x2802b89e , 0x5f058808 , 0xc60cd9b2 , 0xb10be924 , 0x2f6f7c87 , 0x58684c11 , 0xc1611dab ,
0xb6662d3d , 0x76dc4190 , 0x01db7106 , 0x98d220bc , 0xefd5102a , 0x71b18589 , 0x06b6b51f , 0x9fbfe4a5 , 0xe8b8d433 ,
0x7807c9a2 , 0x0f00f934 , 0x9609a88e , 0xe10e9818 , 0x7f6a0dbb , 0x086d3d2d , 0x91646c97 , 0xe6635c01 , 0x6b6b51f4 ,
0x1c6c6162 , 0x856530d8 , 0xf262004e , 0x6c0695ed , 0x1b01a57b , 0x8208f4c1 , 0xf50fc457 , 0x65b0d9c6 , 0x12b7e950 ,
0x8bbeb8ea , 0xfcb9887c , 0x62dd1ddf , 0x15da2d49 , 0x8cd37cf3 , 0xfbd44c65 , 0x4db26158 , 0x3ab551ce , 0xa3bc0074 ,
0xd4bb30e2 , 0x4adfa541 , 0x3dd895d7 , 0xa4d1c46d , 0xd3d6f4fb , 0x4369e96a , 0x346ed9fc , 0xad678846 , 0xda60b8d0 ,
0x44042d73 , 0x33031de5 , 0xaa0a4c5f , 0xdd0d7cc9 , 0x5005713c , 0x270241aa , 0xbe0b1010 , 0xc90c2086 , 0x5768b525 ,
0x206f85b3 , 0xb966d409 , 0xce61e49f , 0x5edef90e , 0x29d9c998 , 0xb0d09822 , 0xc7d7a8b4 , 0x59b33d17 , 0x2eb40d81 ,
0xb7bd5c3b , 0xc0ba6cad , 0xedb88320 , 0x9abfb3b6 , 0x03b6e20c , 0x74b1d29a , 0xead54739 , 0x9dd277af , 0x04db2615 ,
0x73dc1683 , 0xe3630b12 , 0x94643b84 , 0x0d6d6a3e , 0x7a6a5aa8 , 0xe40ecf0b , 0x9309ff9d , 0x0a00ae27 , 0x7d079eb1 ,
0xf00f9344 , 0x8708a3d2 , 0x1e01f268 , 0x6906c2fe , 0xf762575d , 0x806567cb , 0x196c3671 , 0x6e6b06e7 , 0xfed41b76 ,
0x89d32be0 , 0x10da7a5a , 0x67dd4acc , 0xf9b9df6f , 0x8ebeeff9 , 0x17b7be43 , 0x60b08ed5 , 0xd6d6a3e8 , 0xa1d1937e ,
0x38d8c2c4 , 0x4fdff252 , 0xd1bb67f1 , 0xa6bc5767 , 0x3fb506dd , 0x48b2364b , 0xd80d2bda , 0xaf0a1b4c , 0x36034af6 ,
0x41047a60 , 0xdf60efc3 , 0xa867df55 , 0x316e8eef , 0x4669be79 , 0xcb61b38c , 0xbc66831a , 0x256fd2a0 , 0x5268e236 ,
0xcc0c7795 , 0xbb0b4703 , 0x220216b9 , 0x5505262f , 0xc5ba3bbe , 0xb2bd0b28 , 0x2bb45a92 , 0x5cb36a04 , 0xc2d7ffa7 ,
0xb5d0cf31 , 0x2cd99e8b , 0x5bdeae1d , 0x9b64c2b0 , 0xec63f226 , 0x756aa39c , 0x026d930a , 0x9c0906a9 , 0xeb0e363f ,
0x72076785 , 0x05005713 , 0x95bf4a82 , 0xe2b87a14 , 0x7bb12bae , 0x0cb61b38 , 0x92d28e9b , 0xe5d5be0d , 0x7cdcefb7 ,
0x0bdbdf21 , 0x86d3d2d4 , 0xf1d4e242 , 0x68ddb3f8 , 0x1fda836e , 0x81be16cd , 0xf6b9265b , 0x6fb077e1 , 0x18b74777 ,
0x88085ae6 , 0xff0f6a70 , 0x66063bca , 0x11010b5c , 0x8f659eff , 0xf862ae69 , 0x616bffd3 , 0x166ccf45 , 0xa00ae278 ,
0xd70dd2ee , 0x4e048354 , 0x3903b3c2 , 0xa7672661 , 0xd06016f7 , 0x4969474d , 0x3e6e77db , 0xaed16a4a , 0xd9d65adc ,
0x40df0b66 , 0x37d83bf0 , 0xa9bcae53 , 0xdebb9ec5 , 0x47b2cf7f , 0x30b5ffe9 , 0xbdbdf21c , 0xcabac28a , 0x53b39330 ,
0x24b4a3a6 , 0xbad03605 , 0xcdd70693 , 0x54de5729 , 0x23d967bf , 0xb3667a2e , 0xc4614ab8 , 0x5d681b02 , 0x2a6f2b94 ,
0xb40bbe37 , 0xc30c8ea1 , 0x5a05df1b , 0x2d02ef8d ,
} ;
zpl_global zpl_u64 const zpl__crc64_table [ 256 ] = {
0x0000000000000000ull , 0x7ad870c830358979ull , 0xf5b0e190606b12f2ull , 0x8f689158505e9b8bull , 0xc038e5739841b68full , 0xbae095bba8743ff6ull ,
0x358804e3f82aa47dull , 0x4f50742bc81f2d04ull , 0xab28ecb46814fe75ull , 0xd1f09c7c5821770cull , 0x5e980d24087fec87ull , 0x24407dec384a65feull ,
0x6b1009c7f05548faull , 0x11c8790fc060c183ull , 0x9ea0e857903e5a08ull , 0xe478989fa00bd371ull , 0x7d08ff3b88be6f81ull , 0x07d08ff3b88be6f8ull ,
0x88b81eabe8d57d73ull , 0xf2606e63d8e0f40aull , 0xbd301a4810ffd90eull , 0xc7e86a8020ca5077ull , 0x4880fbd87094cbfcull , 0x32588b1040a14285ull ,
0xd620138fe0aa91f4ull , 0xacf86347d09f188dull , 0x2390f21f80c18306ull , 0x594882d7b0f40a7full , 0x1618f6fc78eb277bull , 0x6cc0863448deae02ull ,
0xe3a8176c18803589ull , 0x997067a428b5bcf0ull , 0xfa11fe77117cdf02ull , 0x80c98ebf2149567bull ,
0x0fa11fe77117cdf0ull , 0x75796f2f41224489ull , 0x3a291b04893d698dull , 0x40f16bccb908e0f4ull , 0xcf99fa94e9567b7full , 0xb5418a5cd963f206ull ,
0x513912c379682177ull , 0x2be1620b495da80eull , 0xa489f35319033385ull , 0xde51839b2936bafcull , 0x9101f7b0e12997f8ull , 0xebd98778d11c1e81ull ,
0x64b116208142850aull , 0x1e6966e8b1770c73ull , 0x8719014c99c2b083ull , 0xfdc17184a9f739faull , 0x72a9e0dcf9a9a271ull , 0x08719014c99c2b08ull ,
0x4721e43f0183060cull , 0x3df994f731b68f75ull , 0xb29105af61e814feull , 0xc849756751dd9d87ull , 0x2c31edf8f1d64ef6ull , 0x56e99d30c1e3c78full ,
0xd9810c6891bd5c04ull , 0xa3597ca0a188d57dull , 0xec09088b6997f879ull , 0x96d1784359a27100ull , 0x19b9e91b09fcea8bull , 0x636199d339c963f2ull ,
0xdf7adabd7a6e2d6full , 0xa5a2aa754a5ba416ull , 0x2aca3b2d1a053f9dull , 0x50124be52a30b6e4ull , 0x1f423fcee22f9be0ull , 0x659a4f06d21a1299ull ,
0xeaf2de5e82448912ull , 0x902aae96b271006bull , 0x74523609127ad31aull , 0x0e8a46c1224f5a63ull , 0x81e2d7997211c1e8ull , 0xfb3aa75142244891ull ,
0xb46ad37a8a3b6595ull , 0xceb2a3b2ba0eececull , 0x41da32eaea507767ull , 0x3b024222da65fe1eull , 0xa2722586f2d042eeull , 0xd8aa554ec2e5cb97ull ,
0x57c2c41692bb501cull , 0x2d1ab4dea28ed965ull , 0x624ac0f56a91f461ull , 0x1892b03d5aa47d18ull , 0x97fa21650afae693ull , 0xed2251ad3acf6feaull ,
0x095ac9329ac4bc9bull , 0x7382b9faaaf135e2ull , 0xfcea28a2faafae69ull , 0x8632586aca9a2710ull , 0xc9622c4102850a14ull , 0xb3ba5c8932b0836dull ,
0x3cd2cdd162ee18e6ull , 0x460abd1952db919full , 0x256b24ca6b12f26dull , 0x5fb354025b277b14ull , 0xd0dbc55a0b79e09full , 0xaa03b5923b4c69e6ull ,
0xe553c1b9f35344e2ull , 0x9f8bb171c366cd9bull , 0x10e3202993385610ull , 0x6a3b50e1a30ddf69ull , 0x8e43c87e03060c18ull , 0xf49bb8b633338561ull ,
0x7bf329ee636d1eeaull , 0x012b592653589793ull , 0x4e7b2d0d9b47ba97ull , 0x34a35dc5ab7233eeull , 0xbbcbcc9dfb2ca865ull , 0xc113bc55cb19211cull ,
0x5863dbf1e3ac9decull , 0x22bbab39d3991495ull , 0xadd33a6183c78f1eull , 0xd70b4aa9b3f20667ull , 0x985b3e827bed2b63ull , 0xe2834e4a4bd8a21aull ,
0x6debdf121b863991ull , 0x1733afda2bb3b0e8ull , 0xf34b37458bb86399ull , 0x8993478dbb8deae0ull , 0x06fbd6d5ebd3716bull , 0x7c23a61ddbe6f812ull ,
0x3373d23613f9d516ull , 0x49aba2fe23cc5c6full , 0xc6c333a67392c7e4ull , 0xbc1b436e43a74e9dull , 0x95ac9329ac4bc9b5ull , 0xef74e3e19c7e40ccull ,
0x601c72b9cc20db47ull , 0x1ac40271fc15523eull , 0x5594765a340a7f3aull , 0x2f4c0692043ff643ull , 0xa02497ca54616dc8ull , 0xdafce7026454e4b1ull ,
0x3e847f9dc45f37c0ull , 0x445c0f55f46abeb9ull , 0xcb349e0da4342532ull , 0xb1eceec59401ac4bull , 0xfebc9aee5c1e814full , 0x8464ea266c2b0836ull ,
0x0b0c7b7e3c7593bdull , 0x71d40bb60c401ac4ull , 0xe8a46c1224f5a634ull , 0x927c1cda14c02f4dull , 0x1d148d82449eb4c6ull , 0x67ccfd4a74ab3dbfull ,
0x289c8961bcb410bbull , 0x5244f9a98c8199c2ull , 0xdd2c68f1dcdf0249ull , 0xa7f41839ecea8b30ull , 0x438c80a64ce15841ull , 0x3954f06e7cd4d138ull ,
0xb63c61362c8a4ab3ull , 0xcce411fe1cbfc3caull , 0x83b465d5d4a0eeceull , 0xf96c151de49567b7ull , 0x76048445b4cbfc3cull , 0x0cdcf48d84fe7545ull ,
0x6fbd6d5ebd3716b7ull , 0x15651d968d029fceull , 0x9a0d8ccedd5c0445ull , 0xe0d5fc06ed698d3cull , 0xaf85882d2576a038ull , 0xd55df8e515432941ull ,
0x5a3569bd451db2caull , 0x20ed197575283bb3ull , 0xc49581ead523e8c2ull , 0xbe4df122e51661bbull , 0x3125607ab548fa30ull , 0x4bfd10b2857d7349ull ,
0x04ad64994d625e4dull , 0x7e7514517d57d734ull , 0xf11d85092d094cbfull , 0x8bc5f5c11d3cc5c6ull , 0x12b5926535897936ull , 0x686de2ad05bcf04full ,
0xe70573f555e26bc4ull , 0x9ddd033d65d7e2bdull , 0xd28d7716adc8cfb9ull , 0xa85507de9dfd46c0ull , 0x273d9686cda3dd4bull , 0x5de5e64efd965432ull ,
0xb99d7ed15d9d8743ull , 0xc3450e196da80e3aull , 0x4c2d9f413df695b1ull , 0x36f5ef890dc31cc8ull , 0x79a59ba2c5dc31ccull , 0x037deb6af5e9b8b5ull ,
0x8c157a32a5b7233eull , 0xf6cd0afa9582aa47ull , 0x4ad64994d625e4daull , 0x300e395ce6106da3ull , 0xbf66a804b64ef628ull , 0xc5bed8cc867b7f51ull ,
0x8aeeace74e645255ull , 0xf036dc2f7e51db2cull , 0x7f5e4d772e0f40a7ull , 0x05863dbf1e3ac9deull , 0xe1fea520be311aafull , 0x9b26d5e88e0493d6ull ,
0x144e44b0de5a085dull , 0x6e963478ee6f8124ull , 0x21c640532670ac20ull , 0x5b1e309b16452559ull , 0xd476a1c3461bbed2ull , 0xaeaed10b762e37abull ,
0x37deb6af5e9b8b5bull , 0x4d06c6676eae0222ull , 0xc26e573f3ef099a9ull , 0xb8b627f70ec510d0ull , 0xf7e653dcc6da3dd4ull , 0x8d3e2314f6efb4adull ,
0x0256b24ca6b12f26ull , 0x788ec2849684a65full , 0x9cf65a1b368f752eull , 0xe62e2ad306bafc57ull , 0x6946bb8b56e467dcull , 0x139ecb4366d1eea5ull ,
0x5ccebf68aecec3a1ull , 0x2616cfa09efb4ad8ull , 0xa97e5ef8cea5d153ull , 0xd3a62e30fe90582aull , 0xb0c7b7e3c7593bd8ull , 0xca1fc72bf76cb2a1ull ,
0x45775673a732292aull , 0x3faf26bb9707a053ull , 0x70ff52905f188d57ull , 0x0a2722586f2d042eull , 0x854fb3003f739fa5ull , 0xff97c3c80f4616dcull ,
0x1bef5b57af4dc5adull , 0x61372b9f9f784cd4ull , 0xee5fbac7cf26d75full , 0x9487ca0fff135e26ull , 0xdbd7be24370c7322ull , 0xa10fceec0739fa5bull ,
0x2e675fb4576761d0ull , 0x54bf2f7c6752e8a9ull , 0xcdcf48d84fe75459ull , 0xb71738107fd2dd20ull , 0x387fa9482f8c46abull , 0x42a7d9801fb9cfd2ull ,
0x0df7adabd7a6e2d6ull , 0x772fdd63e7936bafull , 0xf8474c3bb7cdf024ull , 0x829f3cf387f8795dull , 0x66e7a46c27f3aa2cull , 0x1c3fd4a417c62355ull ,
0x935745fc4798b8deull , 0xe98f353477ad31a7ull , 0xa6df411fbfb21ca3ull , 0xdc0731d78f8795daull , 0x536fa08fdfd90e51ull , 0x29b7d047efec8728ull ,
} ;
zpl_u32 zpl_crc32 ( void const * data , zpl_isize len ) {
zpl_isize remaining ;
zpl_u32 result = ~ ( cast ( zpl_u32 ) 0 ) ;
zpl_u8 const * c = cast ( zpl_u8 const * ) data ;
for ( remaining = len ; remaining - - ; c + + ) result = ( result > > 8 ) ^ ( zpl__crc32_table [ ( result ^ * c ) & 0xff ] ) ;
return ~ result ;
}
zpl_u64 zpl_crc64 ( void const * data , zpl_isize len ) {
zpl_isize remaining ;
zpl_u64 result = ( cast ( zpl_u64 ) 0 ) ;
zpl_u8 const * c = cast ( zpl_u8 const * ) data ;
for ( remaining = len ; remaining - - ; c + + ) result = ( result > > 8 ) ^ ( zpl__crc64_table [ ( result ^ * c ) & 0xff ] ) ;
return result ;
}
zpl_u32 zpl_fnv32 ( void const * data , zpl_isize len ) {
zpl_isize i ;
zpl_u32 h = 0x811c9dc5 ;
zpl_u8 const * c = cast ( zpl_u8 const * ) data ;
for ( i = 0 ; i < len ; i + + ) h = ( h * 0x01000193 ) ^ c [ i ] ;
return h ;
}
zpl_u64 zpl_fnv64 ( void const * data , zpl_isize len ) {
zpl_isize i ;
zpl_u64 h = 0xcbf29ce484222325ull ;
zpl_u8 const * c = cast ( zpl_u8 const * ) data ;
for ( i = 0 ; i < len ; i + + ) h = ( h * 0x100000001b3ll ) ^ c [ i ] ;
return h ;
}
zpl_u32 zpl_fnv32a ( void const * data , zpl_isize len ) {
zpl_isize i ;
zpl_u32 h = 0x811c9dc5 ;
zpl_u8 const * c = cast ( zpl_u8 const * ) data ;
for ( i = 0 ; i < len ; i + + ) h = ( h ^ c [ i ] ) * 0x01000193 ;
return h ;
}
zpl_u64 zpl_fnv64a ( void const * data , zpl_isize len ) {
zpl_isize i ;
zpl_u64 h = 0xcbf29ce484222325ull ;
zpl_u8 const * c = cast ( zpl_u8 const * ) data ;
for ( i = 0 ; i < len ; i + + ) h = ( h ^ c [ i ] ) * 0x100000001b3ll ;
return h ;
}
// base64 implementation based on https://nachtimwald.com/2017/11/18/base64-encode-and-decode-in-c/
//
zpl_global zpl_u8 zpl__base64_chars [ ] = " ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ " ;
/* generated table based on: */
#if 0
void zpl__base64_decode_table ( ) {
zpl_i32 inv [ 80 ] ;
zpl_isize i ;
zpl_memset ( inv , - 1 , zpl_size_of ( inv ) ) ;
for ( i = 0 ; i < zpl_size_of ( zpl__base64_chars ) - 1 ; i + + ) {
inv [ zpl__base64_chars [ i ] - 43 ] = i ;
}
}
# endif
/* === */
zpl_global zpl_i32 zpl__base64_dec_table [ ] = {
62 , - 1 , - 1 , - 1 , 63 , 52 , 53 , 54 , 55 , 56 , 57 , 58 ,
59 , 60 , 61 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , 0 , 1 , 2 , 3 , 4 , 5 ,
6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 ,
21 , 22 , 23 , 24 , 25 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , 26 , 27 , 28 ,
29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 ,
43 , 44 , 45 , 46 , 47 , 48 , 49 , 50 , 51 } ;
zpl_isize zpl__base64_encoded_size ( zpl_isize len ) {
zpl_isize ret = len ;
if ( len % 3 ! = 0 ) {
ret + = 3 - ( len % 3 ) ;
}
ret / = 3 ;
ret * = 4 ;
return ret ;
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
zpl_isize zpl__base64_decoded_size ( void const * data ) {
zpl_isize len , ret , i ;
const zpl_u8 * s = cast ( const zpl_u8 * ) data ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
if ( s = = NULL ) {
return 0 ;
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
len = zpl_strlen ( cast ( const char * ) s ) ;
ret = len / 4 * 3 ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
for ( i = len ; i - - > 0 ; ) {
if ( s [ i ] = = ' = ' ) {
ret - - ;
} else {
break ;
}
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
return ret ;
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
zpl_b32 zpl__base64_valid_char ( zpl_u8 c ) {
if ( c > = ' 0 ' & & c < = ' 9 ' )
return true ;
if ( c > = ' A ' & & c < = ' Z ' )
return true ;
if ( c > = ' a ' & & c < = ' z ' )
return true ;
if ( c = = ' + ' | | c = = ' / ' | | c = = ' = ' )
return true ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
return false ;
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
zpl_u8 * zpl_base64_encode ( zpl_allocator a , void const * data , zpl_isize len ) {
const zpl_u8 * s = cast ( const zpl_u8 * ) data ;
zpl_u8 * ret = NULL ;
zpl_isize enc_len , i , j , v ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
if ( data = = NULL | | len = = 0 ) {
return NULL ;
}
enc_len = zpl__base64_encoded_size ( len ) ;
ret = cast ( zpl_u8 * ) zpl_alloc ( a , enc_len + 1 ) ;
ret [ enc_len ] = 0 ;
for ( i = 0 , j = 0 ; i < len ; i + = 3 , j + = 4 ) {
v = s [ i ] ;
v = ( i + 1 < len ) ? ( v < < 8 | s [ i + 1 ] ) : ( v < < 8 ) ;
v = ( i + 2 < len ) ? ( v < < 8 | s [ i + 2 ] ) : ( v < < 8 ) ;
ret [ j ] = zpl__base64_chars [ ( v > > 18 ) & 0x3F ] ;
ret [ j + 1 ] = zpl__base64_chars [ ( v > > 12 ) & 0x3F ] ;
if ( i + 1 < len )
ret [ j + 2 ] = zpl__base64_chars [ ( v > > 6 ) & 0x3F ] ;
else ret [ j + 2 ] = ' = ' ;
if ( i + 2 < len )
ret [ j + 3 ] = zpl__base64_chars [ v & 0x3F ] ;
else ret [ j + 3 ] = ' = ' ;
}
return ret ;
}
zpl_u8 * zpl_base64_decode ( zpl_allocator a , void const * data , zpl_isize len ) {
const zpl_u8 * s = cast ( const zpl_u8 * ) data ;
zpl_u8 * ret = NULL ;
zpl_isize alen , i , j , v ;
if ( data = = NULL ) {
return NULL ;
}
alen = zpl__base64_decoded_size ( s ) ;
ret = cast ( zpl_u8 * ) zpl_alloc ( a , alen + 1 ) ;
ZPL_ASSERT_NOT_NULL ( ret ) ;
ret [ alen ] = 0 ;
for ( i = 0 ; i < len ; i + + ) {
if ( ! zpl__base64_valid_char ( s [ i ] ) )
return NULL ;
}
for ( i = 0 , j = 0 ; i < len ; i + = 4 , j + = 3 ) {
v = zpl__base64_dec_table [ s [ i ] - 43 ] ;
v = ( v < < 6 ) | zpl__base64_dec_table [ s [ i + 1 ] - 43 ] ;
v = ( s [ i + 2 ] = = ' = ' ) ? ( v < < 6 ) : ( ( v < < 6 ) | zpl__base64_dec_table [ s [ i + 2 ] - 43 ] ) ;
v = ( s [ i + 3 ] = = ' = ' ) ? ( v < < 6 ) : ( ( v < < 6 ) | zpl__base64_dec_table [ s [ i + 3 ] - 43 ] ) ;
ret [ j ] = ( v > > 16 ) & 0xFF ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
if ( s [ i + 2 ] ! = ' = ' )
ret [ j + 1 ] = ( v > > 8 ) & 0xFF ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
if ( s [ i + 3 ] ! = ' = ' )
ret [ j + 2 ] = v & 0xFF ;
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
return ret ;
}
zpl_u32 zpl_murmur32_seed ( void const * data , zpl_isize len , zpl_u32 seed ) {
zpl_u32 const c1 = 0xcc9e2d51 ;
zpl_u32 const c2 = 0x1b873593 ;
zpl_u32 const r1 = 15 ;
zpl_u32 const r2 = 13 ;
zpl_u32 const m = 5 ;
zpl_u32 const n = 0xe6546b64 ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
zpl_isize i , nblocks = len / 4 ;
zpl_u32 hash = seed , k1 = 0 ;
zpl_u32 const * blocks = cast ( zpl_u32 const * ) data ;
zpl_u8 const * tail = cast ( zpl_u8 const * ) ( data ) + nblocks * 4 ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
for ( i = 0 ; i < nblocks ; i + + ) {
zpl_u32 k = blocks [ i ] ;
k * = c1 ;
k = ( k < < r1 ) | ( k > > ( 32 - r1 ) ) ;
k * = c2 ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
hash ^ = k ;
hash = ( ( hash < < r2 ) | ( hash > > ( 32 - r2 ) ) ) * m + n ;
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
switch ( len & 3 ) {
case 3 : k1 ^ = tail [ 2 ] < < 16 ;
case 2 : k1 ^ = tail [ 1 ] < < 8 ;
case 1 :
k1 ^ = tail [ 0 ] ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
k1 * = c1 ;
k1 = ( k1 < < r1 ) | ( k1 > > ( 32 - r1 ) ) ;
k1 * = c2 ;
hash ^ = k1 ;
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
hash ^ = len ;
hash ^ = ( hash > > 16 ) ;
hash * = 0x85ebca6b ;
hash ^ = ( hash > > 13 ) ;
hash * = 0xc2b2ae35 ;
hash ^ = ( hash > > 16 ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
return hash ;
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
zpl_u64 zpl_murmur64_seed ( void const * data_ , zpl_isize len , zpl_u64 seed ) {
zpl_u64 const m = 0xc6a4a7935bd1e995ULL ;
zpl_i32 const r = 47 ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
zpl_u64 h = seed ^ ( len * m ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
zpl_u64 const * data = cast ( zpl_u64 const * ) data_ ;
zpl_u8 const * data2 = cast ( zpl_u8 const * ) data_ ;
zpl_u64 const * end = data + ( len / 8 ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
while ( data ! = end ) {
zpl_u64 k = * data + + ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
k * = m ;
k ^ = k > > r ;
k * = m ;
h ^ = k ;
h * = m ;
}
switch ( len & 7 ) {
case 7 : h ^ = cast ( zpl_u64 ) ( data2 [ 6 ] ) < < 48 ;
case 6 : h ^ = cast ( zpl_u64 ) ( data2 [ 5 ] ) < < 40 ;
case 5 : h ^ = cast ( zpl_u64 ) ( data2 [ 4 ] ) < < 32 ;
case 4 : h ^ = cast ( zpl_u64 ) ( data2 [ 3 ] ) < < 24 ;
case 3 : h ^ = cast ( zpl_u64 ) ( data2 [ 2 ] ) < < 16 ;
case 2 : h ^ = cast ( zpl_u64 ) ( data2 [ 1 ] ) < < 8 ;
case 1 : h ^ = cast ( zpl_u64 ) ( data2 [ 0 ] ) ;
h * = m ;
} ;
h ^ = h > > r ;
h * = m ;
h ^ = h > > r ;
return h ;
}
ZPL_END_C_DECLS
2021-11-29 08:23:08 +00:00
# endif
# if defined(ZPL_MODULE_REGEX)
2022-09-11 17:42:06 +00:00
// file: source/regex.c
ZPL_BEGIN_C_DECLS
typedef enum zplreOp {
ZPL_RE_OP_BEGIN_CAPTURE ,
ZPL_RE_OP_END_CAPTURE ,
ZPL_RE_OP_BEGINNING_OF_LINE ,
ZPL_RE_OP_END_OF_LINE ,
ZPL_RE_OP_EXACT_MATCH ,
ZPL_RE_OP_META_MATCH ,
ZPL_RE_OP_ANY ,
ZPL_RE_OP_ANY_OF ,
ZPL_RE_OP_ANY_BUT ,
ZPL_RE_OP_ZERO_OR_MORE ,
ZPL_RE_OP_ONE_OR_MORE ,
ZPL_RE_OP_ZERO_OR_MORE_SHORTEST ,
ZPL_RE_OP_ONE_OR_MORE_SHORTEST ,
ZPL_RE_OP_ZERO_OR_ONE ,
ZPL_RE_OP_BRANCH_START ,
ZPL_RE_OP_BRANCH_END
} zplreOp ;
typedef enum zplreCode {
ZPL_RE_CODE_NULL = 0x0000 ,
ZPL_RE_CODE_WHITESPACE = 0x0100 ,
ZPL_RE_CODE_NOT_WHITESPACE = 0x0200 ,
ZPL_RE_CODE_DIGIT = 0x0300 ,
ZPL_RE_CODE_NOT_DIGIT = 0x0400 ,
ZPL_RE_CODE_ALPHA = 0x0500 ,
ZPL_RE_CODE_LOWER = 0x0600 ,
ZPL_RE_CODE_UPPER = 0x0700 ,
ZPL_RE_CODE_WORD = 0x0800 ,
ZPL_RE_CODE_NOT_WORD = 0x0900 ,
ZPL_RE_CODE_XDIGIT = 0x0a00 ,
ZPL_RE_CODE_PRINTABLE = 0x0b00 ,
} zplreCode ;
typedef struct {
zpl_isize op , offset ;
} zpl_re_ctx ;
enum {
ZPL_RE__NO_MATCH = - 1 ,
ZPL_RE__INTERNAL_FAILURE = - 2 ,
} ;
static char const ZPL_RE__META_CHARS [ ] = " ^$()[].*+?| \\ " ;
static char const ZPL_RE__WHITESPACE [ ] = " \r \t \n \v \f " ;
# define ZPL_RE__LITERAL(str) (str), zpl_size_of(str)-1
static zpl_re_ctx zpl_re__exec_single ( zpl_re * re , zpl_isize op , char const * str , zpl_isize str_len , zpl_isize offset , zpl_re_capture * captures , zpl_isize max_capture_count ) ;
static zpl_re_ctx zpl_re__exec ( zpl_re * re , zpl_isize op , char const * str , zpl_isize str_len , zpl_isize offset , zpl_re_capture * captures , zpl_isize max_capture_count ) ;
static zpl_re_ctx zpl_re__ctx_no_match ( zpl_isize op ) {
zpl_re_ctx c ;
c . op = op ;
c . offset = ZPL_RE__NO_MATCH ;
return c ;
}
static zpl_re_ctx zpl_re__ctx_internal_failure ( zpl_isize op ) {
zpl_re_ctx c ;
c . op = op ;
c . offset = ZPL_RE__INTERNAL_FAILURE ;
return c ;
}
static zpl_u8 zpl_re__hex ( char const * s ) {
return ( ( zpl_char_to_hex_digit ( * s ) < < 4 ) & 0xf0 ) | ( zpl_char_to_hex_digit ( * ( s + 1 ) ) & 0x0f ) ;
}
static zpl_isize zpl_re__strfind ( char const * s , zpl_isize len , char c , zpl_isize offset ) {
if ( offset < len ) {
char const * found = ( char const * ) zpl_memchr ( s + offset , c , len - offset ) ;
if ( found )
return found - s ;
}
return - 1 ;
}
static zpl_b32 zpl_re__match_escape ( char c , int code ) {
switch ( code ) {
case ZPL_RE_CODE_NULL : return c = = 0 ;
case ZPL_RE_CODE_WHITESPACE : return zpl_re__strfind ( ZPL_RE__LITERAL ( ZPL_RE__WHITESPACE ) , c , 0 ) > = 0 ;
case ZPL_RE_CODE_NOT_WHITESPACE : return zpl_re__strfind ( ZPL_RE__LITERAL ( ZPL_RE__WHITESPACE ) , c , 0 ) < 0 ;
case ZPL_RE_CODE_DIGIT : return ( c > = ' 0 ' & & c < = ' 9 ' ) ;
case ZPL_RE_CODE_NOT_DIGIT : return ! ( c > = ' 0 ' & & c < = ' 9 ' ) ;
case ZPL_RE_CODE_ALPHA : return ( c > = ' A ' & & c < = ' Z ' ) | | ( c > = ' a ' & & c < = ' z ' ) ;
case ZPL_RE_CODE_LOWER : return ( c > = ' a ' & & c < = ' z ' ) ;
case ZPL_RE_CODE_UPPER : return ( c > = ' A ' & & c < = ' Z ' ) ;
/* TODO(bill): Make better? */
case ZPL_RE_CODE_WORD : return ( c > = ' A ' & & c < = ' Z ' ) | | ( c > = ' a ' & & c < = ' z ' ) | | ( c > = ' 0 ' & & c < = ' 9 ' ) | | c = = ' _ ' ;
case ZPL_RE_CODE_NOT_WORD : return ! ( ( c > = ' A ' & & c < = ' Z ' ) | | ( c > = ' a ' & & c < = ' z ' ) | | ( c > = ' 0 ' & & c < = ' 9 ' ) | | c = = ' _ ' ) ;
/* TODO(bill): Maybe replace with between tests? */
case ZPL_RE_CODE_XDIGIT : return zpl_re__strfind ( ZPL_RE__LITERAL ( " 0123456789ABCDEFabcdef " ) , c , 0 ) > = 0 ;
case ZPL_RE_CODE_PRINTABLE : return c > = 0x20 & & c < = 0x7e ;
default : break ;
}
return 0 ;
}
static zpl_re_ctx zpl_re__consume ( zpl_re * re , zpl_isize op , char const * str , zpl_isize str_len , zpl_isize offset , zpl_re_capture * captures , zpl_isize max_capture_count , zpl_b32 is_greedy )
{
zpl_re_ctx c , best_c , next_c ;
c . op = op ;
c . offset = offset ;
best_c . op = ZPL_RE__NO_MATCH ;
best_c . offset = offset ;
for ( ; ; ) {
c = zpl_re__exec_single ( re , op , str , str_len , c . offset , 0 , 0 ) ;
if ( c . offset > str_len | | c . offset = = - 1 ) break ;
if ( c . op > = re - > buf_len ) return c ;
next_c = zpl_re__exec ( re , c . op , str , str_len , c . offset , captures , max_capture_count ) ;
if ( next_c . offset < = str_len ) {
if ( captures )
zpl_re__exec ( re , c . op , str , str_len , c . offset , captures , max_capture_count ) ;
best_c = next_c ;
if ( ! is_greedy ) break ;
}
if ( best_c . op > re - > buf_len )
best_c . op = c . op ;
}
return best_c ;
}
static zpl_re_ctx zpl_re__exec_single ( zpl_re * re , zpl_isize op , char const * str , zpl_isize str_len , zpl_isize offset , zpl_re_capture * captures , zpl_isize max_capture_count ) {
zpl_re_ctx ctx ;
zpl_isize buffer_len ;
zpl_isize match_len ;
zpl_isize next_op ;
zpl_isize skip ;
switch ( re - > buf [ op + + ] ) {
case ZPL_RE_OP_BEGIN_CAPTURE : {
zpl_u8 capture = re - > buf [ op + + ] ;
if ( captures & & ( capture < max_capture_count ) )
captures [ capture ] . str = str + offset ;
} break ;
case ZPL_RE_OP_END_CAPTURE : {
zpl_u8 capture = re - > buf [ op + + ] ;
if ( captures & & ( capture < max_capture_count ) )
captures [ capture ] . len = ( str + offset ) - captures [ capture ] . str ;
} break ;
case ZPL_RE_OP_BEGINNING_OF_LINE : {
if ( offset ! = 0 )
return zpl_re__ctx_no_match ( op ) ;
} break ;
case ZPL_RE_OP_END_OF_LINE : {
if ( offset ! = str_len )
return zpl_re__ctx_no_match ( op ) ;
} break ;
case ZPL_RE_OP_BRANCH_START : {
skip = re - > buf [ op + + ] ;
ctx = zpl_re__exec ( re , op , str , str_len , offset , captures , max_capture_count ) ;
if ( ctx . offset < = str_len ) {
offset = ctx . offset ;
op = ctx . op ;
} else {
ctx = zpl_re__exec ( re , op + skip , str , str_len , offset , captures , max_capture_count ) ;
offset = ctx . offset ;
op = ctx . op ;
}
} break ;
case ZPL_RE_OP_BRANCH_END : {
skip = re - > buf [ op + + ] ;
op + = skip ;
} break ;
case ZPL_RE_OP_ANY : {
if ( offset < str_len ) {
offset + + ;
break ;
}
return zpl_re__ctx_no_match ( op ) ;
} break ;
case ZPL_RE_OP_ANY_OF : {
zpl_isize i ;
char cin = str [ offset ] ;
buffer_len = re - > buf [ op + + ] ;
if ( offset > = str_len )
return zpl_re__ctx_no_match ( op + buffer_len ) ;
for ( i = 0 ; i < buffer_len ; i + + ) {
char cmatch = ( char ) re - > buf [ op + i ] ;
if ( ! cmatch ) {
i + + ;
if ( zpl_re__match_escape ( cin , re - > buf [ op + i ] < < 8 ) )
break ;
} else if ( cin = = cmatch ) {
break ;
}
}
if ( i = = buffer_len )
return zpl_re__ctx_no_match ( op + buffer_len ) ;
offset + + ;
op + = buffer_len ;
} break ;
case ZPL_RE_OP_ANY_BUT : {
zpl_isize i ;
char cin = str [ offset ] ;
buffer_len = re - > buf [ op + + ] ;
if ( offset > = str_len )
return zpl_re__ctx_no_match ( op + buffer_len ) ;
for ( i = 0 ; i < buffer_len ; i + + ) {
char cmatch = ( char ) re - > buf [ op + i ] ;
if ( ! cmatch ) {
i + + ;
if ( zpl_re__match_escape ( cin , re - > buf [ op + i ] < < 8 ) )
return zpl_re__ctx_no_match ( op + buffer_len ) ;
} else if ( cin = = cmatch ) {
return zpl_re__ctx_no_match ( op + buffer_len ) ;
}
}
offset + + ;
op + = buffer_len ;
} break ;
case ZPL_RE_OP_EXACT_MATCH : {
match_len = re - > buf [ op + + ] ;
if ( ( match_len > ( str_len - offset ) ) | |
zpl_strncmp ( str + offset , ( const char * ) re - > buf + op , match_len ) ! = 0 )
return zpl_re__ctx_no_match ( op + match_len ) ;
op + = match_len ;
offset + = match_len ;
} break ;
case ZPL_RE_OP_META_MATCH : {
char cin = ( char ) re - > buf [ op + + ] ;
char cmatch = str [ offset + + ] ;
if ( ! cin ) {
if ( zpl_re__match_escape ( cmatch , re - > buf [ op + + ] < < 8 ) )
break ;
}
else if ( cin = = cmatch ) break ;
return zpl_re__ctx_no_match ( op ) ;
} break ;
case ZPL_RE_OP_ZERO_OR_MORE : {
ctx = zpl_re__consume ( re , op , str , str_len , offset , captures , max_capture_count , 1 ) ;
offset = ctx . offset ;
op = ctx . op ;
} break ;
case ZPL_RE_OP_ONE_OR_MORE : {
ctx = zpl_re__exec_single ( re , op , str , str_len , offset , captures , max_capture_count ) ;
if ( ctx . offset > str_len )
return ctx ;
ctx = zpl_re__consume ( re , op , str , str_len , offset , captures , max_capture_count , 1 ) ;
offset = ctx . offset ;
op = ctx . op ;
} break ;
case ZPL_RE_OP_ZERO_OR_MORE_SHORTEST : {
ctx = zpl_re__consume ( re , op , str , str_len , offset , captures , max_capture_count , 0 ) ;
offset = ctx . offset ;
op = ctx . op ;
} break ;
case ZPL_RE_OP_ONE_OR_MORE_SHORTEST : {
ctx = zpl_re__exec_single ( re , op , str , str_len , offset , captures , max_capture_count ) ;
if ( ctx . offset > str_len )
return ctx ;
ctx = zpl_re__consume ( re , op , str , str_len , offset , captures , max_capture_count , 0 ) ;
offset = ctx . offset ;
op = ctx . op ;
} break ;
case ZPL_RE_OP_ZERO_OR_ONE : {
ctx = zpl_re__exec_single ( re , op , str , str_len , offset , captures , max_capture_count ) ;
if ( ctx . offset < = str_len ) {
zpl_re_ctx possible_ctx = zpl_re__exec ( re , ctx . op , str , str_len , ctx . offset , captures , max_capture_count ) ;
if ( possible_ctx . offset < = str_len ) {
op = possible_ctx . op ;
offset = possible_ctx . offset ;
break ;
}
}
next_op = ctx . op ;
ctx = zpl_re__exec ( re , next_op , str , str_len , offset , captures , max_capture_count ) ;
if ( ctx . offset < = str_len ) {
op = ctx . op ;
offset = ctx . offset ;
break ;
}
return zpl_re__ctx_no_match ( op ) ;
} break ;
default : {
return zpl_re__ctx_internal_failure ( op ) ;
} break ;
}
ctx . op = op ;
ctx . offset = offset ;
return ctx ;
}
static zpl_re_ctx zpl_re__exec ( zpl_re * re , zpl_isize op , char const * str , zpl_isize str_len , zpl_isize offset , zpl_re_capture * captures , zpl_isize max_capture_count ) {
zpl_re_ctx c ;
c . op = op ;
c . offset = offset ;
while ( c . op < re - > buf_len ) {
c = zpl_re__exec_single ( re , c . op , str , str_len , c . offset , captures , max_capture_count ) ;
if ( c . offset > str_len | | c . offset = = - 1 )
break ;
}
return c ;
}
static zpl_regex_error zpl_re__emit_ops ( zpl_re * re , zpl_isize op_count , . . . ) {
va_list va ;
if ( re - > buf_len + op_count > re - > buf_cap ) {
if ( ! re - > can_realloc ) {
return ZPL_RE_ERROR_TOO_LONG ;
}
else {
zpl_isize new_cap = ( re - > buf_cap * 2 ) + op_count ;
re - > buf = ( char * ) zpl_resize ( re - > backing , re - > buf , re - > buf_cap , new_cap ) ;
re - > buf_cap = new_cap ;
}
}
va_start ( va , op_count ) ;
for ( zpl_isize i = 0 ; i < op_count ; i + + )
{
zpl_i32 v = va_arg ( va , zpl_i32 ) ;
if ( v > 256 )
return ZPL_RE_ERROR_TOO_LONG ;
re - > buf [ re - > buf_len + + ] = ( char ) v ;
}
va_end ( va ) ;
return ZPL_RE_ERROR_NONE ;
}
static zpl_regex_error zpl_re__emit_ops_buffer ( zpl_re * re , zpl_isize op_count , char const * buffer ) {
if ( re - > buf_len + op_count > re - > buf_cap ) {
if ( ! re - > can_realloc ) {
return ZPL_RE_ERROR_TOO_LONG ;
}
else {
zpl_isize new_cap = ( re - > buf_cap * 2 ) + op_count ;
re - > buf = ( char * ) zpl_resize ( re - > backing , re - > buf , re - > buf_cap , new_cap ) ;
re - > buf_cap = new_cap ;
}
}
for ( zpl_isize i = 0 ; i < op_count ; i + + )
{
re - > buf [ re - > buf_len + + ] = buffer [ i ] ;
}
return ZPL_RE_ERROR_NONE ;
}
static int zpl_re__encode_escape ( char code ) {
switch ( code ) {
default : break ; /* NOTE(bill): It's a normal character */
/* TODO(bill): Are there anymore? */
case ' t ' : return ' \t ' ;
case ' n ' : return ' \n ' ;
case ' r ' : return ' \r ' ;
case ' f ' : return ' \f ' ;
case ' v ' : return ' \v ' ;
case ' 0 ' : return ZPL_RE_CODE_NULL ;
case ' s ' : return ZPL_RE_CODE_WHITESPACE ;
case ' S ' : return ZPL_RE_CODE_NOT_WHITESPACE ;
case ' d ' : return ZPL_RE_CODE_DIGIT ;
case ' D ' : return ZPL_RE_CODE_NOT_DIGIT ;
case ' a ' : return ZPL_RE_CODE_ALPHA ;
case ' l ' : return ZPL_RE_CODE_LOWER ;
case ' u ' : return ZPL_RE_CODE_UPPER ;
case ' w ' : return ZPL_RE_CODE_WORD ;
case ' W ' : return ZPL_RE_CODE_NOT_WORD ;
case ' x ' : return ZPL_RE_CODE_XDIGIT ;
case ' p ' : return ZPL_RE_CODE_PRINTABLE ;
}
return code ;
}
static zpl_regex_error zpl_re__parse_group ( zpl_re * re , char const * pattern , zpl_isize len , zpl_isize offset , zpl_isize * new_offset ) {
zpl_regex_error err = ZPL_RE_ERROR_NONE ;
char buffer [ 256 ] = { 0 } ;
zpl_isize buffer_len = 0 , buffer_cap = zpl_size_of ( buffer ) ;
zpl_b32 closed = 0 ;
zplreOp op = ZPL_RE_OP_ANY_OF ;
if ( pattern [ offset ] = = ' ^ ' ) {
offset + + ;
op = ZPL_RE_OP_ANY_BUT ;
}
while ( ! closed & &
err = = ZPL_RE_ERROR_NONE & &
offset < len )
{
if ( pattern [ offset ] = = ' ] ' ) {
err = zpl_re__emit_ops ( re , 2 , ( zpl_i32 ) op , ( zpl_i32 ) buffer_len ) ;
if ( err ) break ;
err = zpl_re__emit_ops_buffer ( re , buffer_len , ( const char * ) buffer ) ;
if ( err ) break ;
offset + + ;
closed = 1 ;
break ;
}
if ( buffer_len > = buffer_cap )
return ZPL_RE_ERROR_TOO_LONG ;
if ( pattern [ offset ] = = ' \\ ' ) {
offset + + ;
if ( ( offset + 1 < len ) & & zpl_char_is_hex_digit ( * ( pattern + offset ) ) ) {
buffer [ buffer_len + + ] = zpl_re__hex ( ( pattern + offset ) ) ;
offset + + ;
}
else if ( offset < len ) {
zpl_i32 code = zpl_re__encode_escape ( pattern [ offset ] ) ;
if ( ! code | | code > 0xff ) {
buffer [ buffer_len + + ] = 0 ;
if ( buffer_len > = buffer_cap )
return ZPL_RE_ERROR_TOO_LONG ;
buffer [ buffer_len + + ] = ( code > > 8 ) & 0xff ;
}
else {
buffer [ buffer_len + + ] = code & 0xff ;
}
}
}
else {
buffer [ buffer_len + + ] = ( unsigned char ) pattern [ offset ] ;
}
offset + + ;
}
if ( err ) return err ;
if ( ! closed ) return ZPL_RE_ERROR_MISMATCHED_BLOCKS ;
if ( new_offset ) * new_offset = offset ;
return ZPL_RE_ERROR_NONE ;
}
static zpl_regex_error zpl_re__compile_quantifier ( zpl_re * re , zpl_isize last_buf_len , unsigned char quantifier ) {
zpl_regex_error err ;
zpl_isize move_size ;
if ( ( re - > buf [ last_buf_len ] = = ZPL_RE_OP_EXACT_MATCH ) & &
( re - > buf [ last_buf_len + 1 ] > 1 ) )
{
unsigned char last_char = re - > buf [ re - > buf_len - 1 ] ;
re - > buf [ last_buf_len + 1 ] - - ;
re - > buf_len - - ;
err = zpl_re__emit_ops ( re , 4 , ( zpl_i32 ) quantifier , ( zpl_i32 ) ZPL_RE_OP_EXACT_MATCH , 1 , ( zpl_i32 ) last_char ) ;
if ( err ) return err ;
return ZPL_RE_ERROR_NONE ;
}
move_size = re - > buf_len - last_buf_len + 1 ;
err = zpl_re__emit_ops ( re , 1 , 0 ) ;
if ( err ) return err ;
zpl_memmove ( re - > buf + last_buf_len + 1 , re - > buf + last_buf_len , move_size ) ;
re - > buf [ last_buf_len ] = quantifier ;
return ZPL_RE_ERROR_NONE ;
}
static zpl_regex_error zpl_re__parse ( zpl_re * re , char const * pattern , zpl_isize len , zpl_isize offset , zpl_isize level , zpl_isize * new_offset ) {
zpl_regex_error err = ZPL_RE_ERROR_NONE ;
zpl_isize last_buf_len = re - > buf_len ;
zpl_isize branch_begin = re - > buf_len ;
zpl_isize branch_op = - 1 ;
while ( offset < len ) {
switch ( pattern [ offset + + ] ) {
case ' ^ ' : {
err = zpl_re__emit_ops ( re , 1 , ZPL_RE_OP_BEGINNING_OF_LINE ) ;
if ( err ) return err ;
} break ;
case ' $ ' : {
err = zpl_re__emit_ops ( re , 1 , ZPL_RE_OP_END_OF_LINE ) ;
if ( err ) return err ;
} break ;
case ' ( ' : {
zpl_isize capture = re - > capture_count + + ;
last_buf_len = re - > buf_len ;
err = zpl_re__emit_ops ( re , 2 , ZPL_RE_OP_BEGIN_CAPTURE , ( zpl_i32 ) capture ) ;
if ( err ) return err ;
err = zpl_re__parse ( re , pattern , len , offset , level + 1 , & offset ) ;
if ( ( offset > len ) | | ( pattern [ offset - 1 ] ! = ' ) ' ) )
return ZPL_RE_ERROR_MISMATCHED_CAPTURES ;
err = zpl_re__emit_ops ( re , 2 , ZPL_RE_OP_END_CAPTURE , ( zpl_i32 ) capture ) ;
if ( err ) return err ;
} break ;
case ' ) ' : {
if ( branch_op ! = - 1 )
re - > buf [ branch_op + 1 ] = ( unsigned char ) ( re - > buf_len - ( branch_op + 2 ) ) ;
if ( level = = 0 )
return ZPL_RE_ERROR_MISMATCHED_CAPTURES ;
if ( new_offset ) * new_offset = offset ;
return ZPL_RE_ERROR_NONE ;
} break ;
case ' [ ' : {
last_buf_len = re - > buf_len ;
err = zpl_re__parse_group ( re , pattern , len , offset , & offset ) ;
if ( offset > len )
return err ;
} break ;
/* NOTE(bill): Branching magic! */
case ' | ' : {
if ( branch_begin > = re - > buf_len ) {
return ZPL_RE_ERROR_BRANCH_FAILURE ;
} else {
zpl_isize size = re - > buf_len - branch_begin ;
err = zpl_re__emit_ops ( re , 4 , 0 , 0 , ZPL_RE_OP_BRANCH_END , 0 ) ;
if ( err ) return err ;
zpl_memmove ( re - > buf + branch_begin + 2 , re - > buf + branch_begin , size ) ;
re - > buf [ branch_begin ] = ZPL_RE_OP_BRANCH_START ;
re - > buf [ branch_begin + 1 ] = ( size + 2 ) & 0xff ;
branch_op = re - > buf_len - 2 ;
}
} break ;
case ' . ' : {
last_buf_len = re - > buf_len ;
err = zpl_re__emit_ops ( re , 1 , ZPL_RE_OP_ANY ) ;
if ( err ) return err ;
} break ;
case ' * ' :
case ' + ' :
{
unsigned char quantifier = ZPL_RE_OP_ONE_OR_MORE ;
if ( pattern [ offset - 1 ] = = ' * ' )
quantifier = ZPL_RE_OP_ZERO_OR_MORE ;
if ( last_buf_len > = re - > buf_len )
return ZPL_RE_ERROR_INVALID_QUANTIFIER ;
if ( ( re - > buf [ last_buf_len ] < ZPL_RE_OP_EXACT_MATCH ) | |
( re - > buf [ last_buf_len ] > ZPL_RE_OP_ANY_BUT ) )
return ZPL_RE_ERROR_INVALID_QUANTIFIER ;
if ( ( offset < len ) & & ( pattern [ offset ] = = ' ? ' ) ) {
quantifier = ZPL_RE_OP_ONE_OR_MORE_SHORTEST ;
offset + + ;
}
err = zpl_re__compile_quantifier ( re , last_buf_len , quantifier ) ;
if ( err ) return err ;
} break ;
case ' ? ' : {
if ( last_buf_len > = re - > buf_len )
return ZPL_RE_ERROR_INVALID_QUANTIFIER ;
if ( ( re - > buf [ last_buf_len ] < ZPL_RE_OP_EXACT_MATCH ) | |
( re - > buf [ last_buf_len ] > ZPL_RE_OP_ANY_BUT ) )
return ZPL_RE_ERROR_INVALID_QUANTIFIER ;
err = zpl_re__compile_quantifier ( re , last_buf_len ,
( unsigned char ) ZPL_RE_OP_ZERO_OR_ONE ) ;
if ( err ) return err ;
} break ;
case ' \\ ' : {
last_buf_len = re - > buf_len ;
if ( ( offset + 1 < len ) & & zpl_char_is_hex_digit ( * ( pattern + offset ) ) ) {
unsigned char hex_value = zpl_re__hex ( ( pattern + offset ) ) ;
offset + = 2 ;
err = zpl_re__emit_ops ( re , 2 , ZPL_RE_OP_META_MATCH , ( int ) hex_value ) ;
if ( err ) return err ;
} else if ( offset < len ) {
int code = zpl_re__encode_escape ( pattern [ offset + + ] ) ;
if ( ! code | | ( code > 0xff ) ) {
err = zpl_re__emit_ops ( re , 3 , ZPL_RE_OP_META_MATCH , 0 , ( int ) ( ( code > > 8 ) & 0xff ) ) ;
if ( err ) return err ;
} else {
err = zpl_re__emit_ops ( re , 2 , ZPL_RE_OP_META_MATCH , ( int ) code ) ;
if ( err ) return err ;
}
}
} break ;
/* NOTE(bill): Exact match */
default : {
char const * match_start ;
zpl_isize size = 0 ;
offset - - ;
match_start = pattern + offset ;
while ( ( offset < len ) & &
( zpl_re__strfind ( ZPL_RE__LITERAL ( ZPL_RE__META_CHARS ) , pattern [ offset ] , 0 ) < 0 ) ) {
size + + , offset + + ;
}
last_buf_len = re - > buf_len ;
err = zpl_re__emit_ops ( re , 2 , ZPL_RE_OP_EXACT_MATCH , ( int ) size ) ;
if ( err ) return err ;
err = zpl_re__emit_ops_buffer ( re , size , ( char const * ) match_start ) ;
if ( err ) return err ;
} break ;
}
}
if ( new_offset ) * new_offset = offset ;
return ZPL_RE_ERROR_NONE ;
}
zpl_regex_error zpl_re_compile_from_buffer ( zpl_re * re , char const * pattern , zpl_isize pattern_len , void * buffer , zpl_isize buffer_len ) {
zpl_regex_error err ;
re - > capture_count = 0 ;
re - > buf = ( char * ) buffer ;
re - > buf_len = 0 ;
re - > buf_cap = re - > buf_len ;
re - > can_realloc = 0 ;
err = zpl_re__parse ( re , pattern , pattern_len , 0 , 0 , 0 ) ;
return err ;
}
zpl_regex_error zpl_re_compile ( zpl_re * re , zpl_allocator backing , char const * pattern , zpl_isize pattern_len ) {
zpl_regex_error err ;
zpl_isize cap = pattern_len + 128 ;
zpl_isize offset = 0 ;
re - > backing = backing ;
re - > capture_count = 0 ;
re - > buf = ( char * ) zpl_alloc ( backing , cap ) ;
re - > buf_len = 0 ;
re - > buf_cap = cap ;
re - > can_realloc = 1 ;
err = zpl_re__parse ( re , pattern , pattern_len , 0 , 0 , & offset ) ;
if ( offset ! = pattern_len )
zpl_free ( backing , re - > buf ) ;
return err ;
}
zpl_isize zpl_re_capture_count ( zpl_re * re ) { return re - > capture_count ; }
zpl_b32 zpl_re_match ( zpl_re * re , char const * str , zpl_isize len , zpl_re_capture * captures , zpl_isize max_capture_count , zpl_isize * offset ) {
if ( re & & re - > buf_len > 0 ) {
if ( re - > buf [ 0 ] = = ZPL_RE_OP_BEGINNING_OF_LINE ) {
zpl_re_ctx c = zpl_re__exec ( re , 0 , str , len , 0 , captures , max_capture_count ) ;
if ( c . offset > = 0 & & c . offset < = len ) { if ( offset ) * offset = c . offset ; return 1 ; } ;
if ( c . offset = = ZPL_RE__INTERNAL_FAILURE ) return 0 ;
} else {
zpl_isize i ;
for ( i = 0 ; i < len ; i + + ) {
zpl_re_ctx c = zpl_re__exec ( re , 0 , str , len , i , captures , max_capture_count ) ;
if ( c . offset > = 0 & & c . offset < = len ) { if ( offset ) * offset = c . offset ; return 1 ; } ;
if ( c . offset = = ZPL_RE__INTERNAL_FAILURE ) return 0 ;
}
}
return 0 ;
}
return 1 ;
}
zpl_b32 zpl_re_match_all ( zpl_re * re , char const * str , zpl_isize str_len , zpl_isize max_capture_count ,
zpl_re_capture * * out_captures )
{
char * end = ( char * ) str + str_len ;
char * p = ( char * ) str ;
zpl_buffer_make ( zpl_re_capture , cps , zpl_heap ( ) , max_capture_count ) ;
zpl_isize offset = 0 ;
while ( p < end )
{
zpl_b32 ok = zpl_re_match ( re , p , end - p , cps , max_capture_count , & offset ) ;
if ( ! ok ) {
zpl_buffer_free ( cps ) ;
return false ;
}
p + = offset ;
for ( zpl_isize i = 0 ; i < max_capture_count ; i + + ) {
zpl_array_append ( * out_captures , cps [ i ] ) ;
}
}
zpl_buffer_free ( cps ) ;
return true ;
}
ZPL_END_C_DECLS
2021-11-29 08:23:08 +00:00
# endif
# if defined(ZPL_MODULE_DLL)
2022-09-11 17:42:06 +00:00
// file: source/dll.c
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
# if defined(ZPL_SYSTEM_UNIX) || defined(ZPL_SYSTEM_MACOS)
# include <dlfcn.h>
# endif
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_BEGIN_C_DECLS
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
////////////////////////////////////////////////////////////////
//
// DLL Handling
//
//
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
# if defined(ZPL_SYSTEM_WINDOWS)
zpl_dll_handle zpl_dll_load ( char const * filepath ) {
return cast ( zpl_dll_handle ) LoadLibraryA ( filepath ) ;
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
void zpl_dll_unload ( zpl_dll_handle dll ) {
FreeLibrary ( cast ( HMODULE ) dll ) ;
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
zpl_dll_proc zpl_dll_proc_address ( zpl_dll_handle dll , char const * proc_name ) {
return cast ( zpl_dll_proc ) GetProcAddress ( cast ( HMODULE ) dll , proc_name ) ;
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
# else // POSIX
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
zpl_dll_handle zpl_dll_load ( char const * filepath ) {
return cast ( zpl_dll_handle ) dlopen ( filepath , RTLD_LAZY | RTLD_GLOBAL ) ;
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
void zpl_dll_unload ( zpl_dll_handle dll ) {
dlclose ( dll ) ;
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
zpl_dll_proc zpl_dll_proc_address ( zpl_dll_handle dll , char const * proc_name ) {
return cast ( zpl_dll_proc ) dlsym ( dll , proc_name ) ;
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
# endif
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_END_C_DECLS
2021-11-29 08:23:08 +00:00
# endif
# if defined(ZPL_MODULE_OPTS)
2022-09-11 17:42:06 +00:00
// file: source/opts.c
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
////////////////////////////////////////////////////////////////
//
// CLI Options
//
//
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_BEGIN_C_DECLS
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
void zpl_opts_init ( zpl_opts * opts , zpl_allocator a , char const * app ) {
zpl_opts opts_ = { 0 } ;
* opts = opts_ ;
opts - > alloc = a ;
opts - > appname = app ;
zpl_array_init ( opts - > entries , a ) ;
zpl_array_init ( opts - > positioned , a ) ;
zpl_array_init ( opts - > errors , a ) ;
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
void zpl_opts_free ( zpl_opts * opts ) {
for ( zpl_i32 i = 0 ; i < zpl_array_count ( opts - > entries ) ; + + i ) {
zpl_opts_entry * e = opts - > entries + i ;
if ( e - > type = = ZPL_OPTS_STRING ) {
zpl_string_free ( e - > text ) ;
}
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
zpl_array_free ( opts - > entries ) ;
zpl_array_free ( opts - > positioned ) ;
zpl_array_free ( opts - > errors ) ;
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
void zpl_opts_add ( zpl_opts * opts , char const * name , char const * lname , const char * desc , zpl_u8 type ) {
zpl_opts_entry e = { 0 } ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
e . name = name ;
e . lname = lname ;
e . desc = desc ;
e . type = type ;
e . met = false ;
e . pos = false ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
zpl_array_append ( opts - > entries , e ) ;
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
zpl_opts_entry * zpl__opts_find ( zpl_opts * opts , char const * name , zpl_usize len , zpl_b32 longname ) {
zpl_opts_entry * e = 0 ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
for ( int i = 0 ; i < zpl_array_count ( opts - > entries ) ; + + i ) {
e = opts - > entries + i ;
char const * n = ( longname ? e - > lname : e - > name ) ;
if ( ! n ) continue ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
if ( zpl_strnlen ( name , len ) = = zpl_strlen ( n ) & & ! zpl_strncmp ( n , name , len ) ) { return e ; }
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
return NULL ;
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
void zpl_opts_positional_add ( zpl_opts * opts , char const * name ) {
zpl_opts_entry * e = zpl__opts_find ( opts , name , zpl_strlen ( name ) , true ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
if ( e ) {
e - > pos = true ;
zpl_array_append_at ( opts - > positioned , e , 0 ) ;
}
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
zpl_b32 zpl_opts_positionals_filled ( zpl_opts * opts ) { return zpl_array_count ( opts - > positioned ) = = 0 ; }
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
zpl_string zpl_opts_string ( zpl_opts * opts , char const * name , char const * fallback ) {
zpl_opts_entry * e = zpl__opts_find ( opts , name , zpl_strlen ( name ) , true ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
return ( char * ) ( ( e & & e - > met ) ? e - > text : fallback ) ;
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
zpl_f64 zpl_opts_real ( zpl_opts * opts , char const * name , zpl_f64 fallback ) {
zpl_opts_entry * e = zpl__opts_find ( opts , name , zpl_strlen ( name ) , true ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
return ( e & & e - > met ) ? e - > real : fallback ;
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
zpl_i64 zpl_opts_integer ( zpl_opts * opts , char const * name , zpl_i64 fallback ) {
zpl_opts_entry * e = zpl__opts_find ( opts , name , zpl_strlen ( name ) , true ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
return ( e & & e - > met ) ? e - > integer : fallback ;
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
void zpl__opts_set_value ( zpl_opts * opts , zpl_opts_entry * t , char * b ) {
t - > met = true ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
switch ( t - > type ) {
case ZPL_OPTS_STRING : {
t - > text = zpl_string_make ( opts - > alloc , b ) ;
} break ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
case ZPL_OPTS_FLOAT : {
t - > real = zpl_str_to_f64 ( b , NULL ) ;
} break ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
case ZPL_OPTS_INT : {
t - > integer = zpl_str_to_i64 ( b , NULL , 10 ) ;
} break ;
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
for ( zpl_isize i = 0 ; i < zpl_array_count ( opts - > positioned ) ; i + + ) {
if ( ! zpl_strcmp ( opts - > positioned [ i ] - > lname , t - > lname ) ) {
zpl_array_remove_at ( opts - > positioned , i ) ;
break ;
}
}
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
zpl_b32 zpl_opts_has_arg ( zpl_opts * opts , char const * name ) {
zpl_opts_entry * e = zpl__opts_find ( opts , name , zpl_strlen ( name ) , true ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
if ( e ) { return e - > met ; }
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
return false ;
}
void zpl_opts_print_help ( zpl_opts * opts ) {
zpl_printf ( " USAGE: %s " , opts - > appname ) ;
for ( zpl_isize i = zpl_array_count ( opts - > entries ) ; i > = 0 ; - - i ) {
zpl_opts_entry * e = opts - > entries + i ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
if ( e - > pos = = ( zpl_b32 ) true ) { zpl_printf ( " [%s] " , e - > lname ) ; }
}
zpl_printf ( " \n OPTIONS: \n " ) ;
for ( zpl_isize i = 0 ; i < zpl_array_count ( opts - > entries ) ; + + i ) {
zpl_opts_entry * e = opts - > entries + i ;
if ( e - > name ) {
if ( e - > lname ) { zpl_printf ( " \t -%s, --%s: %s \n " , e - > name , e - > lname , e - > desc ) ; }
else { zpl_printf ( " \t -%s: %s \n " , e - > name , e - > desc ) ; }
} else { zpl_printf ( " \t --%s: %s \n " , e - > lname , e - > desc ) ; }
}
}
void zpl_opts_print_errors ( zpl_opts * opts ) {
for ( int i = 0 ; i < zpl_array_count ( opts - > errors ) ; + + i ) {
zpl_opts_err * err = ( opts - > errors + i ) ;
zpl_printf ( " ERROR: " ) ;
switch ( err - > type ) {
case ZPL_OPTS_ERR_OPTION : zpl_printf ( " Invalid option \" %s \" " , err - > val ) ; break ;
case ZPL_OPTS_ERR_VALUE : zpl_printf ( " Invalid value \" %s \" " , err - > val ) ; break ;
case ZPL_OPTS_ERR_MISSING_VALUE : zpl_printf ( " Missing value for option \" %s \" " , err - > val ) ; break ;
case ZPL_OPTS_ERR_EXTRA_VALUE : zpl_printf ( " Extra value for option \" %s \" " , err - > val ) ; break ;
}
zpl_printf ( " \n " ) ;
}
}
void zpl__opts_push_error ( zpl_opts * opts , char * b , zpl_u8 errtype ) {
zpl_opts_err err = { 0 } ;
err . val = b ;
err . type = errtype ;
zpl_array_append ( opts - > errors , err ) ;
}
zpl_b32 zpl_opts_compile ( zpl_opts * opts , int argc , char * * argv ) {
zpl_b32 had_errors = false ;
for ( int i = 1 ; i < argc ; + + i ) {
char * p = argv [ i ] ;
if ( * p ) {
p = cast ( char * ) zpl_str_trim ( p , false ) ;
if ( * p = = ' - ' ) {
zpl_opts_entry * t = 0 ;
zpl_b32 checkln = false ;
if ( * ( p + 1 ) = = ' - ' ) {
checkln = true ;
+ + p ;
}
char * b = p + 1 , * e = b ;
while ( zpl_char_is_alphanumeric ( * e ) | | * e = = ' - ' | | * e = = ' _ ' ) { + + e ; }
t = zpl__opts_find ( opts , b , ( e - b ) , checkln ) ;
if ( t ) {
char * ob = b ;
b = e ;
/**/ if ( * e = = ' = ' ) {
if ( t - > type = = ZPL_OPTS_FLAG ) {
* e = ' \0 ' ;
zpl__opts_push_error ( opts , ob , ZPL_OPTS_ERR_EXTRA_VALUE ) ;
had_errors = true ;
continue ;
}
b = e = e + 1 ;
} else if ( * e = = ' \0 ' ) {
char * sp = argv [ i + 1 ] ;
if ( sp & & * sp ! = ' - ' & & ( zpl_array_count ( opts - > positioned ) < 1 | | t - > type ! = ZPL_OPTS_FLAG ) ) {
if ( t - > type = = ZPL_OPTS_FLAG ) {
zpl__opts_push_error ( opts , b , ZPL_OPTS_ERR_EXTRA_VALUE ) ;
had_errors = true ;
continue ;
}
p = sp ;
b = e = sp ;
+ + i ;
} else {
if ( t - > type ! = ZPL_OPTS_FLAG ) {
zpl__opts_push_error ( opts , ob , ZPL_OPTS_ERR_MISSING_VALUE ) ;
had_errors = true ;
continue ;
}
t - > met = true ;
continue ;
}
}
e = cast ( char * ) zpl_str_control_skip ( e , ' \0 ' ) ;
zpl__opts_set_value ( opts , t , b ) ;
} else {
zpl__opts_push_error ( opts , b , ZPL_OPTS_ERR_OPTION ) ;
had_errors = true ;
}
} else if ( zpl_array_count ( opts - > positioned ) ) {
zpl_opts_entry * l = zpl_array_back ( opts - > positioned ) ;
zpl_array_pop ( opts - > positioned ) ;
zpl__opts_set_value ( opts , l , p ) ;
} else {
zpl__opts_push_error ( opts , p , ZPL_OPTS_ERR_VALUE ) ;
had_errors = true ;
}
}
}
return ! had_errors ;
}
ZPL_END_C_DECLS
# endif
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
# if defined(ZPL_MODULE_PROCESS)
// file: source/process.c
////////////////////////////////////////////////////////////////
//
// Process creation and manipulation methods
//
//
ZPL_BEGIN_C_DECLS
static ZPL_ALWAYS_INLINE void zpl__pr_close_file_handle ( zpl_file * f ) {
ZPL_ASSERT_NOT_NULL ( f ) ;
f - > fd . p = NULL ;
}
static ZPL_ALWAYS_INLINE void zpl__pr_close_file_handles ( zpl_pr * process ) {
ZPL_ASSERT_NOT_NULL ( process ) ;
zpl__pr_close_file_handle ( & process - > in ) ;
zpl__pr_close_file_handle ( & process - > out ) ;
zpl__pr_close_file_handle ( & process - > err ) ;
process - > f_stdin = process - > f_stdout = process - > f_stderr = NULL ;
# ifdef ZPL_SYSTEM_WINDOWS
process - > win32_handle = NULL ;
# else
ZPL_NOT_IMPLEMENTED ;
# endif
}
enum {
ZPL_PR_HANDLE_MODE_READ ,
ZPL_PR_HANDLE_MODE_WRITE ,
ZPL_PR_HANDLE_MODES ,
} ;
void * zpl__pr_open_handle ( zpl_u8 type , const char * mode , void * * handle ) {
# ifdef ZPL_SYSTEM_WINDOWS
void * pipes [ ZPL_PR_HANDLE_MODES ] ;
zpl_i32 fd ;
const zpl_u32 flag_inherit = 0x00000001 ;
SECURITY_ATTRIBUTES sa = { zpl_size_of ( sa ) , 0 , 1 } ;
if ( ! CreatePipe ( & pipes [ 0 ] , & pipes [ 1 ] , cast ( LPSECURITY_ATTRIBUTES ) & sa , 0 ) ) {
return NULL ;
}
if ( ! SetHandleInformation ( pipes [ type ] , flag_inherit , 0 ) ) {
return NULL ;
}
fd = _open_osfhandle ( cast ( zpl_intptr ) pipes [ type ] , 0 ) ;
if ( fd ! = - 1 ) {
* handle = pipes [ 1 - type ] ;
return _fdopen ( fd , mode ) ;
}
return NULL ;
# else
ZPL_NOT_IMPLEMENTED ;
return NULL ;
# endif
}
zpl_i32 zpl_pr_create ( zpl_pr * process , const char * * args , zpl_isize argc , zpl_pr_si si , zpl_pr_opts options ) {
ZPL_ASSERT_NOT_NULL ( process ) ;
zpl_zero_item ( process ) ;
# ifdef ZPL_SYSTEM_WINDOWS
zpl_string cli , env ;
zpl_b32 c_env = false ;
STARTUPINFOW psi = { 0 } ;
PROCESS_INFORMATION pi = { 0 } ;
zpl_i32 err_code = 0 ;
zpl_allocator a = zpl_heap ( ) ;
const zpl_u32 use_std_handles = 0x00000100 ;
psi . cb = zpl_size_of ( psi ) ;
psi . dwFlags = use_std_handles | si . flags ;
if ( options & ZPL_PR_OPTS_CUSTOM_ENV ) {
env = zpl_string_join ( zpl_heap ( ) , cast ( const char * * ) si . env , si . env_count , " \0 \0 " ) ;
env = zpl_string_appendc ( env , " \0 " ) ;
c_env = true ;
}
else if ( ! ( options & ZPL_PR_OPTS_INHERIT_ENV ) ) {
env = ( zpl_string ) " \0 \0 \0 \0 " ;
} else {
env = ( zpl_string ) NULL ;
}
process - > f_stdin = zpl__pr_open_handle ( ZPL_PR_HANDLE_MODE_WRITE , " wb " , & psi . hStdInput ) ;
process - > f_stdout = zpl__pr_open_handle ( ZPL_PR_HANDLE_MODE_READ , " rb " , & psi . hStdOutput ) ;
if ( options & ZPL_PR_OPTS_COMBINE_STD_OUTPUT ) {
process - > f_stderr = process - > f_stdout ;
psi . hStdError = psi . hStdOutput ;
} else {
process - > f_stderr = zpl__pr_open_handle ( ZPL_PR_HANDLE_MODE_READ , " rb " , & psi . hStdError ) ;
}
cli = zpl_string_join ( zpl_heap ( ) , args , argc , " " ) ;
psi . dwX = si . posx ;
psi . dwY = si . posy ;
psi . dwXSize = si . resx ;
psi . dwYSize = si . resy ;
psi . dwXCountChars = si . bufx ;
psi . dwYCountChars = si . bufy ;
psi . dwFillAttribute = si . fill_attr ;
psi . wShowWindow = si . show_window ;
wchar_t * w_cli = zpl__alloc_utf8_to_ucs2 ( a , cli , NULL ) ;
wchar_t * w_workdir = zpl__alloc_utf8_to_ucs2 ( a , si . workdir , NULL ) ;
if ( ! CreateProcessW (
NULL ,
w_cli ,
NULL ,
NULL ,
1 ,
0 ,
env ,
w_workdir ,
cast ( LPSTARTUPINFOW ) & psi ,
cast ( LPPROCESS_INFORMATION ) & pi
) ) {
err_code = - 1 ;
goto pr_free_data ;
}
process - > win32_handle = pi . hProcess ;
CloseHandle ( pi . hThread ) ;
zpl_file_connect_handle ( & process - > in , process - > f_stdin ) ;
zpl_file_connect_handle ( & process - > out , process - > f_stdout ) ;
zpl_file_connect_handle ( & process - > err , process - > f_stderr ) ;
pr_free_data :
zpl_string_free ( cli ) ;
zpl_free ( a , w_cli ) ;
zpl_free ( a , w_workdir ) ;
if ( c_env )
zpl_string_free ( env ) ;
return err_code ;
# else
ZPL_NOT_IMPLEMENTED ;
return - 1 ;
# endif
}
zpl_i32 zpl_pr_join ( zpl_pr * process ) {
zpl_i32 ret_code ;
ZPL_ASSERT_NOT_NULL ( process ) ;
# ifdef ZPL_SYSTEM_WINDOWS
if ( process - > f_stdin ) {
fclose ( cast ( FILE * ) process - > f_stdin ) ;
}
WaitForSingleObject ( process - > win32_handle , INFINITE ) ;
if ( ! GetExitCodeProcess ( process - > win32_handle , cast ( LPDWORD ) & ret_code ) ) {
zpl_pr_destroy ( process ) ;
return - 1 ;
}
zpl_pr_destroy ( process ) ;
return ret_code ;
# else
ZPL_NOT_IMPLEMENTED ;
ret_code = - 1 ;
return ret_code ;
# endif
}
void zpl_pr_destroy ( zpl_pr * process ) {
ZPL_ASSERT_NOT_NULL ( process ) ;
# ifdef ZPL_SYSTEM_WINDOWS
if ( process - > f_stdin ) {
fclose ( cast ( FILE * ) process - > f_stdin ) ;
}
fclose ( cast ( FILE * ) process - > f_stdout ) ;
if ( process - > f_stderr ! = process - > f_stdout ) {
fclose ( cast ( FILE * ) process - > f_stderr ) ;
}
CloseHandle ( process - > win32_handle ) ;
zpl__pr_close_file_handles ( process ) ;
# else
ZPL_NOT_IMPLEMENTED ;
# endif
}
void zpl_pr_terminate ( zpl_pr * process , zpl_i32 err_code ) {
ZPL_ASSERT_NOT_NULL ( process ) ;
# ifdef ZPL_SYSTEM_WINDOWS
TerminateProcess ( process - > win32_handle , cast ( UINT ) err_code ) ;
zpl_pr_destroy ( process ) ;
# else
ZPL_NOT_IMPLEMENTED ;
# endif
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
ZPL_END_C_DECLS
2021-11-29 08:23:08 +00:00
# endif
2022-09-11 17:42:06 +00:00
# if defined(ZPL_MODULE_MATH)
// file: source/math.c
# if defined(ZPL_COMPILER_TINYC) && defined(ZPL_NO_MATH_H)
# undef ZPL_NO_MATH_H
# endif
# if !defined(ZPL_NO_MATH_H)
# include <math.h>
# endif
ZPL_BEGIN_C_DECLS
////////////////////////////////////////////////////////////////
//
// Math
//
zpl_f32 zpl_to_radians ( zpl_f32 degrees ) { return degrees * ZPL_TAU / 360.0f ; }
zpl_f32 zpl_to_degrees ( zpl_f32 radians ) { return radians * 360.0f / ZPL_TAU ; }
zpl_f32 zpl_angle_diff ( zpl_f32 radians_a , zpl_f32 radians_b ) {
zpl_f32 delta = zpl_mod ( radians_b - radians_a , ZPL_TAU ) ;
delta = zpl_mod ( delta + 1.5f * ZPL_TAU , ZPL_TAU ) ;
delta - = 0.5f * ZPL_TAU ;
return delta ;
}
zpl_f32 zpl_copy_sign ( zpl_f32 x , zpl_f32 y ) {
zpl_i32 ix , iy ;
zpl_f32 r ;
zpl_memcopy ( & ix , & x , zpl_size_of ( x ) ) ;
zpl_memcopy ( & iy , & y , zpl_size_of ( y ) ) ;
ix & = 0x7fffffff ;
ix | = iy & 0x80000000 ;
zpl_memcopy ( & r , & ix , zpl_size_of ( ix ) ) ;
return r ;
}
zpl_f32 zpl_remainder ( zpl_f32 x , zpl_f32 y ) { return x - ( zpl_round ( x / y ) * y ) ; }
zpl_f32 zpl_mod ( zpl_f32 x , zpl_f32 y ) {
zpl_f32 result ;
y = zpl_abs ( y ) ;
result = zpl_remainder ( zpl_abs ( x ) , y ) ;
if ( zpl_sign ( result ) > 0.0f ) result + = y ;
return zpl_copy_sign ( result , x ) ;
}
zpl_f64 zpl_copy_sign64 ( zpl_f64 x , zpl_f64 y ) {
zpl_i64 ix , iy ;
zpl_f64 r ;
zpl_memcopy ( & ix , & x , zpl_size_of ( x ) ) ;
zpl_memcopy ( & iy , & y , zpl_size_of ( y ) ) ;
ix & = 0x7fffffffffffffff ;
ix | = iy & 0x8000000000000000 ;
zpl_memcopy ( & r , & ix , zpl_size_of ( ix ) ) ;
return r ;
}
zpl_f64 zpl_floor64 ( zpl_f64 x ) { return cast ( zpl_f64 ) ( ( x > = 0.0 ) ? cast ( zpl_i64 ) x : cast ( zpl_i64 ) ( x - 0.9999999999999999 ) ) ; }
zpl_f64 zpl_ceil64 ( zpl_f64 x ) { return cast ( zpl_f64 ) ( ( x < 0 ) ? cast ( zpl_i64 ) x : ( cast ( zpl_i64 ) x ) + 1 ) ; }
zpl_f64 zpl_round64 ( zpl_f64 x ) { return cast ( zpl_f64 ) ( ( x > = 0.0 ) ? zpl_floor64 ( x + 0.5 ) : zpl_ceil64 ( x - 0.5 ) ) ; }
zpl_f64 zpl_remainder64 ( zpl_f64 x , zpl_f64 y ) { return x - ( zpl_round64 ( x / y ) * y ) ; }
zpl_f64 zpl_abs64 ( zpl_f64 x ) { return x < 0 ? - x : x ; }
zpl_f64 zpl_sign64 ( zpl_f64 x ) { return x < 0 ? - 1.0 : + 1.0 ; }
zpl_f64 zpl_mod64 ( zpl_f64 x , zpl_f64 y ) {
zpl_f64 result ;
y = zpl_abs64 ( y ) ;
result = zpl_remainder64 ( zpl_abs64 ( x ) , y ) ;
if ( zpl_sign64 ( result ) ) result + = y ;
return zpl_copy_sign64 ( result , x ) ;
}
zpl_f32 zpl_quake_rsqrt ( zpl_f32 a ) {
union {
int i ;
zpl_f32 f ;
} t ;
zpl_f32 x2 ;
zpl_f32 const three_halfs = 1.5f ;
x2 = a * 0.5f ;
t . f = a ;
t . i = 0x5f375a86 - ( t . i > > 1 ) ; /* What the fuck? */
t . f = t . f * ( three_halfs - ( x2 * t . f * t . f ) ) ; /* 1st iteration */
t . f = t . f * ( three_halfs - ( x2 * t . f * t . f ) ) ; /* 2nd iteration, this can be removed */
return t . f ;
}
# if defined(ZPL_NO_MATH_H)
# if defined(_MSC_VER)
zpl_f32 zpl_rsqrt ( zpl_f32 a ) { return _mm_cvtss_f32 ( _mm_rsqrt_ss ( _mm_set_ss ( a ) ) ) ; }
zpl_f32 zpl_sqrt ( zpl_f32 a ) { return _mm_cvtss_f32 ( _mm_sqrt_ss ( _mm_set_ss ( a ) ) ) ; } ;
zpl_f32 zpl_sin ( zpl_f32 a ) {
static zpl_f32 const a0 = + 1.91059300966915117e-31 f ;
static zpl_f32 const a1 = + 1.00086760103908896f ;
static zpl_f32 const a2 = - 1.21276126894734565e-2 f ;
static zpl_f32 const a3 = - 1.38078780785773762e-1 f ;
static zpl_f32 const a4 = - 2.67353392911981221e-2 f ;
static zpl_f32 const a5 = + 2.08026600266304389e-2 f ;
static zpl_f32 const a6 = - 3.03996055049204407e-3 f ;
static zpl_f32 const a7 = + 1.38235642404333740e-4 f ;
return a0 + a * ( a1 + a * ( a2 + a * ( a3 + a * ( a4 + a * ( a5 + a * ( a6 + a * a7 ) ) ) ) ) ) ;
}
zpl_f32 zpl_cos ( zpl_f32 a ) {
static zpl_f32 const a0 = + 1.00238601909309722f ;
static zpl_f32 const a1 = - 3.81919947353040024e-2 f ;
static zpl_f32 const a2 = - 3.94382342128062756e-1 f ;
static zpl_f32 const a3 = - 1.18134036025221444e-1 f ;
static zpl_f32 const a4 = + 1.07123798512170878e-1 f ;
static zpl_f32 const a5 = - 1.86637164165180873e-2 f ;
static zpl_f32 const a6 = + 9.90140908664079833e-4 f ;
static zpl_f32 const a7 = - 5.23022132118824778e-14 f ;
return a0 + a * ( a1 + a * ( a2 + a * ( a3 + a * ( a4 + a * ( a5 + a * ( a6 + a * a7 ) ) ) ) ) ) ;
}
zpl_f32 zpl_tan ( zpl_f32 radians ) {
zpl_f32 rr = radians * radians ;
zpl_f32 a = 9.5168091e-03 f ;
a * = rr ;
a + = 2.900525e-03 f ;
a * = rr ;
a + = 2.45650893e-02 f ;
a * = rr ;
a + = 5.33740603e-02 f ;
a * = rr ;
a + = 1.333923995e-01 f ;
a * = rr ;
a + = 3.333314036e-01 f ;
a * = rr ;
a + = 1.0f ;
a * = radians ;
return a ;
}
zpl_f32 zpl_arcsin ( zpl_f32 a ) { return zpl_arctan2 ( a , zpl_sqrt ( ( 1.0f + a ) * ( 1.0f - a ) ) ) ; }
zpl_f32 zpl_arccos ( zpl_f32 a ) { return zpl_arctan2 ( zpl_sqrt ( ( 1.0f + a ) * ( 1.0f - a ) ) , a ) ; }
zpl_f32 zpl_arctan ( zpl_f32 a ) {
zpl_f32 u = a * a ;
zpl_f32 u2 = u * u ;
zpl_f32 u3 = u2 * u ;
zpl_f32 u4 = u3 * u ;
zpl_f32 f = 1.0f + 0.33288950512027f * u - 0.08467922817644f * u2 + 0.03252232640125f * u3 - 0.00749305860992f * u4 ;
return a / f ;
}
zpl_f32 zpl_arctan2 ( zpl_f32 y , zpl_f32 x ) {
if ( zpl_abs ( x ) > zpl_abs ( y ) ) {
zpl_f32 a = zpl_arctan ( y / x ) ;
if ( x > 0.0f )
return a ;
else
return y > 0.0f ? a + ZPL_TAU_OVER_2 : a - ZPL_TAU_OVER_2 ;
} else {
zpl_f32 a = zpl_arctan ( x / y ) ;
if ( x > 0.0f )
return y > 0.0f ? ZPL_TAU_OVER_4 - a : - ZPL_TAU_OVER_4 - a ;
else
return y > 0.0f ? ZPL_TAU_OVER_4 + a : - ZPL_TAU_OVER_4 + a ;
}
}
zpl_f32 zpl_exp ( zpl_f32 a ) {
union {
zpl_f32 f ;
int i ;
} u , v ;
u . i = ( int ) ( 6051102 * a + 1056478197 ) ;
v . i = ( int ) ( 1056478197 - 6051102 * a ) ;
return u . f / v . f ;
}
zpl_f32 zpl_log ( zpl_f32 a ) {
union {
zpl_f32 f ;
int i ;
} u = { a } ;
return ( u . i - 1064866805 ) * 8.262958405176314e-8 f ; /* 1 / 12102203.0; */
}
zpl_f32 zpl_pow ( zpl_f32 a , zpl_f32 b ) {
int flipped = 0 , e ;
zpl_f32 f , r = 1.0f ;
if ( b < 0 ) {
flipped = 1 ;
b = - b ;
}
e = ( int ) b ;
f = zpl_exp ( b - e ) ;
while ( e ) {
if ( e & 1 ) r * = a ;
a * = a ;
e > > = 1 ;
}
r * = f ;
return flipped ? 1.0f / r : r ;
}
# else
zpl_f32 zpl_rsqrt ( zpl_f32 a ) { return 1.0f / __builtin_sqrt ( a ) ; }
zpl_f32 zpl_sqrt ( zpl_f32 a ) { return __builtin_sqrt ( a ) ; }
zpl_f32 zpl_sin ( zpl_f32 radians ) { return __builtin_sinf ( radians ) ; }
zpl_f32 zpl_cos ( zpl_f32 radians ) { return __builtin_cosf ( radians ) ; }
zpl_f32 zpl_tan ( zpl_f32 radians ) { return __builtin_tanf ( radians ) ; }
zpl_f32 zpl_arcsin ( zpl_f32 a ) { return __builtin_asinf ( a ) ; }
zpl_f32 zpl_arccos ( zpl_f32 a ) { return __builtin_acosf ( a ) ; }
zpl_f32 zpl_arctan ( zpl_f32 a ) { return __builtin_atanf ( a ) ; }
zpl_f32 zpl_arctan2 ( zpl_f32 y , zpl_f32 x ) { return __builtin_atan2f ( y , x ) ; }
zpl_f32 zpl_exp ( zpl_f32 x ) { return __builtin_expf ( x ) ; }
zpl_f32 zpl_log ( zpl_f32 x ) { return __builtin_logf ( x ) ; }
// TODO: Should this be zpl_exp(y * zpl_log(x)) ???
zpl_f32 zpl_pow ( zpl_f32 x , zpl_f32 y ) { return __builtin_powf ( x , y ) ; }
# endif
# else
zpl_f32 zpl_rsqrt ( zpl_f32 a ) { return 1.0f / sqrtf ( a ) ; }
zpl_f32 zpl_sqrt ( zpl_f32 a ) { return sqrtf ( a ) ; } ;
zpl_f32 zpl_sin ( zpl_f32 radians ) { return sinf ( radians ) ; } ;
zpl_f32 zpl_cos ( zpl_f32 radians ) { return cosf ( radians ) ; } ;
zpl_f32 zpl_tan ( zpl_f32 radians ) { return tanf ( radians ) ; } ;
zpl_f32 zpl_arcsin ( zpl_f32 a ) { return asinf ( a ) ; } ;
zpl_f32 zpl_arccos ( zpl_f32 a ) { return acosf ( a ) ; } ;
zpl_f32 zpl_arctan ( zpl_f32 a ) { return atanf ( a ) ; } ;
zpl_f32 zpl_arctan2 ( zpl_f32 y , zpl_f32 x ) { return atan2f ( y , x ) ; } ;
zpl_f32 zpl_exp ( zpl_f32 x ) { return expf ( x ) ; }
zpl_f32 zpl_log ( zpl_f32 x ) { return logf ( x ) ; }
zpl_f32 zpl_pow ( zpl_f32 x , zpl_f32 y ) { return powf ( x , y ) ; }
# endif
zpl_f32 zpl_exp2 ( zpl_f32 x ) { return zpl_exp ( ZPL_LOG_TWO * x ) ; }
zpl_f32 zpl_log2 ( zpl_f32 x ) { return zpl_log ( x ) / ZPL_LOG_TWO ; }
zpl_f32 zpl_fast_exp ( zpl_f32 x ) {
/* NOTE: Only works in the range -1 <= x <= +1 */
zpl_f32 e = 1.0f + x * ( 1.0f + x * 0.5f * ( 1.0f + x * 0.3333333333f * ( 1.0f + x * 0.25f * ( 1.0f + x * 0.2f ) ) ) ) ;
return e ;
}
zpl_f32 zpl_fast_exp2 ( zpl_f32 x ) { return zpl_fast_exp ( ZPL_LOG_TWO * x ) ; }
zpl_f32 zpl_round ( zpl_f32 x ) { return ( float ) ( ( x > = 0.0f ) ? zpl_floor ( x + 0.5f ) : zpl_ceil ( x - 0.5f ) ) ; }
zpl_f32 zpl_floor ( zpl_f32 x ) { return ( float ) ( ( x > = 0.0f ) ? ( int ) x : ( int ) ( x - 0.9999999999999999f ) ) ; }
zpl_f32 zpl_ceil ( zpl_f32 x ) { return ( float ) ( ( x < 0.0f ) ? ( int ) x : ( ( int ) x ) + 1 ) ; }
zpl_f32 zpl_half_to_float ( zpl_half value ) {
union {
unsigned int i ;
zpl_f32 f ;
} result ;
int s = ( value > > 15 ) & 0x001 ;
int e = ( value > > 10 ) & 0x01f ;
int m = value & 0x3ff ;
if ( e = = 0 ) {
if ( m = = 0 ) {
/* Plus or minus zero */
result . i = ( unsigned int ) ( s < < 31 ) ;
return result . f ;
} else {
/* Denormalized number */
while ( ! ( m & 0x00000400 ) ) {
m < < = 1 ;
e - = 1 ;
}
e + = 1 ;
m & = ~ 0x00000400 ;
}
} else if ( e = = 31 ) {
if ( m = = 0 ) {
/* Positive or negative infinity */
result . i = ( unsigned int ) ( ( s < < 31 ) | 0x7f800000 ) ;
return result . f ;
} else {
/* Nan */
result . i = ( unsigned int ) ( ( s < < 31 ) | 0x7f800000 | ( m < < 13 ) ) ;
return result . f ;
}
}
e = e + ( 127 - 15 ) ;
m = m < < 13 ;
result . i = ( unsigned int ) ( ( s < < 31 ) | ( e < < 23 ) | m ) ;
return result . f ;
}
zpl_half zpl_float_to_half ( zpl_f32 value ) {
union {
unsigned int i ;
zpl_f32 f ;
} v ;
int i , s , e , m ;
v . f = value ;
i = ( int ) v . i ;
s = ( i > > 16 ) & 0x00008000 ;
e = ( ( i > > 23 ) & 0x000000ff ) - ( 127 - 15 ) ;
m = i & 0x007fffff ;
if ( e < = 0 ) {
if ( e < - 10 ) return ( zpl_half ) s ;
m = ( m | 0x00800000 ) > > ( 1 - e ) ;
if ( m & 0x00001000 ) m + = 0x00002000 ;
return ( zpl_half ) ( s | ( m > > 13 ) ) ;
} else if ( e = = 0xff - ( 127 - 15 ) ) {
if ( m = = 0 ) {
return ( zpl_half ) ( s | 0x7c00 ) ; /* NOTE: infinity */
} else {
/* NOTE: NAN */
m > > = 13 ;
return ( zpl_half ) ( s | 0x7c00 | m | ( m = = 0 ) ) ;
}
} else {
if ( m & 0x00001000 ) {
m + = 0x00002000 ;
if ( m & 0x00800000 ) {
m = 0 ;
e + = 1 ;
}
}
if ( e > 30 ) {
zpl_f32 volatile f = 1e12 f ;
int j ;
for ( j = 0 ; j < 10 ; j + + ) f * = f ; /* NOTE: Cause overflow */
return ( zpl_half ) ( s | 0x7c00 ) ;
}
return ( zpl_half ) ( s | ( e < < 10 ) | ( m > > 13 ) ) ;
}
}
# define ZPL_VEC2_2OP(a, c, post) \
a - > x = c . x post ; \
a - > y = c . y post ;
# define ZPL_VEC2_3OP(a, b, op, c, post) \
a - > x = b . x op c . x post ; \
a - > y = b . y op c . y post ;
# define ZPL_VEC3_2OP(a, c, post) \
a - > x = c . x post ; \
a - > y = c . y post ; \
a - > z = c . z post ;
# define ZPL_VEC3_3OP(a, b, op, c, post) \
a - > x = b . x op c . x post ; \
a - > y = b . y op c . y post ; \
a - > z = b . z op c . z post ;
# define ZPL_VEC4_2OP(a, c, post) \
a - > x = c . x post ; \
a - > y = c . y post ; \
a - > z = c . z post ; \
a - > w = c . w post ;
# define ZPL_VEC4_3OP(a, b, op, c, post) \
a - > x = b . x op c . x post ; \
a - > y = b . y op c . y post ; \
a - > z = b . z op c . z post ; \
a - > w = b . w op c . w post ;
zpl_vec2 zpl_vec2f_zero ( void ) {
zpl_vec2 v = { 0 , 0 } ;
return v ;
}
zpl_vec2 zpl_vec2f ( zpl_f32 x , zpl_f32 y ) {
zpl_vec2 v ;
v . x = x ;
v . y = y ;
return v ;
}
zpl_vec2 zpl_vec2fv ( zpl_f32 x [ 2 ] ) {
zpl_vec2 v ;
v . x = x [ 0 ] ;
v . y = x [ 1 ] ;
return v ;
}
zpl_vec3 zpl_vec3f_zero ( void ) {
zpl_vec3 v = { 0 , 0 , 0 } ;
return v ;
}
zpl_vec3 zpl_vec3f ( zpl_f32 x , zpl_f32 y , zpl_f32 z ) {
zpl_vec3 v ;
v . x = x ;
v . y = y ;
v . z = z ;
return v ;
}
zpl_vec3 zpl_vec3fv ( zpl_f32 x [ 3 ] ) {
zpl_vec3 v ;
v . x = x [ 0 ] ;
v . y = x [ 1 ] ;
v . z = x [ 2 ] ;
return v ;
}
zpl_vec4 zpl_vec4f_zero ( void ) {
zpl_vec4 v = { 0 , 0 , 0 , 0 } ;
return v ;
}
zpl_vec4 zpl_vec4f ( zpl_f32 x , zpl_f32 y , zpl_f32 z , zpl_f32 w ) {
zpl_vec4 v ;
v . x = x ;
v . y = y ;
v . z = z ;
v . w = w ;
return v ;
}
zpl_vec4 zpl_vec4fv ( zpl_f32 x [ 4 ] ) {
zpl_vec4 v ;
v . x = x [ 0 ] ;
v . y = x [ 1 ] ;
v . z = x [ 2 ] ;
v . w = x [ 3 ] ;
return v ;
}
zpl_f32 zpl_vec2_max ( zpl_vec2 v ) { return zpl_max ( v . x , v . y ) ; }
zpl_f32 zpl_vec2_side ( zpl_vec2 p , zpl_vec2 q , zpl_vec2 r ) { return ( ( q . x - p . x ) * ( r . y - p . y ) - ( r . x - p . x ) * ( q . y - p . y ) ) ; }
void zpl_vec2_add ( zpl_vec2 * d , zpl_vec2 v0 , zpl_vec2 v1 ) { ZPL_VEC2_3OP ( d , v0 , + , v1 , + 0 ) ; }
void zpl_vec2_sub ( zpl_vec2 * d , zpl_vec2 v0 , zpl_vec2 v1 ) { ZPL_VEC2_3OP ( d , v0 , - , v1 , + 0 ) ; }
void zpl_vec2_mul ( zpl_vec2 * d , zpl_vec2 v , zpl_f32 s ) { ZPL_VEC2_2OP ( d , v , * s ) ; }
void zpl_vec2_div ( zpl_vec2 * d , zpl_vec2 v , zpl_f32 s ) { ZPL_VEC2_2OP ( d , v , / s ) ; }
zpl_f32 zpl_vec3_max ( zpl_vec3 v ) { return zpl_max3 ( v . x , v . y , v . z ) ; }
void zpl_vec3_add ( zpl_vec3 * d , zpl_vec3 v0 , zpl_vec3 v1 ) { ZPL_VEC3_3OP ( d , v0 , + , v1 , + 0 ) ; }
void zpl_vec3_sub ( zpl_vec3 * d , zpl_vec3 v0 , zpl_vec3 v1 ) { ZPL_VEC3_3OP ( d , v0 , - , v1 , + 0 ) ; }
void zpl_vec3_mul ( zpl_vec3 * d , zpl_vec3 v , zpl_f32 s ) { ZPL_VEC3_2OP ( d , v , * s ) ; }
void zpl_vec3_div ( zpl_vec3 * d , zpl_vec3 v , zpl_f32 s ) { ZPL_VEC3_2OP ( d , v , / s ) ; }
void zpl_vec4_add ( zpl_vec4 * d , zpl_vec4 v0 , zpl_vec4 v1 ) { ZPL_VEC4_3OP ( d , v0 , + , v1 , + 0 ) ; }
void zpl_vec4_sub ( zpl_vec4 * d , zpl_vec4 v0 , zpl_vec4 v1 ) { ZPL_VEC4_3OP ( d , v0 , - , v1 , + 0 ) ; }
void zpl_vec4_mul ( zpl_vec4 * d , zpl_vec4 v , zpl_f32 s ) { ZPL_VEC4_2OP ( d , v , * s ) ; }
void zpl_vec4_div ( zpl_vec4 * d , zpl_vec4 v , zpl_f32 s ) { ZPL_VEC4_2OP ( d , v , / s ) ; }
void zpl_vec2_addeq ( zpl_vec2 * d , zpl_vec2 v ) { ZPL_VEC2_3OP ( d , ( * d ) , + , v , + 0 ) ; }
void zpl_vec2_subeq ( zpl_vec2 * d , zpl_vec2 v ) { ZPL_VEC2_3OP ( d , ( * d ) , - , v , + 0 ) ; }
void zpl_vec2_muleq ( zpl_vec2 * d , zpl_f32 s ) { ZPL_VEC2_2OP ( d , ( * d ) , * s ) ; }
void zpl_vec2_diveq ( zpl_vec2 * d , zpl_f32 s ) { ZPL_VEC2_2OP ( d , ( * d ) , / s ) ; }
void zpl_vec3_addeq ( zpl_vec3 * d , zpl_vec3 v ) { ZPL_VEC3_3OP ( d , ( * d ) , + , v , + 0 ) ; }
void zpl_vec3_subeq ( zpl_vec3 * d , zpl_vec3 v ) { ZPL_VEC3_3OP ( d , ( * d ) , - , v , + 0 ) ; }
void zpl_vec3_muleq ( zpl_vec3 * d , zpl_f32 s ) { ZPL_VEC3_2OP ( d , ( * d ) , * s ) ; }
void zpl_vec3_diveq ( zpl_vec3 * d , zpl_f32 s ) { ZPL_VEC3_2OP ( d , ( * d ) , / s ) ; }
void zpl_vec4_addeq ( zpl_vec4 * d , zpl_vec4 v ) { ZPL_VEC4_3OP ( d , ( * d ) , + , v , + 0 ) ; }
void zpl_vec4_subeq ( zpl_vec4 * d , zpl_vec4 v ) { ZPL_VEC4_3OP ( d , ( * d ) , - , v , + 0 ) ; }
void zpl_vec4_muleq ( zpl_vec4 * d , zpl_f32 s ) { ZPL_VEC4_2OP ( d , ( * d ) , * s ) ; }
void zpl_vec4_diveq ( zpl_vec4 * d , zpl_f32 s ) { ZPL_VEC4_2OP ( d , ( * d ) , / s ) ; }
# undef ZPL_VEC2_2OP
# undef ZPL_VEC2_3OP
# undef ZPL_VEC3_3OP
# undef ZPL_VEC3_2OP
# undef ZPL_VEC4_2OP
# undef ZPL_VEC4_3OP
zpl_f32 zpl_vec2_dot ( zpl_vec2 v0 , zpl_vec2 v1 ) { return v0 . x * v1 . x + v0 . y * v1 . y ; }
zpl_f32 zpl_vec3_dot ( zpl_vec3 v0 , zpl_vec3 v1 ) { return v0 . x * v1 . x + v0 . y * v1 . y + v0 . z * v1 . z ; }
zpl_f32 zpl_vec4_dot ( zpl_vec4 v0 , zpl_vec4 v1 ) { return v0 . x * v1 . x + v0 . y * v1 . y + v0 . z * v1 . z + v0 . w * v1 . w ; }
void zpl_vec2_cross ( zpl_f32 * d , zpl_vec2 v0 , zpl_vec2 v1 ) { * d = v0 . x * v1 . y - v1 . x * v0 . y ; }
void zpl_vec3_cross ( zpl_vec3 * d , zpl_vec3 v0 , zpl_vec3 v1 ) {
d - > x = v0 . y * v1 . z - v0 . z * v1 . y ;
d - > y = v0 . z * v1 . x - v0 . x * v1 . z ;
d - > z = v0 . x * v1 . y - v0 . y * v1 . x ;
}
zpl_f32 zpl_vec2_mag2 ( zpl_vec2 v ) { return zpl_vec2_dot ( v , v ) ; }
zpl_f32 zpl_vec3_mag2 ( zpl_vec3 v ) { return zpl_vec3_dot ( v , v ) ; }
zpl_f32 zpl_vec4_mag2 ( zpl_vec4 v ) { return zpl_vec4_dot ( v , v ) ; }
/* TODO: Create custom sqrt function */
zpl_f32 zpl_vec2_mag ( zpl_vec2 v ) { return zpl_sqrt ( zpl_vec2_dot ( v , v ) ) ; }
zpl_f32 zpl_vec3_mag ( zpl_vec3 v ) { return zpl_sqrt ( zpl_vec3_dot ( v , v ) ) ; }
zpl_f32 zpl_vec4_mag ( zpl_vec4 v ) { return zpl_sqrt ( zpl_vec4_dot ( v , v ) ) ; }
void zpl_vec2_norm ( zpl_vec2 * d , zpl_vec2 v ) {
zpl_f32 inv_mag = zpl_rsqrt ( zpl_vec2_dot ( v , v ) ) ;
zpl_vec2_mul ( d , v , inv_mag ) ;
}
void zpl_vec3_norm ( zpl_vec3 * d , zpl_vec3 v ) {
zpl_f32 inv_mag = zpl_rsqrt ( zpl_vec3_dot ( v , v ) ) ;
zpl_vec3_mul ( d , v , inv_mag ) ;
}
void zpl_vec4_norm ( zpl_vec4 * d , zpl_vec4 v ) {
zpl_f32 inv_mag = zpl_rsqrt ( zpl_vec4_dot ( v , v ) ) ;
zpl_vec4_mul ( d , v , inv_mag ) ;
}
void zpl_vec2_norm0 ( zpl_vec2 * d , zpl_vec2 v ) {
zpl_f32 mag = zpl_vec2_mag ( v ) ;
if ( mag > 0 )
zpl_vec2_div ( d , v , mag ) ;
else
* d = zpl_vec2f_zero ( ) ;
}
void zpl_vec3_norm0 ( zpl_vec3 * d , zpl_vec3 v ) {
zpl_f32 mag = zpl_vec3_mag ( v ) ;
if ( mag > 0 )
zpl_vec3_div ( d , v , mag ) ;
else
* d = zpl_vec3f_zero ( ) ;
}
void zpl_vec4_norm0 ( zpl_vec4 * d , zpl_vec4 v ) {
zpl_f32 mag = zpl_vec4_mag ( v ) ;
if ( mag > 0 )
zpl_vec4_div ( d , v , mag ) ;
else
* d = zpl_vec4f_zero ( ) ;
}
void zpl_vec2_reflect ( zpl_vec2 * d , zpl_vec2 i , zpl_vec2 n ) {
zpl_vec2 b = n ;
zpl_vec2_muleq ( & b , 2.0f * zpl_vec2_dot ( n , i ) ) ;
zpl_vec2_sub ( d , i , b ) ;
}
void zpl_vec3_reflect ( zpl_vec3 * d , zpl_vec3 i , zpl_vec3 n ) {
zpl_vec3 b = n ;
zpl_vec3_muleq ( & b , 2.0f * zpl_vec3_dot ( n , i ) ) ;
zpl_vec3_sub ( d , i , b ) ;
}
void zpl_vec2_refract ( zpl_vec2 * d , zpl_vec2 i , zpl_vec2 n , zpl_f32 eta ) {
zpl_vec2 a , b ;
zpl_f32 dv , k ;
dv = zpl_vec2_dot ( n , i ) ;
k = 1.0f - eta * eta * ( 1.0f - dv * dv ) ;
zpl_vec2_mul ( & a , i , eta ) ;
zpl_vec2_mul ( & b , n , eta * dv * zpl_sqrt ( k ) ) ;
zpl_vec2_sub ( d , a , b ) ;
zpl_vec2_muleq ( d , ( float ) ( k > = 0.0f ) ) ;
}
void zpl_vec3_refract ( zpl_vec3 * d , zpl_vec3 i , zpl_vec3 n , zpl_f32 eta ) {
zpl_vec3 a , b ;
zpl_f32 dv , k ;
dv = zpl_vec3_dot ( n , i ) ;
k = 1.0f - eta * eta * ( 1.0f - dv * dv ) ;
zpl_vec3_mul ( & a , i , eta ) ;
zpl_vec3_mul ( & b , n , eta * dv * zpl_sqrt ( k ) ) ;
zpl_vec3_sub ( d , a , b ) ;
zpl_vec3_muleq ( d , ( float ) ( k > = 0.0f ) ) ;
}
zpl_f32 zpl_vec2_aspect_ratio ( zpl_vec2 v ) { return ( v . y < 0.0001f ) ? 0.0f : v . x / v . y ; }
void zpl_mat2_transpose ( zpl_mat2 * m ) { zpl_float22_transpose ( zpl_float22_m ( m ) ) ; }
void zpl_mat2_identity ( zpl_mat2 * m ) { zpl_float22_identity ( zpl_float22_m ( m ) ) ; }
void zpl_mat2_mul ( zpl_mat2 * out , zpl_mat2 * m1 , zpl_mat2 * m2 ) {
zpl_float22_mul ( zpl_float22_m ( out ) , zpl_float22_m ( m1 ) , zpl_float22_m ( m2 ) ) ;
}
void zpl_float22_identity ( zpl_f32 m [ 2 ] [ 2 ] ) {
m [ 0 ] [ 0 ] = 1 ;
m [ 0 ] [ 1 ] = 0 ;
m [ 1 ] [ 0 ] = 0 ;
m [ 1 ] [ 1 ] = 1 ;
}
void zpl_mat2_copy ( zpl_mat2 * out , zpl_mat2 * m ) {
zpl_memcopy ( out , m , sizeof ( zpl_mat3 ) ) ;
}
void zpl_mat2_mul_vec2 ( zpl_vec2 * out , zpl_mat2 * m , zpl_vec2 in ) { zpl_float22_mul_vec2 ( out , zpl_float22_m ( m ) , in ) ; }
zpl_mat2 * zpl_mat2_v ( zpl_vec2 m [ 2 ] ) { return ( zpl_mat2 * ) m ; }
zpl_mat2 * zpl_mat2_f ( zpl_f32 m [ 2 ] [ 2 ] ) { return ( zpl_mat2 * ) m ; }
zpl_float2 * zpl_float22_m ( zpl_mat2 * m ) { return ( zpl_float2 * ) m ; }
zpl_float2 * zpl_float22_v ( zpl_vec2 m [ 2 ] ) { return ( zpl_float2 * ) m ; }
zpl_float2 * zpl_float22_4 ( zpl_f32 m [ 4 ] ) { return ( zpl_float2 * ) m ; }
void zpl_float22_transpose ( zpl_f32 ( * vec ) [ 2 ] ) {
int i , j ;
for ( j = 0 ; j < 2 ; j + + ) {
for ( i = j + 1 ; i < 2 ; i + + ) {
zpl_f32 t = vec [ i ] [ j ] ;
vec [ i ] [ j ] = vec [ j ] [ i ] ;
vec [ j ] [ i ] = t ;
}
}
}
void zpl_float22_mul ( zpl_f32 ( * out ) [ 2 ] , zpl_f32 ( * mat1 ) [ 2 ] , zpl_f32 ( * mat2 ) [ 2 ] ) {
int i , j ;
zpl_f32 temp1 [ 2 ] [ 2 ] , temp2 [ 2 ] [ 2 ] ;
if ( mat1 = = out ) {
zpl_memcopy ( temp1 , mat1 , sizeof ( temp1 ) ) ;
mat1 = temp1 ;
}
if ( mat2 = = out ) {
zpl_memcopy ( temp2 , mat2 , sizeof ( temp2 ) ) ;
mat2 = temp2 ;
}
for ( j = 0 ; j < 2 ; j + + ) {
for ( i = 0 ; i < 2 ; i + + ) { out [ j ] [ i ] = mat1 [ 0 ] [ i ] * mat2 [ j ] [ 0 ] + mat1 [ 1 ] [ i ] * mat2 [ j ] [ 1 ] ; }
}
}
void zpl_float22_mul_vec2 ( zpl_vec2 * out , zpl_f32 m [ 2 ] [ 2 ] , zpl_vec2 v ) {
out - > x = m [ 0 ] [ 0 ] * v . x + m [ 0 ] [ 1 ] * v . y ;
out - > y = m [ 1 ] [ 0 ] * v . x + m [ 1 ] [ 1 ] * v . y ;
}
zpl_f32 zpl_mat2_determinate ( zpl_mat2 * m ) {
zpl_float2 * e = zpl_float22_m ( m ) ;
return e [ 0 ] [ 0 ] * e [ 1 ] [ 1 ] - e [ 1 ] [ 0 ] * e [ 0 ] [ 1 ] ;
}
void zpl_mat2_inverse ( zpl_mat2 * out , zpl_mat2 * in ) {
zpl_float2 * o = zpl_float22_m ( out ) ;
zpl_float2 * i = zpl_float22_m ( in ) ;
zpl_f32 ood = 1.0f / zpl_mat2_determinate ( in ) ;
o [ 0 ] [ 0 ] = + i [ 1 ] [ 1 ] * ood ;
o [ 0 ] [ 1 ] = - i [ 0 ] [ 1 ] * ood ;
o [ 1 ] [ 0 ] = - i [ 1 ] [ 0 ] * ood ;
o [ 1 ] [ 1 ] = + i [ 0 ] [ 0 ] * ood ;
}
void zpl_mat3_transpose ( zpl_mat3 * m ) { zpl_float33_transpose ( zpl_float33_m ( m ) ) ; }
void zpl_mat3_identity ( zpl_mat3 * m ) { zpl_float33_identity ( zpl_float33_m ( m ) ) ; }
void zpl_mat3_copy ( zpl_mat3 * out , zpl_mat3 * m ) {
zpl_memcopy ( out , m , sizeof ( zpl_mat3 ) ) ;
}
void zpl_mat3_mul ( zpl_mat3 * out , zpl_mat3 * m1 , zpl_mat3 * m2 ) {
zpl_float33_mul ( zpl_float33_m ( out ) , zpl_float33_m ( m1 ) , zpl_float33_m ( m2 ) ) ;
}
void zpl_float33_identity ( zpl_f32 m [ 3 ] [ 3 ] ) {
m [ 0 ] [ 0 ] = 1 ;
m [ 0 ] [ 1 ] = 0 ;
m [ 0 ] [ 2 ] = 0 ;
m [ 1 ] [ 0 ] = 0 ;
m [ 1 ] [ 1 ] = 1 ;
m [ 1 ] [ 2 ] = 0 ;
m [ 2 ] [ 0 ] = 0 ;
m [ 2 ] [ 1 ] = 0 ;
m [ 2 ] [ 2 ] = 1 ;
}
void zpl_mat3_mul_vec3 ( zpl_vec3 * out , zpl_mat3 * m , zpl_vec3 in ) { zpl_float33_mul_vec3 ( out , zpl_float33_m ( m ) , in ) ; }
zpl_mat3 * zpl_mat3_v ( zpl_vec3 m [ 3 ] ) { return ( zpl_mat3 * ) m ; }
zpl_mat3 * zpl_mat3_f ( zpl_f32 m [ 3 ] [ 3 ] ) { return ( zpl_mat3 * ) m ; }
zpl_float3 * zpl_float33_m ( zpl_mat3 * m ) { return ( zpl_float3 * ) m ; }
zpl_float3 * zpl_float33_v ( zpl_vec3 m [ 3 ] ) { return ( zpl_float3 * ) m ; }
zpl_float3 * zpl_float33_9 ( zpl_f32 m [ 9 ] ) { return ( zpl_float3 * ) m ; }
void zpl_float33_transpose ( zpl_f32 ( * vec ) [ 3 ] ) {
int i , j ;
for ( j = 0 ; j < 3 ; j + + ) {
for ( i = j + 1 ; i < 3 ; i + + ) {
zpl_f32 t = vec [ i ] [ j ] ;
vec [ i ] [ j ] = vec [ j ] [ i ] ;
vec [ j ] [ i ] = t ;
}
}
}
void zpl_float33_mul ( zpl_f32 ( * out ) [ 3 ] , zpl_f32 ( * mat1 ) [ 3 ] , zpl_f32 ( * mat2 ) [ 3 ] ) {
int i , j ;
zpl_f32 temp1 [ 3 ] [ 3 ] , temp2 [ 3 ] [ 3 ] ;
if ( mat1 = = out ) {
zpl_memcopy ( temp1 , mat1 , sizeof ( temp1 ) ) ;
mat1 = temp1 ;
}
if ( mat2 = = out ) {
zpl_memcopy ( temp2 , mat2 , sizeof ( temp2 ) ) ;
mat2 = temp2 ;
}
for ( j = 0 ; j < 3 ; j + + ) {
for ( i = 0 ; i < 3 ; i + + ) {
out [ j ] [ i ] = mat1 [ 0 ] [ i ] * mat2 [ j ] [ 0 ] + mat1 [ 1 ] [ i ] * mat2 [ j ] [ 1 ] + mat1 [ 2 ] [ i ] * mat2 [ j ] [ 2 ] ;
}
}
}
void zpl_float33_mul_vec3 ( zpl_vec3 * out , zpl_f32 m [ 3 ] [ 3 ] , zpl_vec3 v ) {
out - > x = m [ 0 ] [ 0 ] * v . x + m [ 0 ] [ 1 ] * v . y + m [ 0 ] [ 2 ] * v . z ;
out - > y = m [ 1 ] [ 0 ] * v . x + m [ 1 ] [ 1 ] * v . y + m [ 1 ] [ 2 ] * v . z ;
out - > z = m [ 2 ] [ 0 ] * v . x + m [ 2 ] [ 1 ] * v . y + m [ 2 ] [ 2 ] * v . z ;
}
zpl_f32 zpl_mat3_determinate ( zpl_mat3 * m ) {
zpl_float3 * e = zpl_float33_m ( m ) ;
zpl_f32 d =
+ e [ 0 ] [ 0 ] * ( e [ 1 ] [ 1 ] * e [ 2 ] [ 2 ] - e [ 1 ] [ 2 ] * e [ 2 ] [ 1 ] )
- e [ 0 ] [ 1 ] * ( e [ 1 ] [ 0 ] * e [ 2 ] [ 2 ] - e [ 1 ] [ 2 ] * e [ 2 ] [ 0 ] )
+ e [ 0 ] [ 2 ] * ( e [ 1 ] [ 0 ] * e [ 2 ] [ 1 ] - e [ 1 ] [ 1 ] * e [ 2 ] [ 0 ] ) ;
return d ;
}
void zpl_mat3_inverse ( zpl_mat3 * out , zpl_mat3 * in ) {
zpl_float3 * o = zpl_float33_m ( out ) ;
zpl_float3 * i = zpl_float33_m ( in ) ;
zpl_f32 ood = 1.0f / zpl_mat3_determinate ( in ) ;
o [ 0 ] [ 0 ] = + ( i [ 1 ] [ 1 ] * i [ 2 ] [ 2 ] - i [ 2 ] [ 1 ] * i [ 1 ] [ 2 ] ) * ood ;
o [ 0 ] [ 1 ] = - ( i [ 1 ] [ 0 ] * i [ 2 ] [ 2 ] - i [ 2 ] [ 0 ] * i [ 1 ] [ 2 ] ) * ood ;
o [ 0 ] [ 2 ] = + ( i [ 1 ] [ 0 ] * i [ 2 ] [ 1 ] - i [ 2 ] [ 0 ] * i [ 1 ] [ 1 ] ) * ood ;
o [ 1 ] [ 0 ] = - ( i [ 0 ] [ 1 ] * i [ 2 ] [ 2 ] - i [ 2 ] [ 1 ] * i [ 0 ] [ 2 ] ) * ood ;
o [ 1 ] [ 1 ] = + ( i [ 0 ] [ 0 ] * i [ 2 ] [ 2 ] - i [ 2 ] [ 0 ] * i [ 0 ] [ 2 ] ) * ood ;
o [ 1 ] [ 2 ] = - ( i [ 0 ] [ 0 ] * i [ 2 ] [ 1 ] - i [ 2 ] [ 0 ] * i [ 0 ] [ 1 ] ) * ood ;
o [ 2 ] [ 0 ] = + ( i [ 0 ] [ 1 ] * i [ 1 ] [ 2 ] - i [ 1 ] [ 1 ] * i [ 0 ] [ 2 ] ) * ood ;
o [ 2 ] [ 1 ] = - ( i [ 0 ] [ 0 ] * i [ 1 ] [ 2 ] - i [ 1 ] [ 0 ] * i [ 0 ] [ 2 ] ) * ood ;
o [ 2 ] [ 2 ] = + ( i [ 0 ] [ 0 ] * i [ 1 ] [ 1 ] - i [ 1 ] [ 0 ] * i [ 0 ] [ 1 ] ) * ood ;
}
void zpl_mat4_transpose ( zpl_mat4 * m ) { zpl_float44_transpose ( zpl_float44_m ( m ) ) ; }
void zpl_mat4_identity ( zpl_mat4 * m ) { zpl_float44_identity ( zpl_float44_m ( m ) ) ; }
void zpl_mat4_copy ( zpl_mat4 * out , zpl_mat4 * m ) {
zpl_memcopy ( out , m , sizeof ( zpl_mat4 ) ) ;
}
void zpl_mat4_mul ( zpl_mat4 * out , zpl_mat4 * m1 , zpl_mat4 * m2 ) {
zpl_float44_mul ( zpl_float44_m ( out ) , zpl_float44_m ( m1 ) , zpl_float44_m ( m2 ) ) ;
}
void zpl_float44_identity ( zpl_f32 m [ 4 ] [ 4 ] ) {
m [ 0 ] [ 0 ] = 1 ;
m [ 0 ] [ 1 ] = 0 ;
m [ 0 ] [ 2 ] = 0 ;
m [ 0 ] [ 3 ] = 0 ;
m [ 1 ] [ 0 ] = 0 ;
m [ 1 ] [ 1 ] = 1 ;
m [ 1 ] [ 2 ] = 0 ;
m [ 1 ] [ 3 ] = 0 ;
m [ 2 ] [ 0 ] = 0 ;
m [ 2 ] [ 1 ] = 0 ;
m [ 2 ] [ 2 ] = 1 ;
m [ 2 ] [ 3 ] = 0 ;
m [ 3 ] [ 0 ] = 0 ;
m [ 3 ] [ 1 ] = 0 ;
m [ 3 ] [ 2 ] = 0 ;
m [ 3 ] [ 3 ] = 1 ;
}
void zpl_mat4_mul_vec4 ( zpl_vec4 * out , zpl_mat4 * m , zpl_vec4 in ) { zpl_float44_mul_vec4 ( out , zpl_float44_m ( m ) , in ) ; }
zpl_mat4 * zpl_mat4_v ( zpl_vec4 m [ 4 ] ) { return ( zpl_mat4 * ) m ; }
zpl_mat4 * zpl_mat4_f ( zpl_f32 m [ 4 ] [ 4 ] ) { return ( zpl_mat4 * ) m ; }
zpl_float4 * zpl_float44_m ( zpl_mat4 * m ) { return ( zpl_float4 * ) m ; }
zpl_float4 * zpl_float44_v ( zpl_vec4 m [ 4 ] ) { return ( zpl_float4 * ) m ; }
zpl_float4 * zpl_float44_16 ( zpl_f32 m [ 16 ] ) { return ( zpl_float4 * ) m ; }
void zpl_float44_transpose ( zpl_f32 ( * vec ) [ 4 ] ) {
zpl_f32 tmp ;
tmp = vec [ 1 ] [ 0 ] ;
vec [ 1 ] [ 0 ] = vec [ 0 ] [ 1 ] ;
vec [ 0 ] [ 1 ] = tmp ;
tmp = vec [ 2 ] [ 0 ] ;
vec [ 2 ] [ 0 ] = vec [ 0 ] [ 2 ] ;
vec [ 0 ] [ 2 ] = tmp ;
tmp = vec [ 3 ] [ 0 ] ;
vec [ 3 ] [ 0 ] = vec [ 0 ] [ 3 ] ;
vec [ 0 ] [ 3 ] = tmp ;
tmp = vec [ 2 ] [ 1 ] ;
vec [ 2 ] [ 1 ] = vec [ 1 ] [ 2 ] ;
vec [ 1 ] [ 2 ] = tmp ;
tmp = vec [ 3 ] [ 1 ] ;
vec [ 3 ] [ 1 ] = vec [ 1 ] [ 3 ] ;
vec [ 1 ] [ 3 ] = tmp ;
tmp = vec [ 3 ] [ 2 ] ;
vec [ 3 ] [ 2 ] = vec [ 2 ] [ 3 ] ;
vec [ 2 ] [ 3 ] = tmp ;
}
void zpl_float44_mul ( zpl_f32 ( * out ) [ 4 ] , zpl_f32 ( * mat1 ) [ 4 ] , zpl_f32 ( * mat2 ) [ 4 ] ) {
int i , j ;
zpl_f32 temp1 [ 4 ] [ 4 ] , temp2 [ 4 ] [ 4 ] ;
if ( mat1 = = out ) {
zpl_memcopy ( temp1 , mat1 , sizeof ( temp1 ) ) ;
mat1 = temp1 ;
}
if ( mat2 = = out ) {
zpl_memcopy ( temp2 , mat2 , sizeof ( temp2 ) ) ;
mat2 = temp2 ;
}
for ( j = 0 ; j < 4 ; j + + ) {
for ( i = 0 ; i < 4 ; i + + ) {
out [ j ] [ i ] =
mat1 [ 0 ] [ i ] * mat2 [ j ] [ 0 ] + mat1 [ 1 ] [ i ] * mat2 [ j ] [ 1 ]
+ mat1 [ 2 ] [ i ] * mat2 [ j ] [ 2 ] + mat1 [ 3 ] [ i ] * mat2 [ j ] [ 3 ] ;
}
}
}
void zpl_float44_mul_vec4 ( zpl_vec4 * out , zpl_f32 m [ 4 ] [ 4 ] , zpl_vec4 v ) {
out - > x = m [ 0 ] [ 0 ] * v . x + m [ 1 ] [ 0 ] * v . y + m [ 2 ] [ 0 ] * v . z + m [ 3 ] [ 0 ] * v . w ;
out - > y = m [ 0 ] [ 1 ] * v . x + m [ 1 ] [ 1 ] * v . y + m [ 2 ] [ 1 ] * v . z + m [ 3 ] [ 1 ] * v . w ;
out - > z = m [ 0 ] [ 2 ] * v . x + m [ 1 ] [ 2 ] * v . y + m [ 2 ] [ 2 ] * v . z + m [ 3 ] [ 2 ] * v . w ;
out - > w = m [ 0 ] [ 3 ] * v . x + m [ 1 ] [ 3 ] * v . y + m [ 2 ] [ 3 ] * v . z + m [ 3 ] [ 3 ] * v . w ;
}
void zpl_mat4_inverse ( zpl_mat4 * out , zpl_mat4 * in ) {
zpl_float4 * o = zpl_float44_m ( out ) ;
zpl_float4 * m = zpl_float44_m ( in ) ;
zpl_f32 ood ;
zpl_f32 sf00 = m [ 2 ] [ 2 ] * m [ 3 ] [ 3 ] - m [ 3 ] [ 2 ] * m [ 2 ] [ 3 ] ;
zpl_f32 sf01 = m [ 2 ] [ 1 ] * m [ 3 ] [ 3 ] - m [ 3 ] [ 1 ] * m [ 2 ] [ 3 ] ;
zpl_f32 sf02 = m [ 2 ] [ 1 ] * m [ 3 ] [ 2 ] - m [ 3 ] [ 1 ] * m [ 2 ] [ 2 ] ;
zpl_f32 sf03 = m [ 2 ] [ 0 ] * m [ 3 ] [ 3 ] - m [ 3 ] [ 0 ] * m [ 2 ] [ 3 ] ;
zpl_f32 sf04 = m [ 2 ] [ 0 ] * m [ 3 ] [ 2 ] - m [ 3 ] [ 0 ] * m [ 2 ] [ 2 ] ;
zpl_f32 sf05 = m [ 2 ] [ 0 ] * m [ 3 ] [ 1 ] - m [ 3 ] [ 0 ] * m [ 2 ] [ 1 ] ;
zpl_f32 sf06 = m [ 1 ] [ 2 ] * m [ 3 ] [ 3 ] - m [ 3 ] [ 2 ] * m [ 1 ] [ 3 ] ;
zpl_f32 sf07 = m [ 1 ] [ 1 ] * m [ 3 ] [ 3 ] - m [ 3 ] [ 1 ] * m [ 1 ] [ 3 ] ;
zpl_f32 sf08 = m [ 1 ] [ 1 ] * m [ 3 ] [ 2 ] - m [ 3 ] [ 1 ] * m [ 1 ] [ 2 ] ;
zpl_f32 sf09 = m [ 1 ] [ 0 ] * m [ 3 ] [ 3 ] - m [ 3 ] [ 0 ] * m [ 1 ] [ 3 ] ;
zpl_f32 sf10 = m [ 1 ] [ 0 ] * m [ 3 ] [ 2 ] - m [ 3 ] [ 0 ] * m [ 1 ] [ 2 ] ;
zpl_f32 sf11 = m [ 1 ] [ 1 ] * m [ 3 ] [ 3 ] - m [ 3 ] [ 1 ] * m [ 1 ] [ 3 ] ;
zpl_f32 sf12 = m [ 1 ] [ 0 ] * m [ 3 ] [ 1 ] - m [ 3 ] [ 0 ] * m [ 1 ] [ 1 ] ;
zpl_f32 sf13 = m [ 1 ] [ 2 ] * m [ 2 ] [ 3 ] - m [ 2 ] [ 2 ] * m [ 1 ] [ 3 ] ;
zpl_f32 sf14 = m [ 1 ] [ 1 ] * m [ 2 ] [ 3 ] - m [ 2 ] [ 1 ] * m [ 1 ] [ 3 ] ;
zpl_f32 sf15 = m [ 1 ] [ 1 ] * m [ 2 ] [ 2 ] - m [ 2 ] [ 1 ] * m [ 1 ] [ 2 ] ;
zpl_f32 sf16 = m [ 1 ] [ 0 ] * m [ 2 ] [ 3 ] - m [ 2 ] [ 0 ] * m [ 1 ] [ 3 ] ;
zpl_f32 sf17 = m [ 1 ] [ 0 ] * m [ 2 ] [ 2 ] - m [ 2 ] [ 0 ] * m [ 1 ] [ 2 ] ;
zpl_f32 sf18 = m [ 1 ] [ 0 ] * m [ 2 ] [ 1 ] - m [ 2 ] [ 0 ] * m [ 1 ] [ 1 ] ;
o [ 0 ] [ 0 ] = + ( m [ 1 ] [ 1 ] * sf00 - m [ 1 ] [ 2 ] * sf01 + m [ 1 ] [ 3 ] * sf02 ) ;
o [ 1 ] [ 0 ] = - ( m [ 1 ] [ 0 ] * sf00 - m [ 1 ] [ 2 ] * sf03 + m [ 1 ] [ 3 ] * sf04 ) ;
o [ 2 ] [ 0 ] = + ( m [ 1 ] [ 0 ] * sf01 - m [ 1 ] [ 1 ] * sf03 + m [ 1 ] [ 3 ] * sf05 ) ;
o [ 3 ] [ 0 ] = - ( m [ 1 ] [ 0 ] * sf02 - m [ 1 ] [ 1 ] * sf04 + m [ 1 ] [ 2 ] * sf05 ) ;
o [ 0 ] [ 1 ] = - ( m [ 0 ] [ 1 ] * sf00 - m [ 0 ] [ 2 ] * sf01 + m [ 0 ] [ 3 ] * sf02 ) ;
o [ 1 ] [ 1 ] = + ( m [ 0 ] [ 0 ] * sf00 - m [ 0 ] [ 2 ] * sf03 + m [ 0 ] [ 3 ] * sf04 ) ;
o [ 2 ] [ 1 ] = - ( m [ 0 ] [ 0 ] * sf01 - m [ 0 ] [ 1 ] * sf03 + m [ 0 ] [ 3 ] * sf05 ) ;
o [ 3 ] [ 1 ] = + ( m [ 0 ] [ 0 ] * sf02 - m [ 0 ] [ 1 ] * sf04 + m [ 0 ] [ 2 ] * sf05 ) ;
o [ 0 ] [ 2 ] = + ( m [ 0 ] [ 1 ] * sf06 - m [ 0 ] [ 2 ] * sf07 + m [ 0 ] [ 3 ] * sf08 ) ;
o [ 1 ] [ 2 ] = - ( m [ 0 ] [ 0 ] * sf06 - m [ 0 ] [ 2 ] * sf09 + m [ 0 ] [ 3 ] * sf10 ) ;
o [ 2 ] [ 2 ] = + ( m [ 0 ] [ 0 ] * sf11 - m [ 0 ] [ 1 ] * sf09 + m [ 0 ] [ 3 ] * sf12 ) ;
o [ 3 ] [ 2 ] = - ( m [ 0 ] [ 0 ] * sf08 - m [ 0 ] [ 1 ] * sf10 + m [ 0 ] [ 2 ] * sf12 ) ;
o [ 0 ] [ 3 ] = - ( m [ 0 ] [ 1 ] * sf13 - m [ 0 ] [ 2 ] * sf14 + m [ 0 ] [ 3 ] * sf15 ) ;
o [ 1 ] [ 3 ] = + ( m [ 0 ] [ 0 ] * sf13 - m [ 0 ] [ 2 ] * sf16 + m [ 0 ] [ 3 ] * sf17 ) ;
o [ 2 ] [ 3 ] = - ( m [ 0 ] [ 0 ] * sf14 - m [ 0 ] [ 1 ] * sf16 + m [ 0 ] [ 3 ] * sf18 ) ;
o [ 3 ] [ 3 ] = + ( m [ 0 ] [ 0 ] * sf15 - m [ 0 ] [ 1 ] * sf17 + m [ 0 ] [ 2 ] * sf18 ) ;
ood = 1.0f / ( m [ 0 ] [ 0 ] * o [ 0 ] [ 0 ] + m [ 0 ] [ 1 ] * o [ 1 ] [ 0 ] + m [ 0 ] [ 2 ] * o [ 2 ] [ 0 ] + m [ 0 ] [ 3 ] * o [ 3 ] [ 0 ] ) ;
o [ 0 ] [ 0 ] * = ood ; o [ 1 ] [ 0 ] * = ood ; o [ 2 ] [ 0 ] * = ood ; o [ 3 ] [ 0 ] * = ood ;
o [ 0 ] [ 1 ] * = ood ; o [ 1 ] [ 1 ] * = ood ; o [ 2 ] [ 1 ] * = ood ; o [ 3 ] [ 1 ] * = ood ;
o [ 0 ] [ 2 ] * = ood ; o [ 1 ] [ 2 ] * = ood ; o [ 2 ] [ 2 ] * = ood ; o [ 3 ] [ 2 ] * = ood ;
o [ 0 ] [ 3 ] * = ood ; o [ 1 ] [ 3 ] * = ood ; o [ 2 ] [ 3 ] * = ood ; o [ 3 ] [ 3 ] * = ood ;
}
void zpl_mat4_axis_angle ( zpl_mat4 * out , zpl_vec3 v , zpl_f32 angle_radians ) {
zpl_f32 c , s ;
zpl_vec3 axis , t ;
zpl_float4 * rot ;
c = zpl_cos ( angle_radians ) ;
s = zpl_sin ( angle_radians ) ;
zpl_vec3_norm ( & axis , v ) ;
zpl_vec3_mul ( & t , axis , 1.0f - c ) ;
zpl_mat4_identity ( out ) ;
rot = zpl_float44_m ( out ) ;
rot [ 0 ] [ 0 ] = c + t . x * axis . x ;
rot [ 0 ] [ 1 ] = 0 + t . x * axis . y + s * axis . z ;
rot [ 0 ] [ 2 ] = 0 + t . x * axis . z - s * axis . y ;
rot [ 0 ] [ 3 ] = 0 ;
rot [ 1 ] [ 0 ] = 0 + t . y * axis . x - s * axis . z ;
rot [ 1 ] [ 1 ] = c + t . y * axis . y ;
rot [ 1 ] [ 2 ] = 0 + t . y * axis . z + s * axis . x ;
rot [ 1 ] [ 3 ] = 0 ;
rot [ 2 ] [ 0 ] = 0 + t . z * axis . x + s * axis . y ;
rot [ 2 ] [ 1 ] = 0 + t . z * axis . y - s * axis . x ;
rot [ 2 ] [ 2 ] = c + t . z * axis . z ;
rot [ 2 ] [ 3 ] = 0 ;
}
void zpl_mat4_to_translate ( zpl_mat4 * out , zpl_vec3 v ) {
zpl_mat4_identity ( out ) ;
out - > col [ 3 ] . xyz = v ;
}
void zpl_mat4_to_rotate ( zpl_mat4 * out , zpl_vec3 v , zpl_f32 angle_radians ) {
zpl_mat4_axis_angle ( out , v , angle_radians ) ;
}
void zpl_mat4_to_scale ( zpl_mat4 * out , zpl_vec3 v ) {
zpl_mat4_identity ( out ) ;
out - > col [ 0 ] . x = v . x ;
out - > col [ 1 ] . y = v . y ;
out - > col [ 2 ] . z = v . z ;
}
void zpl_mat4_to_scalef ( zpl_mat4 * out , zpl_f32 s ) {
zpl_mat4_identity ( out ) ;
out - > col [ 0 ] . x = s ;
out - > col [ 1 ] . y = s ;
out - > col [ 2 ] . z = s ;
}
void zpl_mat4_translate ( zpl_mat4 * m , zpl_vec3 v ) {
zpl_mat4 mm ;
zpl_mat4_to_translate ( & mm , v ) ;
zpl_mat4_mul ( m , m , & mm ) ;
}
void zpl_mat4_rotate ( zpl_mat4 * m , zpl_vec3 v , zpl_f32 angle_radians ) {
zpl_mat4 mm ;
zpl_mat4_axis_angle ( & mm , v , angle_radians ) ;
zpl_mat4_mul ( m , m , & mm ) ;
}
void zpl_mat4_scale ( zpl_mat4 * m , zpl_vec3 v ) {
zpl_mat4 mm ;
zpl_mat4_to_scale ( & mm , v ) ;
zpl_mat4_mul ( m , m , & mm ) ;
}
void zpl_mat4_scalef ( zpl_mat4 * m , zpl_f32 s ) {
zpl_mat4 mm ;
zpl_mat4_to_scalef ( & mm , s ) ;
zpl_mat4_mul ( m , m , & mm ) ;
}
void zpl_mat4_ortho2d ( zpl_mat4 * out , zpl_f32 left , zpl_f32 right , zpl_f32 bottom , zpl_f32 top ) {
zpl_float4 * m ;
zpl_mat4_identity ( out ) ;
m = zpl_float44_m ( out ) ;
m [ 0 ] [ 0 ] = 2.0f / ( right - left ) ;
m [ 1 ] [ 1 ] = 2.0f / ( top - bottom ) ;
m [ 2 ] [ 2 ] = - 1.0f ;
m [ 3 ] [ 0 ] = - ( right + left ) / ( right - left ) ;
m [ 3 ] [ 1 ] = - ( top + bottom ) / ( top - bottom ) ;
}
void zpl_mat4_ortho3d ( zpl_mat4 * out , zpl_f32 left , zpl_f32 right , zpl_f32 bottom , zpl_f32 top , zpl_f32 z_near , zpl_f32 z_far ) {
zpl_float4 * m ;
zpl_mat4_identity ( out ) ;
m = zpl_float44_m ( out ) ;
m [ 0 ] [ 0 ] = + 2.0f / ( right - left ) ;
m [ 1 ] [ 1 ] = + 2.0f / ( top - bottom ) ;
m [ 2 ] [ 2 ] = - 2.0f / ( z_far - z_near ) ;
m [ 3 ] [ 0 ] = - ( right + left ) / ( right - left ) ;
m [ 3 ] [ 1 ] = - ( top + bottom ) / ( top - bottom ) ;
m [ 3 ] [ 2 ] = - ( z_far + z_near ) / ( z_far - z_near ) ;
}
void zpl_mat4_perspective ( zpl_mat4 * out , zpl_f32 fovy , zpl_f32 aspect , zpl_f32 z_near , zpl_f32 z_far ) {
zpl_f32 tan_half_fovy = zpl_tan ( 0.5f * fovy ) ;
zpl_mat4 zero_mat = { 0 } ;
zpl_float4 * m = zpl_float44_m ( out ) ;
* out = zero_mat ;
m [ 0 ] [ 0 ] = 1.0f / ( aspect * tan_half_fovy ) ;
m [ 1 ] [ 1 ] = 1.0f / ( tan_half_fovy ) ;
m [ 2 ] [ 2 ] = - ( z_far + z_near ) / ( z_far - z_near ) ;
m [ 2 ] [ 3 ] = - 1.0f ;
m [ 3 ] [ 2 ] = - 2.0f * z_far * z_near / ( z_far - z_near ) ;
}
void zpl_mat4_infinite_perspective ( zpl_mat4 * out , zpl_f32 fovy , zpl_f32 aspect , zpl_f32 z_near ) {
zpl_f32 range = zpl_tan ( 0.5f * fovy ) * z_near ;
zpl_f32 left = - range * aspect ;
zpl_f32 right = range * aspect ;
zpl_f32 bottom = - range ;
zpl_f32 top = range ;
zpl_mat4 zero_mat = { 0 } ;
zpl_float4 * m = zpl_float44_m ( out ) ;
* out = zero_mat ;
m [ 0 ] [ 0 ] = ( 2.0f * z_near ) / ( right - left ) ;
m [ 1 ] [ 1 ] = ( 2.0f * z_near ) / ( top - bottom ) ;
m [ 2 ] [ 2 ] = - 1.0f ;
m [ 2 ] [ 3 ] = - 1.0f ;
m [ 3 ] [ 2 ] = - 2.0f * z_near ;
}
void zpl_mat4_ortho2d_dx ( zpl_mat4 * out , zpl_f32 left , zpl_f32 right , zpl_f32 bottom , zpl_f32 top ) {
zpl_float4 * m ;
zpl_mat4_identity ( out ) ;
m = zpl_float44_m ( out ) ;
m [ 0 ] [ 0 ] = 2.0f / ( right - left ) ;
m [ 1 ] [ 1 ] = 2.0f / ( top - bottom ) ;
m [ 2 ] [ 2 ] = - 1.0f ;
m [ 3 ] [ 0 ] = - ( right + left ) / ( right - left ) ;
m [ 3 ] [ 1 ] = - ( top + bottom ) / ( top - bottom ) ;
}
void zpl_mat4_ortho3d_dx ( zpl_mat4 * out , zpl_f32 left , zpl_f32 right , zpl_f32 bottom , zpl_f32 top , zpl_f32 z_near , zpl_f32 z_far ) {
zpl_float4 * m ;
zpl_mat4_identity ( out ) ;
m = zpl_float44_m ( out ) ;
m [ 0 ] [ 0 ] = + 2.0f / ( right - left ) ;
m [ 1 ] [ 1 ] = + 2.0f / ( top - bottom ) ;
m [ 2 ] [ 2 ] = - 1.0f / ( z_far - z_near ) ;
m [ 3 ] [ 0 ] = - ( right + left ) / ( right - left ) ;
m [ 3 ] [ 1 ] = - ( top + bottom ) / ( top - bottom ) ;
m [ 3 ] [ 2 ] = - ( z_near ) / ( z_far - z_near ) ;
}
void zpl_mat4_perspective_dx ( zpl_mat4 * out , zpl_f32 fovy , zpl_f32 aspect , zpl_f32 z_near , zpl_f32 z_far ) {
zpl_f32 tan_half_fovy = zpl_tan ( 0.5f * fovy ) ;
zpl_mat4 zero_mat = { 0 } ;
zpl_float4 * m = zpl_float44_m ( out ) ;
* out = zero_mat ;
m [ 0 ] [ 0 ] = 1.0f / ( aspect * tan_half_fovy ) ;
m [ 1 ] [ 1 ] = 1.0f / ( tan_half_fovy ) ;
m [ 2 ] [ 2 ] = - ( z_far ) / ( z_far - z_near ) ;
m [ 2 ] [ 3 ] = - 1.0f ;
m [ 3 ] [ 2 ] = - z_near / ( z_far - z_near ) ;
}
void zpl_mat4_infinite_perspective_dx ( zpl_mat4 * out , zpl_f32 fovy , zpl_f32 aspect , zpl_f32 z_near ) {
zpl_f32 tan_half_fovy = zpl_tan ( 0.5f * fovy ) ;
zpl_mat4 zero_mat = { 0 } ;
zpl_float4 * m = zpl_float44_m ( out ) ;
* out = zero_mat ;
m [ 0 ] [ 0 ] = 1.0f / ( aspect * tan_half_fovy ) ;
m [ 1 ] [ 1 ] = 1.0f / ( tan_half_fovy ) ;
m [ 2 ] [ 2 ] = - 1.0f ;
m [ 2 ] [ 3 ] = - 1.0f ;
m [ 3 ] [ 2 ] = - z_near ;
}
void zpl_mat4_look_at ( zpl_mat4 * out , zpl_vec3 eye , zpl_vec3 centre , zpl_vec3 up ) {
zpl_vec3 f , s , u ;
zpl_float4 * m ;
zpl_vec3_sub ( & f , centre , eye ) ;
zpl_vec3_norm ( & f , f ) ;
zpl_vec3_cross ( & s , f , up ) ;
zpl_vec3_norm ( & s , s ) ;
zpl_vec3_cross ( & u , s , f ) ;
zpl_mat4_identity ( out ) ;
m = zpl_float44_m ( out ) ;
m [ 0 ] [ 0 ] = + s . x ;
m [ 1 ] [ 0 ] = + s . y ;
m [ 2 ] [ 0 ] = + s . z ;
m [ 0 ] [ 1 ] = + u . x ;
m [ 1 ] [ 1 ] = + u . y ;
m [ 2 ] [ 1 ] = + u . z ;
m [ 0 ] [ 2 ] = - f . x ;
m [ 1 ] [ 2 ] = - f . y ;
m [ 2 ] [ 2 ] = - f . z ;
m [ 3 ] [ 0 ] = - zpl_vec3_dot ( s , eye ) ;
m [ 3 ] [ 1 ] = - zpl_vec3_dot ( u , eye ) ;
m [ 3 ] [ 2 ] = + zpl_vec3_dot ( f , eye ) ;
}
void zpl_mat4_look_at_lh ( zpl_mat4 * out , zpl_vec3 eye , zpl_vec3 centre , zpl_vec3 up ) {
zpl_vec3 f , s , u ;
zpl_float4 * m ;
zpl_vec3_sub ( & f , centre , eye ) ;
zpl_vec3_norm ( & f , f ) ;
zpl_vec3_cross ( & s , up , f ) ;
zpl_vec3_norm ( & s , s ) ;
zpl_vec3_cross ( & u , f , s ) ;
zpl_mat4_identity ( out ) ;
m = zpl_float44_m ( out ) ;
m [ 0 ] [ 0 ] = + s . x ;
m [ 1 ] [ 0 ] = + s . y ;
m [ 2 ] [ 0 ] = + s . z ;
m [ 0 ] [ 1 ] = + u . x ;
m [ 1 ] [ 1 ] = + u . y ;
m [ 2 ] [ 1 ] = + u . z ;
m [ 0 ] [ 2 ] = + f . x ;
m [ 1 ] [ 2 ] = + f . y ;
m [ 2 ] [ 2 ] = + f . z ;
m [ 3 ] [ 0 ] = - zpl_vec3_dot ( s , eye ) ;
m [ 3 ] [ 1 ] = - zpl_vec3_dot ( u , eye ) ;
m [ 3 ] [ 2 ] = - zpl_vec3_dot ( f , eye ) ;
}
zpl_quat zpl_quatf ( zpl_f32 x , zpl_f32 y , zpl_f32 z , zpl_f32 w ) {
zpl_quat q ;
q . x = x ;
q . y = y ;
q . z = z ;
q . w = w ;
return q ;
}
zpl_quat zpl_quatfv ( zpl_f32 e [ 4 ] ) {
zpl_quat q ;
q . x = e [ 0 ] ;
q . y = e [ 1 ] ;
q . z = e [ 2 ] ;
q . w = e [ 3 ] ;
return q ;
}
zpl_quat zpl_quat_axis_angle ( zpl_vec3 axis , zpl_f32 angle_radians ) {
zpl_quat q ;
zpl_vec3_norm ( & q . xyz , axis ) ;
zpl_vec3_muleq ( & q . xyz , zpl_sin ( 0.5f * angle_radians ) ) ;
q . w = zpl_cos ( 0.5f * angle_radians ) ;
return q ;
}
zpl_quat zpl_quat_euler_angles ( zpl_f32 pitch , zpl_f32 yaw , zpl_f32 roll ) {
/* TODO: Do without multiplication, i.e. make it faster */
zpl_quat q , p , y , r ;
p = zpl_quat_axis_angle ( zpl_vec3f ( 1 , 0 , 0 ) , pitch ) ;
y = zpl_quat_axis_angle ( zpl_vec3f ( 0 , 1 , 0 ) , yaw ) ;
r = zpl_quat_axis_angle ( zpl_vec3f ( 0 , 0 , 1 ) , roll ) ;
zpl_quat_mul ( & q , y , p ) ;
zpl_quat_muleq ( & q , r ) ;
return q ;
}
zpl_quat zpl_quat_identity ( void ) {
zpl_quat q = { 0 , 0 , 0 , 1 } ;
return q ;
}
void zpl_quat_add ( zpl_quat * d , zpl_quat q0 , zpl_quat q1 ) { zpl_vec4_add ( & d - > xyzw , q0 . xyzw , q1 . xyzw ) ; }
void zpl_quat_sub ( zpl_quat * d , zpl_quat q0 , zpl_quat q1 ) { zpl_vec4_sub ( & d - > xyzw , q0 . xyzw , q1 . xyzw ) ; }
void zpl_quat_mul ( zpl_quat * d , zpl_quat q0 , zpl_quat q1 ) {
d - > x = q0 . w * q1 . x + q0 . x * q1 . w + q0 . y * q1 . z - q0 . z * q1 . y ;
d - > y = q0 . w * q1 . y - q0 . x * q1 . z + q0 . y * q1 . w + q0 . z * q1 . x ;
d - > z = q0 . w * q1 . z + q0 . x * q1 . y - q0 . y * q1 . x + q0 . z * q1 . w ;
d - > w = q0 . w * q1 . w - q0 . x * q1 . x - q0 . y * q1 . y - q0 . z * q1 . z ;
}
void zpl_quat_div ( zpl_quat * d , zpl_quat q0 , zpl_quat q1 ) {
zpl_quat iq1 ;
zpl_quat_inverse ( & iq1 , q1 ) ;
zpl_quat_mul ( d , q0 , iq1 ) ;
}
void zpl_quat_mulf ( zpl_quat * d , zpl_quat q0 , zpl_f32 s ) { zpl_vec4_mul ( & d - > xyzw , q0 . xyzw , s ) ; }
void zpl_quat_divf ( zpl_quat * d , zpl_quat q0 , zpl_f32 s ) { zpl_vec4_div ( & d - > xyzw , q0 . xyzw , s ) ; }
void zpl_quat_addeq ( zpl_quat * d , zpl_quat q ) { zpl_vec4_addeq ( & d - > xyzw , q . xyzw ) ; }
void zpl_quat_subeq ( zpl_quat * d , zpl_quat q ) { zpl_vec4_subeq ( & d - > xyzw , q . xyzw ) ; }
void zpl_quat_muleq ( zpl_quat * d , zpl_quat q ) { zpl_quat_mul ( d , * d , q ) ; }
void zpl_quat_diveq ( zpl_quat * d , zpl_quat q ) { zpl_quat_div ( d , * d , q ) ; }
void zpl_quat_muleqf ( zpl_quat * d , zpl_f32 s ) { zpl_vec4_muleq ( & d - > xyzw , s ) ; }
void zpl_quat_diveqf ( zpl_quat * d , zpl_f32 s ) { zpl_vec4_diveq ( & d - > xyzw , s ) ; }
zpl_f32 zpl_quat_dot ( zpl_quat q0 , zpl_quat q1 ) {
zpl_f32 r = zpl_vec3_dot ( q0 . xyz , q1 . xyz ) + q0 . w * q1 . w ;
return r ;
}
zpl_f32 zpl_quat_mag ( zpl_quat q ) {
zpl_f32 r = zpl_sqrt ( zpl_quat_dot ( q , q ) ) ;
return r ;
}
void zpl_quat_norm ( zpl_quat * d , zpl_quat q ) { zpl_quat_divf ( d , q , zpl_quat_mag ( q ) ) ; }
void zpl_quat_conj ( zpl_quat * d , zpl_quat q ) {
d - > xyz = zpl_vec3f ( - q . x , - q . y , - q . z ) ;
d - > w = q . w ;
}
void zpl_quat_inverse ( zpl_quat * d , zpl_quat q ) {
zpl_quat_conj ( d , q ) ;
zpl_quat_diveqf ( d , zpl_quat_dot ( q , q ) ) ;
}
void zpl_quat_axis ( zpl_vec3 * axis , zpl_quat q ) {
zpl_quat n ;
zpl_quat_norm ( & n , q ) ;
zpl_vec3_div ( axis , n . xyz , zpl_sin ( zpl_arccos ( q . w ) ) ) ;
}
zpl_f32 zpl_quat_angle ( zpl_quat q ) {
zpl_f32 mag = zpl_quat_mag ( q ) ;
zpl_f32 c = q . w * ( 1.0f / mag ) ;
zpl_f32 angle = 2.0f * zpl_arccos ( c ) ;
return angle ;
}
zpl_f32 zpl_quat_roll ( zpl_quat q ) {
return zpl_arctan2 ( 2.0f * q . x * q . y + q . z * q . w , q . x * q . x + q . w * q . w - q . y * q . y - q . z * q . z ) ;
}
zpl_f32 zpl_quat_pitch ( zpl_quat q ) {
return zpl_arctan2 ( 2.0f * q . y * q . z + q . w * q . x , q . w * q . w - q . x * q . x - q . y * q . y + q . z * q . z ) ;
}
zpl_f32 zpl_quat_yaw ( zpl_quat q ) { return zpl_arcsin ( - 2.0f * ( q . x * q . z - q . w * q . y ) ) ; }
void zpl_quat_rotate_vec3 ( zpl_vec3 * d , zpl_quat q , zpl_vec3 v ) {
/* zpl_vec3 t = 2.0f * cross(q.xyz, v);
* * d = q . w * t + v + cross ( q . xyz , t ) ;
*/
zpl_vec3 t , p ;
zpl_vec3_cross ( & t , q . xyz , v ) ;
zpl_vec3_muleq ( & t , 2.0f ) ;
zpl_vec3_cross ( & p , q . xyz , t ) ;
zpl_vec3_mul ( d , t , q . w ) ;
zpl_vec3_addeq ( d , v ) ;
zpl_vec3_addeq ( d , p ) ;
}
void zpl_mat4_from_quat ( zpl_mat4 * out , zpl_quat q ) {
zpl_float4 * m ;
zpl_quat a ;
zpl_f32 xx , yy , zz , xy , xz , yz , wx , wy , wz ;
zpl_quat_norm ( & a , q ) ;
xx = a . x * a . x ;
yy = a . y * a . y ;
zz = a . z * a . z ;
xy = a . x * a . y ;
xz = a . x * a . z ;
yz = a . y * a . z ;
wx = a . w * a . x ;
wy = a . w * a . y ;
wz = a . w * a . z ;
zpl_mat4_identity ( out ) ;
m = zpl_float44_m ( out ) ;
m [ 0 ] [ 0 ] = 1.0f - 2.0f * ( yy + zz ) ;
m [ 0 ] [ 1 ] = 2.0f * ( xy + wz ) ;
m [ 0 ] [ 2 ] = 2.0f * ( xz - wy ) ;
m [ 1 ] [ 0 ] = 2.0f * ( xy - wz ) ;
m [ 1 ] [ 1 ] = 1.0f - 2.0f * ( xx + zz ) ;
m [ 1 ] [ 2 ] = 2.0f * ( yz + wx ) ;
m [ 2 ] [ 0 ] = 2.0f * ( xz + wy ) ;
m [ 2 ] [ 1 ] = 2.0f * ( yz - wx ) ;
m [ 2 ] [ 2 ] = 1.0f - 2.0f * ( xx + yy ) ;
}
void zpl_quat_from_mat4 ( zpl_quat * out , zpl_mat4 * mat ) {
zpl_float4 * m ;
zpl_f32 four_x_squared_minus_1 , four_y_squared_minus_1 , four_z_squared_minus_1 , four_w_squared_minus_1 ,
four_biggest_squared_minus_1 ;
int biggest_index = 0 ;
zpl_f32 biggest_value , mult ;
m = zpl_float44_m ( mat ) ;
four_x_squared_minus_1 = m [ 0 ] [ 0 ] - m [ 1 ] [ 1 ] - m [ 2 ] [ 2 ] ;
four_y_squared_minus_1 = m [ 1 ] [ 1 ] - m [ 0 ] [ 0 ] - m [ 2 ] [ 2 ] ;
four_z_squared_minus_1 = m [ 2 ] [ 2 ] - m [ 0 ] [ 0 ] - m [ 1 ] [ 1 ] ;
four_w_squared_minus_1 = m [ 0 ] [ 0 ] + m [ 1 ] [ 1 ] + m [ 2 ] [ 2 ] ;
four_biggest_squared_minus_1 = four_w_squared_minus_1 ;
if ( four_x_squared_minus_1 > four_biggest_squared_minus_1 ) {
four_biggest_squared_minus_1 = four_x_squared_minus_1 ;
biggest_index = 1 ;
}
if ( four_y_squared_minus_1 > four_biggest_squared_minus_1 ) {
four_biggest_squared_minus_1 = four_y_squared_minus_1 ;
biggest_index = 2 ;
}
if ( four_z_squared_minus_1 > four_biggest_squared_minus_1 ) {
four_biggest_squared_minus_1 = four_z_squared_minus_1 ;
biggest_index = 3 ;
}
biggest_value = zpl_sqrt ( four_biggest_squared_minus_1 + 1.0f ) * 0.5f ;
mult = 0.25f / biggest_value ;
switch ( biggest_index ) {
case 0 :
out - > w = biggest_value ;
out - > x = ( m [ 1 ] [ 2 ] - m [ 2 ] [ 1 ] ) * mult ;
out - > y = ( m [ 2 ] [ 0 ] - m [ 0 ] [ 2 ] ) * mult ;
out - > z = ( m [ 0 ] [ 1 ] - m [ 1 ] [ 0 ] ) * mult ;
break ;
case 1 :
out - > w = ( m [ 1 ] [ 2 ] - m [ 2 ] [ 1 ] ) * mult ;
out - > x = biggest_value ;
out - > y = ( m [ 0 ] [ 1 ] + m [ 1 ] [ 0 ] ) * mult ;
out - > z = ( m [ 2 ] [ 0 ] + m [ 0 ] [ 2 ] ) * mult ;
break ;
case 2 :
out - > w = ( m [ 2 ] [ 0 ] - m [ 0 ] [ 2 ] ) * mult ;
out - > x = ( m [ 0 ] [ 1 ] + m [ 1 ] [ 0 ] ) * mult ;
out - > y = biggest_value ;
out - > z = ( m [ 1 ] [ 2 ] + m [ 2 ] [ 1 ] ) * mult ;
break ;
case 3 :
out - > w = ( m [ 0 ] [ 1 ] - m [ 1 ] [ 0 ] ) * mult ;
out - > x = ( m [ 2 ] [ 0 ] + m [ 0 ] [ 2 ] ) * mult ;
out - > y = ( m [ 1 ] [ 2 ] + m [ 2 ] [ 1 ] ) * mult ;
out - > z = biggest_value ;
break ;
}
}
zpl_f32 zpl_plane_distance ( zpl_plane * p , zpl_vec3 v ) {
return ( p - > a * v . x + p - > b * v . y + p - > c * v . z + p - > d ) ;
}
void zpl_frustum_create ( zpl_frustum * out , zpl_mat4 * camera , zpl_mat4 * proj ) {
zpl_mat4 pv ;
zpl_mat4_mul ( & pv , camera , proj ) ;
zpl_plane * fp = 0 ;
zpl_f32 rmag ;
fp = & out - > x1 ;
fp - > a = pv . x . w + pv . x . x ;
fp - > b = pv . y . w + pv . x . y ;
fp - > c = pv . z . w + pv . x . z ;
fp - > d = pv . w . w + pv . x . w ;
rmag = zpl_rsqrt ( zpl_square ( fp - > a ) + zpl_square ( fp - > b ) + zpl_square ( fp - > c ) ) ;
fp - > a * = rmag ;
fp - > b * = rmag ;
fp - > c * = rmag ;
fp - > d * = rmag ;
fp = & out - > x2 ;
fp - > a = pv . x . w - pv . x . x ;
fp - > b = pv . y . w - pv . x . y ;
fp - > c = pv . z . w - pv . x . z ;
fp - > d = pv . w . w - pv . x . w ;
rmag = zpl_rsqrt ( zpl_square ( fp - > a ) + zpl_square ( fp - > b ) + zpl_square ( fp - > c ) ) ;
fp - > a * = rmag ;
fp - > b * = rmag ;
fp - > c * = rmag ;
fp - > d * = rmag ;
fp = & out - > y1 ;
fp - > a = pv . x . w - pv . y . x ;
fp - > b = pv . y . w - pv . y . y ;
fp - > c = pv . z . w - pv . y . w ;
fp - > d = pv . w . w - pv . y . z ;
rmag = zpl_rsqrt ( zpl_square ( fp - > a ) + zpl_square ( fp - > b ) + zpl_square ( fp - > c ) ) ;
fp - > a * = rmag ;
fp - > b * = rmag ;
fp - > c * = rmag ;
fp - > d * = rmag ;
fp = & out - > y2 ;
fp - > a = pv . x . w + pv . y . x ;
fp - > b = pv . y . w + pv . y . y ;
fp - > c = pv . z . w + pv . y . z ;
fp - > d = pv . w . w + pv . y . w ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
rmag = zpl_rsqrt ( zpl_square ( fp - > a ) + zpl_square ( fp - > b ) + zpl_square ( fp - > c ) ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
fp - > a * = rmag ;
fp - > b * = rmag ;
fp - > c * = rmag ;
fp - > d * = rmag ; ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
fp = & out - > z1 ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
fp - > a = pv . x . w + pv . z . x ;
fp - > b = pv . y . w + pv . z . y ;
fp - > c = pv . z . w + pv . z . z ;
fp - > d = pv . w . w + pv . z . w ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
rmag = zpl_rsqrt ( zpl_square ( fp - > a ) + zpl_square ( fp - > b ) + zpl_square ( fp - > c ) ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
fp - > a * = rmag ;
fp - > b * = rmag ;
fp - > c * = rmag ;
fp - > d * = rmag ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
fp = & out - > z2 ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
fp - > a = pv . x . w - pv . z . x ;
fp - > b = pv . y . w - pv . z . y ;
fp - > c = pv . z . w - pv . z . z ;
fp - > d = pv . w . w - pv . z . w ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
rmag = zpl_rsqrt ( zpl_square ( fp - > a ) + zpl_square ( fp - > b ) + zpl_square ( fp - > c ) ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
fp - > a * = rmag ;
fp - > b * = rmag ;
fp - > c * = rmag ;
fp - > d * = rmag ;
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
zpl_b8 zpl_frustum_sphere_inside ( zpl_frustum * frustum , zpl_vec3 center , zpl_f32 radius ) {
if ( zpl_plane_distance ( & frustum - > x1 , center ) < = - radius ) return 0 ;
if ( zpl_plane_distance ( & frustum - > x2 , center ) < = - radius ) return 0 ;
if ( zpl_plane_distance ( & frustum - > y1 , center ) < = - radius ) return 0 ;
if ( zpl_plane_distance ( & frustum - > y2 , center ) < = - radius ) return 0 ;
if ( zpl_plane_distance ( & frustum - > z1 , center ) < = - radius ) return 0 ;
if ( zpl_plane_distance ( & frustum - > z2 , center ) < = - radius ) return 0 ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
return 1 ;
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
zpl_b8 zpl_frustum_point_inside ( zpl_frustum * frustum , zpl_vec3 point ) {
return zpl_frustum_sphere_inside ( frustum , point , 0.0f ) ;
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
zpl_b8 zpl_frustum_box_inside ( zpl_frustum * frustum , zpl_aabb3 aabb ) {
zpl_vec3 box , center ;
zpl_vec3 v , b ;
zpl_vec3_sub ( & box , aabb . max , aabb . min ) ;
zpl_vec3_diveq ( & box , 2.0f ) ;
zpl_vec3_add ( & center , aabb . min , box ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
b = zpl_vec3f ( - box . x , - box . y , - box . z ) ;
zpl_vec3_add ( & v , b , center ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
if ( zpl_frustum_point_inside ( frustum , v ) ) return 1 ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
b = zpl_vec3f ( + box . x , - box . y , - box . z ) ;
zpl_vec3_add ( & v , b , center ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
if ( zpl_frustum_point_inside ( frustum , v ) ) return 1 ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
b = zpl_vec3f ( - box . x , + box . y , - box . z ) ;
zpl_vec3_add ( & v , b , center ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
if ( zpl_frustum_point_inside ( frustum , v ) ) return 1 ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
b = zpl_vec3f ( + box . x , + box . y , - box . z ) ;
zpl_vec3_add ( & v , b , center ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
if ( zpl_frustum_point_inside ( frustum , v ) ) return 1 ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
b = zpl_vec3f ( + box . x , + box . y , + box . z ) ;
zpl_vec3_add ( & v , b , center ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
if ( zpl_frustum_point_inside ( frustum , v ) ) return 1 ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
b = zpl_vec3f ( - box . x , + box . y , + box . z ) ;
zpl_vec3_add ( & v , b , center ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
if ( zpl_frustum_point_inside ( frustum , v ) ) return 1 ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
b = zpl_vec3f ( - box . x , - box . y , + box . z ) ;
zpl_vec3_add ( & v , b , center ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
if ( zpl_frustum_point_inside ( frustum , v ) ) return 1 ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
b = zpl_vec3f ( + box . x , - box . y , + box . z ) ;
zpl_vec3_add ( & v , b , center ) ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
if ( zpl_frustum_point_inside ( frustum , v ) ) return 1 ;
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
return 0 ;
}
2021-11-29 08:23:08 +00:00
2022-09-11 17:42:06 +00:00
zpl_f32 zpl_lerp ( zpl_f32 a , zpl_f32 b , zpl_f32 t ) { return a * ( 1.0f - t ) + b * t ; }
zpl_f32 zpl_unlerp ( zpl_f32 t , zpl_f32 a , zpl_f32 b ) { return ( t - a ) / ( b - a ) ; }
zpl_f32 zpl_smooth_step ( zpl_f32 a , zpl_f32 b , zpl_f32 t ) {
zpl_f32 x = ( t - a ) / ( b - a ) ;
return x * x * ( 3.0f - 2.0f * x ) ;
}
zpl_f32 zpl_smoother_step ( zpl_f32 a , zpl_f32 b , zpl_f32 t ) {
zpl_f32 x = ( t - a ) / ( b - a ) ;
return x * x * x * ( x * ( 6.0f * x - 15.0f ) + 10.0f ) ;
}
# define ZPL_VEC_LERPN(N, d, a, b, t) \
zpl_vec # # N db ; \
zpl_vec # # N # # _sub ( & db , b , a ) ; \
zpl_vec # # N # # _muleq ( & db , t ) ; \
zpl_vec # # N # # _add ( d , a , db )
void zpl_vec2_lerp ( zpl_vec2 * d , zpl_vec2 a , zpl_vec2 b , zpl_f32 t ) { ZPL_VEC_LERPN ( 2 , d , a , b , t ) ; }
void zpl_vec3_lerp ( zpl_vec3 * d , zpl_vec3 a , zpl_vec3 b , zpl_f32 t ) { ZPL_VEC_LERPN ( 3 , d , a , b , t ) ; }
void zpl_vec4_lerp ( zpl_vec4 * d , zpl_vec4 a , zpl_vec4 b , zpl_f32 t ) { ZPL_VEC_LERPN ( 4 , d , a , b , t ) ; }
# undef ZPL_VEC_LERPN
void zpl_vec2_cslerp ( zpl_vec2 * d , zpl_vec2 a , zpl_vec2 v0 , zpl_vec2 b , zpl_vec2 v1 , zpl_f32 t ) {
zpl_f32 t2 = t * t ;
zpl_f32 ti = ( t - 1 ) ;
zpl_f32 ti2 = ti * ti ;
zpl_f32 h00 = ( 1 + 2 * t ) * ti2 ;
zpl_f32 h10 = t * ti2 ;
zpl_f32 h01 = t2 * ( 3 - 2 * t ) ;
zpl_f32 h11 = t2 * ti ;
d - > x = h00 * a . x + h10 * v0 . x + h01 * b . x + h11 * v1 . x ;
d - > y = h00 * a . y + h10 * v0 . y + h01 * b . y + h11 * v1 . y ;
}
void zpl_vec3_cslerp ( zpl_vec3 * d , zpl_vec3 a , zpl_vec3 v0 , zpl_vec3 b , zpl_vec3 v1 , zpl_f32 t ) {
zpl_f32 t2 = t * t ;
zpl_f32 ti = ( t - 1 ) ;
zpl_f32 ti2 = ti * ti ;
zpl_f32 h00 = ( 1 + 2 * t ) * ti2 ;
zpl_f32 h10 = t * ti2 ;
zpl_f32 h01 = t2 * ( 3 - 2 * t ) ;
zpl_f32 h11 = t2 * ti ;
d - > x = h00 * a . x + h10 * v0 . x + h01 * b . x + h11 * v1 . x ;
d - > y = h00 * a . y + h10 * v0 . y + h01 * b . y + h11 * v1 . y ;
d - > z = h00 * a . z + h10 * v0 . z + h01 * b . z + h11 * v1 . z ;
}
void zpl_vec2_dcslerp ( zpl_vec2 * d , zpl_vec2 a , zpl_vec2 v0 , zpl_vec2 b , zpl_vec2 v1 , zpl_f32 t ) {
zpl_f32 t2 = t * t ;
zpl_f32 dh00 = 6 * t2 - 6 * t ;
zpl_f32 dh10 = 3 * t2 - 4 * t + 1 ;
zpl_f32 dh01 = - 6 * t2 + 6 * t ;
zpl_f32 dh11 = 3 * t2 - 2 * t ;
d - > x = dh00 * a . x + dh10 * v0 . x + dh01 * b . x + dh11 * v1 . x ;
d - > y = dh00 * a . y + dh10 * v0 . y + dh01 * b . y + dh11 * v1 . y ;
}
void zpl_vec3_dcslerp ( zpl_vec3 * d , zpl_vec3 a , zpl_vec3 v0 , zpl_vec3 b , zpl_vec3 v1 , zpl_f32 t ) {
zpl_f32 t2 = t * t ;
zpl_f32 dh00 = 6 * t2 - 6 * t ;
zpl_f32 dh10 = 3 * t2 - 4 * t + 1 ;
zpl_f32 dh01 = - 6 * t2 + 6 * t ;
zpl_f32 dh11 = 3 * t2 - 2 * t ;
d - > x = dh00 * a . x + dh10 * v0 . x + dh01 * b . x + dh11 * v1 . x ;
d - > y = dh00 * a . y + dh10 * v0 . y + dh01 * b . y + dh11 * v1 . y ;
d - > z = dh00 * a . z + dh10 * v0 . z + dh01 * b . z + dh11 * v1 . z ;
}
void zpl_quat_lerp ( zpl_quat * d , zpl_quat a , zpl_quat b , zpl_f32 t ) { zpl_vec4_lerp ( & d - > xyzw , a . xyzw , b . xyzw , t ) ; }
void zpl_quat_nlerp ( zpl_quat * d , zpl_quat a , zpl_quat b , zpl_f32 t ) {
zpl_quat_lerp ( d , a , b , t ) ;
zpl_quat_norm ( d , * d ) ;
}
void zpl_quat_slerp ( zpl_quat * d , zpl_quat a , zpl_quat b , zpl_f32 t ) {
zpl_quat x , y , z ;
zpl_f32 cos_theta , angle ;
zpl_f32 s1 , s0 , is ;
z = b ;
cos_theta = zpl_quat_dot ( a , b ) ;
if ( cos_theta < 0.0f ) {
z = zpl_quatf ( - b . x , - b . y , - b . z , - b . w ) ;
cos_theta = - cos_theta ;
}
if ( cos_theta > 1.0f ) {
/* NOTE: Use lerp not nlerp as it's not a real angle or they are not normalized */
zpl_quat_lerp ( d , a , b , t ) ;
}
angle = zpl_arccos ( cos_theta ) ;
s1 = zpl_sin ( ( 1.0f - t ) * angle ) ;
s0 = zpl_sin ( t * angle ) ;
is = 1.0f / zpl_sin ( angle ) ;
zpl_quat_mulf ( & x , a , s1 ) ;
zpl_quat_mulf ( & y , z , s0 ) ;
zpl_quat_add ( d , x , y ) ;
zpl_quat_muleqf ( d , is ) ;
}
void zpl_quat_slerp_approx ( zpl_quat * d , zpl_quat a , zpl_quat b , zpl_f32 t ) {
/* NOTE: Derived by taylor expanding the geometric interpolation equation
* Even works okay for nearly anti - parallel versors ! ! !
*/
/* NOTE: Extra interations cannot be used as they require angle^4 which is not worth it to approximate */
zpl_f32 tp = t + ( 1.0f - zpl_quat_dot ( a , b ) ) / 3.0f * t * ( - 2.0f * t * t + 3.0f * t - 1.0f ) ;
zpl_quat_nlerp ( d , a , b , tp ) ;
}
void zpl_quat_nquad ( zpl_quat * d , zpl_quat p , zpl_quat a , zpl_quat b , zpl_quat q , zpl_f32 t ) {
zpl_quat x , y ;
zpl_quat_nlerp ( & x , p , q , t ) ;
zpl_quat_nlerp ( & y , a , b , t ) ;
zpl_quat_nlerp ( d , x , y , 2.0f * t * ( 1.0f - t ) ) ;
}
void zpl_quat_squad ( zpl_quat * d , zpl_quat p , zpl_quat a , zpl_quat b , zpl_quat q , zpl_f32 t ) {
zpl_quat x , y ;
zpl_quat_slerp ( & x , p , q , t ) ;
zpl_quat_slerp ( & y , a , b , t ) ;
zpl_quat_slerp ( d , x , y , 2.0f * t * ( 1.0f - t ) ) ;
}
void zpl_quat_squad_approx ( zpl_quat * d , zpl_quat p , zpl_quat a , zpl_quat b , zpl_quat q , zpl_f32 t ) {
zpl_quat x , y ;
zpl_quat_slerp_approx ( & x , p , q , t ) ;
zpl_quat_slerp_approx ( & y , a , b , t ) ;
zpl_quat_slerp_approx ( d , x , y , 2.0f * t * ( 1.0f - t ) ) ;
}
zpl_rect2 zpl_rect2f ( zpl_vec2 pos , zpl_vec2 dim ) {
zpl_rect2 r ;
r . pos = pos ;
r . dim = dim ;
return r ;
}
zpl_rect3 zpl_rect3f ( zpl_vec3 pos , zpl_vec3 dim ) {
zpl_rect3 r ;
r . pos = pos ;
r . dim = dim ;
return r ;
}
zpl_aabb2 zpl_aabb2f ( zpl_f32 minx , zpl_f32 miny , zpl_f32 maxx , zpl_f32 maxy ) {
zpl_aabb2 r ;
r . min = zpl_vec2f ( minx , miny ) ;
r . max = zpl_vec2f ( maxx , maxy ) ;
return r ;
}
zpl_aabb3 zpl_aabb3f ( zpl_f32 minx , zpl_f32 miny , zpl_f32 minz , zpl_f32 maxx , zpl_f32 maxy , zpl_f32 maxz ) {
zpl_aabb3 r ;
r . min = zpl_vec3f ( minx , miny , minz ) ;
r . max = zpl_vec3f ( maxx , maxy , maxz ) ;
return r ;
}
zpl_aabb2 zpl_aabb2_rect2 ( zpl_rect2 a ) {
zpl_aabb2 r ;
r . min = a . pos ;
zpl_vec2_add ( & r . max , a . pos , a . dim ) ;
return r ;
}
zpl_aabb3 zpl_aabb3_rect3 ( zpl_rect3 a ) {
zpl_aabb3 r ;
r . min = a . pos ;
zpl_vec3_add ( & r . max , a . pos , a . dim ) ;
return r ;
}
zpl_rect2 zpl_rect2_aabb2 ( zpl_aabb2 a ) {
zpl_rect2 r ;
r . pos = a . min ;
zpl_vec2_sub ( & r . dim , a . max , a . min ) ;
return r ;
}
zpl_rect3 zpl_rect3_aabb3 ( zpl_aabb3 a ) {
zpl_rect3 r ;
r . pos = a . min ;
zpl_vec3_sub ( & r . dim , a . max , a . min ) ;
return r ;
}
int zpl_rect2_contains ( zpl_rect2 a , zpl_f32 x , zpl_f32 y ) {
zpl_f32 min_x = zpl_min ( a . pos . x , a . pos . x + a . dim . x ) ;
zpl_f32 max_x = zpl_max ( a . pos . x , a . pos . x + a . dim . x ) ;
zpl_f32 min_y = zpl_min ( a . pos . y , a . pos . y + a . dim . y ) ;
zpl_f32 max_y = zpl_max ( a . pos . y , a . pos . y + a . dim . y ) ;
int result = ( x > = min_x ) & ( x < max_x ) & ( y > = min_y ) & ( y < max_y ) ;
return result ;
}
int zpl_rect2_contains_vec2 ( zpl_rect2 a , zpl_vec2 p ) { return zpl_rect2_contains ( a , p . x , p . y ) ; }
int zpl_rect2_intersects ( zpl_rect2 a , zpl_rect2 b ) {
zpl_rect2 r = { 0 } ;
return zpl_rect2_intersection_result ( a , b , & r ) ;
}
int zpl_rect2_intersection_result ( zpl_rect2 a , zpl_rect2 b , zpl_rect2 * intersection ) {
zpl_f32 a_min_x = zpl_min ( a . pos . x , a . pos . x + a . dim . x ) ;
zpl_f32 a_max_x = zpl_max ( a . pos . x , a . pos . x + a . dim . x ) ;
zpl_f32 a_min_y = zpl_min ( a . pos . y , a . pos . y + a . dim . y ) ;
zpl_f32 a_max_y = zpl_max ( a . pos . y , a . pos . y + a . dim . y ) ;
zpl_f32 b_min_x = zpl_min ( b . pos . x , b . pos . x + b . dim . x ) ;
zpl_f32 b_max_x = zpl_max ( b . pos . x , b . pos . x + b . dim . x ) ;
zpl_f32 b_min_y = zpl_min ( b . pos . y , b . pos . y + b . dim . y ) ;
zpl_f32 b_max_y = zpl_max ( b . pos . y , b . pos . y + b . dim . y ) ;
zpl_f32 x0 = zpl_max ( a_min_x , b_min_x ) ;
zpl_f32 y0 = zpl_max ( a_min_y , b_min_y ) ;
zpl_f32 x1 = zpl_min ( a_max_x , b_max_x ) ;
zpl_f32 y1 = zpl_min ( a_max_y , b_max_y ) ;
if ( ( x0 < x1 ) & & ( y0 < y1 ) ) {
zpl_rect2 r = zpl_rect2f ( zpl_vec2f ( x0 , y0 ) , zpl_vec2f ( x1 - x0 , y1 - y0 ) ) ;
* intersection = r ;
return 1 ;
} else {
zpl_rect2 r = { 0 } ;
* intersection = r ;
return 0 ;
}
}
int zpl_aabb2_contains ( zpl_aabb2 a , zpl_f32 x , zpl_f32 y ) {
return ( zpl_is_between_limit ( x , a . min . x , a . max . x ) & & zpl_is_between_limit ( y , a . min . y , a . max . y ) ) ;
}
int zpl_aabb3_contains ( zpl_aabb3 a , zpl_f32 x , zpl_f32 y , zpl_f32 z ) {
return ( zpl_is_between_limit ( x , a . min . x , a . max . x ) & & zpl_is_between_limit ( y , a . min . y , a . max . y ) & & zpl_is_between_limit ( z , a . min . z , a . max . z ) ) ;
}
zpl_aabb2 zpl_aabb2_cut_left ( zpl_aabb2 * a , zpl_f32 b ) {
zpl_f32 minx = a - > min . x ;
a - > min . x = zpl_min ( a - > max . x , a - > min . x + b ) ;
return zpl_aabb2f ( minx , a - > min . y , a - > min . x , a - > max . y ) ;
}
zpl_aabb2 zpl_aabb2_cut_right ( zpl_aabb2 * a , zpl_f32 b ) {
zpl_f32 maxx = a - > max . x ;
a - > max . x = zpl_max ( a - > min . x , a - > max . x - b ) ;
return zpl_aabb2f ( a - > max . x , a - > min . y , maxx , a - > max . y ) ;
}
zpl_aabb2 zpl_aabb2_cut_top ( zpl_aabb2 * a , zpl_f32 b ) {
zpl_f32 miny = a - > min . y ;
a - > min . y = zpl_min ( a - > max . y , a - > min . y + b ) ;
return zpl_aabb2f ( a - > min . x , miny , a - > max . x , a - > min . y ) ;
}
zpl_aabb2 zpl_aabb2_cut_bottom ( zpl_aabb2 * a , zpl_f32 b ) {
zpl_f32 maxy = a - > max . y ;
a - > max . y = zpl_max ( a - > min . y , a - > max . y - b ) ;
return zpl_aabb2f ( a - > min . x , a - > max . y , a - > max . x , maxy ) ;
}
zpl_aabb2 zpl_aabb2_get_left ( const zpl_aabb2 * a , zpl_f32 b ) {
zpl_f32 minx = a - > min . x ;
zpl_f32 aminx = zpl_min ( a - > max . x , a - > min . x + b ) ;
return zpl_aabb2f ( minx , a - > min . y , aminx , a - > max . y ) ;
}
zpl_aabb2 zpl_aabb2_get_right ( const zpl_aabb2 * a , zpl_f32 b ) {
zpl_f32 maxx = a - > max . x ;
zpl_f32 amaxx = zpl_max ( a - > min . x , a - > max . x - b ) ;
return zpl_aabb2f ( amaxx , a - > min . y , maxx , a - > max . y ) ;
}
zpl_aabb2 zpl_aabb2_get_top ( const zpl_aabb2 * a , zpl_f32 b ) {
zpl_f32 miny = a - > min . y ;
zpl_f32 aminy = zpl_min ( a - > max . y , a - > min . y + b ) ;
return zpl_aabb2f ( a - > min . x , miny , a - > max . x , aminy ) ;
}
zpl_aabb2 zpl_aabb2_get_bottom ( const zpl_aabb2 * a , zpl_f32 b ) {
zpl_f32 maxy = a - > max . y ;
zpl_f32 amaxy = zpl_max ( a - > min . y , a - > max . y - b ) ;
return zpl_aabb2f ( a - > min . x , amaxy , a - > max . x , maxy ) ;
}
zpl_aabb2 zpl_aabb2_add_left ( const zpl_aabb2 * a , zpl_f32 b ) {
return zpl_aabb2f ( a - > min . x - b , a - > min . y , a - > min . x , a - > max . y ) ;
}
zpl_aabb2 zpl_aabb2_add_right ( const zpl_aabb2 * a , zpl_f32 b ) {
return zpl_aabb2f ( a - > max . x , a - > min . y , a - > max . x + b , a - > max . y ) ;
}
zpl_aabb2 zpl_aabb2_add_top ( const zpl_aabb2 * a , zpl_f32 b ) {
return zpl_aabb2f ( a - > min . x , a - > min . y - b , a - > max . x , a - > min . y ) ;
}
zpl_aabb2 zpl_aabb2_add_bottom ( const zpl_aabb2 * a , zpl_f32 b ) {
return zpl_aabb2f ( a - > min . x , a - > max . y , a - > max . x , a - > max . y + b ) ;
}
zpl_aabb2 zpl_aabb2_contract ( const zpl_aabb2 * a , zpl_f32 b ) {
zpl_aabb2 r = * a ;
zpl_vec2 vb = zpl_vec2f ( b , b ) ;
zpl_vec2_addeq ( & r . min , vb ) ;
zpl_vec2_subeq ( & r . max , vb ) ;
if ( zpl_vec2_mag2 ( r . min ) > zpl_vec2_mag2 ( r . max ) ) {
return zpl_aabb2f ( 0 , 0 , 0 , 0 ) ;
}
return r ;
}
zpl_aabb2 zpl_aabb2_expand ( const zpl_aabb2 * a , zpl_f32 b ) {
return zpl_aabb2_contract ( a , - b ) ;
}
ZPL_END_C_DECLS
2021-11-29 08:23:08 +00:00
# endif
2022-09-11 17:42:06 +00:00
# if defined(ZPL_MODULE_THREADING)
// file: source/threading/fence.c
ZPL_BEGIN_C_DECLS
# if defined(_MSC_VER)
/* Microsoft C/C++-compatible compiler */
# include <intrin.h>
# elif defined(__GNUC__) && (defined(__x86_64__) || defined(__i386__))
/* GCC-compatible compiler, targeting x86/x86-64 */
# include <x86intrin.h>
# elif defined(__GNUC__) && defined(__ARM_NEON__)
/* GCC-compatible compiler, targeting ARM with NEON */
# include <arm_neon.h>
# elif defined(__GNUC__) && defined(__IWMMXT__)
/* GCC-compatible compiler, targeting ARM with WMMX */
# include <mmintrin.h>
# elif (defined(__GNUC__) || defined(__xlC__)) && (defined(__VEC__) || defined(__ALTIVEC__))
/* XLC or GCC-compatible compiler, targeting PowerPC with VMX/VSX */
# include <altivec.h>
# elif defined(__GNUC__) && defined(__SPE__)
/* GCC-compatible compiler, targeting PowerPC with SPE */
# include <spe.h>
# endif
void zpl_yield_thread ( void ) {
# if defined(ZPL_SYSTEM_WINDOWS)
_mm_pause ( ) ;
# elif defined(ZPL_SYSTEM_OSX) || defined(ZPL_COMPILER_TINYC)
__asm__ volatile ( " " : : : " memory " ) ;
# elif defined(ZPL_CPU_X86)
_mm_pause ( ) ;
# endif
}
void zpl_mfence ( void ) {
# if defined(ZPL_SYSTEM_WINDOWS)
_ReadWriteBarrier ( ) ;
# elif defined(ZPL_COMPILER_TINYC)
__asm__ volatile ( " " : : : " memory " ) ;
# elif defined(ZPL_SYSTEM_OSX)
__sync_synchronize ( ) ;
# elif defined(ZPL_CPU_X86)
_mm_mfence ( ) ;
# endif
}
void zpl_sfence ( void ) {
# if defined(ZPL_SYSTEM_WINDOWS)
_WriteBarrier ( ) ;
# elif defined(ZPL_SYSTEM_OSX) || defined(ZPL_COMPILER_TINYC)
__asm__ volatile ( " " : : : " memory " ) ;
# elif defined(ZPL_CPU_X86)
_mm_sfence ( ) ;
# endif
}
void zpl_lfence ( void ) {
# if defined(ZPL_SYSTEM_WINDOWS)
_ReadBarrier ( ) ;
# elif defined(ZPL_SYSTEM_OSX) || defined(ZPL_COMPILER_TINYC)
__asm__ volatile ( " " : : : " memory " ) ;
# elif defined(ZPL_CPU_X86)
_mm_lfence ( ) ;
# endif
}
ZPL_END_C_DECLS
// file: source/threading/atomic.c
ZPL_BEGIN_C_DECLS
////////////////////////////////////////////////////////////////
//
// Concurrency
//
//
// IMPORTANT TODO: Use compiler intrinsics for the atomics
# if defined(ZPL_COMPILER_MSVC) && !defined(ZPL_COMPILER_CLANG)
zpl_i32 zpl_atomic32_load ( zpl_atomic32 const * a ) { return a - > value ; }
void zpl_atomic32_store ( zpl_atomic32 * a , zpl_atomicarg ( zpl_i32 ) value ) { a - > value = value ; }
zpl_i32 zpl_atomic32_compare_exchange ( zpl_atomic32 * a , zpl_atomicarg ( zpl_i32 ) expected , zpl_atomicarg ( zpl_i32 ) desired ) {
return _InterlockedCompareExchange ( cast ( long * ) a , desired , expected ) ;
}
zpl_i32 zpl_atomic32_exchange ( zpl_atomic32 * a , zpl_atomicarg ( zpl_i32 ) desired ) {
return _InterlockedExchange ( cast ( long * ) a , desired ) ;
}
zpl_i32 zpl_atomic32_fetch_add ( zpl_atomic32 * a , zpl_atomicarg ( zpl_i32 ) operand ) {
return _InterlockedExchangeAdd ( cast ( long * ) a , operand ) ;
}
zpl_i32 zpl_atomic32_fetch_and ( zpl_atomic32 * a , zpl_atomicarg ( zpl_i32 ) operand ) {
return _InterlockedAnd ( cast ( long * ) a , operand ) ;
}
zpl_i32 zpl_atomic32_fetch_or ( zpl_atomic32 * a , zpl_atomicarg ( zpl_i32 ) operand ) {
return _InterlockedOr ( cast ( long * ) a , operand ) ;
}
zpl_i64 zpl_atomic64_load ( zpl_atomic64 const * a ) {
# if defined(ZPL_ARCH_64_BIT)
return a - > value ;
# elif ZPL_CPU_X86
// NOTE: The most compatible way to get an atomic 64-bit load on x86 is with cmpxchg8b
zpl_atomicarg ( zpl_i64 ) result ;
__asm {
mov esi , a ;
mov ebx , eax ;
mov ecx , edx ;
lock cmpxchg8b [ esi ] ;
mov dword ptr result , eax ;
mov dword ptr result [ 4 ] , edx ;
}
return result ;
# else
# error TODO: atomics for this CPU
# endif
}
void zpl_atomic64_store ( zpl_atomic64 * a , zpl_atomicarg ( zpl_i64 ) value ) {
# if defined(ZPL_ARCH_64_BIT)
a - > value = value ;
# elif ZPL_CPU_X86
// NOTE: The most compatible way to get an atomic 64-bit store on x86 is with cmpxchg8b
__asm {
mov esi , a ;
mov ebx , dword ptr value ;
mov ecx , dword ptr value [ 4 ] ;
retry :
cmpxchg8b [ esi ] ;
jne retry ;
}
# else
# error TODO: atomics for this CPU
# endif
}
zpl_i64 zpl_atomic64_compare_exchange ( zpl_atomic64 * a , zpl_atomicarg ( zpl_i64 ) expected , zpl_atomicarg ( zpl_i64 ) desired ) {
return _InterlockedCompareExchange64 ( cast ( zpl_atomicarg ( zpl_i64 ) * ) a , desired , expected ) ;
}
zpl_i64 zpl_atomic64_exchange ( zpl_atomic64 * a , zpl_atomicarg ( zpl_i64 ) desired ) {
# if defined(ZPL_ARCH_64_BIT)
return _InterlockedExchange64 ( cast ( zpl_atomicarg ( zpl_i64 ) * ) a , desired ) ;
# elif ZPL_CPU_X86
zpl_atomicarg ( zpl_i64 ) expected = a - > value ;
for ( ; ; ) {
zpl_atomicarg ( zpl_i64 ) original = _InterlockedCompareExchange64 ( cast ( zpl_atomicarg ( zpl_i64 ) * ) a , desired , expected ) ;
if ( original = = expected )
return original ;
expected = original ;
}
# else
# error TODO: atomics for this CPU
# endif
}
zpl_i64 zpl_atomic64_fetch_add ( zpl_atomic64 * a , zpl_atomicarg ( zpl_i64 ) operand ) {
# if defined(ZPL_ARCH_64_BIT)
return _InterlockedExchangeAdd64 ( cast ( zpl_atomicarg ( zpl_i64 ) * ) a , operand ) ;
# elif ZPL_CPU_X86
zpl_atomicarg ( zpl_i64 ) expected = a - > value ;
for ( ; ; ) {
zpl_atomicarg ( zpl_i64 ) original = _InterlockedCompareExchange64 ( cast ( zpl_atomicarg ( zpl_i64 ) * ) a , expected + operand , expected ) ;
if ( original = = expected )
return original ;
expected = original ;
}
# else
# error TODO: atomics for this CPU
# endif
}
zpl_i64 zpl_atomic64_fetch_and ( zpl_atomic64 * a , zpl_atomicarg ( zpl_i64 ) operand ) {
# if defined(ZPL_ARCH_64_BIT)
return _InterlockedAnd64 ( cast ( zpl_atomicarg ( zpl_i64 ) * ) a , operand ) ;
# elif ZPL_CPU_X86
zpl_atomicarg ( zpl_i64 ) expected = a - > value ;
for ( ; ; ) {
zpl_atomicarg ( zpl_i64 ) original = _InterlockedCompareExchange64 ( cast ( zpl_atomicarg ( zpl_i64 ) * ) a , expected & operand , expected ) ;
if ( original = = expected )
return original ;
expected = original ;
}
# else
# error TODO: atomics for this CPU
# endif
}
zpl_i64 zpl_atomic64_fetch_or ( zpl_atomic64 * a , zpl_atomicarg ( zpl_i64 ) operand ) {
# if defined(ZPL_ARCH_64_BIT)
return _InterlockedOr64 ( cast ( zpl_atomicarg ( zpl_i64 ) * ) a , operand ) ;
# elif ZPL_CPU_X86
zpl_atomicarg ( zpl_i64 ) expected = a - > value ;
for ( ; ; ) {
zpl_atomicarg ( zpl_i64 ) original = _InterlockedCompareExchange64 ( cast ( zpl_atomicarg ( zpl_i64 ) * ) a , expected | operand , expected ) ;
if ( original = = expected )
return original ;
expected = original ;
}
# else
# error TODO: atomics for this CPU
# endif
}
# elif defined(ZPL_CPU_X86)
zpl_i32 zpl_atomic32_load ( zpl_atomic32 const * a ) { return a - > value ; }
void zpl_atomic32_store ( zpl_atomic32 * a , zpl_atomicarg ( zpl_i32 ) value ) { a - > value = value ; }
zpl_i32 zpl_atomic32_compare_exchange ( zpl_atomic32 * a , zpl_atomicarg ( zpl_i32 ) expected , zpl_atomicarg ( zpl_i32 ) desired ) {
zpl_atomicarg ( zpl_i32 ) original ;
__asm__ (
" lock; cmpxchgl %2, %1 "
: " =a " ( original ) , " +m " ( a - > value )
: " q " ( desired ) , " 0 " ( expected )
) ;
return original ;
}
zpl_i32 zpl_atomic32_exchange ( zpl_atomic32 * a , zpl_atomicarg ( zpl_i32 ) desired ) {
// NOTE: No lock prefix is necessary for xchgl
zpl_atomicarg ( zpl_i32 ) original ;
__asm__ (
" xchgl %0, %1 "
: " =r " ( original ) , " +m " ( a - > value )
: " 0 " ( desired )
) ;
return original ;
}
zpl_i32 zpl_atomic32_fetch_add ( zpl_atomic32 * a , zpl_atomicarg ( zpl_i32 ) operand ) {
zpl_atomicarg ( zpl_i32 ) original ;
__asm__ (
" lock; xaddl %0, %1 "
: " =r " ( original ) , " +m " ( a - > value )
: " 0 " ( operand )
) ;
return original ;
}
zpl_i32 zpl_atomic32_fetch_and ( zpl_atomic32 * a , zpl_atomicarg ( zpl_i32 ) operand ) {
zpl_atomicarg ( zpl_i32 ) original ;
zpl_atomicarg ( zpl_i32 ) tmp ;
__asm__ (
" 1: movl %1, %0 \n "
" movl %0, %2 \n "
" andl %3, %2 \n "
" lock; cmpxchgl %2, %1 \n "
" jne 1b "
: " =&a " ( original ) , " +m " ( a - > value ) , " =&r " ( tmp )
: " r " ( operand )
) ;
return original ;
}
zpl_i32 zpl_atomic32_fetch_or ( zpl_atomic32 * a , zpl_atomicarg ( zpl_i32 ) operand ) {
zpl_atomicarg ( zpl_i32 ) original ;
zpl_atomicarg ( zpl_i32 ) temp ;
__asm__ (
" 1: movl %1, %0 \n "
" movl %0, %2 \n "
" orl %3, %2 \n "
" lock; cmpxchgl %2, %1 \n "
" jne 1b "
: " =&a " ( original ) , " +m " ( a - > value ) , " =&r " ( temp )
: " r " ( operand )
) ;
return original ;
}
zpl_i64 zpl_atomic64_load ( zpl_atomic64 const * a ) {
# if defined(ZPL_ARCH_64_BIT)
return a - > value ;
# else
zpl_atomicarg ( zpl_i64 ) original ;
__asm__ (
" movl %%ebx, %%eax \n "
" movl %%ecx, %%edx \n "
" lock; cmpxchg8b %1 "
: " =&A " ( original )
: " m " ( a - > value )
) ;
return original ;
# endif
}
void zpl_atomic64_store ( zpl_atomic64 * a , zpl_atomicarg ( zpl_i64 ) value ) {
# if defined(ZPL_ARCH_64_BIT)
a - > value = value ;
# else
zpl_atomicarg ( zpl_i64 ) expected = a - > value ;
__asm__ (
" 1: cmpxchg8b %0 \n "
" jne 1b "
: " =m " ( a - > value )
: " b " ( ( zpl_atomicarg ( zpl_i32 ) ) value ) , " c " ( ( zpl_atomicarg ( zpl_i32 ) ) ( value > > 32 ) ) , " A " ( expected )
) ;
# endif
}
zpl_i64 zpl_atomic64_compare_exchange ( zpl_atomic64 * a , zpl_atomicarg ( zpl_i64 ) expected , zpl_atomicarg ( zpl_i64 ) desired ) {
# if defined(ZPL_ARCH_64_BIT)
zpl_atomicarg ( zpl_i64 ) original ;
__asm__ (
" lock; cmpxchgq %2, %1 "
: " =a " ( original ) , " +m " ( a - > value )
: " q " ( desired ) , " 0 " ( expected )
) ;
return original ;
# else
zpl_atomicarg ( zpl_i64 ) original ;
__asm__ (
" lock; cmpxchg8b %1 "
: " =A " ( original ) , " +m " ( a - > value )
: " b " ( ( zpl_atomicarg ( zpl_i32 ) ) desired ) , " c " ( ( zpl_atomicarg ( zpl_i32 ) ) ( desired > > 32 ) ) , " 0 " ( expected )
) ;
return original ;
# endif
}
zpl_i64 zpl_atomic64_exchange ( zpl_atomic64 * a , zpl_atomicarg ( zpl_i64 ) desired ) {
# if defined(ZPL_ARCH_64_BIT)
zpl_atomicarg ( zpl_i64 ) original ;
__asm__ (
" xchgq %0, %1 "
: " =r " ( original ) , " +m " ( a - > value )
: " 0 " ( desired )
) ;
return original ;
# else
zpl_atomicarg ( zpl_i64 ) original = a - > value ;
for ( ; ; ) {
zpl_atomicarg ( zpl_i64 ) previous = zpl_atomic64_compare_exchange ( a , original , desired ) ;
if ( original = = previous )
return original ;
original = previous ;
}
# endif
}
zpl_i64 zpl_atomic64_fetch_add ( zpl_atomic64 * a , zpl_atomicarg ( zpl_i64 ) operand ) {
# if defined(ZPL_ARCH_64_BIT)
zpl_atomicarg ( zpl_i64 ) original ;
__asm__ (
" lock; xaddq %0, %1 "
: " =r " ( original ) , " +m " ( a - > value )
: " 0 " ( operand )
) ;
return original ;
# else
for ( ; ; ) {
zpl_atomicarg ( zpl_i64 ) original = a - > value ;
if ( zpl_atomic64_compare_exchange ( a , original , original + operand ) = = original )
return original ;
}
# endif
}
zpl_i64 zpl_atomic64_fetch_and ( zpl_atomic64 * a , zpl_atomicarg ( zpl_i64 ) operand ) {
# if defined(ZPL_ARCH_64_BIT)
zpl_atomicarg ( zpl_i64 ) original ;
zpl_atomicarg ( zpl_i64 ) tmp ;
__asm__ (
" 1: movq %1, %0 \n "
" movq %0, %2 \n "
" andq %3, %2 \n "
" lock; cmpxchgq %2, %1 \n "
" jne 1b "
: " =&a " ( original ) , " +m " ( a - > value ) , " =&r " ( tmp )
: " r " ( operand )
) ;
return original ;
# else
for ( ; ; ) {
zpl_atomicarg ( zpl_i64 ) original = a - > value ;
if ( zpl_atomic64_compare_exchange ( a , original , original & operand ) = = original )
return original ;
}
# endif
}
zpl_i64 zpl_atomic64_fetch_or ( zpl_atomic64 * a , zpl_atomicarg ( zpl_i64 ) operand ) {
# if defined(ZPL_ARCH_64_BIT)
zpl_atomicarg ( zpl_i64 ) original ;
zpl_atomicarg ( zpl_i64 ) temp ;
__asm__ (
" 1: movq %1, %0 \n "
" movq %0, %2 \n "
" orq %3, %2 \n "
" lock; cmpxchgq %2, %1 \n "
" jne 1b "
: " =&a " ( original ) , " +m " ( a - > value ) , " =&r " ( temp )
: " r " ( operand )
) ;
return original ;
# else
for ( ; ; ) {
zpl_atomicarg ( zpl_i64 ) original = a - > value ;
if ( zpl_atomic64_compare_exchange ( a , original , original | operand ) = = original )
return original ;
}
# endif
}
# elif !defined(ZPL_COMPILER_MSVC)
zpl_i32 zpl_atomic32_load ( zpl_atomic32 const * a ) {
return __atomic_load_n ( ( zpl_i32 * ) & a - > value , __ATOMIC_SEQ_CST ) ;
}
void zpl_atomic32_store ( zpl_atomic32 * a , zpl_atomicarg ( zpl_i32 ) value ) {
__atomic_store ( ( zpl_i32 * ) & a - > value , ( zpl_i32 * ) & value , __ATOMIC_SEQ_CST ) ;
}
zpl_i32 zpl_atomic32_compare_exchange ( zpl_atomic32 * a , zpl_atomicarg ( zpl_i32 ) expected , zpl_atomicarg ( zpl_i32 ) desired ) {
return __atomic_compare_exchange_n ( ( zpl_i32 * ) & a - > value , ( zpl_i32 * ) & expected , desired , false , __ATOMIC_SEQ_CST , __ATOMIC_SEQ_CST ) ;
}
zpl_i32 zpl_atomic32_exchange ( zpl_atomic32 * a , zpl_atomicarg ( zpl_i32 ) desired ) {
return __atomic_exchange_n ( ( zpl_i32 * ) & a - > value , desired , __ATOMIC_SEQ_CST ) ;
}
zpl_i32 zpl_atomic32_fetch_add ( zpl_atomic32 * a , zpl_atomicarg ( zpl_i32 ) operand ) {
return __atomic_fetch_add ( ( zpl_i32 * ) & a - > value , operand , __ATOMIC_SEQ_CST ) ;
}
zpl_i32 zpl_atomic32_fetch_and ( zpl_atomic32 * a , zpl_atomicarg ( zpl_i32 ) operand ) {
return __atomic_fetch_and ( ( zpl_i32 * ) & a - > value , operand , __ATOMIC_SEQ_CST ) ;
}
zpl_i32 zpl_atomic32_fetch_or ( zpl_atomic32 * a , zpl_atomicarg ( zpl_i32 ) operand ) {
return __atomic_fetch_or ( ( zpl_i32 * ) & a - > value , operand , __ATOMIC_SEQ_CST ) ;
}
zpl_i64 zpl_atomic64_load ( zpl_atomic64 const * a ) {
return __atomic_load_n ( ( zpl_i64 * ) & a - > value , __ATOMIC_SEQ_CST ) ;
}
void zpl_atomic64_store ( zpl_atomic64 * a , zpl_atomicarg ( zpl_i64 ) value ) {
__atomic_store ( ( zpl_i64 * ) & a - > value , ( zpl_i64 * ) & value , __ATOMIC_SEQ_CST ) ;
}
zpl_i64 zpl_atomic64_compare_exchange ( zpl_atomic64 * a , zpl_atomicarg ( zpl_i64 ) expected , zpl_atomicarg ( zpl_i64 ) desired ) {
return __atomic_compare_exchange_n ( ( zpl_i64 * ) & a - > value , ( zpl_i64 * ) & expected , desired , false , __ATOMIC_SEQ_CST , __ATOMIC_SEQ_CST ) ;
}
zpl_i64 zpl_atomic64_exchange ( zpl_atomic64 * a , zpl_atomicarg ( zpl_i64 ) desired ) {
return __atomic_exchange_n ( ( zpl_i64 * ) & a - > value , desired , __ATOMIC_SEQ_CST ) ;
}
zpl_i64 zpl_atomic64_fetch_add ( zpl_atomic64 * a , zpl_atomicarg ( zpl_i64 ) operand ) {
return __atomic_fetch_add ( ( zpl_i64 * ) & a - > value , operand , __ATOMIC_SEQ_CST ) ;
}
zpl_i64 zpl_atomic64_fetch_and ( zpl_atomic64 * a , zpl_atomicarg ( zpl_i64 ) operand ) {
return __atomic_fetch_and ( ( zpl_i64 * ) & a - > value , operand , __ATOMIC_SEQ_CST ) ;
}
zpl_i64 zpl_atomic64_fetch_or ( zpl_atomic64 * a , zpl_atomicarg ( zpl_i64 ) operand ) {
return __atomic_fetch_or ( ( zpl_i64 * ) & a - > value , operand , __ATOMIC_SEQ_CST ) ;
}
# else
# error TODO: Implement Atomics for this CPU
# endif
zpl_b32 zpl_atomic32_spin_lock ( zpl_atomic32 * a , zpl_isize time_out ) {
zpl_atomicarg ( zpl_i32 ) old_value = zpl_atomic32_compare_exchange ( a , 1 , 0 ) ;
zpl_i32 counter = 0 ;
while ( old_value ! = 0 & & ( time_out < 0 | | counter + + < time_out ) ) {
zpl_yield_thread ( ) ;
old_value = zpl_atomic32_compare_exchange ( a , 1 , 0 ) ;
zpl_mfence ( ) ;
}
return old_value = = 0 ;
}
void zpl_atomic32_spin_unlock ( zpl_atomic32 * a ) {
zpl_atomic32_store ( a , 0 ) ;
zpl_mfence ( ) ;
}
zpl_b32 zpl_atomic64_spin_lock ( zpl_atomic64 * a , zpl_isize time_out ) {
zpl_atomicarg ( zpl_i64 ) old_value = zpl_atomic64_compare_exchange ( a , 1 , 0 ) ;
zpl_atomicarg ( zpl_i64 ) counter = 0 ;
while ( old_value ! = 0 & & ( time_out < 0 | | counter + + < time_out ) ) {
zpl_yield_thread ( ) ;
old_value = zpl_atomic64_compare_exchange ( a , 1 , 0 ) ;
zpl_mfence ( ) ;
}
return old_value = = 0 ;
}
void zpl_atomic64_spin_unlock ( zpl_atomic64 * a ) {
zpl_atomic64_store ( a , 0 ) ;
zpl_mfence ( ) ;
}
zpl_b32 zpl_atomic32_try_acquire_lock ( zpl_atomic32 * a ) {
zpl_atomicarg ( zpl_i32 ) old_value ;
zpl_yield_thread ( ) ;
old_value = zpl_atomic32_compare_exchange ( a , 1 , 0 ) ;
zpl_mfence ( ) ;
return old_value = = 0 ;
}
zpl_b32 zpl_atomic64_try_acquire_lock ( zpl_atomic64 * a ) {
zpl_atomicarg ( zpl_i64 ) old_value ;
zpl_yield_thread ( ) ;
old_value = zpl_atomic64_compare_exchange ( a , 1 , 0 ) ;
zpl_mfence ( ) ;
return old_value = = 0 ;
}
# if defined(ZPL_ARCH_32_BIT)
void * zpl_atomic_ptr_load ( zpl_atomic_ptr const * a ) {
return ( void * ) cast ( zpl_intptr ) zpl_atomic32_load ( cast ( zpl_atomic32 const * ) a ) ;
}
void zpl_atomic_ptr_store ( zpl_atomic_ptr * a , zpl_atomicarg ( void * ) value ) {
zpl_atomic32_store ( cast ( zpl_atomic32 * ) a , cast ( zpl_atomicarg ( zpl_i32 ) ) cast ( zpl_intptr ) value ) ;
}
void * zpl_atomic_ptr_compare_exchange ( zpl_atomic_ptr * a , zpl_atomicarg ( void * ) expected , zpl_atomicarg ( void * ) desired ) {
return ( void * ) cast ( zpl_intptr ) zpl_atomic32_compare_exchange ( cast ( zpl_atomic32 * ) a , cast ( zpl_atomicarg ( zpl_i32 ) ) cast ( zpl_intptr ) expected , cast ( zpl_atomicarg ( zpl_i32 ) ) cast ( zpl_intptr ) desired ) ;
}
void * zpl_atomic_ptr_exchange ( zpl_atomic_ptr * a , zpl_atomicarg ( void * ) desired ) {
return ( void * ) cast ( zpl_intptr ) zpl_atomic32_exchange ( cast ( zpl_atomic32 * ) a , cast ( zpl_atomicarg ( zpl_i32 ) ) cast ( zpl_intptr ) desired ) ;
}
void * zpl_atomic_ptr_fetch_add ( zpl_atomic_ptr * a , zpl_atomicarg ( void * ) operand ) {
return ( void * ) cast ( zpl_intptr ) zpl_atomic32_fetch_add ( cast ( zpl_atomic32 * ) a , cast ( zpl_atomicarg ( zpl_i32 ) ) cast ( zpl_intptr ) operand ) ;
}
void * zpl_atomic_ptr_fetch_and ( zpl_atomic_ptr * a , zpl_atomicarg ( void * ) operand ) {
return ( void * ) cast ( zpl_intptr ) zpl_atomic32_fetch_and ( cast ( zpl_atomic32 * ) a , cast ( zpl_atomicarg ( zpl_i32 ) ) cast ( zpl_intptr ) operand ) ;
}
void * zpl_atomic_ptr_fetch_or ( zpl_atomic_ptr * a , zpl_atomicarg ( void * ) operand ) {
return ( void * ) cast ( zpl_intptr ) zpl_atomic32_fetch_or ( cast ( zpl_atomic32 * ) a , cast ( zpl_atomicarg ( zpl_i32 ) ) cast ( zpl_intptr ) operand ) ;
}
zpl_b32 zpl_atomic_ptr_spin_lock ( zpl_atomic_ptr * a , zpl_isize time_out ) {
return zpl_atomic32_spin_lock ( cast ( zpl_atomic32 * ) a , time_out ) ;
}
void zpl_atomic_ptr_spin_unlock ( zpl_atomic_ptr * a ) {
zpl_atomic32_spin_unlock ( cast ( zpl_atomic32 * ) a ) ;
}
zpl_b32 zpl_atomic_ptr_try_acquire_lock ( zpl_atomic_ptr * a ) {
return zpl_atomic32_try_acquire_lock ( cast ( zpl_atomic32 * ) a ) ;
}
# elif defined(ZPL_ARCH_64_BIT)
void * zpl_atomic_ptr_load ( zpl_atomic_ptr const * a ) {
return ( void * ) cast ( zpl_intptr ) zpl_atomic64_load ( cast ( zpl_atomic64 const * ) a ) ;
}
void zpl_atomic_ptr_store ( zpl_atomic_ptr * a , zpl_atomicarg ( void * ) value ) {
zpl_atomic64_store ( cast ( zpl_atomic64 * ) a , cast ( zpl_i64 ) cast ( zpl_intptr ) value ) ;
}
void * zpl_atomic_ptr_compare_exchange ( zpl_atomic_ptr * a , zpl_atomicarg ( void * ) expected , zpl_atomicarg ( void * ) desired ) {
return ( void * ) cast ( zpl_intptr ) zpl_atomic64_compare_exchange ( cast ( zpl_atomic64 * ) a , cast ( zpl_i64 ) cast ( zpl_intptr ) expected , cast ( zpl_i64 ) cast ( zpl_intptr ) desired ) ;
}
void * zpl_atomic_ptr_exchange ( zpl_atomic_ptr * a , zpl_atomicarg ( void * ) desired ) {
return ( void * ) cast ( zpl_intptr ) zpl_atomic64_exchange ( cast ( zpl_atomic64 * ) a , cast ( zpl_i64 ) cast ( zpl_intptr ) desired ) ;
}
void * zpl_atomic_ptr_fetch_add ( zpl_atomic_ptr * a , zpl_atomicarg ( void * ) operand ) {
return ( void * ) cast ( zpl_intptr ) zpl_atomic64_fetch_add ( cast ( zpl_atomic64 * ) a , cast ( zpl_i64 ) cast ( zpl_intptr ) operand ) ;
}
void * zpl_atomic_ptr_fetch_and ( zpl_atomic_ptr * a , zpl_atomicarg ( void * ) operand ) {
return ( void * ) cast ( zpl_intptr ) zpl_atomic64_fetch_and ( cast ( zpl_atomic64 * ) a , cast ( zpl_i64 ) cast ( zpl_intptr ) operand ) ;
}
void * zpl_atomic_ptr_fetch_or ( zpl_atomic_ptr * a , zpl_atomicarg ( void * ) operand ) {
return ( void * ) cast ( zpl_intptr ) zpl_atomic64_fetch_or ( cast ( zpl_atomic64 * ) a , cast ( zpl_i64 ) cast ( zpl_intptr ) operand ) ;
}
zpl_b32 zpl_atomic_ptr_spin_lock ( zpl_atomic_ptr * a , zpl_isize time_out ) {
return zpl_atomic64_spin_lock ( cast ( zpl_atomic64 * ) a , time_out ) ;
}
void zpl_atomic_ptr_spin_unlock ( zpl_atomic_ptr * a ) {
zpl_atomic64_spin_unlock ( cast ( zpl_atomic64 * ) a ) ;
}
zpl_b32 zpl_atomic_ptr_try_acquire_lock ( zpl_atomic_ptr * a ) {
return zpl_atomic64_try_acquire_lock ( cast ( zpl_atomic64 * ) a ) ;
}
# endif
ZPL_END_C_DECLS
// file: source/threading/sem.c
ZPL_BEGIN_C_DECLS
void zpl_semaphore_release ( zpl_semaphore * s ) { zpl_semaphore_post ( s , 1 ) ; }
# if defined(ZPL_SYSTEM_WINDOWS)
void zpl_semaphore_init ( zpl_semaphore * s ) { s - > win32_handle = CreateSemaphoreA ( NULL , 0 , ZPL_I32_MAX , NULL ) ; }
void zpl_semaphore_destroy ( zpl_semaphore * s ) { CloseHandle ( s - > win32_handle ) ; }
void zpl_semaphore_post ( zpl_semaphore * s , zpl_i32 count ) { ReleaseSemaphore ( s - > win32_handle , count , NULL ) ; }
void zpl_semaphore_wait ( zpl_semaphore * s ) { WaitForSingleObject ( s - > win32_handle , INFINITE ) ; }
zpl_i32 zpl_semaphore_trywait ( zpl_semaphore * s ) { int r = WaitForSingleObject ( s - > win32_handle , 0 ) ; return r ; }
# elif defined(ZPL_SYSTEM_OSX)
void zpl_semaphore_init ( zpl_semaphore * s ) { semaphore_create ( mach_task_self ( ) , & s - > osx_handle , SYNC_POLICY_FIFO , 0 ) ; }
void zpl_semaphore_destroy ( zpl_semaphore * s ) { semaphore_destroy ( mach_task_self ( ) , s - > osx_handle ) ; }
void zpl_semaphore_post ( zpl_semaphore * s , zpl_i32 count ) { while ( count - - > 0 ) semaphore_signal ( s - > osx_handle ) ; }
void zpl_semaphore_wait ( zpl_semaphore * s ) { semaphore_wait ( s - > osx_handle ) ; }
zpl_i32 zpl_semaphore_trywait ( zpl_semaphore * s ) { mach_timespec_t t ; t . tv_sec = t . tv_nsec = 0 ; kern_return_t r = semaphore_timedwait ( s - > osx_handle , t ) ; return r ; }
# elif defined(ZPL_SYSTEM_UNIX)
void zpl_semaphore_init ( zpl_semaphore * s ) { sem_init ( & s - > unix_handle , 0 , 0 ) ; }
void zpl_semaphore_destroy ( zpl_semaphore * s ) { sem_destroy ( & s - > unix_handle ) ; }
void zpl_semaphore_post ( zpl_semaphore * s , zpl_i32 count ) { while ( count - - > 0 ) sem_post ( & s - > unix_handle ) ; }
void zpl_semaphore_wait ( zpl_semaphore * s ) { int i ; do { i = sem_wait ( & s - > unix_handle ) ; } while ( i = = - 1 & & errno = = EINTR ) ; }
zpl_i32 zpl_semaphore_trywait ( zpl_semaphore * s ) { int r = sem_trywait ( & s - > unix_handle ) ; return r ; }
# else
# error Semaphores for this OS are not implemented
# endif
ZPL_END_C_DECLS
// file: source/threading/mutex.c
ZPL_BEGIN_C_DECLS
void zpl_mutex_init ( zpl_mutex * m ) {
# if defined(ZPL_SYSTEM_WINDOWS)
InitializeCriticalSection ( ( CRITICAL_SECTION * ) m - > win32_critical_section ) ;
# else
pthread_mutex_init ( & m - > pthread_mutex , NULL ) ;
# endif
}
void zpl_mutex_destroy ( zpl_mutex * m ) {
# if defined(ZPL_SYSTEM_WINDOWS)
DeleteCriticalSection ( ( CRITICAL_SECTION * ) m - > win32_critical_section ) ;
# else
pthread_mutex_destroy ( & m - > pthread_mutex ) ;
# endif
}
void zpl_mutex_lock ( zpl_mutex * m ) {
# if defined(ZPL_SYSTEM_WINDOWS)
EnterCriticalSection ( ( CRITICAL_SECTION * ) m - > win32_critical_section ) ;
# else
pthread_mutex_lock ( & m - > pthread_mutex ) ;
# endif
}
zpl_b32 zpl_mutex_try_lock ( zpl_mutex * m ) {
# if defined(ZPL_SYSTEM_WINDOWS)
return TryEnterCriticalSection ( ( CRITICAL_SECTION * ) m - > win32_critical_section ) ;
# else
return pthread_mutex_trylock ( & m - > pthread_mutex ) ;
# endif
}
void zpl_mutex_unlock ( zpl_mutex * m ) {
# if defined(ZPL_SYSTEM_WINDOWS)
LeaveCriticalSection ( ( CRITICAL_SECTION * ) m - > win32_critical_section ) ;
# else
pthread_mutex_unlock ( & m - > pthread_mutex ) ;
# endif
}
ZPL_END_C_DECLS
// file: source/threading/thread.c
ZPL_BEGIN_C_DECLS
zpl_b32 zpl_thread_is_running ( zpl_thread const * t ) { return t - > is_running ! = 0 ; }
void zpl_thread_init_nowait ( zpl_thread * t ) {
zpl_zero_item ( t ) ;
# if defined(ZPL_SYSTEM_WINDOWS)
t - > win32_handle = INVALID_HANDLE_VALUE ;
# endif
t - > nowait = true ;
}
void zpl_thread_init ( zpl_thread * t ) {
zpl_thread_init_nowait ( t ) ;
t - > nowait = false ;
zpl_semaphore_init ( & t - > semaphore ) ;
}
void zpl_thread_destroy ( zpl_thread * t ) {
# if defined(ZPL_SYSTEM_WINDOWS)
if ( t - > win32_handle ! = INVALID_HANDLE_VALUE )
zpl_thread_join ( t ) ;
# else
if ( t - > posix_handle )
zpl_thread_join ( t ) ;
# endif
if ( ! t - > nowait )
zpl_semaphore_destroy ( & t - > semaphore ) ;
}
static void zpl__thread_run ( zpl_thread * t ) {
if ( ! t - > nowait )
zpl_semaphore_release ( & t - > semaphore ) ;
t - > return_value = t - > proc ( t ) ;
}
# if defined(ZPL_SYSTEM_WINDOWS)
static DWORD __stdcall zpl__thread_proc ( void * arg ) {
zpl_thread * t = cast ( zpl_thread * ) arg ;
t - > is_running = true ;
zpl__thread_run ( t ) ;
t - > is_running = false ;
return 0 ;
}
# else
static void * zpl__thread_proc ( void * arg ) {
zpl_thread * t = cast ( zpl_thread * ) arg ;
t - > is_running = true ;
zpl__thread_run ( t ) ;
t - > is_running = false ;
return NULL ;
}
# endif
void zpl_thread_start ( zpl_thread * t , zpl_thread_proc proc , void * user_data ) {
zpl_thread_start_with_stack ( t , proc , user_data , 0 ) ;
}
void zpl_thread_start_with_stack ( zpl_thread * t , zpl_thread_proc proc , void * user_data , zpl_isize stack_size ) {
ZPL_ASSERT ( ! t - > is_running ) ;
ZPL_ASSERT ( proc ! = NULL ) ;
t - > proc = proc ;
t - > user_data = user_data ;
t - > stack_size = stack_size ;
# if defined(ZPL_SYSTEM_WINDOWS)
t - > win32_handle = CreateThread ( NULL , stack_size , zpl__thread_proc , t , 0 , NULL ) ;
ZPL_ASSERT_MSG ( t - > win32_handle ! = NULL , " CreateThread: GetLastError " ) ;
# else
{
pthread_attr_t attr ;
pthread_attr_init ( & attr ) ;
pthread_attr_setdetachstate ( & attr , PTHREAD_CREATE_JOINABLE ) ;
if ( stack_size ! = 0 )
pthread_attr_setstacksize ( & attr , stack_size ) ;
pthread_create ( & t - > posix_handle , & attr , zpl__thread_proc , t ) ;
pthread_attr_destroy ( & attr ) ;
}
# endif
if ( ! t - > nowait )
zpl_semaphore_wait ( & t - > semaphore ) ;
}
void zpl_thread_join ( zpl_thread * t ) {
# if defined(ZPL_SYSTEM_WINDOWS)
WaitForSingleObject ( t - > win32_handle , INFINITE ) ;
CloseHandle ( t - > win32_handle ) ;
t - > win32_handle = INVALID_HANDLE_VALUE ;
# else
pthread_join ( t - > posix_handle , NULL ) ;
t - > posix_handle = 0 ;
# endif
}
zpl_u32 zpl_thread_current_id ( void ) {
zpl_u32 thread_id ;
# if defined(ZPL_SYSTEM_WINDOWS)
# if defined(ZPL_ARCH_32_BIT) && defined(ZPL_CPU_X86)
thread_id = ( cast ( zpl_u32 * ) __readfsdword ( 24 ) ) [ 9 ] ;
# elif defined(ZPL_ARCH_64_BIT) && defined(ZPL_CPU_X86)
thread_id = ( cast ( zpl_u32 * ) __readgsqword ( 48 ) ) [ 18 ] ;
# else
thread_id = GetCurrentThreadId ( ) ;
# endif
# elif defined(ZPL_SYSTEM_OSX) && defined(ZPL_ARCH_64_BIT)
thread_id = pthread_mach_thread_np ( pthread_self ( ) ) ;
# elif defined(ZPL_ARCH_32_BIT) && defined(ZPL_CPU_X86)
__asm__ ( " mov %%gs:0x08,%0 " : " =r " ( thread_id ) ) ;
# elif defined(ZPL_ARCH_64_BIT) && defined(ZPL_CPU_X86)
__asm__ ( " mov %%fs:0x10,%0 " : " =r " ( thread_id ) ) ;
# elif defined(__ARM_ARCH)
thread_id = pthread_self ( ) ;
# else
# error Unsupported architecture for zpl_thread_current_id()
# endif
return thread_id ;
}
void zpl_thread_set_name ( zpl_thread * t , char const * name ) {
# if defined(ZPL_COMPILER_MSVC)
# pragma pack(push, 8)
typedef struct {
DWORD type ;
char const * name ;
DWORD id ;
DWORD flags ;
} zplprivThreadName ;
# pragma pack(pop)
zplprivThreadName tn ;
tn . type = 0x1000 ;
tn . name = name ;
tn . id = GetThreadId ( cast ( HANDLE ) t - > win32_handle ) ;
tn . flags = 0 ;
__try {
RaiseException ( 0x406d1388 , 0 , zpl_size_of ( tn ) / 4 , cast ( ULONG_PTR * ) & tn ) ;
} __except ( 1 /*EXCEPTION_EXECUTE_HANDLER*/ ) {
}
# elif defined(ZPL_SYSTEM_WINDOWS) && !defined(ZPL_COMPILER_MSVC)
zpl_unused ( t ) ;
zpl_unused ( name ) ;
// IMPORTANT TODO: Set thread name for GCC/Clang on windows
return ;
# elif defined(ZPL_SYSTEM_OSX)
// TODO: Test if this works
pthread_setname_np ( name ) ;
# else
zpl_unused ( t ) ;
zpl_unused ( name ) ;
// TODO: Test if this works
// pthread_set_name_np(t->posix_handle, name);
# endif
}
ZPL_END_C_DECLS
// file: source/threading/sync.c
ZPL_BEGIN_C_DECLS
void zpl_sync_init ( zpl_sync * s ) {
zpl_zero_item ( s ) ;
zpl_mutex_init ( & s - > mutex ) ;
zpl_mutex_init ( & s - > start ) ;
zpl_semaphore_init ( & s - > release ) ;
}
void zpl_sync_destroy ( zpl_sync * s ) {
if ( s - > waiting ) {
ZPL_PANIC ( " Cannot destroy while threads are waiting! " ) ;
}
zpl_mutex_destroy ( & s - > mutex ) ;
zpl_mutex_destroy ( & s - > start ) ;
zpl_semaphore_destroy ( & s - > release ) ;
}
void zpl_sync_set_target ( zpl_sync * s , zpl_i32 count ) {
zpl_mutex_lock ( & s - > start ) ;
zpl_mutex_lock ( & s - > mutex ) ;
ZPL_ASSERT ( s - > target = = 0 ) ;
s - > target = count ;
s - > current = 0 ;
s - > waiting = 0 ;
zpl_mutex_unlock ( & s - > mutex ) ;
}
void zpl_sync_release ( zpl_sync * s ) {
if ( s - > waiting ) {
zpl_semaphore_release ( & s - > release ) ;
} else {
s - > target = 0 ;
zpl_mutex_unlock ( & s - > start ) ;
}
}
zpl_i32 zpl_sync_reach ( zpl_sync * s ) {
zpl_i32 n ;
zpl_mutex_lock ( & s - > mutex ) ;
ZPL_ASSERT ( s - > current < s - > target ) ;
n = + + s - > current ; // NOTE: Record this value to avoid possible race if `return s->current` was done
if ( s - > current = = s - > target )
zpl_sync_release ( s ) ;
zpl_mutex_unlock ( & s - > mutex ) ;
return n ;
}
void zpl_sync_reach_and_wait ( zpl_sync * s ) {
zpl_mutex_lock ( & s - > mutex ) ;
ZPL_ASSERT ( s - > current < s - > target ) ;
s - > current + + ;
if ( s - > current = = s - > target ) {
zpl_sync_release ( s ) ;
zpl_mutex_unlock ( & s - > mutex ) ;
} else {
s - > waiting + + ; // NOTE: Waiting, so one more waiter
zpl_mutex_unlock ( & s - > mutex ) ; // NOTE: Release the mutex to other threads
zpl_semaphore_wait ( & s - > release ) ; // NOTE: Wait for merge completion
zpl_mutex_lock ( & s - > mutex ) ; // NOTE: On merge completion, lock mutex
s - > waiting - - ; // NOTE: Done waiting
zpl_sync_release ( s ) ; // NOTE: Restart the next waiter
zpl_mutex_unlock ( & s - > mutex ) ;
}
}
ZPL_END_C_DECLS
// file: source/threading/affinity.c
# if defined(ZPL_SYSTEM_MACOS)
# include <sys / sysctl.h>
# endif
ZPL_BEGIN_C_DECLS
# if defined(ZPL_SYSTEM_WINDOWS) || defined(ZPL_SYSTEM_CYGWIN)
void zpl_affinity_init ( zpl_affinity * a ) {
SYSTEM_LOGICAL_PROCESSOR_INFORMATION * start_processor_info = NULL ;
DWORD length = 0 ;
zpl_b32 result = GetLogicalProcessorInformation ( NULL , & length ) ;
zpl_zero_item ( a ) ;
if ( ! result & & GetLastError ( ) = = 122l /*ERROR_INSUFFICIENT_BUFFER*/ & & length > 0 ) {
start_processor_info = cast ( SYSTEM_LOGICAL_PROCESSOR_INFORMATION * ) zpl_alloc ( zpl_heap_allocator ( ) , length ) ;
result = GetLogicalProcessorInformation ( start_processor_info , & length ) ;
if ( result ) {
SYSTEM_LOGICAL_PROCESSOR_INFORMATION * end_processor_info , * processor_info ;
a - > is_accurate = true ;
a - > core_count = 0 ;
a - > thread_count = 0 ;
end_processor_info = cast ( SYSTEM_LOGICAL_PROCESSOR_INFORMATION * ) zpl_pointer_add ( start_processor_info , length ) ;
for ( processor_info = start_processor_info ;
processor_info < end_processor_info ;
processor_info + + ) {
if ( processor_info - > Relationship = = RelationProcessorCore ) {
zpl_isize thread = zpl_count_set_bits ( processor_info - > ProcessorMask ) ;
if ( thread = = 0 ) {
a - > is_accurate = false ;
} else if ( a - > thread_count + thread > ZPL_WIN32_MAX_THREADS ) {
a - > is_accurate = false ;
} else {
ZPL_ASSERT ( a - > core_count < = a - > thread_count & &
a - > thread_count < ZPL_WIN32_MAX_THREADS ) ;
a - > core_masks [ a - > core_count + + ] = processor_info - > ProcessorMask ;
a - > thread_count + = thread ;
}
}
}
}
zpl_free ( zpl_heap_allocator ( ) , start_processor_info ) ;
}
ZPL_ASSERT ( a - > core_count < = a - > thread_count ) ;
if ( a - > thread_count = = 0 ) {
a - > is_accurate = false ;
a - > core_count = 1 ;
a - > thread_count = 1 ;
a - > core_masks [ 0 ] = 1 ;
}
}
void zpl_affinity_destroy ( zpl_affinity * a ) {
zpl_unused ( a ) ;
}
zpl_b32 zpl_affinity_set ( zpl_affinity * a , zpl_isize core , zpl_isize thread ) {
zpl_usize available_mask , check_mask = 1 ;
ZPL_ASSERT ( thread < zpl_affinity_thread_count_for_core ( a , core ) ) ;
available_mask = a - > core_masks [ core ] ;
for ( ; ; ) {
if ( ( available_mask & check_mask ) ! = 0 ) {
if ( thread - - = = 0 ) {
zpl_usize result = SetThreadAffinityMask ( GetCurrentThread ( ) , check_mask ) ;
return result ! = 0 ;
}
}
check_mask < < = 1 ; // NOTE: Onto the next bit
}
}
zpl_isize zpl_affinity_thread_count_for_core ( zpl_affinity * a , zpl_isize core ) {
ZPL_ASSERT ( core > = 0 & & core < a - > core_count ) ;
return zpl_count_set_bits ( a - > core_masks [ core ] ) ;
}
# elif defined(ZPL_SYSTEM_MACOS)
void zpl_affinity_init ( zpl_affinity * a ) {
zpl_usize count , count_size = zpl_size_of ( count ) ;
a - > is_accurate = false ;
a - > thread_count = 1 ;
a - > core_count = 1 ;
a - > threads_per_core = 1 ;
if ( sysctlbyname ( " hw.logicalcpu " , & count , & count_size , NULL , 0 ) = = 0 ) {
if ( count > 0 ) {
a - > thread_count = count ;
// Get # of physical cores
if ( sysctlbyname ( " hw.physicalcpu " , & count , & count_size , NULL , 0 ) = = 0 ) {
if ( count > 0 ) {
a - > core_count = count ;
a - > threads_per_core = a - > thread_count / count ;
if ( a - > threads_per_core < 1 )
a - > threads_per_core = 1 ;
else
a - > is_accurate = true ;
}
}
}
}
}
void zpl_affinity_destroy ( zpl_affinity * a ) {
zpl_unused ( a ) ;
}
zpl_b32 zpl_affinity_set ( zpl_affinity * a , zpl_isize core , zpl_isize thread_index ) {
zpl_isize index ;
thread_t thread ;
thread_affinity_policy_data_t info ;
kern_return_t result ;
ZPL_ASSERT ( core < a - > core_count ) ;
ZPL_ASSERT ( thread_index < a - > threads_per_core ) ;
index = core * a - > threads_per_core + thread_index ;
thread = mach_thread_self ( ) ;
info . affinity_tag = cast ( integer_t ) index ;
result = thread_policy_set ( thread , THREAD_AFFINITY_POLICY , cast ( thread_policy_t ) & info , THREAD_AFFINITY_POLICY_COUNT ) ;
return result = = KERN_SUCCESS ;
}
zpl_isize zpl_affinity_thread_count_for_core ( zpl_affinity * a , zpl_isize core ) {
ZPL_ASSERT ( core > = 0 & & core < a - > core_count ) ;
return a - > threads_per_core ;
}
# elif defined(ZPL_SYSTEM_LINUX) || defined(ZPL_SYSTEM_FREEBSD) || defined(ZPL_SYSTEM_OPENBSD)
void zpl_affinity_init ( zpl_affinity * a ) {
a - > core_count = sysconf ( _SC_NPROCESSORS_ONLN ) ;
a - > threads_per_core = 1 ;
a - > is_accurate = a - > core_count > 0 ;
a - > core_count = a - > is_accurate ? a - > core_count : 1 ;
a - > thread_count = a - > core_count ;
}
void zpl_affinity_destroy ( zpl_affinity * a ) {
zpl_unused ( a ) ;
}
zpl_b32 zpl_affinity_set ( zpl_affinity * a , zpl_isize core , zpl_isize thread_index ) {
zpl_unused ( a ) ;
zpl_unused ( core ) ;
zpl_unused ( thread_index ) ;
return true ;
}
zpl_isize zpl_affinity_thread_count_for_core ( zpl_affinity * a , zpl_isize core ) {
ZPL_ASSERT ( 0 < = core & & core < a - > core_count ) ;
return a - > threads_per_core ;
}
# elif defined(ZPL_SYSTEM_EMSCRIPTEN)
# error No affinity implementation for Emscripten
# else
# error TODO: Unknown system
# endif
ZPL_END_C_DECLS
2021-11-29 08:23:08 +00:00
# if defined(ZPL_MODULE_JOBS)
2022-09-11 17:42:06 +00:00
// file: source/jobs.c
///////////////////////////////////////////////////////////////
//
// Thread Pool
//
ZPL_BEGIN_C_DECLS
ZPL_RING_DEFINE ( zpl__jobs_ring_ , zpl_thread_job ) ;
zpl_global const zpl_u32 zpl__jobs_chances [ ZPL_JOBS_MAX_PRIORITIES ] = {
2 , 3 , 5 , 7 , 11
} ;
zpl_isize zpl__jobs_entry ( struct zpl_thread * thread ) {
zpl_thread_worker * tw = ( zpl_thread_worker * ) thread - > user_data ;
for ( ; ; ) {
zpl_u32 status = zpl_atomic32_load ( & tw - > status ) ;
switch ( status ) {
case ZPL_JOBS_STATUS_READY : {
zpl_atomic32_store ( & tw - > status , ZPL_JOBS_STATUS_BUSY ) ;
tw - > job . proc ( tw - > job . data ) ;
zpl_atomic32_compare_exchange ( & tw - > status , ZPL_JOBS_STATUS_BUSY , ZPL_JOBS_STATUS_WAITING ) ;
# ifdef ZPL_JOBS_DEBUG
+ + tw - > hits ;
# endif
} break ;
case ZPL_JOBS_STATUS_WAITING : {
# ifdef ZPL_JOBS_DEBUG
+ + tw - > idle ;
# endif
zpl_yield ( ) ;
} break ;
case ZPL_JOBS_STATUS_TERM : {
return 0 ;
} break ;
}
}
return 0 ;
}
void zpl_jobs_init ( zpl_jobs_system * pool , zpl_allocator a , zpl_u32 max_threads ) {
zpl_jobs_init_with_limit ( pool , a , max_threads , ZPL_JOBS_MAX_QUEUE ) ;
}
void zpl_jobs_init_with_limit ( zpl_jobs_system * pool , zpl_allocator a , zpl_u32 max_threads , zpl_u32 max_jobs ) {
zpl_jobs_system pool_ = { 0 } ;
* pool = pool_ ;
pool - > alloc = a ;
pool - > max_threads = max_threads ;
pool - > max_jobs = max_jobs ;
pool - > counter = 0 ;
zpl_buffer_init ( pool - > workers , a , max_threads ) ;
for ( zpl_usize i = 0 ; i < ZPL_JOBS_MAX_PRIORITIES ; + + i ) {
zpl_thread_queue * q = & pool - > queues [ i ] ;
zpl__jobs_ring_init ( & q - > jobs , a , max_jobs ) ;
q - > chance = zpl__jobs_chances [ i ] ;
}
for ( zpl_usize i = 0 ; i < max_threads ; + + i ) {
zpl_thread_worker worker_ = { 0 } ;
zpl_thread_worker * tw = pool - > workers + i ;
* tw = worker_ ;
zpl_thread_init ( & tw - > thread ) ;
zpl_atomic32_store ( & tw - > status , ZPL_JOBS_STATUS_WAITING ) ;
zpl_thread_start ( & tw - > thread , zpl__jobs_entry , ( void * ) tw ) ;
}
}
void zpl_jobs_free ( zpl_jobs_system * pool ) {
for ( zpl_usize i = 0 ; i < pool - > max_threads ; + + i ) {
zpl_thread_worker * tw = pool - > workers + i ;
zpl_atomic32_store ( & tw - > status , ZPL_JOBS_STATUS_TERM ) ;
zpl_thread_destroy ( & tw - > thread ) ;
}
zpl_buffer_free ( pool - > workers ) ;
for ( zpl_usize i = 0 ; i < ZPL_JOBS_MAX_PRIORITIES ; + + i ) {
zpl_thread_queue * q = & pool - > queues [ i ] ;
zpl__jobs_ring_free ( & q - > jobs ) ;
}
}
zpl_b32 zpl_jobs_enqueue_with_priority ( zpl_jobs_system * pool , zpl_jobs_proc proc , void * data , zpl_jobs_priority priority ) {
ZPL_ASSERT ( priority > = 0 & & priority < ZPL_JOBS_MAX_PRIORITIES ) ;
ZPL_ASSERT_NOT_NULL ( proc ) ;
zpl_thread_job job = { 0 } ;
job . proc = proc ;
job . data = data ;
if ( ! zpl_jobs_full ( pool , priority ) ) {
zpl__jobs_ring_append ( & pool - > queues [ priority ] . jobs , job ) ;
return true ;
}
return false ;
}
zpl_b32 zpl_jobs_enqueue ( zpl_jobs_system * pool , zpl_jobs_proc proc , void * data ) {
return zpl_jobs_enqueue_with_priority ( pool , proc , data , ZPL_JOBS_PRIORITY_NORMAL ) ;
}
zpl_b32 zpl_jobs_empty ( zpl_jobs_system * pool , zpl_jobs_priority priority ) {
ZPL_ASSERT ( priority > = 0 & & priority < ZPL_JOBS_MAX_PRIORITIES ) ;
return zpl__jobs_ring_empty ( & pool - > queues [ priority ] . jobs ) ;
}
zpl_b32 zpl_jobs_full ( zpl_jobs_system * pool , zpl_jobs_priority priority ) {
ZPL_ASSERT ( priority > = 0 & & priority < ZPL_JOBS_MAX_PRIORITIES ) ;
return zpl__jobs_ring_full ( & pool - > queues [ priority ] . jobs ) ;
}
zpl_b32 zpl_jobs_done ( zpl_jobs_system * pool ) {
for ( zpl_usize i = 0 ; i < pool - > max_threads ; + + i ) {
zpl_thread_worker * tw = pool - > workers + i ;
if ( zpl_atomic32_load ( & tw - > status ) ! = ZPL_JOBS_STATUS_WAITING ) {
return false ;
}
}
return zpl_jobs_empty_all ( pool ) ;
}
zpl_b32 zpl_jobs_empty_all ( zpl_jobs_system * pool ) {
for ( zpl_usize i = 0 ; i < ZPL_JOBS_MAX_PRIORITIES ; + + i ) {
if ( ! zpl_jobs_empty ( pool , ( zpl_jobs_priority ) i ) ) {
return false ;
}
}
return true ;
}
zpl_b32 zpl_jobs_full_all ( zpl_jobs_system * pool ) {
for ( zpl_usize i = 0 ; i < ZPL_JOBS_MAX_PRIORITIES ; + + i ) {
if ( ! zpl_jobs_full ( pool , ( zpl_jobs_priority ) i ) ) {
return false ;
}
}
return true ;
}
zpl_b32 zpl_jobs_process ( zpl_jobs_system * pool ) {
if ( zpl_jobs_empty_all ( pool ) ) {
return false ;
}
// NOTE: Process the jobs
for ( zpl_usize i = 0 ; i < pool - > max_threads ; + + i ) {
zpl_thread_worker * tw = pool - > workers + i ;
zpl_u32 status = zpl_atomic32_load ( & tw - > status ) ;
zpl_b32 last_empty = false ;
if ( status = = ZPL_JOBS_STATUS_WAITING ) {
for ( zpl_usize j = 0 ; j < ZPL_JOBS_MAX_PRIORITIES ; + + j ) {
zpl_thread_queue * q = & pool - > queues [ j ] ;
if ( zpl_jobs_empty ( pool , ( zpl_jobs_priority ) j ) ) {
last_empty = ( j + 1 = = ZPL_JOBS_MAX_PRIORITIES ) ;
continue ;
}
if ( ! last_empty & & ( ( pool - > counter + + % q - > chance ) ! = 0 ) ) {
continue ;
}
last_empty = false ;
tw - > job = * zpl__jobs_ring_get ( & q - > jobs ) ;
zpl_atomic32_store ( & tw - > status , ZPL_JOBS_STATUS_READY ) ;
# ifdef ZPL_JOBS_DEBUG
+ + q - > hits ;
# endif
break ;
}
}
}
return true ;
}
ZPL_END_C_DECLS
2021-11-29 08:23:08 +00:00
# endif
# endif
# if defined(ZPL_MODULE_PARSER)
2022-09-11 17:42:06 +00:00
// file: source/adt.c
ZPL_BEGIN_C_DECLS
zpl_u8 zpl_adt_make_branch ( zpl_adt_node * node , zpl_allocator backing , char const * name , zpl_b32 is_array ) {
zpl_u8 type = ZPL_ADT_TYPE_OBJECT ;
if ( is_array ) {
type = ZPL_ADT_TYPE_ARRAY ;
}
zpl_adt_node * parent = node - > parent ;
zpl_zero_item ( node ) ;
node - > type = type ;
node - > name = name ;
node - > parent = parent ;
zpl_array_init ( node - > nodes , backing ) ;
return 0 ;
}
zpl_u8 zpl_adt_destroy_branch ( zpl_adt_node * node ) {
ZPL_ASSERT_NOT_NULL ( node ) ;
if ( ( node - > type = = ZPL_ADT_TYPE_OBJECT | | node - > type = = ZPL_ADT_TYPE_ARRAY ) & & node - > nodes ) {
for ( zpl_isize i = 0 ; i < zpl_array_count ( node - > nodes ) ; + + i ) { zpl_adt_destroy_branch ( node - > nodes + i ) ; }
zpl_array_free ( node - > nodes ) ;
}
return 0 ;
}
zpl_u8 zpl_adt_make_leaf ( zpl_adt_node * node , char const * name , zpl_u8 type ) {
ZPL_ASSERT ( type ! = ZPL_ADT_TYPE_OBJECT & & type ! = ZPL_ADT_TYPE_ARRAY ) ;
zpl_adt_node * parent = node - > parent ;
zpl_zero_item ( node ) ;
node - > type = type ;
node - > name = name ;
node - > parent = parent ;
return 0 ;
}
zpl_adt_node * zpl_adt_find ( zpl_adt_node * node , char const * name , zpl_b32 deep_search ) {
if ( node - > type ! = ZPL_ADT_TYPE_OBJECT ) {
return NULL ;
}
for ( zpl_isize i = 0 ; i < zpl_array_count ( node - > nodes ) ; i + + ) {
if ( ! zpl_strcmp ( node - > nodes [ i ] . name , name ) ) {
return ( node - > nodes + i ) ;
}
}
if ( deep_search ) {
for ( zpl_isize i = 0 ; i < zpl_array_count ( node - > nodes ) ; i + + ) {
zpl_adt_node * res = zpl_adt_find ( node - > nodes + i , name , deep_search ) ;
if ( res ! = NULL )
return res ;
}
}
return NULL ;
}
zpl_internal zpl_adt_node * zpl__adt_get_value ( zpl_adt_node * node , char const * value ) {
switch ( node - > type ) {
case ZPL_ADT_TYPE_MULTISTRING :
case ZPL_ADT_TYPE_STRING : {
if ( node - > string & & ! zpl_strcmp ( node - > string , value ) ) {
return node ;
}
} break ;
case ZPL_ADT_TYPE_INTEGER :
case ZPL_ADT_TYPE_REAL : {
char back [ 4096 ] = { 0 } ;
zpl_file tmp ;
/* allocate a file descriptor for a memory-mapped number to string conversion, input source buffer is not cloned, however. */
zpl_file_stream_open ( & tmp , zpl_heap ( ) , ( zpl_u8 * ) back , zpl_size_of ( back ) , ZPL_FILE_STREAM_WRITABLE ) ;
zpl_adt_print_number ( & tmp , node ) ;
zpl_isize fsize = 0 ;
zpl_u8 * buf = zpl_file_stream_buf ( & tmp , & fsize ) ;
if ( ! zpl_strcmp ( ( char const * ) buf , value ) ) {
zpl_file_close ( & tmp ) ;
return node ;
}
zpl_file_close ( & tmp ) ;
} break ;
default : break ; /* node doesn't support value based lookup */
}
return NULL ;
}
zpl_internal zpl_adt_node * zpl__adt_get_field ( zpl_adt_node * node , char * name , char * value ) {
for ( zpl_isize i = 0 ; i < zpl_array_count ( node - > nodes ) ; i + + ) {
if ( ! zpl_strcmp ( node - > nodes [ i ] . name , name ) ) {
zpl_adt_node * child = & node - > nodes [ i ] ;
if ( zpl__adt_get_value ( child , value ) ) {
return node ; /* this object does contain a field of a specified value! */
}
}
}
return NULL ;
}
zpl_adt_node * zpl_adt_query ( zpl_adt_node * node , char const * uri ) {
ZPL_ASSERT_NOT_NULL ( uri ) ;
if ( * uri = = ' / ' ) {
uri + + ;
}
if ( * uri = = 0 ) {
return node ;
}
if ( ! node | | ( node - > type ! = ZPL_ADT_TYPE_OBJECT & & node - > type ! = ZPL_ADT_TYPE_ARRAY ) ) {
return NULL ;
}
# if defined ZPL_ADT_URI_DEBUG || 0
zpl_printf ( " uri: %s \n " , uri ) ;
# endif
char * p = ( char * ) uri , * b = p , * e = p ;
zpl_adt_node * found_node = NULL ;
b = p ;
p = e = ( char * ) zpl_str_skip ( p , ' / ' ) ;
char * buf = zpl_bprintf ( " %.*s " , ( int ) ( e - b ) , b ) ;
/* handle field value lookup */
if ( * b = = ' [ ' ) {
char * l_p = buf + 1 , * l_b = l_p , * l_e = l_p , * l_b2 = l_p , * l_e2 = l_p ;
l_e = ( char * ) zpl_str_skip ( l_p , ' = ' ) ;
l_e2 = ( char * ) zpl_str_skip ( l_p , ' ] ' ) ;
if ( ( ! * l_e & & node - > type ! = ZPL_ADT_TYPE_ARRAY ) | | ! * l_e2 ) {
ZPL_ASSERT_MSG ( 0 , " Invalid field value lookup " ) ;
return NULL ;
}
* l_e2 = 0 ;
/* [field=value] */
if ( * l_e ) {
* l_e = 0 ;
l_b2 = l_e + 1 ;
/* run a value comparison against our own fields */
if ( node - > type = = ZPL_ADT_TYPE_OBJECT ) {
found_node = zpl__adt_get_field ( node , l_b , l_b2 ) ;
}
/* run a value comparison against any child that is an object node */
else if ( node - > type = = ZPL_ADT_TYPE_ARRAY ) {
for ( zpl_isize i = 0 ; i < zpl_array_count ( node - > nodes ) ; i + + ) {
zpl_adt_node * child = & node - > nodes [ i ] ;
if ( child - > type ! = ZPL_ADT_TYPE_OBJECT ) {
continue ;
}
found_node = zpl__adt_get_field ( child , l_b , l_b2 ) ;
if ( found_node )
break ;
}
}
}
/* [value] */
else {
for ( zpl_isize i = 0 ; i < zpl_array_count ( node - > nodes ) ; i + + ) {
zpl_adt_node * child = & node - > nodes [ i ] ;
if ( zpl__adt_get_value ( child , l_b2 ) ) {
found_node = child ;
break ; /* we found a matching value in array, ignore the rest of it */
}
}
}
/* go deeper if uri continues */
if ( * e ) {
return zpl_adt_query ( found_node , e + 1 ) ;
}
}
/* handle field name lookup */
else if ( node - > type = = ZPL_ADT_TYPE_OBJECT ) {
found_node = zpl_adt_find ( node , buf , false ) ;
/* go deeper if uri continues */
if ( * e ) {
return zpl_adt_query ( found_node , e + 1 ) ;
}
}
/* handle array index lookup */
else {
zpl_isize idx = ( zpl_isize ) zpl_str_to_i64 ( buf , NULL , 10 ) ;
if ( idx > = 0 & & idx < zpl_array_count ( node - > nodes ) ) {
found_node = & node - > nodes [ idx ] ;
/* go deeper if uri continues */
if ( * e ) {
return zpl_adt_query ( found_node , e + 1 ) ;
}
}
}
return found_node ;
}
zpl_adt_node * zpl_adt_alloc_at ( zpl_adt_node * parent , zpl_isize index ) {
if ( ! parent | | ( parent - > type ! = ZPL_ADT_TYPE_OBJECT & & parent - > type ! = ZPL_ADT_TYPE_ARRAY ) ) {
return NULL ;
}
if ( ! parent - > nodes )
return NULL ;
if ( index < 0 | | index > zpl_array_count ( parent - > nodes ) )
return NULL ;
zpl_adt_node o = { 0 } ;
o . parent = parent ;
zpl_array_append_at ( parent - > nodes , o , index ) ;
return parent - > nodes + index ;
}
zpl_adt_node * zpl_adt_alloc ( zpl_adt_node * parent ) {
if ( ! parent | | ( parent - > type ! = ZPL_ADT_TYPE_OBJECT & & parent - > type ! = ZPL_ADT_TYPE_ARRAY ) ) {
return NULL ;
}
if ( ! parent - > nodes )
return NULL ;
return zpl_adt_alloc_at ( parent , zpl_array_count ( parent - > nodes ) ) ;
}
void zpl_adt_set_obj ( zpl_adt_node * obj , char const * name , zpl_allocator backing ) {
zpl_adt_make_branch ( obj , backing , name , 0 ) ;
}
void zpl_adt_set_arr ( zpl_adt_node * obj , char const * name , zpl_allocator backing ) {
zpl_adt_make_branch ( obj , backing , name , 1 ) ;
}
void zpl_adt_set_str ( zpl_adt_node * obj , char const * name , char const * value ) {
zpl_adt_make_leaf ( obj , name , ZPL_ADT_TYPE_STRING ) ;
obj - > string = value ;
}
void zpl_adt_set_flt ( zpl_adt_node * obj , char const * name , zpl_f64 value ) {
zpl_adt_make_leaf ( obj , name , ZPL_ADT_TYPE_REAL ) ;
obj - > real = value ;
}
void zpl_adt_set_int ( zpl_adt_node * obj , char const * name , zpl_i64 value ) {
zpl_adt_make_leaf ( obj , name , ZPL_ADT_TYPE_INTEGER ) ;
obj - > integer = value ;
}
zpl_adt_node * zpl_adt_move_node_at ( zpl_adt_node * node , zpl_adt_node * new_parent , zpl_isize index ) {
ZPL_ASSERT_NOT_NULL ( node ) ;
ZPL_ASSERT_NOT_NULL ( new_parent ) ;
zpl_adt_node * old_parent = node - > parent ;
zpl_adt_node * new_node = zpl_adt_alloc_at ( new_parent , index ) ;
* new_node = * node ;
new_node - > parent = new_parent ;
if ( old_parent ) {
zpl_adt_remove_node ( node ) ;
}
return new_node ;
}
zpl_adt_node * zpl_adt_move_node ( zpl_adt_node * node , zpl_adt_node * new_parent ) {
ZPL_ASSERT_NOT_NULL ( node ) ;
ZPL_ASSERT_NOT_NULL ( new_parent ) ;
ZPL_ASSERT ( new_parent - > type = = ZPL_ADT_TYPE_ARRAY | | new_parent - > type = = ZPL_ADT_TYPE_OBJECT ) ;
return zpl_adt_move_node_at ( node , new_parent , zpl_array_count ( new_parent - > nodes ) ) ;
}
void zpl_adt_swap_nodes ( zpl_adt_node * node , zpl_adt_node * other_node ) {
ZPL_ASSERT_NOT_NULL ( node ) ;
ZPL_ASSERT_NOT_NULL ( other_node ) ;
zpl_adt_node * parent = node - > parent ;
zpl_adt_node * other_parent = other_node - > parent ;
zpl_isize index = ( zpl_pointer_diff ( parent - > nodes , node ) / zpl_size_of ( zpl_adt_node ) ) ;
zpl_isize index2 = ( zpl_pointer_diff ( other_parent - > nodes , other_node ) / zpl_size_of ( zpl_adt_node ) ) ;
zpl_adt_node temp = parent - > nodes [ index ] ;
temp . parent = other_parent ;
other_parent - > nodes [ index2 ] . parent = parent ;
parent - > nodes [ index ] = other_parent - > nodes [ index2 ] ;
other_parent - > nodes [ index2 ] = temp ;
}
void zpl_adt_remove_node ( zpl_adt_node * node ) {
ZPL_ASSERT_NOT_NULL ( node ) ;
ZPL_ASSERT_NOT_NULL ( node - > parent ) ;
zpl_adt_node * parent = node - > parent ;
zpl_isize index = ( zpl_pointer_diff ( parent - > nodes , node ) / zpl_size_of ( zpl_adt_node ) ) ;
zpl_array_remove_at ( parent - > nodes , index ) ;
}
zpl_adt_node * zpl_adt_append_obj ( zpl_adt_node * parent , char const * name ) {
zpl_adt_node * o = zpl_adt_alloc ( parent ) ;
zpl_adt_set_obj ( o , name , ZPL_ARRAY_HEADER ( parent - > nodes ) - > allocator ) ;
return o ;
}
zpl_adt_node * zpl_adt_append_arr ( zpl_adt_node * parent , char const * name ) {
zpl_adt_node * o = zpl_adt_alloc ( parent ) ;
zpl_adt_set_arr ( o , name , ZPL_ARRAY_HEADER ( parent - > nodes ) - > allocator ) ;
return o ;
}
zpl_adt_node * zpl_adt_append_str ( zpl_adt_node * parent , char const * name , char const * value ) {
zpl_adt_node * o = zpl_adt_alloc ( parent ) ;
zpl_adt_set_str ( o , name , value ) ;
return o ;
}
zpl_adt_node * zpl_adt_append_flt ( zpl_adt_node * parent , char const * name , zpl_f64 value ) {
zpl_adt_node * o = zpl_adt_alloc ( parent ) ;
zpl_adt_set_flt ( o , name , value ) ;
return o ;
}
zpl_adt_node * zpl_adt_append_int ( zpl_adt_node * parent , char const * name , zpl_i64 value ) {
zpl_adt_node * o = zpl_adt_alloc ( parent ) ;
zpl_adt_set_int ( o , name , value ) ;
return o ;
}
/* parser helpers */
char * zpl_adt_parse_number ( zpl_adt_node * node , char * base_str ) {
ZPL_ASSERT_NOT_NULL ( node ) ;
ZPL_ASSERT_NOT_NULL ( base_str ) ;
char * p = base_str , * e = p ;
zpl_i32 base = 0 ;
zpl_i32 base2 = 0 ;
zpl_u8 base2_offset = 0 ;
zpl_i8 exp = 0 , orig_exp = 0 ;
zpl_u8 neg_zero = 0 ;
zpl_u8 lead_digit = 0 ;
zpl_u8 node_type = 0 ;
zpl_u8 node_props = 0 ;
/* skip false positives and special cases */
if ( ! ! zpl_strchr ( " eE " , * p ) | | ( ! ! zpl_strchr ( " .+- " , * p ) & & ! zpl_char_is_hex_digit ( * ( p + 1 ) ) & & * ( p + 1 ) ! = ' . ' ) ) {
return + + base_str ;
}
node_type = ZPL_ADT_TYPE_INTEGER ;
neg_zero = false ;
zpl_isize ib = 0 ;
char buf [ 48 ] = { 0 } ;
if ( * e = = ' + ' )
+ + e ;
else if ( * e = = ' - ' ) {
buf [ ib + + ] = * e + + ;
}
if ( * e = = ' . ' ) {
node_type = ZPL_ADT_TYPE_REAL ;
node_props = ZPL_ADT_PROPS_IS_PARSED_REAL ;
lead_digit = false ;
buf [ ib + + ] = ' 0 ' ;
do {
buf [ ib + + ] = * e ;
} while ( zpl_char_is_digit ( * + + e ) ) ;
} else {
if ( ! zpl_strncmp ( e , " 0x " , 2 ) | | ! zpl_strncmp ( e , " 0X " , 2 ) ) { node_props = ZPL_ADT_PROPS_IS_HEX ; }
while ( zpl_char_is_hex_digit ( * e ) | | zpl_char_to_lower ( * e ) = = ' x ' ) { buf [ ib + + ] = * e + + ; }
if ( * e = = ' . ' ) {
node_type = ZPL_ADT_TYPE_REAL ;
lead_digit = true ;
zpl_u32 step = 0 ;
do {
buf [ ib + + ] = * e ;
+ + step ;
} while ( zpl_char_is_digit ( * + + e ) ) ;
if ( step < 2 ) { buf [ ib + + ] = ' 0 ' ; }
}
}
/* check if we have a dot here, this is a false positive (IP address, ...) */
if ( * e = = ' . ' ) {
return + + base_str ;
}
zpl_f32 eb = 10 ;
char expbuf [ 6 ] = { 0 } ;
zpl_isize expi = 0 ;
if ( * e & & ! ! zpl_strchr ( " eE " , * e ) ) {
+ + e ;
if ( * e = = ' + ' | | * e = = ' - ' | | zpl_char_is_digit ( * e ) ) {
if ( * e = = ' - ' ) { eb = 0.1f ; }
if ( ! zpl_char_is_digit ( * e ) ) { + + e ; }
while ( zpl_char_is_digit ( * e ) ) { expbuf [ expi + + ] = * e + + ; }
}
orig_exp = exp = ( zpl_u8 ) zpl_str_to_i64 ( expbuf , NULL , 10 ) ;
}
if ( node_type = = ZPL_ADT_TYPE_INTEGER ) {
node - > integer = zpl_str_to_i64 ( buf , 0 , 0 ) ;
# ifndef ZPL_PARSER_DISABLE_ANALYSIS
/* special case: negative zero */
if ( node - > integer = = 0 & & buf [ 0 ] = = ' - ' ) {
neg_zero = true ;
}
# endif
while ( orig_exp - - > 0 ) { node - > integer * = ( zpl_i64 ) eb ; }
} else {
node - > real = zpl_str_to_f64 ( buf , 0 ) ;
# ifndef ZPL_PARSER_DISABLE_ANALYSIS
char * q = buf , * base_string = q , * base_string2 = q ;
base_string = cast ( char * ) zpl_str_skip ( base_string , ' . ' ) ;
* base_string = ' \0 ' ;
base_string2 = base_string + 1 ;
char * base_string_off = base_string2 ;
while ( * base_string_off + + = = ' 0 ' ) base2_offset + + ;
base = ( zpl_i32 ) zpl_str_to_i64 ( q , 0 , 0 ) ;
base2 = ( zpl_i32 ) zpl_str_to_i64 ( base_string2 , 0 , 0 ) ;
if ( exp ) {
exp = exp * ( ! ( eb = = 10.0f ) ? - 1 : 1 ) ;
node_props = ZPL_ADT_PROPS_IS_EXP ;
}
/* special case: negative zero */
if ( base = = 0 & & buf [ 0 ] = = ' - ' ) {
neg_zero = true ;
}
# endif
while ( orig_exp - - > 0 ) { node - > real * = eb ; }
}
node - > type = node_type ;
node - > props = node_props ;
# ifndef ZPL_PARSER_DISABLE_ANALYSIS
node - > base = base ;
node - > base2 = base2 ;
node - > base2_offset = base2_offset ;
node - > exp = exp ;
node - > neg_zero = neg_zero ;
node - > lead_digit = lead_digit ;
# else
zpl_unused ( base ) ;
zpl_unused ( base2 ) ;
zpl_unused ( base2_offset ) ;
zpl_unused ( exp ) ;
zpl_unused ( neg_zero ) ;
zpl_unused ( lead_digit ) ;
# endif
return e ;
}
zpl_adt_error zpl_adt_print_number ( zpl_file * file , zpl_adt_node * node ) {
ZPL_ASSERT_NOT_NULL ( file ) ;
ZPL_ASSERT_NOT_NULL ( node ) ;
if ( node - > type ! = ZPL_ADT_TYPE_INTEGER & & node - > type ! = ZPL_ADT_TYPE_REAL ) {
return ZPL_ADT_ERROR_INVALID_TYPE ;
}
# ifndef ZPL_PARSER_DISABLE_ANALYSIS
if ( node - > neg_zero ) {
zpl_fprintf ( file , " - " ) ;
}
# endif
switch ( node - > type ) {
case ZPL_ADT_TYPE_INTEGER : {
if ( node - > props = = ZPL_ADT_PROPS_IS_HEX ) {
zpl_fprintf ( file , " 0x%llx " , ( long long ) node - > integer ) ;
} else {
zpl_fprintf ( file , " %lld " , ( long long ) node - > integer ) ;
}
} break ;
case ZPL_ADT_TYPE_REAL : {
if ( node - > props = = ZPL_ADT_PROPS_NAN ) {
zpl_fprintf ( file , " NaN " ) ;
} else if ( node - > props = = ZPL_ADT_PROPS_NAN_NEG ) {
zpl_fprintf ( file , " -NaN " ) ;
} else if ( node - > props = = ZPL_ADT_PROPS_INFINITY ) {
zpl_fprintf ( file , " Infinity " ) ;
} else if ( node - > props = = ZPL_ADT_PROPS_INFINITY_NEG ) {
zpl_fprintf ( file , " -Infinity " ) ;
} else if ( node - > props = = ZPL_ADT_PROPS_TRUE ) {
zpl_fprintf ( file , " true " ) ;
} else if ( node - > props = = ZPL_ADT_PROPS_FALSE ) {
zpl_fprintf ( file , " false " ) ;
} else if ( node - > props = = ZPL_ADT_PROPS_NULL ) {
zpl_fprintf ( file , " null " ) ;
# ifndef ZPL_PARSER_DISABLE_ANALYSIS
} else if ( node - > props = = ZPL_ADT_PROPS_IS_EXP ) {
zpl_fprintf ( file , " %lld.%0*d%llde%lld " , ( long long ) node - > base , node - > base2_offset , 0 , ( long long ) node - > base2 , ( long long ) node - > exp ) ;
} else if ( node - > props = = ZPL_ADT_PROPS_IS_PARSED_REAL ) {
if ( ! node - > lead_digit )
zpl_fprintf ( file , " .%0*d%lld " , node - > base2_offset , 0 , ( long long ) node - > base2 ) ;
else
zpl_fprintf ( file , " %lld.%0*d%lld " , ( long long int ) node - > base2_offset , 0 , ( int ) node - > base , ( long long ) node - > base2 ) ;
# endif
} else {
zpl_fprintf ( file , " %f " , node - > real ) ;
}
} break ;
}
return ZPL_ADT_ERROR_NONE ;
}
zpl_adt_error zpl_adt_print_string ( zpl_file * file , zpl_adt_node * node , char const * escaped_chars , char const * escape_symbol ) {
ZPL_ASSERT_NOT_NULL ( file ) ;
ZPL_ASSERT_NOT_NULL ( node ) ;
ZPL_ASSERT_NOT_NULL ( escaped_chars ) ;
if ( node - > type ! = ZPL_ADT_TYPE_STRING & & node - > type ! = ZPL_ADT_TYPE_MULTISTRING ) {
return ZPL_ADT_ERROR_INVALID_TYPE ;
}
/* escape string */
char const * p = node - > string , * b = p ;
do {
p = zpl_str_skip_any ( p , escaped_chars ) ;
zpl_fprintf ( file , " %.*s " , zpl_ptr_diff ( b , p ) , b ) ;
if ( * p & & ! ! zpl_strchr ( escaped_chars , * p ) ) {
zpl_fprintf ( file , " %s%c " , escape_symbol , * p ) ;
p + + ;
}
b = p ;
} while ( * p ) ;
return ZPL_ADT_ERROR_NONE ;
}
zpl_adt_error zpl_adt_str_to_number ( zpl_adt_node * node ) {
ZPL_ASSERT ( node ) ;
if ( node - > type = = ZPL_ADT_TYPE_REAL | | node - > type = = ZPL_ADT_TYPE_INTEGER ) return ZPL_ADT_ERROR_ALREADY_CONVERTED ; /* this is already converted/parsed */
if ( node - > type ! = ZPL_ADT_TYPE_STRING & & node - > type ! = ZPL_ADT_TYPE_MULTISTRING ) {
return ZPL_ADT_ERROR_INVALID_TYPE ;
}
zpl_adt_parse_number ( node , ( char * ) node - > string ) ;
return ZPL_ADT_ERROR_NONE ;
}
ZPL_END_C_DECLS
/* parsers */
// file: source/parsers/json.c
////////////////////////////////////////////////////////////////
//
// JSON5 Parser
//
//
# ifdef ZPL_JSON_DEBUG
# define ZPL_JSON_ASSERT(msg) ZPL_PANIC(msg)
# else
# define ZPL_JSON_ASSERT(msg)
# endif
ZPL_BEGIN_C_DECLS
char * zpl__json_parse_object ( zpl_adt_node * obj , char * base , zpl_allocator a , zpl_u8 * err_code ) ;
char * zpl__json_parse_array ( zpl_adt_node * obj , char * base , zpl_allocator a , zpl_u8 * err_code ) ;
char * zpl__json_parse_value ( zpl_adt_node * obj , char * base , zpl_allocator a , zpl_u8 * err_code ) ;
char * zpl__json_parse_name ( zpl_adt_node * obj , char * base , zpl_u8 * err_code ) ;
char * zpl__json_trim ( char * base , zpl_b32 catch_newline ) ;
void zpl__json_write_value ( zpl_file * f , zpl_adt_node * o , zpl_adt_node * t , zpl_isize indent , zpl_b32 is_inline , zpl_b32 is_last ) ;
# define zpl___ind(x) if (x > 0) zpl_fprintf(f, "%*r", x, ' ');
zpl_u8 zpl_json_parse ( zpl_adt_node * root , char * text , zpl_allocator a ) {
zpl_u8 err_code = ZPL_JSON_ERROR_NONE ;
ZPL_ASSERT ( root ) ;
ZPL_ASSERT ( text ) ;
zpl_zero_item ( root ) ;
text = zpl__json_trim ( text , true ) ;
2023-01-15 15:59:33 +00:00
2022-09-11 17:42:06 +00:00
# ifndef ZPL_PARSER_DISABLE_ANALYSIS
if ( ! zpl_strchr ( " {[ " , * text ) ) {
root - > cfg_mode = true ;
}
# endif
2023-01-15 15:59:33 +00:00
2022-09-11 17:42:06 +00:00
zpl__json_parse_object ( root , text , a , & err_code ) ;
return err_code ;
}
void zpl_json_free ( zpl_adt_node * obj ) {
zpl_adt_destroy_branch ( obj ) ;
}
zpl_string zpl_json_write_string ( zpl_allocator a , zpl_adt_node * obj , zpl_isize indent ) {
zpl_file tmp ;
zpl_file_stream_new ( & tmp , a ) ;
zpl_json_write ( & tmp , obj , indent ) ;
zpl_isize fsize ;
zpl_u8 * buf = zpl_file_stream_buf ( & tmp , & fsize ) ;
zpl_string output = zpl_string_make_length ( a , ( char * ) buf , fsize + 1 ) ;
zpl_file_close ( & tmp ) ;
return output ;
}
/* private */
static ZPL_ALWAYS_INLINE zpl_b32 zpl__json_is_assign_char ( char c ) { return ! ! zpl_strchr ( " :=| " , c ) ; }
static ZPL_ALWAYS_INLINE zpl_b32 zpl__json_is_delim_char ( char c ) { return ! ! zpl_strchr ( " ,| \n " , c ) ; }
ZPL_DEF_INLINE zpl_b32 zpl__json_validate_name ( char const * str , char * err ) ;
# define jx(x) !zpl_char_is_hex_digit(str[x])
ZPL_IMPL_INLINE zpl_b32 zpl__json_validate_name ( char const * str , char * err ) {
while ( * str ) {
/* todo: refactor name validation. */
if ( ( str [ 0 ] = = ' \\ ' & & ! zpl_char_is_control ( str [ 1 ] ) ) & &
( str [ 0 ] = = ' \\ ' & & jx ( 1 ) & & jx ( 2 ) & & jx ( 3 ) & & jx ( 4 ) ) ) {
if ( err ) * err = * str ;
return false ;
}
2023-01-15 15:59:33 +00:00
2022-09-11 17:42:06 +00:00
+ + str ;
}
2023-01-15 15:59:33 +00:00
2022-09-11 17:42:06 +00:00
return true ;
}
# undef jx
char * zpl__json_parse_array ( zpl_adt_node * obj , char * base , zpl_allocator a , zpl_u8 * err_code ) {
ZPL_ASSERT ( obj & & base ) ;
char * p = base ;
2023-01-15 15:59:33 +00:00
2022-09-11 17:42:06 +00:00
obj - > type = ZPL_ADT_TYPE_ARRAY ;
zpl_array_init ( obj - > nodes , a ) ;
2023-01-15 15:59:33 +00:00
2022-09-11 17:42:06 +00:00
while ( * p ) {
p = zpl__json_trim ( p , false ) ;
2023-01-15 15:59:33 +00:00
2022-09-11 17:42:06 +00:00
if ( * p = = ' ] ' ) {
return p ;
}
2023-01-15 15:59:33 +00:00
2022-09-11 17:42:06 +00:00
zpl_adt_node elem = { 0 } ;
p = zpl__json_parse_value ( & elem , p , a , err_code ) ;
2023-01-15 15:59:33 +00:00
2022-09-11 17:42:06 +00:00
if ( * err_code ! = ZPL_JSON_ERROR_NONE ) { return NULL ; }
2023-01-15 15:59:33 +00:00
2022-09-11 17:42:06 +00:00
zpl_array_append ( obj - > nodes , elem ) ;
2023-01-15 15:59:33 +00:00
zpl_array_end ( obj - > nodes ) - > parent = obj ;
2022-09-11 17:42:06 +00:00
p = zpl__json_trim ( p , false ) ;
2023-01-15 15:59:33 +00:00
2022-09-11 17:42:06 +00:00
if ( * p = = ' , ' ) {
+ + p ;
continue ;
} else {
if ( * p ! = ' ] ' ) {
ZPL_JSON_ASSERT ( " end of array unfulfilled " ) ;
* err_code = ZPL_JSON_ERROR_ARRAY_LEFT_OPEN ;
return NULL ;
}
return p ;
}
}
2023-01-15 15:59:33 +00:00
2022-09-11 17:42:06 +00:00
* err_code = ZPL_JSON_ERROR_INTERNAL ;
return NULL ;
}
char * zpl__json_parse_value ( zpl_adt_node * obj , char * base , zpl_allocator a , zpl_u8 * err_code ) {
ZPL_ASSERT ( obj & & base ) ;
char * p = base , * b = p , * e = p ;
2023-01-15 15:59:33 +00:00
2022-09-11 17:42:06 +00:00
/* handle quoted strings */
if ( ! ! zpl_strchr ( " ` \" ' " , * p ) ) {
char c = * p ;
obj - > type = ( c = = ' ` ' ) ? ZPL_ADT_TYPE_MULTISTRING : ZPL_ADT_TYPE_STRING ;
b = e = p + 1 ;
obj - > string = b ;
e = cast ( char * ) zpl_str_skip_literal ( e , c ) ;
* e = ' \0 ' , p = e + 1 ;
} else if ( zpl_char_is_alpha ( * p ) | | ( * p = = ' - ' & & ! zpl_char_is_digit ( * ( p + 1 ) ) ) ) {
/* handle constants */
if ( zpl_str_has_prefix ( p , " true " ) ) {
obj - > type = ZPL_ADT_TYPE_REAL ;
obj - > props = ZPL_ADT_PROPS_TRUE ;
obj - > real = 1 ;
p + = 4 ;
} else if ( zpl_str_has_prefix ( p , " false " ) ) {
obj - > type = ZPL_ADT_TYPE_REAL ;
obj - > props = ZPL_ADT_PROPS_FALSE ;
obj - > real = 0 ;
p + = 5 ;
} else if ( zpl_str_has_prefix ( p , " null " ) ) {
obj - > type = ZPL_ADT_TYPE_REAL ;
obj - > props = ZPL_ADT_PROPS_NULL ;
obj - > real = 0 ;
p + = 4 ;
} else if ( zpl_str_has_prefix ( p , " Infinity " ) ) {
obj - > type = ZPL_ADT_TYPE_REAL ;
obj - > real = ZPL_INFINITY ;
obj - > props = ZPL_ADT_PROPS_INFINITY ;
p + = 8 ;
} else if ( zpl_str_has_prefix ( p , " -Infinity " ) ) {
obj - > type = ZPL_ADT_TYPE_REAL ;
obj - > real = - ZPL_INFINITY ;
obj - > props = ZPL_ADT_PROPS_INFINITY_NEG ;
p + = 9 ;
} else if ( zpl_str_has_prefix ( p , " NaN " ) ) {
obj - > type = ZPL_ADT_TYPE_REAL ;
obj - > real = ZPL_NAN ;
obj - > props = ZPL_ADT_PROPS_NAN ;
p + = 3 ;
} else if ( zpl_str_has_prefix ( p , " -NaN " ) ) {
obj - > type = ZPL_ADT_TYPE_REAL ;
obj - > real = - ZPL_NAN ;
obj - > props = ZPL_ADT_PROPS_NAN_NEG ;
p + = 4 ;
} else {
ZPL_JSON_ASSERT ( " unknown keyword " ) ;
* err_code = ZPL_JSON_ERROR_UNKNOWN_KEYWORD ;
return NULL ;
}
} else if ( zpl_char_is_digit ( * p ) | | * p = = ' + ' | | * p = = ' - ' | | * p = = ' . ' ) {
/* handle numbers */
/* defer operation to our helper method. */
p = zpl_adt_parse_number ( obj , p ) ;
} else if ( ! ! zpl_strchr ( " [{ " , * p ) ) {
/* handle compound objects */
p = zpl__json_parse_object ( obj , p , a , err_code ) ;
+ + p ;
}
2023-01-15 15:59:33 +00:00
2022-09-11 17:42:06 +00:00
return p ;
}
char * zpl__json_parse_object ( zpl_adt_node * obj , char * base , zpl_allocator a , zpl_u8 * err_code ) {
ZPL_ASSERT ( obj & & base ) ;
char * p = base ;
2023-01-15 15:59:33 +00:00
2022-09-11 17:42:06 +00:00
p = zpl__json_trim ( p , false ) ;
/**/ if ( * p = = ' { ' ) { + + p ; }
else if ( * p = = ' [ ' ) { /* special case for when we call this func on an array. */
+ + p ;
obj - > type = ZPL_ADT_TYPE_ARRAY ;
return zpl__json_parse_array ( obj , p , a , err_code ) ;
}
2023-01-15 15:59:33 +00:00
2022-09-11 17:42:06 +00:00
zpl_array_init ( obj - > nodes , a ) ;
obj - > type = ZPL_ADT_TYPE_OBJECT ;
2023-01-15 15:59:33 +00:00
2022-09-11 17:42:06 +00:00
do {
zpl_adt_node node = { 0 } ;
p = zpl__json_trim ( p , false ) ;
if ( * p = = ' } ' & & obj - > type = = ZPL_ADT_TYPE_OBJECT ) return p ;
else if ( * p = = ' ] ' & & obj - > type = = ZPL_ADT_TYPE_ARRAY ) return p ;
else if ( ! ! zpl_strchr ( " }] " , * p ) ) {
ZPL_JSON_ASSERT ( " mismatched end pair " ) ;
* err_code = ZPL_JSON_ERROR_OBJECT_END_PAIR_MISMATCHED ;
return NULL ;
}
2023-01-15 15:59:33 +00:00
2022-09-11 17:42:06 +00:00
/* First, we parse the key, then we proceed to the value itself. */
p = zpl__json_parse_name ( & node , p , err_code ) ;
if ( err_code & & * err_code ! = ZPL_JSON_ERROR_NONE ) { return NULL ; }
p = zpl__json_trim ( p + 1 , false ) ;
p = zpl__json_parse_value ( & node , p , a , err_code ) ;
if ( err_code & & * err_code ! = ZPL_JSON_ERROR_NONE ) { return NULL ; }
2023-01-15 15:59:33 +00:00
2022-09-11 17:42:06 +00:00
zpl_array_append ( obj - > nodes , node ) ;
2023-01-15 15:59:33 +00:00
zpl_array_end ( obj - > nodes ) - > parent = obj ;
2022-09-11 17:42:06 +00:00
char * end_p = p ; zpl_unused ( end_p ) ;
p = zpl__json_trim ( p , true ) ;
2023-01-15 15:59:33 +00:00
2022-09-11 17:42:06 +00:00
/* this code analyses the keyvalue pair delimiter used in the packet. */
if ( zpl__json_is_delim_char ( * p ) ) {
# ifndef ZPL_PARSER_DISABLE_ANALYSIS
zpl_adt_node * n = zpl_array_end ( obj - > nodes ) ;
n - > delim_style = ZPL_ADT_DELIM_STYLE_COMMA ;
2023-01-15 15:59:33 +00:00
2022-09-11 17:42:06 +00:00
if ( * p = = ' \n ' )
n - > delim_style = ZPL_ADT_DELIM_STYLE_NEWLINE ;
else if ( * p = = ' | ' ) {
n - > delim_style = ZPL_ADT_DELIM_STYLE_LINE ;
n - > delim_line_width = cast ( zpl_u8 ) ( p - end_p ) ;
}
# endif
+ + p ;
}
p = zpl__json_trim ( p , false ) ;
} while ( * p ) ;
return p ;
}
char * zpl__json_parse_name ( zpl_adt_node * node , char * base , zpl_u8 * err_code ) {
char * p = base , * b = p , * e = p ;
zpl_u8 name_style = 0 ;
2023-01-15 15:59:33 +00:00
2022-09-11 17:42:06 +00:00
if ( * p = = ' " ' | | * p = = ' \' ' | | zpl_char_is_alpha ( * p ) | | * p = = ' _ ' | | * p = = ' $ ' ) {
if ( * p = = ' " ' | | * p = = ' \' ' ) {
# ifndef ZPL_PARSER_DISABLE_ANALYSIS
if ( * p = = ' " ' ) {
node - > name_style = ZPL_ADT_NAME_STYLE_DOUBLE_QUOTE ;
} else if ( * p = = ' \' ' ) {
node - > name_style = ZPL_ADT_NAME_STYLE_SINGLE_QUOTE ;
}
# endif
char c = * p ;
b = + + p ;
e = cast ( char * ) zpl_str_control_skip ( b , c ) ;
node - > name = b ;
2023-01-15 15:59:33 +00:00
2022-09-11 17:42:06 +00:00
/* we can safely null-terminate here, since "e" points to the quote pair end. */
* e + + = ' \0 ' ;
}
else {
b = e = p ;
zpl_str_advance_while ( e , * e & & ( zpl_char_is_alphanumeric ( * e ) | | * e = = ' _ ' ) & & ! zpl_char_is_space ( * e ) & & ! zpl__json_is_assign_char ( * e ) ) ;
node - > name = b ;
name_style = ZPL_ADT_NAME_STYLE_NO_QUOTES ;
/* we defer null-termination as it can potentially wipe our assign char as well. */
}
2023-01-15 15:59:33 +00:00
2022-09-11 17:42:06 +00:00
char * assign_p = e ; zpl_unused ( assign_p ) ;
p = zpl__json_trim ( e , false ) ;
# ifndef ZPL_PARSER_DISABLE_ANALYSIS
node - > assign_line_width = cast ( zpl_u8 ) ( p - assign_p ) ;
# endif
2023-01-15 15:59:33 +00:00
2022-09-11 17:42:06 +00:00
if ( * p & & ! zpl__json_is_assign_char ( * p ) ) {
ZPL_JSON_ASSERT ( " invalid assignment " ) ;
* err_code = ZPL_JSON_ERROR_INVALID_ASSIGNMENT ;
return NULL ;
}
else
{
# ifndef ZPL_PARSER_DISABLE_ANALYSIS
if ( * p = = ' = ' )
node - > assign_style = ZPL_ADT_ASSIGN_STYLE_EQUALS ;
else if ( * p = = ' | ' )
node - > assign_style = ZPL_ADT_ASSIGN_STYLE_LINE ;
else node - > assign_style = ZPL_ADT_ASSIGN_STYLE_COLON ;
# endif
}
2023-01-15 15:59:33 +00:00
2022-09-11 17:42:06 +00:00
/* since we already know the assign style, we can cut it here for unquoted names */
if ( name_style = = ZPL_ADT_NAME_STYLE_NO_QUOTES & & * e ) {
* e = ' \0 ' ;
# ifndef ZPL_PARSER_DISABLE_ANALYSIS
node - > name_style = name_style ;
# endif
}
}
2023-01-15 15:59:33 +00:00
2022-09-11 17:42:06 +00:00
if ( node - > name & & ! zpl__json_validate_name ( node - > name , NULL ) ) {
ZPL_JSON_ASSERT ( " invalid name " ) ;
* err_code = ZPL_JSON_ERROR_INVALID_NAME ;
return NULL ;
}
2023-01-15 15:59:33 +00:00
2022-09-11 17:42:06 +00:00
return p ;
}
char * zpl__json_trim ( char * base , zpl_b32 catch_newline ) {
ZPL_ASSERT_NOT_NULL ( base ) ;
char * p = base ;
do {
if ( zpl_str_has_prefix ( p , " // " ) ) {
const char * e = zpl_str_skip ( p , ' \n ' ) ;
p + = ( e - p ) ;
}
else if ( zpl_str_has_prefix ( p , " /* " ) ) {
const char * e = zpl_str_skip ( p + 2 , ' * ' ) ;
if ( * e & & * ( e + 1 ) = = ' / ' ) {
e + = 2 ; /* advance past end comment block */
p + = ( e - p ) ;
}
}
else if ( * p = = ' \n ' & & catch_newline ) {
return p ;
}
else if ( ! zpl_char_is_space ( * p ) ) {
return p ;
}
} while ( * p + + ) ;
return NULL ;
}
void zpl_json_write ( zpl_file * f , zpl_adt_node * o , zpl_isize indent ) {
if ( ! o )
return ;
2023-01-15 15:59:33 +00:00
2022-09-11 17:42:06 +00:00
ZPL_ASSERT ( o - > type = = ZPL_ADT_TYPE_OBJECT | | o - > type = = ZPL_ADT_TYPE_ARRAY ) ;
2023-01-15 15:59:33 +00:00
2022-09-11 17:42:06 +00:00
zpl___ind ( indent - 4 ) ;
# ifndef ZPL_PARSER_DISABLE_ANALYSIS
if ( ! o - > cfg_mode )
# else
if ( 1 )
# endif
2023-01-15 15:59:33 +00:00
zpl_fprintf ( f , " %c \n " , o - > type = = ZPL_ADT_TYPE_OBJECT ? ' { ' : ' [ ' ) ;
2022-09-11 17:42:06 +00:00
else
{
indent - = 4 ;
}
2023-01-15 15:59:33 +00:00
2022-09-11 17:42:06 +00:00
if ( o - > nodes ) {
zpl_isize cnt = zpl_array_count ( o - > nodes ) ;
2023-01-15 15:59:33 +00:00
2022-09-11 17:42:06 +00:00
for ( int i = 0 ; i < cnt ; + + i ) {
zpl__json_write_value ( f , o - > nodes + i , o , indent , false , ! ( i < cnt - 1 ) ) ;
}
}
2023-01-15 15:59:33 +00:00
2022-09-11 17:42:06 +00:00
zpl___ind ( indent ) ;
2023-01-15 15:59:33 +00:00
2022-09-11 17:42:06 +00:00
if ( indent > 0 ) {
zpl_fprintf ( f , " %c " , o - > type = = ZPL_ADT_TYPE_OBJECT ? ' } ' : ' ] ' ) ;
} else {
# ifndef ZPL_PARSER_DISABLE_ANALYSIS
if ( ! o - > cfg_mode )
# endif
2023-01-15 15:59:33 +00:00
zpl_fprintf ( f , " %c \n " , o - > type = = ZPL_ADT_TYPE_OBJECT ? ' } ' : ' ] ' ) ;
2022-09-11 17:42:06 +00:00
}
}
void zpl__json_write_value ( zpl_file * f , zpl_adt_node * o , zpl_adt_node * t , zpl_isize indent , zpl_b32 is_inline , zpl_b32 is_last ) {
zpl_adt_node * node = o ;
indent + = 4 ;
2023-01-15 15:59:33 +00:00
2022-09-11 17:42:06 +00:00
if ( ! is_inline ) {
zpl___ind ( indent ) ;
2023-01-15 15:59:33 +00:00
2022-09-11 17:42:06 +00:00
if ( t - > type ! = ZPL_ADT_TYPE_ARRAY ) {
# ifndef ZPL_PARSER_DISABLE_ANALYSIS
switch ( node - > name_style ) {
case ZPL_ADT_NAME_STYLE_DOUBLE_QUOTE : {
zpl_fprintf ( f , " \" %s \" " , node - > name ) ;
} break ;
2023-01-15 15:59:33 +00:00
2022-09-11 17:42:06 +00:00
case ZPL_ADT_NAME_STYLE_SINGLE_QUOTE : {
zpl_fprintf ( f , " \' %s \' " , node - > name ) ;
} break ;
2023-01-15 15:59:33 +00:00
2022-09-11 17:42:06 +00:00
case ZPL_ADT_NAME_STYLE_NO_QUOTES : {
zpl_fprintf ( f , " %s " , node - > name ) ;
} break ;
}
2023-01-15 15:59:33 +00:00
2022-09-11 17:42:06 +00:00
if ( o - > assign_style = = ZPL_ADT_ASSIGN_STYLE_COLON )
zpl_fprintf ( f , " : " ) ;
else {
zpl___ind ( zpl_max ( o - > assign_line_width , 1 ) ) ;
2023-01-15 15:59:33 +00:00
2022-09-11 17:42:06 +00:00
if ( o - > assign_style = = ZPL_ADT_ASSIGN_STYLE_EQUALS )
zpl_fprintf ( f , " = " ) ;
else if ( o - > assign_style = = ZPL_ADT_ASSIGN_STYLE_LINE ) {
zpl_fprintf ( f , " | " ) ;
}
}
# else
zpl_fprintf ( f , " \" %s \" : " , node - > name ) ;
# endif
}
}
2023-01-15 15:59:33 +00:00
2022-09-11 17:42:06 +00:00
switch ( node - > type ) {
case ZPL_ADT_TYPE_STRING : {
zpl_fprintf ( f , " \" " ) ;
zpl_adt_print_string ( f , node , " \" " , " \\ " ) ;
zpl_fprintf ( f , " \" " ) ;
} break ;
2023-01-15 15:59:33 +00:00
2022-09-11 17:42:06 +00:00
case ZPL_ADT_TYPE_MULTISTRING : {
zpl_fprintf ( f , " ` " ) ;
zpl_adt_print_string ( f , node , " ` " , " \\ " ) ;
zpl_fprintf ( f , " ` " ) ;
} break ;
2023-01-15 15:59:33 +00:00
2022-09-11 17:42:06 +00:00
case ZPL_ADT_TYPE_ARRAY : {
zpl_fprintf ( f , " [ " ) ;
zpl_isize elemn = zpl_array_count ( node - > nodes ) ;
for ( int j = 0 ; j < elemn ; + + j ) {
zpl_isize ind = ( ( node - > nodes + j ) - > type = = ZPL_ADT_TYPE_OBJECT | | ( node - > nodes + j ) - > type = = ZPL_ADT_TYPE_ARRAY ) ? 0 : - 4 ;
zpl__json_write_value ( f , node - > nodes + j , o , ind , true , true ) ;
2023-01-15 15:59:33 +00:00
2022-09-11 17:42:06 +00:00
if ( j < elemn - 1 ) { zpl_fprintf ( f , " , " ) ; }
}
zpl_fprintf ( f , " ] " ) ;
} break ;
2023-01-15 15:59:33 +00:00
2022-09-11 17:42:06 +00:00
case ZPL_ADT_TYPE_REAL :
case ZPL_ADT_TYPE_INTEGER : {
zpl_adt_print_number ( f , node ) ;
} break ;
2023-01-15 15:59:33 +00:00
2022-09-11 17:42:06 +00:00
case ZPL_ADT_TYPE_OBJECT : {
zpl_json_write ( f , node , indent ) ;
} break ;
}
2023-01-15 15:59:33 +00:00
2022-09-11 17:42:06 +00:00
if ( ! is_inline ) {
# ifndef ZPL_PARSER_DISABLE_ANALYSIS
if ( o - > delim_style ! = ZPL_ADT_DELIM_STYLE_COMMA ) {
if ( o - > delim_style = = ZPL_ADT_DELIM_STYLE_NEWLINE )
zpl_fprintf ( f , " \n " ) ;
else if ( o - > delim_style = = ZPL_ADT_DELIM_STYLE_LINE ) {
zpl___ind ( o - > delim_line_width ) ;
zpl_fprintf ( f , " | \n " ) ;
}
}
else {
if ( ! is_last ) {
zpl_fprintf ( f , " , \n " ) ;
} else {
zpl_fprintf ( f , " \n " ) ;
}
}
# else
if ( ! is_last ) {
zpl_fprintf ( f , " , \n " ) ;
} else {
zpl_fprintf ( f , " \n " ) ;
}
# endif
}
}
# undef zpl___ind
ZPL_END_C_DECLS
// file: source/parsers/csv.c
# ifdef ZPL_CSV_DEBUG
# define ZPL_CSV_ASSERT(msg) ZPL_PANIC(msg)
# else
# define ZPL_CSV_ASSERT(msg)
# endif
ZPL_BEGIN_C_DECLS
zpl_u8 zpl_csv_parse_delimiter ( zpl_csv_object * root , char * text , zpl_allocator allocator , zpl_b32 has_header , char delim ) {
zpl_csv_error err = ZPL_CSV_ERROR_NONE ;
ZPL_ASSERT_NOT_NULL ( root ) ;
ZPL_ASSERT_NOT_NULL ( text ) ;
zpl_zero_item ( root ) ;
zpl_adt_make_branch ( root , allocator , NULL , has_header ? false : true ) ;
char * p = text , * b = p , * e = p ;
zpl_isize colc = 0 , total_colc = 0 ;
do {
char d = 0 ;
p = cast ( char * ) zpl_str_trim ( p , false ) ;
if ( * p = = 0 ) break ;
zpl_adt_node row_item = { 0 } ;
row_item . type = ZPL_ADT_TYPE_STRING ;
# ifndef ZPL_PARSER_DISABLE_ANALYSIS
row_item . name_style = ZPL_ADT_NAME_STYLE_NO_QUOTES ;
# endif
/* handle string literals */
if ( * p = = ' " ' ) {
p = b = e = p + 1 ;
row_item . string = b ;
# ifndef ZPL_PARSER_DISABLE_ANALYSIS
row_item . name_style = ZPL_ADT_NAME_STYLE_DOUBLE_QUOTE ;
# endif
do {
e = cast ( char * ) zpl_str_skip ( e , ' " ' ) ;
if ( * e & & * ( e + 1 ) = = ' " ' ) {
e + = 2 ;
}
else break ;
} while ( * e ) ;
if ( * e = = 0 ) {
ZPL_CSV_ASSERT ( " unmatched quoted string " ) ;
err = ZPL_CSV_ERROR_UNEXPECTED_END_OF_INPUT ;
return err ;
}
* e = 0 ;
p = cast ( char * ) zpl_str_trim ( e + 1 , true ) ;
d = * p ;
/* unescape escaped quotes (so that unescaped text escapes :) */
{
char * ep = b ;
do {
if ( * ep = = ' " ' & & * ( ep + 1 ) = = ' " ' ) {
zpl_memmove ( ep , ep + 1 , zpl_strlen ( ep ) ) ;
}
ep + + ;
} while ( * ep ) ;
}
}
else if ( * p = = delim ) {
d = * p ;
row_item . string = " " ;
}
else if ( * p ) {
/* regular data */
b = e = p ;
row_item . string = b ;
do {
e + + ;
} while ( * e & & * e ! = delim & & * e ! = ' \n ' ) ;
if ( * e ) {
p = cast ( char * ) zpl_str_trim ( e , true ) ;
while ( zpl_char_is_space ( * ( e - 1 ) ) ) { e - - ; }
d = * p ;
* e = 0 ;
}
else {
d = 0 ;
p = e ;
}
/* check if number and process if so */
zpl_b32 skip_number = false ;
char * num_p = b ;
do {
if ( ! zpl_char_is_hex_digit ( * num_p ) & & ( ! zpl_strchr ( " +-.eExX " , * num_p ) ) ) {
skip_number = true ;
break ;
}
} while ( * num_p + + ) ;
if ( ! skip_number ) {
zpl_adt_str_to_number ( & row_item ) ;
}
}
if ( colc > = zpl_array_count ( root - > nodes ) ) {
zpl_adt_append_arr ( root , NULL ) ;
}
zpl_array_append ( root - > nodes [ colc ] . nodes , row_item ) ;
if ( d = = delim ) {
colc + + ;
p + + ;
}
else if ( d = = ' \n ' | | d = = 0 ) {
/* check if number of rows is not mismatched */
if ( total_colc < colc ) total_colc = colc ;
else if ( total_colc ! = colc ) {
ZPL_CSV_ASSERT ( " mismatched rows " ) ;
err = ZPL_CSV_ERROR_MISMATCHED_ROWS ;
return err ;
}
colc = 0 ;
if ( d ! = 0 ) p + + ;
}
} while ( * p ) ;
if ( zpl_array_count ( root - > nodes ) = = 0 ) {
ZPL_CSV_ASSERT ( " unexpected end of input. stream is empty. " ) ;
err = ZPL_CSV_ERROR_UNEXPECTED_END_OF_INPUT ;
return err ;
}
/* consider first row as a header. */
if ( has_header ) {
for ( zpl_isize i = 0 ; i < zpl_array_count ( root - > nodes ) ; i + + ) {
zpl_csv_object * col = root - > nodes + i ;
zpl_csv_object * hdr = col - > nodes ;
col - > name = hdr - > string ;
zpl_array_remove_at ( col - > nodes , 0 ) ;
}
}
return err ;
}
void zpl_csv_free ( zpl_csv_object * obj ) {
zpl_adt_destroy_branch ( obj ) ;
}
void zpl__csv_write_record ( zpl_file * file , zpl_csv_object * node ) {
switch ( node - > type ) {
case ZPL_ADT_TYPE_STRING : {
# ifndef ZPL_PARSER_DISABLE_ANALYSIS
switch ( node - > name_style ) {
case ZPL_ADT_NAME_STYLE_DOUBLE_QUOTE : {
zpl_fprintf ( file , " \" " ) ;
zpl_adt_print_string ( file , node , " \" " , " \" " ) ;
zpl_fprintf ( file , " \" " ) ;
} break ;
case ZPL_ADT_NAME_STYLE_NO_QUOTES : {
# endif
zpl_fprintf ( file , " %s " , node - > string ) ;
# ifndef ZPL_PARSER_DISABLE_ANALYSIS
} break ;
}
# endif
} break ;
case ZPL_ADT_TYPE_REAL :
case ZPL_ADT_TYPE_INTEGER : {
zpl_adt_print_number ( file , node ) ;
} break ;
}
}
void zpl__csv_write_header ( zpl_file * file , zpl_csv_object * header ) {
zpl_csv_object temp = * header ;
temp . string = temp . name ;
temp . type = ZPL_ADT_TYPE_STRING ;
zpl__csv_write_record ( file , & temp ) ;
}
void zpl_csv_write_delimiter ( zpl_file * file , zpl_csv_object * obj , char delimiter ) {
ZPL_ASSERT_NOT_NULL ( file ) ;
ZPL_ASSERT_NOT_NULL ( obj ) ;
ZPL_ASSERT ( obj - > nodes ) ;
zpl_isize cols = zpl_array_count ( obj - > nodes ) ;
if ( cols = = 0 ) return ;
zpl_isize rows = zpl_array_count ( obj - > nodes [ 0 ] . nodes ) ;
if ( rows = = 0 ) return ;
zpl_b32 has_headers = obj - > nodes [ 0 ] . name ! = NULL ;
if ( has_headers ) {
for ( zpl_isize i = 0 ; i < cols ; i + + ) {
zpl__csv_write_header ( file , & obj - > nodes [ i ] ) ;
if ( i + 1 ! = cols ) {
zpl_fprintf ( file , " %c " , delimiter ) ;
}
}
zpl_fprintf ( file , " \n " ) ;
}
for ( zpl_isize r = 0 ; r < rows ; r + + ) {
for ( zpl_isize i = 0 ; i < cols ; i + + ) {
zpl__csv_write_record ( file , & obj - > nodes [ i ] . nodes [ r ] ) ;
if ( i + 1 ! = cols ) {
zpl_fprintf ( file , " %c " , delimiter ) ;
}
}
zpl_fprintf ( file , " \n " ) ;
}
}
zpl_string zpl_csv_write_string_delimiter ( zpl_allocator a , zpl_csv_object * obj , char delimiter ) {
zpl_file tmp ;
zpl_file_stream_new ( & tmp , a ) ;
zpl_csv_write_delimiter ( & tmp , obj , delimiter ) ;
zpl_isize fsize ;
zpl_u8 * buf = zpl_file_stream_buf ( & tmp , & fsize ) ;
zpl_string output = zpl_string_make_length ( a , ( char * ) buf , fsize + 1 ) ;
zpl_file_close ( & tmp ) ;
return output ;
}
ZPL_END_C_DECLS
2021-11-29 08:23:08 +00:00
# endif
# if defined(ZPL_COMPILER_MSVC)
# pragma warning(pop)
# endif
# if defined(__GCC__) || defined(__GNUC__) || defined(__clang__)
# pragma GCC diagnostic pop
# endif
# endif // ZPL_IMPLEMENTATION
# if !defined(ZPL_PICO_CUSTOM_ROUTINES)
# undef zpl__printf_err
# undef zpl__printf_err_va
# undef zpl__strlen
# endif
# if defined(ZPL_EXPOSE_TYPES)
2022-09-11 17:42:06 +00:00
typedef zpl_u8 u8 ;
typedef zpl_i8 i8 ;
typedef zpl_u16 u16 ;
typedef zpl_i16 i16 ;
typedef zpl_u32 u32 ;
typedef zpl_i32 i32 ;
typedef zpl_u64 u64 ;
typedef zpl_i64 i64 ;
typedef zpl_b8 b8 ;
typedef zpl_b16 b16 ;
typedef zpl_b32 b32 ;
typedef zpl_f32 f32 ;
typedef zpl_f64 f64 ;
typedef zpl_rune rune ;
typedef zpl_usize usize ;
typedef zpl_isize isize ;
typedef zpl_uintptr uintptr ;
typedef zpl_intptr intptr ;
2021-11-29 08:23:08 +00:00
# endif // ZPL_EXPOSE_TYPES
# endif // ZPL_H
// TOC:
// zpl.h
// zpl_hedley.h
// header/opts.h
// header/essentials/helpers.h
// header/essentials/memory.h
// header/essentials/memory_custom.h
// header/essentials/types.h
// header/essentials/collections/buffer.h
// header/essentials/collections/list.h
// header/essentials/collections/hashtable.h
// header/essentials/collections/ring.h
// header/essentials/collections/array.h
// header/essentials/debug.h
// header/process.h
// header/threading/fence.h
// header/threading/mutex.h
// header/threading/sync.h
// header/threading/affinity.h
// header/threading/atomic.h
// header/threading/thread.h
// header/threading/sem.h
// header/math.h
// header/jobs.h
// header/parsers/json.h
// header/parsers/csv.h
// header/dll.h
// header/adt.h
// header/core/file_tar.h
// header/core/memory_virtual.h
// header/core/random.h
// header/core/file_stream.h
// header/core/string.h
// header/core/misc.h
// header/core/file.h
// header/core/stringlib.h
// header/core/sort.h
// header/core/print.h
// header/core/system.h
// header/core/file_misc.h
// header/core/time.h
// header/hashing.h
// header/regex.h
// source/hashing.c
// source/adt.c
// source/process.c
// source/essentials/array.c
// source/essentials/debug.c
// source/essentials/memory_custom.c
// source/essentials/memory.c
// source/dll.c
// source/regex.c
// source/threading/mutex.c
// source/threading/affinity.c
// source/threading/atomic.c
// source/threading/sync.c
// source/threading/thread.c
// source/threading/fence.c
// source/threading/sem.c
// source/parsers/csv.c
// source/parsers/json.c
// source/jobs.c
// source/core/file_stream.c
// source/core/stringlib.c
// source/core/misc.c
// source/core/file_misc.c
// source/core/file.c
// source/core/memory_virtual.c
// source/core/print.c
// source/core/time.c
// source/core/string.c
2022-09-11 17:42:06 +00:00
// source/core/random.c
// source/core/sort.c
// source/core/file_tar.c
// source/opts.c
// source/math.c