diff --git a/architecture/Intrinsics.h b/architecture/Intrinsics.h new file mode 100644 index 0000000..7399a6f --- /dev/null +++ b/architecture/Intrinsics.h @@ -0,0 +1,18 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_ARCHITECTURE_INTRINSICS_H +#define TOS_ARCHITECTURE_INTRINSICS_H + +#if ARM + #include "arm/Intrinsics.h" +#else + #include "x86/Intrinsics.h" +#endif + +#endif \ No newline at end of file diff --git a/architecture/arm/CpuInfo.cpp b/architecture/arm/CpuInfo.cpp index 5db8d38..163ae84 100644 --- a/architecture/arm/CpuInfo.cpp +++ b/architecture/arm/CpuInfo.cpp @@ -36,9 +36,9 @@ uint64 cpu_info_features() { return feature_bitfield; } -void cpu_info_cache(int32_t level, CpuCacheInfo* cache) { - uint32_t ccsidr; // Cache Size ID Register - uint32_t line_size, associativity, num_sets; +void cpu_info_cache(int32 level, CpuCacheInfo* cache) { + uint32 ccsidr; // Cache Size ID Register + uint32 line_size, associativity, num_sets; cache->level = level; cache->size = 0; @@ -48,9 +48,9 @@ void cpu_info_cache(int32_t level, CpuCacheInfo* cache) { cache->line_size = 0; // Select cache level and type in CSSELR - uint32_t csselr = level << 1; // Data or unified cache - __asm__ volatile("msr csselr_el1, %0" : : "r" (csselr)); - __asm__ volatile("mrs %0, ccsidr_el1" : "=r" (ccsidr)); + uint32 csselr = level << 1; // Data or unified cache + asm volatile("msr csselr_el1, %0" : : "r" (csselr)); + asm volatile("mrs %0, ccsidr_el1" : "=r" (ccsidr)); // Extract cache details from CCSIDR line_size = (ccsidr & 0x7) + 4; // Line size in log2 words diff --git a/architecture/arm/Intrinsics.h b/architecture/arm/Intrinsics.h new file mode 100644 index 0000000..3af425f --- /dev/null +++ b/architecture/arm/Intrinsics.h @@ -0,0 +1,40 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_ARCHITECTURE_ARM_INTRINSICS_ARM_H +#define TOS_ARCHITECTURE_ARM_INTRINSICS_ARM_H + +#include +#include + +#include "../../stdlib/Types.h" + +#define intrin_sqrt_f32(a) svget1_f32(svsqrt_f32(svdup_f32((a)))) +#define intrin_sqrt_f64(a) svget1_f64(svsqrt_f64(svdup_f64((a)))) + +#define intrin_rsqrt_f32(a) svget1_f32(svrsqrte_f32(svdup_f32((a)))) +#define intrin_rsqrt_f64(a) svget1_f64(svrsqrte_f64(svdup_f64((a)))) + +#define intrin_round_f32(a) svget1_f32(svrndn_f32(svdup_f32((a)))) +#define intrin_round_to_int32(a) svget1_s32(svcvtn_f32_s32(svdup_f32((a)), SVE_32B)) +#define intrin_floor_f32(a) svget1_f32(svfloor_f32(svdup_f32((a)))) +#define intrin_ceil_f32(a) svget1_f32(svceil_f32(svdup_f32((a)))) + +#define intrin_fence_memory() __dmb(0xF) +#define intrin_fence_write() __dmb(0xB) +#define intrin_fence_load() __dmb(0x7) +#define intrin_invalidate_cache() asm volatile("dc ivac, %0" : : "r"(address) : "memory") + +#define intrin_crc32_u8(crc, data) __crc32b((crc), (data)) +#define intrin_crc32_u16(crc, data) __crc32h((crc), (data)) +#define intrin_crc32_u32(crc, data) __crc32w((crc), (data)) +#define intrin_crc32_u64(crc, data) __crc32d((crc), (data)) + +#define intrin_timestamp_counter() ({ uint64_t cntvct; asm volatile("mrs %0, cntvct_el0" : "=r"(cntvct)); cntvct; }) + +#endif \ No newline at end of file diff --git a/architecture/x86/CpuInfo.cpp b/architecture/x86/CpuInfo.cpp index 4f3263f..a8f86df 100644 --- a/architecture/x86/CpuInfo.cpp +++ b/architecture/x86/CpuInfo.cpp @@ -33,7 +33,7 @@ static inline void cpuid(int32 cpuInfo[4], int32 function_id) { - __asm__ volatile( + asm volatile( "cpuid" : "=a" (cpuInfo[0]), "=b" (cpuInfo[1]), "=c" (cpuInfo[2]), "=d" (cpuInfo[3]) : "a" (function_id) diff --git a/architecture/x86/Intrinsics.h b/architecture/x86/Intrinsics.h new file mode 100644 index 0000000..1c8fd89 --- /dev/null +++ b/architecture/x86/Intrinsics.h @@ -0,0 +1,56 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_ARCHITECTURE_X86_INTRINSICS_H +#define TOS_ARCHITECTURE_X86_INTRINSICS_H + +#include +#include + +#if _WIN32 + #include +#elif __linux__ + #include + #include +#endif + +#include "../../stdlib/Types.h" + +#ifdef _MSC_VER + #define intrin_sqrt_f32(a) _mm_cvtss_f32(_mm_sqrt_ss(_mm_set_ss((a)))) +#else + #define intrin_sqrt_f32(a) ({ float res; asm volatile("sqrtss %0, %1" : "=x"(res) : "x"(a)); res; }) +#endif + +#ifdef _MSC_VER + #define intrin_sqrt_f64(a) _mm_cvtsd_f64(_mm_sqrt_sd(_mm_set_sd((a)), _mm_set_sd((a)))) +#else + #define intrin_sqrt_f64(a) ({ double res; asm volatile("sqrtsd %0, %1" : "=x" (res) : "x" (a)); res; }) +#endif + +#define intrin_rsqrt_f32(a) _mm_cvtss_f32(_mm_rsqrt_ss(_mm_set_ss((a)))) +#define intrin_rsqrt_f64(a) _mm_cvtsd_f64(_mm_div_sd(_mm_set_sd(1.0), _mm_sqrt_sd(_mm_set_sd((a)), _mm_set_sd((a))))) + +#define intrin_round_f32(a) _mm_cvtss_f32(_mm_round_ss(_mm_setzero_ps(), _mm_set_ss((a)), (_MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC))) +#define intrin_round_to_int32(a) _mm_cvtss_si32(_mm_set_ss((a))) +#define intrin_floor_f32(a) _mm_cvtss_f32(_mm_floor_ss(_mm_setzero_ps(), _mm_set_ss((a)))) +#define intrin_ceil_f32(a) _mm_cvtss_f32(_mm_ceil_ss(_mm_setzero_ps(), _mm_set_ss((a)))) + +#define intrin_fence_memory() _mm_mfence() +#define intrin_fence_write() _mm_sfence() +#define intrin_fence_load() _mm_lfence() +#define intrin_invalidate_cache() _mm_clflush() + +#define intrin_crc32_u8(crc, data) _mm_crc32_u8((crc), (data)) +#define intrin_crc32_u16(crc, data) _mm_crc32_u16((crc), (data)) +#define intrin_crc32_u32(crc, data) _mm_crc32_u32((crc), (data)) +#define intrin_crc32_u64(crc, data) _mm_crc32_u64((crc), (data)) + +#define intrin_timestamp_counter() __rdtsc() + +#endif \ No newline at end of file diff --git a/asset/Asset.h b/asset/Asset.h index e748901..792b066 100644 --- a/asset/Asset.h +++ b/asset/Asset.h @@ -23,8 +23,7 @@ struct Asset { // Could be 0 if there is no official id uint32 official_id; - // @performance We would like to use a bool but windows only supports 32bit atomic values as smallest value - // Maybe if we would set the IS_LOADED_STATE in the enum as the highest bit we could use the state variable and check it with >= + // @performance Maybe if we would set the IS_LOADED_STATE in the enum as the highest bit we could use the state variable and check it with >= int32 is_loaded; // Describes how much ram/vram the asset uses diff --git a/asset/AssetArchive.h b/asset/AssetArchive.h index 5ddba8d..42bafdc 100644 --- a/asset/AssetArchive.h +++ b/asset/AssetArchive.h @@ -27,6 +27,7 @@ #include "AssetManagementSystem.h" #include "../system/FileUtils.cpp" #include "../stdlib/Simd.h" +#include "../compiler/CompilerUtils.h" #define ASSET_ARCHIVE_VERSION 1 @@ -71,7 +72,7 @@ struct AssetArchive { }; // Calculates how large the header memory has to be to hold all its information -int32 asset_archive_header_size(AssetArchive* archive, byte* data) +int32 asset_archive_header_size(AssetArchive* __restrict archive, const byte* __restrict data) { data += sizeof(archive->header.version); @@ -88,7 +89,7 @@ int32 asset_archive_header_size(AssetArchive* archive, byte* data) + asset_dependency_count * sizeof(int32); } -void asset_archive_header_load(AssetArchiveHeader* header, byte* data, int32 steps = 8) +void asset_archive_header_load(AssetArchiveHeader* __restrict header, const byte* __restrict data, int32 steps = 8) { header->version = SWAP_ENDIAN_LITTLE(*((int32 *) data)); data += sizeof(header->version); diff --git a/audio/Audio.cpp b/audio/Audio.cpp index b99f113..879b380 100644 --- a/audio/Audio.cpp +++ b/audio/Audio.cpp @@ -17,7 +17,7 @@ #include "AudioSetting.h" #include "Wav.h" -void audio_from_file(Audio* audio, const char* path, RingMemory* ring) +void audio_from_file(Audio* __restrict audio, const char* __restrict path, RingMemory* __restrict ring) { FileBody file; file_read(path, &file, ring); @@ -40,7 +40,7 @@ int32 audio_data_size(const Audio* audio) } inline -uint32 audio_header_from_data(const byte* data, Audio* audio) +uint32 audio_header_from_data(const byte* __restrict data, Audio* __restrict audio) { const byte* start = data; @@ -62,7 +62,7 @@ uint32 audio_header_from_data(const byte* data, Audio* audio) } inline -uint32 audio_header_to_data(const Audio* audio, byte* data) +uint32 audio_header_to_data(const Audio* __restrict audio, byte* __restrict data) { byte* start = data; @@ -79,7 +79,7 @@ uint32 audio_header_to_data(const Audio* audio, byte* data) return (int32) (data - start); } -uint32 audio_from_data(const byte* data, Audio* audio) +uint32 audio_from_data(const byte* __restrict data, Audio* __restrict audio) { data += audio_header_from_data(data, audio); @@ -89,7 +89,7 @@ uint32 audio_from_data(const byte* data, Audio* audio) return audio_data_size(audio); } -uint32 audio_to_data(const Audio* audio, byte* data) +uint32 audio_to_data(const Audio* __restrict audio, byte* __restrict data) { data += audio_header_to_data(audio, data); diff --git a/audio/AudioMixer.h b/audio/AudioMixer.h index 48892ae..8798495 100644 --- a/audio/AudioMixer.h +++ b/audio/AudioMixer.h @@ -71,7 +71,7 @@ enum AudioMixerState { struct AudioMixer { ChunkMemory audio_instances; AudioMixerState state_old; - AudioMixerState state_new; + int32 state_new; uint64 effect; @@ -98,13 +98,13 @@ struct AudioMixer { bool audio_mixer_is_active(AudioMixer* mixer) { if (mixer->state_old == AUDIO_MIXER_STATE_ACTIVE - && atomic_get_relaxed((int32 *) &mixer->state_new) == AUDIO_MIXER_STATE_ACTIVE + && atomic_get_relaxed(&mixer->state_new) == AUDIO_MIXER_STATE_ACTIVE ) { return true; } AudioMixerState mixer_state; - if ((mixer_state = (AudioMixerState) atomic_get_relaxed((int32 *) &mixer->state_new)) != mixer->state_old) { + if ((mixer_state = (AudioMixerState) atomic_get_relaxed(&mixer->state_new)) != mixer->state_old) { if (mixer->state_old == AUDIO_MIXER_STATE_UNINITIALIZED) { audio_load( mixer->window, diff --git a/camera/Camera.h b/camera/Camera.h index b08557a..f2e52d3 100644 --- a/camera/Camera.h +++ b/camera/Camera.h @@ -10,9 +10,8 @@ #define TOS_CAMERA_H #include "../stdlib/Types.h" - #include "../math/matrix/MatrixFloat32.h" - +#include "../compiler/CompilerUtils.h" #include "CameraMovement.h" #define CAMERA_MAX_INPUTS 4 @@ -40,6 +39,8 @@ struct Camera { f32 sensitivity; f32 zoom; + // @question Consider to make these f32 values. + // Yes, this uses obviously more space BUT we use these values very often in vertex calculations and always have to cast it uint16 viewport_width; uint16 viewport_height; diff --git a/command/AppCmdBuffer.cpp b/command/AppCmdBuffer.cpp index faa7129..7551044 100644 --- a/command/AppCmdBuffer.cpp +++ b/command/AppCmdBuffer.cpp @@ -25,8 +25,10 @@ #include "AppCmdBuffer.h" #include "../camera/Camera.h" #include "../ui/UILayout.h" +#include "../ui/UILayout.cpp" #include "../ui/UITheme.h" #include "../system/FileUtils.cpp" +#include "../compiler/CompilerUtils.h" // @todo Move the different functions to their own respective files (e.g. CmdAsset.cpp, CmdLayout.cpp) @@ -464,7 +466,7 @@ UIThemeStyle* cmd_theme_load_sync( inline void cmd_layout_populate_sync( AppCmdBuffer* cb, - UILayout* layout, UIThemeStyle* theme, + UILayout* layout, const UIThemeStyle* theme, const Camera* camera ) { layout_from_theme(layout, theme, camera); @@ -496,7 +498,7 @@ UILayout* cmd_ui_load(AppCmdBuffer* cb, Command* cmd) pos += sizeof(uintptr_t); char* layout_path = (char *) pos; - str_move_to((char **) &pos, '\0'); ++pos; + str_move_to((const char **) &pos, '\0'); ++pos; UIThemeStyle* general_theme = (UIThemeStyle *) pos; pos += sizeof(uintptr_t); @@ -505,7 +507,7 @@ UILayout* cmd_ui_load(AppCmdBuffer* cb, Command* cmd) pos += sizeof(uintptr_t); char* theme_path = (char *) pos; - str_move_to((char **) &pos, '\0'); ++pos; + str_move_to((const char **) &pos, '\0'); ++pos; Camera* camera = (Camera *) pos; diff --git a/compiler/CompilerUtils.h b/compiler/CompilerUtils.h new file mode 100644 index 0000000..aec3403 --- /dev/null +++ b/compiler/CompilerUtils.h @@ -0,0 +1,20 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_COMPILER_COMPILER_UTILS_H +#define TOS_COMPILER_COMPILER_UTILS_H + +#include "../utils/TestUtils.h" + +#if _MSC_VER + #include "msvc/CompilerUtils.h" +#elif __GNUC__ + #include "gcc/CompilerUtils.h" +#endif + +#endif \ No newline at end of file diff --git a/compiler/gcc/Atomic.h b/compiler/gcc/Atomic.h new file mode 100644 index 0000000..b1df890 --- /dev/null +++ b/compiler/gcc/Atomic.h @@ -0,0 +1,212 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_COMPILER_GCC_ATOMIC_H +#define TOS_COMPILER_GCC_ATOMIC_H + +#include "../../stdlib/Types.h" +#include + +inline void atomic_set_relaxed(void** target, void* value) { __atomic_store_n(target, value, __ATOMIC_RELAXED); } +inline void* atomic_get_relaxed(void** target) { return __atomic_load_n(target, __ATOMIC_RELAXED); } +inline void atomic_set_relaxed(volatile int32* value, int32 new_value) { __atomic_store_n(value, new_value, __ATOMIC_RELAXED); } +inline void atomic_set_relaxed(volatile int64* value, int64 new_value) { __atomic_store_n(value, new_value, __ATOMIC_RELAXED); } +inline int32 atomic_fetch_set_relaxed(volatile int32* value, int32 new_value) { return __atomic_exchange_n(value, new_value, __ATOMIC_RELAXED); } +inline int64 atomic_fetch_set_relaxed(volatile int64* value, int64 new_value) { return __atomic_exchange_n(value, new_value, __ATOMIC_RELAXED); } +inline int32 atomic_get_relaxed(volatile int32* value) { return __atomic_load_n((int32 *) value, __ATOMIC_RELAXED); } +inline int64 atomic_get_relaxed(volatile int64* value) { return __atomic_load_n((int64 *) value, __ATOMIC_RELAXED); } +inline void atomic_increment_relaxed(volatile int32* value) { __atomic_add_fetch(value, 1, __ATOMIC_RELAXED); } +inline void atomic_decrement_relaxed(volatile int32* value) { __atomic_sub_fetch(value, 1, __ATOMIC_RELAXED); } +inline void atomic_increment_relaxed(volatile int64* value) { __atomic_add_fetch(value, 1, __ATOMIC_RELAXED); } +inline void atomic_decrement_relaxed(volatile int64* value) { __atomic_sub_fetch(value, 1, __ATOMIC_RELAXED); } +inline void atomic_add_relaxed(volatile int32* value, int32 increment) { __atomic_add_fetch(value, increment, __ATOMIC_RELAXED); } +inline void atomic_sub_relaxed(volatile int32* value, int32 decrement) { __atomic_sub_fetch(value, decrement, __ATOMIC_RELAXED); } +inline void atomic_add_relaxed(volatile int64* value, int64 increment) { __atomic_add_fetch(value, increment, __ATOMIC_RELAXED); } +inline void atomic_sub_relaxed(volatile int64* value, int64 decrement) { __atomic_sub_fetch(value, decrement, __ATOMIC_RELAXED); } +inline int32 atomic_compare_exchange_weak_relaxed(volatile int32* value, int32* expected, int32 desired) { __atomic_compare_exchange_n(value, expected, desired, 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED); return *expected; } +inline int32 atomic_fetch_add_relaxed(volatile int32* value, int32 operand) { return __atomic_add_fetch(value, operand, __ATOMIC_RELAXED); } +inline int32 atomic_fetch_sub_relaxed(volatile int32* value, int32 operand) { return __atomic_sub_fetch(value, operand, __ATOMIC_RELAXED); } +inline int64 atomic_fetch_add_relaxed(volatile int64* value, int64 operand) { return __atomic_add_fetch(value, operand, __ATOMIC_RELAXED); } +inline int64 atomic_fetch_sub_relaxed(volatile int64* value, int64 operand) { return __atomic_sub_fetch(value, operand, __ATOMIC_RELAXED); } +inline void atomic_set_relaxed(volatile uint32* value, uint32 new_value) { __atomic_store_n(value, new_value, __ATOMIC_RELAXED); } +inline void atomic_set_relaxed(volatile uint64* value, uint64 new_value) { __atomic_store_n(value, new_value, __ATOMIC_RELAXED); } +inline uint32 atomic_fetch_set_relaxed(volatile uint32* value, uint32 new_value) { return __atomic_exchange_n(value, new_value, __ATOMIC_RELAXED); } +inline uint64 atomic_fetch_set_relaxed(volatile uint64* value, uint64 new_value) { return __atomic_exchange_n(value, new_value, __ATOMIC_RELAXED); } +inline uint32 atomic_get_relaxed(volatile uint32* value) { return __atomic_load_n((uint32 *) value, __ATOMIC_RELAXED); } +inline uint64 atomic_get_relaxed(volatile uint64* value) { return __atomic_load_n((uint64 *) value, __ATOMIC_RELAXED); } +inline void atomic_increment_relaxed(volatile uint32* value) { __atomic_add_fetch(value, 1, __ATOMIC_RELAXED); } +inline void atomic_decrement_relaxed(volatile uint32* value) { __atomic_sub_fetch(value, 1, __ATOMIC_RELAXED); } +inline void atomic_increment_relaxed(volatile uint64* value) { __atomic_add_fetch(value, 1, __ATOMIC_RELAXED); } +inline void atomic_decrement_relaxed(volatile uint64* value) { __atomic_sub_fetch(value, 1, __ATOMIC_RELAXED); } +inline void atomic_add_relaxed(volatile uint32* value, uint32 increment) { __atomic_add_fetch(value, increment, __ATOMIC_RELAXED); } +inline void atomic_sub_relaxed(volatile uint32* value, uint32 decrement) { __atomic_sub_fetch(value, decrement, __ATOMIC_RELAXED); } +inline uint32 atomic_compare_exchange_weak_relaxed(volatile uint32* value, uint32* expected, uint32 desired) { __atomic_compare_exchange_n(value, expected, desired, 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED); return *expected; } +inline uint32 atomic_fetch_add_relaxed(volatile uint32* value, uint32 operand) { return __atomic_add_fetch(value, operand, __ATOMIC_RELAXED); } +inline uint32 atomic_fetch_sub_relaxed(volatile uint32* value, uint32 operand) { return __atomic_sub_fetch(value, operand, __ATOMIC_RELAXED); } +inline uint64 atomic_fetch_add_relaxed(volatile uint64* value, uint64 operand) { return __atomic_add_fetch(value, operand, __ATOMIC_RELAXED); } +inline uint64 atomic_fetch_sub_relaxed(volatile uint64* value, uint64 operand) { return __atomic_sub_fetch(value, operand, __ATOMIC_RELAXED); } +inline void atomic_and_relaxed(volatile uint32* value, uint32 mask) { __atomic_fetch_and(value, mask, __ATOMIC_RELAXED); } +inline void atomic_and_relaxed(volatile int32* value, int32 mask) { __atomic_fetch_and(value, mask, __ATOMIC_RELAXED); } +inline void atomic_and_relaxed(volatile uint64* value, uint64 mask) { __atomic_fetch_and(value, mask, __ATOMIC_RELAXED); } +inline void atomic_and_relaxed(volatile int64* value, int64 mask) { __atomic_fetch_and(value, mask, __ATOMIC_RELAXED); } +inline void atomic_or_relaxed(volatile uint32* value, uint32 mask) { __atomic_fetch_or(value, mask, __ATOMIC_RELAXED); } +inline void atomic_or_relaxed(volatile int32* value, int32 mask) { __atomic_fetch_or(value, mask, __ATOMIC_RELAXED); } +inline void atomic_or_relaxed(volatile uint64* value, uint64 mask) { __atomic_fetch_or(value, mask, __ATOMIC_RELAXED); } +inline void atomic_or_relaxed(volatile int64* value, int64 mask) { __atomic_fetch_or(value, mask, __ATOMIC_RELAXED); } + +inline void atomic_set_acquire(void** target, void* value) { __atomic_store_n(target, value, __ATOMIC_ACQUIRE); } +inline void* atomic_get_acquire(void** target) { return __atomic_load_n(target, __ATOMIC_ACQUIRE); } +inline void atomic_set_acquire(volatile int32* value, int32 new_value) { __atomic_store_n(value, new_value, __ATOMIC_ACQUIRE); } +inline void atomic_set_acquire(volatile int64* value, int64 new_value) { __atomic_store_n(value, new_value, __ATOMIC_ACQUIRE); } +inline int32 atomic_fetch_set_acquire(volatile int32* value, int32 new_value) { return __atomic_exchange_n(value, new_value, __ATOMIC_ACQUIRE); } +inline int64 atomic_fetch_set_acquire(volatile int64* value, int64 new_value) { return __atomic_exchange_n(value, new_value, __ATOMIC_ACQUIRE); } +inline int32 atomic_get_acquire(volatile int32* value) { return __atomic_load_n((int32 *) value, __ATOMIC_ACQUIRE); } +inline int64 atomic_get_acquire(volatile int64* value) { return __atomic_load_n((int64 *) value, __ATOMIC_ACQUIRE); } +inline void atomic_increment_acquire(volatile int32* value) { __atomic_add_fetch(value, 1, __ATOMIC_ACQUIRE); } +inline void atomic_decrement_acquire(volatile int32* value) { __atomic_sub_fetch(value, 1, __ATOMIC_ACQUIRE); } +inline void atomic_increment_acquire(volatile int64* value) { __atomic_add_fetch(value, 1, __ATOMIC_ACQUIRE); } +inline void atomic_decrement_acquire(volatile int64* value) { __atomic_sub_fetch(value, 1, __ATOMIC_ACQUIRE); } +inline void atomic_add_acquire(volatile int32* value, int32 increment) { __atomic_add_fetch(value, increment, __ATOMIC_ACQUIRE); } +inline void atomic_sub_acquire(volatile int32* value, int32 decrement) { __atomic_sub_fetch(value, decrement, __ATOMIC_ACQUIRE); } +inline void atomic_add_acquire(volatile int64* value, int64 increment) { __atomic_add_fetch(value, increment, __ATOMIC_ACQUIRE); } +inline void atomic_sub_acquire(volatile int64* value, int64 decrement) { __atomic_sub_fetch(value, decrement, __ATOMIC_ACQUIRE); } +inline int32 atomic_compare_exchange_weak_acquire(volatile int32* value, int32* expected, int32 desired) { __atomic_compare_exchange_n(value, expected, desired, 0, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE); return *expected; } +inline int32 atomic_fetch_add_acquire(volatile int32* value, int32 operand) { return __atomic_add_fetch(value, operand, __ATOMIC_ACQUIRE); } +inline int32 atomic_fetch_sub_acquire(volatile int32* value, int32 operand) { return __atomic_sub_fetch(value, operand, __ATOMIC_ACQUIRE); } +inline int64 atomic_fetch_add_acquire(volatile int64* value, int64 operand) { return __atomic_add_fetch(value, operand, __ATOMIC_ACQUIRE); } +inline int64 atomic_fetch_sub_acquire(volatile int64* value, int64 operand) { return __atomic_sub_fetch(value, operand, __ATOMIC_ACQUIRE); } +inline void atomic_set_acquire(volatile uint32* value, uint32 new_value) { __atomic_store_n(value, new_value, __ATOMIC_ACQUIRE); } +inline void atomic_set_acquire(volatile uint64* value, uint64 new_value) { __atomic_store_n(value, new_value, __ATOMIC_ACQUIRE); } +inline uint32 atomic_fetch_set_acquire(volatile uint32* value, uint32 new_value) { return __atomic_exchange_n(value, new_value, __ATOMIC_ACQUIRE); } +inline uint64 atomic_fetch_set_acquire(volatile uint64* value, uint64 new_value) { return __atomic_exchange_n(value, new_value, __ATOMIC_ACQUIRE); } +inline uint32 atomic_get_acquire(volatile uint32* value) { return __atomic_load_n((uint32 *) value, __ATOMIC_ACQUIRE); } +inline uint64 atomic_get_acquire(volatile uint64* value) { return __atomic_load_n((uint64 *) value, __ATOMIC_ACQUIRE); } +inline void atomic_increment_acquire(volatile uint32* value) { __atomic_add_fetch(value, 1, __ATOMIC_ACQUIRE); } +inline void atomic_decrement_acquire(volatile uint32* value) { __atomic_sub_fetch(value, 1, __ATOMIC_ACQUIRE); } +inline void atomic_increment_acquire(volatile uint64* value) { __atomic_add_fetch(value, 1, __ATOMIC_ACQUIRE); } +inline void atomic_decrement_acquire(volatile uint64* value) { __atomic_sub_fetch(value, 1, __ATOMIC_ACQUIRE); } +inline void atomic_add_acquire(volatile uint32* value, uint32 increment) { __atomic_add_fetch(value, increment, __ATOMIC_ACQUIRE); } +inline void atomic_sub_acquire(volatile uint32* value, uint32 decrement) { __atomic_sub_fetch(value, decrement, __ATOMIC_ACQUIRE); } +inline uint32 atomic_compare_exchange_weak_acquire(volatile uint32* value, uint32* expected, uint32 desired) { __atomic_compare_exchange_n(value, expected, desired, 0, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE); return *expected; } +inline uint32 atomic_fetch_add_acquire(volatile uint32* value, uint32 operand) { return __atomic_add_fetch(value, operand, __ATOMIC_ACQUIRE); } +inline uint32 atomic_fetch_sub_acquire(volatile uint32* value, uint32 operand) { return __atomic_sub_fetch(value, operand, __ATOMIC_ACQUIRE); } +inline uint64 atomic_fetch_add_acquire(volatile uint64* value, uint64 operand) { return __atomic_add_fetch(value, operand, __ATOMIC_ACQUIRE); } +inline uint64 atomic_fetch_sub_acquire(volatile uint64* value, uint64 operand) { return __atomic_sub_fetch(value, operand, __ATOMIC_ACQUIRE); } +inline void atomic_and_acquire(volatile uint32* value, uint32 mask) { __atomic_fetch_and(value, mask, __ATOMIC_ACQUIRE); } +inline void atomic_and_acquire(volatile int32* value, int32 mask) { __atomic_fetch_and(value, mask, __ATOMIC_ACQUIRE); } +inline void atomic_and_acquire(volatile uint64* value, uint64 mask) { __atomic_fetch_and(value, mask, __ATOMIC_ACQUIRE); } +inline void atomic_and_acquire(volatile int64* value, int64 mask) { __atomic_fetch_and(value, mask, __ATOMIC_ACQUIRE); } +inline void atomic_or_acquire(volatile uint32* value, uint32 mask) { __atomic_fetch_or(value, mask, __ATOMIC_ACQUIRE); } +inline void atomic_or_acquire(volatile int32* value, int32 mask) { __atomic_fetch_or(value, mask, __ATOMIC_ACQUIRE); } +inline void atomic_or_acquire(volatile uint64* value, uint64 mask) { __atomic_fetch_or(value, mask, __ATOMIC_ACQUIRE); } +inline void atomic_or_acquire(volatile int64* value, int64 mask) { __atomic_fetch_or(value, mask, __ATOMIC_ACQUIRE); } + +inline void atomic_set_release(void** target, void* value) { __atomic_store_n(target, value, __ATOMIC_RELEASE); } +inline void* atomic_get_release(void** target) { return __atomic_load_n(target, __ATOMIC_RELEASE); } +inline void atomic_set_release(volatile int32* value, int32 new_value) { __atomic_store_n(value, new_value, __ATOMIC_RELEASE); } +inline void atomic_set_release(volatile int64* value, int64 new_value) { __atomic_store_n(value, new_value, __ATOMIC_RELEASE); } +inline int32 atomic_fetch_set_release(volatile int32* value, int32 new_value) { return __atomic_exchange_n(value, new_value, __ATOMIC_RELEASE); } +inline int64 atomic_fetch_set_release(volatile int64* value, int64 new_value) { return __atomic_exchange_n(value, new_value, __ATOMIC_RELEASE); } +inline int32 atomic_get_release(volatile int32* value) { return __atomic_load_n((int32 *) value, __ATOMIC_RELEASE); } +inline int64 atomic_get_release(volatile int64* value) { return __atomic_load_n((int64 *) value, __ATOMIC_RELEASE); } +inline void atomic_increment_release(volatile int32* value) { __atomic_add_fetch(value, 1, __ATOMIC_RELEASE); } +inline void atomic_decrement_release(volatile int32* value) { __atomic_sub_fetch(value, 1, __ATOMIC_RELEASE); } +inline void atomic_increment_release(volatile int64* value) { __atomic_add_fetch(value, 1, __ATOMIC_RELEASE); } +inline void atomic_decrement_release(volatile int64* value) { __atomic_sub_fetch(value, 1, __ATOMIC_RELEASE); } +inline void atomic_add_release(volatile int32* value, int32 increment) { __atomic_add_fetch(value, increment, __ATOMIC_RELEASE); } +inline void atomic_sub_release(volatile int32* value, int32 decrement) { __atomic_sub_fetch(value, decrement, __ATOMIC_RELEASE); } +inline void atomic_add_release(volatile int64* value, int64 increment) { __atomic_add_fetch(value, increment, __ATOMIC_RELEASE); } +inline void atomic_sub_release(volatile int64* value, int64 decrement) { __atomic_sub_fetch(value, decrement, __ATOMIC_RELEASE); } +inline int32 atomic_compare_exchange_weak_release(volatile int32* value, int32* expected, int32 desired) { __atomic_compare_exchange_n(value, expected, desired, 0, __ATOMIC_RELEASE, __ATOMIC_RELEASE); return *expected; } +inline int32 atomic_fetch_add_release(volatile int32* value, int32 operand) { return __atomic_add_fetch(value, operand, __ATOMIC_RELEASE); } +inline int32 atomic_fetch_sub_release(volatile int32* value, int32 operand) { return __atomic_sub_fetch(value, operand, __ATOMIC_RELEASE); } +inline int64 atomic_fetch_add_release(volatile int64* value, int64 operand) { return __atomic_add_fetch(value, operand, __ATOMIC_RELEASE); } +inline int64 atomic_fetch_sub_release(volatile int64* value, int64 operand) { return __atomic_sub_fetch(value, operand, __ATOMIC_RELEASE); } +inline void atomic_set_release(volatile uint32* value, uint32 new_value) { __atomic_store_n(value, new_value, __ATOMIC_RELEASE); } +inline void atomic_set_release(volatile uint64* value, uint64 new_value) { __atomic_store_n(value, new_value, __ATOMIC_RELEASE); } +inline uint32 atomic_fetch_set_release(volatile uint32* value, uint32 new_value) { return __atomic_exchange_n(value, new_value, __ATOMIC_RELEASE); } +inline uint64 atomic_fetch_set_release(volatile uint64* value, uint64 new_value) { return __atomic_exchange_n(value, new_value, __ATOMIC_RELEASE); } +inline uint32 atomic_get_release(volatile uint32* value) { return __atomic_load_n((uint32 *) value, __ATOMIC_RELEASE); } +inline uint64 atomic_get_release(volatile uint64* value) { return __atomic_load_n((uint64 *) value, __ATOMIC_RELEASE); } +inline void atomic_increment_release(volatile uint32* value) { __atomic_add_fetch(value, 1, __ATOMIC_RELEASE); } +inline void atomic_decrement_release(volatile uint32* value) { __atomic_sub_fetch(value, 1, __ATOMIC_RELEASE); } +inline void atomic_increment_release(volatile uint64* value) { __atomic_add_fetch(value, 1, __ATOMIC_RELEASE); } +inline void atomic_decrement_release(volatile uint64* value) { __atomic_sub_fetch(value, 1, __ATOMIC_RELEASE); } +inline void atomic_add_release(volatile uint32* value, uint32 increment) { __atomic_add_fetch(value, increment, __ATOMIC_RELEASE); } +inline void atomic_sub_release(volatile uint32* value, uint32 decrement) { __atomic_sub_fetch(value, decrement, __ATOMIC_RELEASE); } +inline uint32 atomic_compare_exchange_weak_release(volatile uint32* value, uint32* expected, uint32 desired) { __atomic_compare_exchange_n(value, expected, desired, 0, __ATOMIC_RELEASE, __ATOMIC_RELEASE); return *expected; } +inline uint32 atomic_fetch_add_release(volatile uint32* value, uint32 operand) { return __atomic_add_fetch(value, operand, __ATOMIC_RELEASE); } +inline uint32 atomic_fetch_sub_release(volatile uint32* value, uint32 operand) { return __atomic_sub_fetch(value, operand, __ATOMIC_RELEASE); } +inline uint64 atomic_fetch_add_release(volatile uint64* value, uint64 operand) { return __atomic_add_fetch(value, operand, __ATOMIC_RELEASE); } +inline uint64 atomic_fetch_sub_release(volatile uint64* value, uint64 operand) { return __atomic_sub_fetch(value, operand, __ATOMIC_RELEASE); } +inline void atomic_and_release(volatile uint32* value, uint32 mask) { __atomic_fetch_and(value, mask, __ATOMIC_RELEASE); } +inline void atomic_and_release(volatile int32* value, int32 mask) { __atomic_fetch_and(value, mask, __ATOMIC_RELEASE); } +inline void atomic_and_release(volatile uint64* value, uint64 mask) { __atomic_fetch_and(value, mask, __ATOMIC_RELEASE); } +inline void atomic_and_release(volatile int64* value, int64 mask) { __atomic_fetch_and(value, mask, __ATOMIC_RELEASE); } +inline void atomic_or_release(volatile uint32* value, uint32 mask) { __atomic_fetch_or(value, mask, __ATOMIC_RELEASE); } +inline void atomic_or_release(volatile int32* value, int32 mask) { __atomic_fetch_or(value, mask, __ATOMIC_RELEASE); } +inline void atomic_or_release(volatile uint64* value, uint64 mask) { __atomic_fetch_or(value, mask, __ATOMIC_RELEASE); } +inline void atomic_or_release(volatile int64* value, int64 mask) { __atomic_fetch_or(value, mask, __ATOMIC_RELEASE); } + +inline void atomic_set_acquire_release(void** target, void* value) { __atomic_store_n(target, value, __ATOMIC_SEQ_CST); } +inline void* atomic_get_acquire_release(void** target) { return __atomic_load_n(target, __ATOMIC_SEQ_CST); } +inline void atomic_set_acquire_release(volatile int32* value, int32 new_value) { __atomic_store_n(value, new_value, __ATOMIC_SEQ_CST); } +inline void atomic_set_acquire_release(volatile int64* value, int64 new_value) { __atomic_store_n(value, new_value, __ATOMIC_SEQ_CST); } +inline int32 atomic_fetch_set_acquire_release(volatile int32* value, int32 new_value) { return __atomic_exchange_n(value, new_value, __ATOMIC_SEQ_CST); } +inline int64 atomic_fetch_set_acquire_release(volatile int64* value, int64 new_value) { return __atomic_exchange_n(value, new_value, __ATOMIC_SEQ_CST); } +inline int32 atomic_get_acquire_release(volatile int32* value) { return __atomic_load_n((int32 *) value, __ATOMIC_SEQ_CST); } +inline int64 atomic_get_acquire_release(volatile int64* value) { return __atomic_load_n((int64 *) value, __ATOMIC_SEQ_CST); } +inline void atomic_increment_acquire_release(volatile int32* value) { __atomic_add_fetch(value, 1, __ATOMIC_SEQ_CST); } +inline void atomic_decrement_acquire_release(volatile int32* value) { __atomic_sub_fetch(value, 1, __ATOMIC_SEQ_CST); } +inline void atomic_increment_acquire_release(volatile int64* value) { __atomic_add_fetch(value, 1, __ATOMIC_SEQ_CST); } +inline void atomic_decrement_acquire_release(volatile int64* value) { __atomic_sub_fetch(value, 1, __ATOMIC_SEQ_CST); } +inline void atomic_add_acquire_release(volatile int32* value, int32 increment) { __atomic_add_fetch(value, increment, __ATOMIC_SEQ_CST); } +inline void atomic_sub_acquire_release(volatile int32* value, int32 decrement) { __atomic_sub_fetch(value, decrement, __ATOMIC_SEQ_CST); } +inline void atomic_add_acquire_release(volatile int64* value, int64 increment) { __atomic_add_fetch(value, increment, __ATOMIC_SEQ_CST); } +inline void atomic_sub_acquire_release(volatile int64* value, int64 decrement) { __atomic_sub_fetch(value, decrement, __ATOMIC_SEQ_CST); } +inline int32 atomic_compare_exchange_weak_acquire_release(volatile int32* value, int32* expected, int32 desired) { __atomic_compare_exchange_n(value, expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); return *expected; } +inline int32 atomic_fetch_add_acquire_release(volatile int32* value, int32 operand) { return __atomic_add_fetch(value, operand, __ATOMIC_SEQ_CST); } +inline int32 atomic_fetch_sub_acquire_release(volatile int32* value, int32 operand) { return __atomic_sub_fetch(value, operand, __ATOMIC_SEQ_CST); } +inline int64 atomic_fetch_add_acquire_release(volatile int64* value, int64 operand) { return __atomic_add_fetch(value, operand, __ATOMIC_SEQ_CST); } +inline int64 atomic_fetch_sub_acquire_release(volatile int64* value, int64 operand) { return __atomic_sub_fetch(value, operand, __ATOMIC_SEQ_CST); } +inline void atomic_set_acquire_release(volatile uint32* value, uint32 new_value) { __atomic_store_n(value, new_value, __ATOMIC_SEQ_CST); } +inline void atomic_set_acquire_release(volatile uint64* value, uint64 new_value) { __atomic_store_n(value, new_value, __ATOMIC_SEQ_CST); } +inline uint32 atomic_fetch_set_acquire_release(volatile uint32* value, uint32 new_value) { return __atomic_exchange_n(value, new_value, __ATOMIC_SEQ_CST); } +inline uint64 atomic_fetch_set_acquire_release(volatile uint64* value, uint64 new_value) { return __atomic_exchange_n(value, new_value, __ATOMIC_SEQ_CST); } +inline uint32 atomic_get_acquire_release(volatile uint32* value) { return __atomic_load_n((uint32 *) value, __ATOMIC_SEQ_CST); } +inline uint64 atomic_get_acquire_release(volatile uint64* value) { return __atomic_load_n((uint64 *) value, __ATOMIC_SEQ_CST); } +inline void atomic_increment_acquire_release(volatile uint32* value) { __atomic_add_fetch(value, 1, __ATOMIC_SEQ_CST); } +inline void atomic_decrement_acquire_release(volatile uint32* value) { __atomic_sub_fetch(value, 1, __ATOMIC_SEQ_CST); } +inline void atomic_increment_acquire_release(volatile uint64* value) { __atomic_add_fetch(value, 1, __ATOMIC_SEQ_CST); } +inline void atomic_decrement_acquire_release(volatile uint64* value) { __atomic_sub_fetch(value, 1, __ATOMIC_SEQ_CST); } +inline void atomic_add_acquire_release(volatile uint32* value, uint32 increment) { __atomic_add_fetch(value, increment, __ATOMIC_SEQ_CST); } +inline void atomic_sub_acquire_release(volatile uint32* value, uint32 decrement) { __atomic_sub_fetch(value, decrement, __ATOMIC_SEQ_CST); } +inline uint32 atomic_compare_exchange_weak_acquire_release(volatile uint32* value, uint32* expected, uint32 desired) { __atomic_compare_exchange_n(value, expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); return *expected; } +inline uint32 atomic_fetch_add_acquire_release(volatile uint32* value, uint32 operand) { return __atomic_add_fetch(value, operand, __ATOMIC_SEQ_CST); } +inline uint32 atomic_fetch_sub_acquire_release(volatile uint32* value, uint32 operand) { return __atomic_sub_fetch(value, operand, __ATOMIC_SEQ_CST); } +inline uint64 atomic_fetch_add_acquire_release(volatile uint64* value, uint64 operand) { return __atomic_add_fetch(value, operand, __ATOMIC_SEQ_CST); } +inline uint64 atomic_fetch_sub_acquire_release(volatile uint64* value, uint64 operand) { return __atomic_sub_fetch(value, operand, __ATOMIC_SEQ_CST); } +inline void atomic_and_acquire_release(volatile uint32* value, uint32 mask) { __atomic_fetch_and(value, mask, __ATOMIC_SEQ_CST); } +inline void atomic_and_acquire_release(volatile int32* value, int32 mask) { __atomic_fetch_and(value, mask, __ATOMIC_SEQ_CST); } +inline void atomic_and_acquire_release(volatile uint64* value, uint64 mask) { __atomic_fetch_and(value, mask, __ATOMIC_SEQ_CST); } +inline void atomic_and_acquire_release(volatile int64* value, int64 mask) { __atomic_fetch_and(value, mask, __ATOMIC_SEQ_CST); } +inline void atomic_or_acquire_release(volatile uint32* value, uint32 mask) { __atomic_fetch_or(value, mask, __ATOMIC_SEQ_CST); } +inline void atomic_or_acquire_release(volatile int32* value, int32 mask) { __atomic_fetch_or(value, mask, __ATOMIC_SEQ_CST); } +inline void atomic_or_acquire_release(volatile uint64* value, uint64 mask) { __atomic_fetch_or(value, mask, __ATOMIC_SEQ_CST); } +inline void atomic_or_acquire_release(volatile int64* value, int64 mask) { __atomic_fetch_or(value, mask, __ATOMIC_SEQ_CST); } + +// Check out the intrinsic functions fence_memory and fence_write +// These are much faster and could accomplish what you are doing +#define atomic_fence_acquire() __atomic_thread_fence(__ATOMIC_ACQUIRE) + +// Check out the intrinsic functions fence_memory and fence_write +// These are much faster and could accomplish what you are doing +#define atomic_fence_release() __atomic_thread_fence(__ATOMIC_RELEASE) + + +#endif \ No newline at end of file diff --git a/compiler/gcc/CompilerUtils.h b/compiler/gcc/CompilerUtils.h new file mode 100644 index 0000000..42773de --- /dev/null +++ b/compiler/gcc/CompilerUtils.h @@ -0,0 +1,25 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_COMPILER_GCC_COMPILER_UTILS_H +#define TOS_COMPILER_GCC_COMPILER_UTILS_H + +#include "../../utils/TestUtils.h" + +#define PACKED_STRUCT __attribute__((__packed__)) +#define UNPACKED_STRUCT ((void) 0) + +#define EXPORT_LIB extern "C" __attribute__((visibility("default"))) + +#if DEBUG + #define UNREACHABLE() ASSERT_SIMPLE(false) +#else + #define UNREACHABLE() __builtin_unreachable() +#endif + +#endif \ No newline at end of file diff --git a/compiler/msvc/CompilerUtils.h b/compiler/msvc/CompilerUtils.h new file mode 100644 index 0000000..6461532 --- /dev/null +++ b/compiler/msvc/CompilerUtils.h @@ -0,0 +1,28 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_COMPILER_MSVC_COMPILER_UTILS_H +#define TOS_COMPILER_MSVC_COMPILER_UTILS_H + +#include "../../utils/TestUtils.h" +#include + +#define PACKED_STRUCT __pragma(pack(push, 1)) +#define UNPACKED_STRUCT __pragma(pack(pop)) + +#define EXPORT_LIB extern "C" __declspec(dllexport) + +typedef SSIZE_T ssize_t; + +#if DEBUG + #define UNREACHABLE() ASSERT_SIMPLE(false) +#else + #define UNREACHABLE() __assume(0) +#endif + +#endif \ No newline at end of file diff --git a/font/Font.h b/font/Font.h index 99adfb1..5fda67d 100644 --- a/font/Font.h +++ b/font/Font.h @@ -17,10 +17,8 @@ struct GlyphMetrics { }; struct GlyphTextureCoords { - f32 x1; - f32 y1; - f32 x2; - f32 y2; + v2_f32 start; + v2_f32 end; }; #define GLYPH_SIZE 40 @@ -147,14 +145,14 @@ void font_from_file_txt( {strtof(++pos, &pos), strtof(++pos, &pos), strtof(++pos, &pos), strtof(++pos, &pos)} }; - font->glyphs[glyph_index].metrics.width = font->glyphs[glyph_index].coords.x2 - font->glyphs[glyph_index].coords.x1; - font->glyphs[glyph_index].metrics.height = font->glyphs[glyph_index].coords.y2 - font->glyphs[glyph_index].coords.y1; + font->glyphs[glyph_index].metrics.width = font->glyphs[glyph_index].coords.end.x - font->glyphs[glyph_index].coords.start.x; + font->glyphs[glyph_index].metrics.height = font->glyphs[glyph_index].coords.end.y - font->glyphs[glyph_index].coords.start.y; - font->glyphs[glyph_index].coords.x1 /= image_width; - font->glyphs[glyph_index].coords.x2 /= image_width; + font->glyphs[glyph_index].coords.start.x /= image_width; + font->glyphs[glyph_index].coords.end.x /= image_width; - font->glyphs[glyph_index].coords.y1 /= image_height; - font->glyphs[glyph_index].coords.y2 /= image_height; + font->glyphs[glyph_index].coords.start.y /= image_height; + font->glyphs[glyph_index].coords.end.y /= image_height; ++glyph_index; @@ -263,9 +261,9 @@ void font_invert_coordinates(Font* font) { // @todo Implement y-offset correction for (uint32 i = 0; i < font->glyph_count; ++i) { - float temp = font->glyphs[i].coords.y1; - font->glyphs[i].coords.y1 = 1.0f - font->glyphs[i].coords.y2; - font->glyphs[i].coords.y2 = 1.0f - temp; + float temp = font->glyphs[i].coords.start.y; + font->glyphs[i].coords.start.y = 1.0f - font->glyphs[i].coords.end.y; + font->glyphs[i].coords.end.y = 1.0f - temp; } } diff --git a/gpuapi/RenderUtils.h b/gpuapi/RenderUtils.h index 91fc251..961f2c5 100644 --- a/gpuapi/RenderUtils.h +++ b/gpuapi/RenderUtils.h @@ -13,267 +13,112 @@ #include #include "../stdlib/Types.h" #include "../utils/StringUtils.h" -#include "../math/matrix/MatrixFloat32.h" #include "../font/Font.h" #include "../object/Vertex.h" -#include "../ui/UITheme.h" -#include "../ui/UIElement.h" #include "../ui/UIAlignment.h" - -// @performance Create improved vertex generation for components (input + button, chat, ...) where we don't use as many -// degenerate triangle - -// @todo in many places we use ->value_int. We should load it as a value_float and also define it as float in the theme. -// This way we wouldn't have to convert the value +#include "../architecture/Intrinsics.h" inline -void vertex_degenerate_create( - Vertex3DTextureColorIndex* __restrict vertices, uint32* __restrict index, f32 zindex, +int32 vertex_degenerate_create( + Vertex3DTextureColor* __restrict vertices, f32 zindex, f32 x, f32 y ) { // Degenerate triangles // They are alternating every loop BUT since we use references they look the same in code // WARNING: Before using we must make sure that the 0 index is defined // The easiest way is to just define a "degenerate" starting point - vertices[*index] = {{vertices[*index - 1].position.x, vertices[*index - 1].position.y, zindex}, {0, 0}, 0}; - ++(*index); + vertices[0] = {{vertices[0 - 1].position.x, vertices[0 - 1].position.y, zindex}, {0, 0}}; + vertices[1] = {{x, y, zindex}, {0, 0}}; - vertices[*index] = {{x, y, zindex}, {0, 0}, 0}; - ++(*index); + return 2; } inline -void vertex_line_create( - Vertex3DTextureColorIndex* __restrict vertices, uint32* __restrict index, f32 zindex, - f32 x1, f32 y1, f32 x2, f32 y2, f32 thickness, int32 align_h, int32 align_v, - f32 color_index = 0, f32 tex_x1 = 0.0f, f32 tex_y1 = 0.0f, f32 tex_x2 = 0.0f, f32 tex_y2 = 0.0f +void adjust_aligned_position( + f32* __restrict x, f32* __restrict y, + f32 width, f32 height, + byte alignment +) +{ + if (alignment & UI_ALIGN_H_RIGHT) { + *x -= width; + } else if (alignment & UI_ALIGN_H_CENTER) { + *x -= width / 2; + } + + if (alignment & UI_ALIGN_V_TOP) { + *y -= height; + } else if (alignment & UI_ALIGN_V_CENTER) { + *y -= height / 2; + } +} + +inline +int32 vertex_line_create( + Vertex3DTextureColor* __restrict vertices, f32 zindex, + v2_f32 start, v2_f32 end, f32 thickness, byte alignment, + uint32 rgba = 0 ) { - if (align_h == UI_ALIGN_H_RIGHT) { - x1 -= thickness; - x2 -= thickness; - } else if (align_h == UI_ALIGN_H_CENTER) { - x1 -= thickness / 2; - x2 -= thickness / 2; + if (alignment & UI_ALIGN_H_RIGHT) { + start.x -= thickness; + end.x -= thickness; + } else if (alignment & UI_ALIGN_H_CENTER) { + start.x -= thickness / 2; + end.x -= thickness / 2; } - if (align_v == UI_ALIGN_V_TOP) { - y1 -= thickness; - y2 -= thickness; - } else if (align_v == UI_ALIGN_V_CENTER) { - y1 -= thickness / 2; - y2 -= thickness / 2; + if (alignment & UI_ALIGN_V_TOP) { + start.y -= thickness; + end.y -= thickness; + } else if (alignment & UI_ALIGN_V_CENTER) { + start.y -= thickness / 2; + end.y -= thickness / 2; } - f32 n1 = -(y2 - y1); - f32 n2 = x2 - x1; - f32 n_ = oms_rsqrt(n2 * n2 + n1 * n1); + f32 n1 = -(end.y - start.y); + f32 n2 = end.x - start.x; + f32 n_ = intrin_rsqrt_f32(n2 * n2 + n1 * n1); f32 norm1 = n1 * n_; f32 norm2 = n2 * n_; - vertex_degenerate_create(vertices, index, zindex, x1, y1); + int32 idx = vertex_degenerate_create(vertices, zindex, start.x, start.y); - int32 idx = *index; + vertices[idx++] = {{start.x, start.y, zindex}, {-((f32) rgba), 0.0f}}; + vertices[idx++] = {{start.x + thickness * norm1, start.y + thickness * norm2, zindex}, {-((f32) rgba), 0.0f}}; + vertices[idx++] = {{end.x, end.y, zindex}, {-((f32) rgba), 0.0f}}; + vertices[idx++] = {{end.x + thickness * norm1, end.y + thickness * norm2, zindex}, {-((f32) rgba), 0.0f}}; - vertices[idx++] = {{x1, y1, zindex}, {tex_x1, tex_y1}, color_index}; - vertices[idx++] = {{x1 + thickness * norm1, y1 + thickness * norm2, zindex}, {tex_x1, tex_y2}, color_index}; - vertices[idx++] = {{x2, y2, zindex}, {tex_x2, tex_y1}, color_index}; - vertices[idx++] = {{x2 + thickness * norm1, y2 + thickness * norm2, zindex}, {tex_x2, tex_y2}, color_index}; - - *index = idx; + return idx; } // @performance Do we really want to create the UI as one continuous mesh? // Individual meshes without degenerates might be faster inline -void vertex_rect_create( - Vertex3DTextureColorIndex* __restrict vertices, uint32* __restrict index, f32 zindex, - f32 x, f32 y, f32 width, f32 height, int32 align_h, int32 align_v, - f32 color_index = 0, f32 tex_x1 = 0.0f, f32 tex_y1 = 0.0f, f32 tex_x2 = 0.0f, f32 tex_y2 = 0.0f +int32 vertex_rect_create( + Vertex3DTextureColor* __restrict vertices, f32 zindex, + v4_f32 dimension, byte alignment, + uint32 rgba = 0, v2_f32 tex1 = {0}, v2_f32 tex2 = {0} ) { - if (align_h == UI_ALIGN_H_RIGHT) { - x -= width; - } else if (align_h == UI_ALIGN_H_CENTER) { - x -= width / 2; + if (alignment) { + adjust_aligned_position(&dimension.x, &dimension.y, dimension.width, dimension.height, alignment); } - if (align_v == UI_ALIGN_V_TOP) { - y -= height; - } else if (align_v == UI_ALIGN_V_CENTER) { - y -= height / 2; + if (rgba) { + tex1.x = -((f32) rgba); + tex2.x = -((f32) rgba); } - vertex_degenerate_create(vertices, index, zindex, x, y); + int32 idx = vertex_degenerate_create(vertices, zindex, dimension.x, dimension.y); - f32 y_height = y + height; - f32 x_width = x + width; + f32 y_height = dimension.y + dimension.height; + f32 x_width = dimension.x + dimension.width; - // Rectangle - int32 idx = *index; + vertices[idx++] = {{dimension.x, dimension.y, zindex}, {tex1.x, tex1.y}}; + vertices[idx++] = {{dimension.x, y_height, zindex}, {tex1.x, tex2.y}}; + vertices[idx++] = {{x_width, dimension.y, zindex}, {tex2.x, tex1.y}}; + vertices[idx++] = {{x_width, y_height, zindex}, {tex2.x, tex2.y}}; - vertices[idx++] = {{x, y, zindex}, {tex_x1, tex_y1}, color_index}; - vertices[idx++] = {{x, y_height, zindex}, {tex_x1, tex_y2}, color_index}; - vertices[idx++] = {{x_width, y, zindex}, {tex_x2, tex_y1}, color_index}; - vertices[idx++] = {{x_width, y_height, zindex}, {tex_x2, tex_y2}, color_index}; - - *index = idx; -} - -// @todo also allow background -> we can benefit from reduced vertex count -// All we have to do is add 3 more vertices (= inside vertices) -inline -void vertex_rect_border_create( - Vertex3DTextureColorIndex* __restrict vertices, uint32* __restrict index, f32 zindex, - f32 x, f32 y, f32 width, f32 height, f32 thickness, int32 align_h, int32 align_v, - f32 color_index = 0, f32 tex_x1 = 0.0f, f32 tex_y1 = 0.0f, f32 tex_x2 = 0.0f, f32 tex_y2 = 0.0f -) { - if (align_h == UI_ALIGN_H_RIGHT) { - x -= width; - } else if (align_h == UI_ALIGN_H_CENTER) { - x -= width / 2; - } - - if (align_v == UI_ALIGN_V_TOP) { - y -= height; - } else if (align_v == UI_ALIGN_V_CENTER) { - y -= height / 2; - } - - vertex_degenerate_create(vertices, index, zindex, x, y); - - // @bug While this works for the whole rectangle it doesn't work for individual borders - // @todo We need a version where you can define individual borders - - f32 y_height = y + height; - f32 y_thickness = y + thickness; - f32 x_width = x + width; - f32 x_thickness = x + thickness; - - // Rectangle - // Top border - vertices[*index].position.x = x; - vertices[*index].position.y = y; - vertices[*index].position.z = zindex; - vertices[*index].tex_coord.x = tex_x1; - vertices[*index].tex_coord.y = tex_y1; - vertices[*index].color = color_index; - ++(*index); - - vertices[*index].position.x = x; - vertices[*index].position.y = y_thickness; - vertices[*index].position.z = zindex; - vertices[*index].tex_coord.x = tex_x1; - vertices[*index].tex_coord.y = tex_y2; - vertices[*index].color = color_index; - ++(*index); - - vertices[*index].position.x = x_width; - vertices[*index].position.y = y; - vertices[*index].position.z = zindex; - vertices[*index].tex_coord.x = tex_x2; - vertices[*index].tex_coord.y = tex_y1; - vertices[*index].color = color_index; - ++(*index); - - vertices[*index].position.x = x_width; - vertices[*index].position.y = y_thickness; - vertices[*index].position.z = zindex; - vertices[*index].tex_coord.x = tex_x2; - vertices[*index].tex_coord.y = tex_y2; - vertices[*index].color = color_index; - ++(*index); - - // Right border - vertices[*index].position.x = x_width - thickness; - vertices[*index].position.y = y_thickness; - vertices[*index].position.z = zindex; - vertices[*index].tex_coord.x = tex_x2; - vertices[*index].tex_coord.y = tex_y2; - vertices[*index].color = color_index; - ++(*index); - - vertices[*index].position.x = x_width; - vertices[*index].position.y = y_height; - vertices[*index].position.z = zindex; - vertices[*index].tex_coord.x = tex_x1; - vertices[*index].tex_coord.y = tex_y2; - vertices[*index].color = color_index; - ++(*index); - - vertices[*index].position.x = x_width - thickness; - vertices[*index].position.y = y_height; - vertices[*index].position.z = zindex; - vertices[*index].tex_coord.x = tex_x2; - vertices[*index].tex_coord.y = tex_y1; - vertices[*index].color = color_index; - ++(*index); - - // Bottom border - vertices[*index].position.x = x_width - thickness; - vertices[*index].position.y = y_height - thickness; - vertices[*index].position.z = zindex; - vertices[*index].tex_coord.x = tex_x2; - vertices[*index].tex_coord.y = tex_y2; - vertices[*index].color = color_index; - ++(*index); - - vertices[*index].position.x = x; - vertices[*index].position.y = y_height; - vertices[*index].position.z = zindex; - vertices[*index].tex_coord.x = tex_x1; - vertices[*index].tex_coord.y = tex_y2; - vertices[*index].color = color_index; - ++(*index); - - vertices[*index].position.x = x; - vertices[*index].position.y = y_height - thickness; - vertices[*index].position.z = zindex; - vertices[*index].tex_coord.x = tex_x2; - vertices[*index].tex_coord.y = tex_y1; - vertices[*index].color = color_index; - ++(*index); - - // Left border - vertices[*index].position.x = x_thickness; - vertices[*index].position.y = y_height - thickness; - vertices[*index].position.z = zindex; - vertices[*index].tex_coord.x = tex_x2; - vertices[*index].tex_coord.y = tex_y2; - vertices[*index].color = color_index; - ++(*index); - - vertices[*index].position.x = x; - vertices[*index].position.y = y_thickness; - vertices[*index].position.z = zindex; - vertices[*index].tex_coord.x = tex_x1; - vertices[*index].tex_coord.y = tex_y2; - vertices[*index].color = color_index; - ++(*index); - - vertices[*index].position.x = x_thickness; - vertices[*index].position.y = y_thickness; - vertices[*index].position.z = zindex; - vertices[*index].tex_coord.x = tex_x2; - vertices[*index].tex_coord.y = tex_y1; - vertices[*index].color = color_index; - ++(*index); -} - -void vertex_input(Vertex3DTextureColorIndex* __restrict vertices, uint32* __restrict index, f32 zindex, - f32 x, f32 y, f32 width, f32 height, int32 align_h, int32 align_v, - f32 color_index = 0, f32 tex_x1 = 0.0f, f32 tex_y1 = 0.0f, f32 tex_x2 = 0.0f, f32 tex_y2 = 0.0f -) -{ - vertex_rect_border_create( - vertices, index, zindex, - x, y, width, height, 1, UI_ALIGN_H_LEFT, UI_ALIGN_V_BOTTOM, - 12, 0.0f, 0.0f - ); - - vertex_rect_create( - vertices, index, zindex, - x + 1, y + 1, width - 2, height - 2, UI_ALIGN_H_LEFT, UI_ALIGN_V_BOTTOM, - 14, 0.0f, 0.0f - ); + return idx; } static inline @@ -365,36 +210,30 @@ void text_calculate_dimensions( // we might want to implement distance field font atlas // @todo We should be able to cut off text at an arbitrary position, not just at a line_height incremental // we could probably get the MIN of the glyph height and the remaining window height -v2_f32 vertex_text_create( - Vertex3DTextureColorIndex* __restrict vertices, uint32* __restrict index, f32 zindex, - f32 x, f32 y, f32 width, f32 height, int32 align_h, int32 align_v, - const Font* __restrict font, const char* __restrict text, f32 size, f32 color_index = 0 +v3_int32 vertex_text_create( + Vertex3DTextureColor* __restrict vertices, f32 zindex, + v4_f32 dimension, byte alignment, + const Font* __restrict font, const char* __restrict text, + f32 size, uint32 rgba = 0, + f32 font_weight = 1.0f ) { int32 length = utf8_strlen(text); bool is_ascii = (int32) strlen(text) == length; f32 scale = size / font->size; // If we do a different alignment we need to pre-calculate the width and height - if (align_h != 0 || align_v != 0) { - if (align_h != 0 && align_v != 0) { - text_calculate_dimensions(&width, &height, font, text, is_ascii, scale, length); - } else if (align_h != 0) { - width = text_calculate_dimensions_width(font, text, is_ascii, scale, length); + if (alignment & (UI_ALIGN_H_RIGHT | UI_ALIGN_H_CENTER | UI_ALIGN_V_TOP | UI_ALIGN_V_CENTER)) { + if ((alignment & (UI_ALIGN_H_RIGHT | UI_ALIGN_H_CENTER)) + && (alignment & (UI_ALIGN_V_TOP | UI_ALIGN_V_CENTER)) + ) { + text_calculate_dimensions(&dimension.width, &dimension.height, font, text, is_ascii, scale, length); + } else if (alignment & (UI_ALIGN_H_RIGHT | UI_ALIGN_H_CENTER)) { + dimension.width = text_calculate_dimensions_width(font, text, is_ascii, scale, length); } else { - height = text_calculate_dimensions_height(font, text, scale, length); + dimension.height = text_calculate_dimensions_height(font, text, scale, length); } - if (align_h == UI_ALIGN_H_RIGHT) { - x -= width; - } else if (align_h == UI_ALIGN_H_CENTER) { - x -= width / 2; - } - - if (align_v == UI_ALIGN_V_TOP) { - y -= height; - } else if (align_v == UI_ALIGN_V_CENTER) { - y -= height / 2; - } + adjust_aligned_position(&dimension.x, &dimension.y, dimension.width, dimension.height, alignment); } f32 line_height_scaled = font->line_height * scale; @@ -402,15 +241,17 @@ v2_f32 vertex_text_create( f32 rendered_width = 0; f32 rendered_height = line_height_scaled; - f32 offset_x = x; + int32 idx = 0; + + f32 offset_x = dimension.x; for (int32 i = 0; i < length; ++i) { int32 character = is_ascii ? text[i] : utf8_get_char_at(text, i); if (character == '\n') { rendered_height += line_height_scaled; - rendered_width = OMS_MAX(rendered_width, offset_x - x); + rendered_width = OMS_MAX(rendered_width, offset_x - dimension.x); - y -= line_height_scaled; - offset_x = x; + dimension.y -= line_height_scaled; + offset_x = dimension.x; continue; } @@ -420,15 +261,17 @@ v2_f32 vertex_text_create( continue; } - f32 offset_y = y + glyph->metrics.offset_y * scale; + f32 offset_y = dimension.y + glyph->metrics.offset_y * scale; offset_x += glyph->metrics.offset_x * scale; - // @performance Consider to handle whitespaces just by offsetting - vertex_rect_create( - vertices, index, zindex, - offset_x, offset_y, glyph->metrics.width * scale, glyph->metrics.height * scale, UI_ALIGN_H_LEFT, UI_ALIGN_V_BOTTOM, - color_index, glyph->coords.x1, glyph->coords.y1, glyph->coords.x2, glyph->coords.y2 - ); + if (character != ' ' && character != '\t') { + // @todo We should probably inline the code here, we might be able to even optimize it then + idx += vertex_rect_create( + vertices, zindex, + {offset_x, offset_y, glyph->metrics.width * scale, glyph->metrics.height * scale}, 0, + rgba, glyph->coords.start, glyph->coords.end + ); + } offset_x += (glyph->metrics.width + glyph->metrics.advance_x) * scale; } @@ -439,150 +282,7 @@ v2_f32 vertex_text_create( // This way we can ensure no overflow easily // @todo implement line alignment, currently only total alignment is considered - return {rendered_width, rendered_height}; + return {(int32) rendered_width, (int32) rendered_height, idx}; } -inline -void entity_world_space(f32* world_space, const f32* local_space, const f32* model_mat) -{ - mat4vec4_mult(model_mat, local_space, world_space); -} - -inline -void entity_view_space(f32* view_space, const f32* world_space, const f32* view_mat) -{ - mat4vec4_mult(view_mat, world_space, view_space); -} - -inline -void entity_clip_space(f32* clip_space, const f32* view_space, const f32* projection_mat) -{ - mat4vec4_mult(projection_mat, view_space, clip_space); -} - -inline -void entity_clip_space_mat(f32* result_mat, const f32* model_mat, const f32* view_mat, const f32* projection_mat) -{ - f32 temp[16]; - mat4mat4_mult(projection_mat, view_mat, temp); - mat4mat4_mult(temp, model_mat, result_mat); -} - -/** - * Create the matrix used to transform from local space to clip space - * - * This allows us to transform multiple objects with the same matrix - * - * Vclip = Mprojection * Mview * Mmodel * Vlocal - */ -void entity_clip_space_mat_sse(f32* result_mat, const f32* model_mat, const f32* view_mat, const f32* projection_mat) -{ - __m128 temp[4]; - - __m128 a[4]; - __m128 b[4]; - - a[0] = _mm_load_ps(projection_mat); - a[1] = _mm_load_ps(&projection_mat[4]); - a[2] = _mm_load_ps(&projection_mat[8]); - a[3] = _mm_load_ps(&projection_mat[12]); - - b[0] = _mm_load_ps(view_mat); - b[1] = _mm_load_ps(&view_mat[4]); - b[2] = _mm_load_ps(&view_mat[8]); - b[3] = _mm_load_ps(&view_mat[12]); - _MM_TRANSPOSE4_PS(b[0], b[1], b[2], b[3]); - - mat4mat4_mult_sse(a, b, temp); - - a[0] = temp[0]; - a[1] = temp[1]; - a[2] = temp[2]; - a[3] = temp[3]; - - b[0] = _mm_load_ps(model_mat); - b[1] = _mm_load_ps(&model_mat[4]); - b[2] = _mm_load_ps(&model_mat[8]); - b[3] = _mm_load_ps(&model_mat[12]); - _MM_TRANSPOSE4_PS(b[0], b[1], b[2], b[3]); - - mat4mat4_mult_sse(a, b, temp); - _mm_store_ps(&result_mat[0], temp[0]); - _mm_store_ps(&result_mat[4], temp[1]); - _mm_store_ps(&result_mat[8], temp[2]); - _mm_store_ps(&result_mat[12], temp[3]); -} - -inline -void entity_clip_space_from_local(f32* clip_space, const f32* local_space, const f32* mat) -{ - mat4vec4_mult(mat, local_space, clip_space); -} - -inline -void entity_clip_space_from_local_sse(f32* clip_space, const f32* local_space, const f32* mat) -{ - mat4vec4_mult_sse(mat, local_space, clip_space); -} - -/* -inline -void entity_screen_space(f32* screen_space, const f32* clip_space, const f32* viewport_mat) -{ - // @todo implement -} -*/ - -inline -void entity_world_space_sse(f32* world_space, const f32* local_space, const f32* model_mat) -{ - mat4vec4_mult_sse(model_mat, local_space, world_space); -} - -inline -void entity_view_space_sse(f32* view_space, const f32* world_space, const f32* view_mat) -{ - mat4vec4_mult_sse(view_mat, world_space, view_space); -} - -inline -void entity_clip_space_sse(f32* clip_space, const f32* view_space, const f32* projection_mat) -{ - mat4vec4_mult_sse(projection_mat, view_space, clip_space); -} - -/* -inline -void entity_screen_space_sse(f32* screen_space, const f32* clip_space, const f32* viewport_mat) -{ - // @todo implement -} -*/ - -inline -void entity_world_space_sse(__m128* world_space, const __m128* local_space, const __m128* model_mat) -{ - mat4vec4_mult_sse(model_mat, local_space, world_space); -} - -inline -void entity_view_space_sse(__m128* view_space, const __m128* world_space, const __m128* view_mat) -{ - mat4vec4_mult_sse(view_mat, world_space, view_space); -} - -inline -void entity_clip_space_sse(__m128* clip_space, const __m128* view_space, const __m128* projection_mat) -{ - mat4vec4_mult_sse(projection_mat, view_space, clip_space); -} - -/* -inline -void entity_screen_space_sse(__m128* screen_space, const __m128* clip_space, const __m128* viewport_mat) -{ - // @todo implement -} -*/ - #endif \ No newline at end of file diff --git a/gpuapi/UIUtils.h b/gpuapi/UIUtils.h deleted file mode 100644 index 360de9e..0000000 --- a/gpuapi/UIUtils.h +++ /dev/null @@ -1,252 +0,0 @@ -/** - * Jingga - * - * @copyright Jingga - * @license OMS License 2.0 - * @version 1.0.0 - * @link https://jingga.app - */ -#ifndef TOS_GPUAPI_UI_UTILS_H -#define TOS_GPUAPI_UI_UTILS_H - -#include -#include - -void ui_input_create(Vertex3DTextureColorIndex* __restrict vertices, uint32* __restrict index, f32 zindex, - f32 x, f32 y, f32 width, f32 height, int32 align_h, int32 align_v, - uint32 color_index = 0, f32 tex_x1 = 0.0f, f32 tex_y1 = 0.0f, f32 tex_x2 = 0.0f, f32 tex_y2 = 0.0f -) -{ - vertex_rect_border_create( - vertices, index, zindex, - x, y, width, height, 1, UI_ALIGN_H_LEFT, UI_ALIGN_V_BOTTOM, - 12, 0.0f, 0.0f - ); - - vertex_rect_create( - vertices, index, zindex, - x + 1, y + 1, width - 2, height - 2, UI_ALIGN_H_LEFT, UI_ALIGN_V_BOTTOM, - 14, 0.0f, 0.0f - ); -} - - -// @todo implement shadow (offset + angle + diffuse) or should this be a shader only thing? if so this would be a problem for us since we are handling text in the same shader as simple shapes -// we might want to implement distance field font atlas -f32 ui_text_create( - Vertex3DTextureColorIndex* __restrict vertices, uint32* __restrict index, f32 zindex, - UIThemeStyle* theme, UIElement* element -) { - if (element->vertex_count > 0) { - memcpy(vertices + *index, element->vertices, sizeof(Vertex3DTextureColorIndex) * element->vertex_count); - - return vertices[element->vertex_count - 1].position.x; - } - - // @performance see comment for setup_theme() - - // Load element data - HashEntryVoidP* element_entry = (HashEntryVoidP *) hashmap_get_entry(&theme->hash_map, element->name, element->id); - UIAttributeGroup* element_group = (UIAttributeGroup *) element_entry->value; - - // Load general style - UIAttribute* style = ui_attribute_from_group(element_group, UI_ATTRIBUTE_TYPE_STYLE); - HashEntryVoidP* style_entry = NULL; - UIAttributeGroup* style_group = NULL; - - if (style) { - style_entry = (HashEntryVoidP *) hashmap_get_entry(&theme->hash_map, style->value_str); - style_group = (UIAttributeGroup *) style_entry->value; - } - - UIAttribute* x; - UIAttribute* y; - - // Load parent data (for position data) - UIAttribute* parent = ui_attribute_from_group(element_group, UI_ATTRIBUTE_TYPE_PARENT); - if (parent) { - HashEntryVoidP* parent_entry = (HashEntryVoidP *) hashmap_get_entry(&theme->hash_map, parent->value_str); - UIAttributeGroup* parent_group = (UIAttributeGroup *) parent_entry->value; - - x = ui_attribute_from_group(parent_group, UI_ATTRIBUTE_TYPE_POSITION_X); - y = ui_attribute_from_group(parent_group, UI_ATTRIBUTE_TYPE_POSITION_Y); - - // @question Do we have more values which can be inherited from the parent? - // We don't want to inherit implicit stuff like size, background etc. These things should be defined explicitly - } else { - x = ui_attribute_from_group(element_group, UI_ATTRIBUTE_TYPE_POSITION_X); - y = ui_attribute_from_group(element_group, UI_ATTRIBUTE_TYPE_POSITION_Y); - } - - UIAttribute* width = ui_attribute_from_group(element_group, UI_ATTRIBUTE_TYPE_DIMENSION_WIDTH); - UIAttribute* height = ui_attribute_from_group(element_group, UI_ATTRIBUTE_TYPE_DIMENSION_HEIGHT); - UIAttribute* align_h = ui_attribute_from_group(element_group, UI_ATTRIBUTE_TYPE_ALIGN_H); - UIAttribute* align_v = ui_attribute_from_group(element_group, UI_ATTRIBUTE_TYPE_ALIGN_V); - UIAttribute* text = ui_attribute_from_group(element_group, UI_ATTRIBUTE_TYPE_CONTENT); - UIAttribute* size = ui_attribute_from_group(element_group, UI_ATTRIBUTE_TYPE_FONT_SIZE); - UIAttribute* color_index = ui_attribute_from_group(element_group, UI_ATTRIBUTE_TYPE_FONT_COLOR); - - int32 length = utf8_strlen(text->value_str); - bool is_ascii = strlen(text->value_str) == length; - f32 scale = size->value_float / theme->font->size; - - // If we do a different alignment we need to pre-calculate the width and height - if (align_h != NULL || align_v != NULL) { - f32 tmp_width = (f32) width->value_int; - f32 tmp_height = (f32) height->value_int; - - if (align_h != NULL && align_v != NULL) { - text_calculate_dimensions(&tmp_width, &tmp_height, theme->font, text->value_str, is_ascii, scale, length); - } else if (align_h != NULL) { - tmp_width = text_calculate_dimensions_width(theme->font, text->value_str, is_ascii, scale, length); - } else { - tmp_height = text_calculate_dimensions_height(theme->font, text->value_str, scale, length); - } - - if (align_h->value_int == UI_ALIGN_H_RIGHT) { - x -= width->value_int; - } else if (align_h->value_int == UI_ALIGN_H_CENTER) { - x -= width->value_int / 2; - } - - if (align_v->value_int == UI_ALIGN_V_TOP) { - y -= height->value_int; - } else if (align_v->value_int == UI_ALIGN_V_CENTER) { - y -= height->value_int / 2; - } - } - - int32 start = *index; - f32 offset_x = (f32) x->value_int; - f32 offset_y = (f32) y->value_int; - - int32 first_char = is_ascii ? text->value_str[0] : utf8_get_char_at(text->value_str, 0); - for (int32 i = (first_char == '\n' ? 1 : 0); i < length; ++i) { - int32 character = is_ascii ? text->value_str[i] : utf8_get_char_at(text->value_str, i); - - if (character == '\n') { - offset_y += theme->font->line_height * scale; - offset_x = (f32) x->value_int; - - continue; - } - - Glyph* glyph = font_glyph_find(theme->font, character); - if (!glyph) { - continue; - } - - f32 offset_y2 = offset_y + glyph->metrics.offset_y * scale; - offset_x += glyph->metrics.offset_x * scale; - - // @performance Consider to handle whitespaces just by offsetting - vertex_rect_create( - vertices, index, zindex, - offset_x, offset_y2, glyph->metrics.width * scale, glyph->metrics.height * scale, UI_ALIGN_H_LEFT, UI_ALIGN_V_BOTTOM, - color_index->value_float, glyph->coords.x1, glyph->coords.y1, glyph->coords.x2, glyph->coords.y2 - ); - - offset_x += (glyph->metrics.width + glyph->metrics.advance_x) * scale; - } - - element->vertex_count = *index - start; - memcpy(element->vertices, vertices + start, sizeof(Vertex3DTextureColorIndex) * element->vertex_count); - - // @todo See todo of vertex_text function - // @performance use elements->vertices and also cache result in there - - return offset_x; -} - -void ui_button_create( - Vertex3DTextureColorIndex* __restrict vertices, uint32* __restrict index, f32 zindex, - UIThemeStyle* theme, UIElement* element -) -{ - // @todo handle different states and ongoing animations - // We cannot return early in such cases - if (element->vertex_count > 0) { - memcpy(vertices + *index, element->vertices, sizeof(Vertex3DTextureColorIndex) * element->vertex_count); - return; - } - - // @performance see comment for setup_theme() - - // Load element data - HashEntryVoidP* element_entry = (HashEntryVoidP *) hashmap_get_entry(&theme->hash_map, element->name, element->id); - UIAttributeGroup* element_group = (UIAttributeGroup *) element_entry->value; - - // Load general style - UIAttribute* style = ui_attribute_from_group(element_group, UI_ATTRIBUTE_TYPE_STYLE); - HashEntryVoidP* style_entry = NULL; - UIAttributeGroup* style_group = NULL; - - if (style) { - style_entry = (HashEntryVoidP *) hashmap_get_entry(&theme->hash_map, style->value_str); - style_group = (UIAttributeGroup *) style_entry->value; - } - - UIAttribute* x; - UIAttribute* y; - - // Load parent data (for position data) - UIAttribute* parent = ui_attribute_from_group(element_group, UI_ATTRIBUTE_TYPE_PARENT); - if (parent) { - HashEntryVoidP* parent_entry = (HashEntryVoidP *) hashmap_get_entry(&theme->hash_map, parent->value_str); - UIAttributeGroup* parent_group = (UIAttributeGroup *) parent_entry->value; - - x = ui_attribute_from_group(parent_group, UI_ATTRIBUTE_TYPE_POSITION_X); - y = ui_attribute_from_group(parent_group, UI_ATTRIBUTE_TYPE_POSITION_Y); - - // @question Do we have more values which can be inherited from the parent? - // We don't want to inherit implicit stuff like size, background etc. These things should be defined explicitly - } else { - x = ui_attribute_from_group(element_group, UI_ATTRIBUTE_TYPE_POSITION_X); - y = ui_attribute_from_group(element_group, UI_ATTRIBUTE_TYPE_POSITION_Y); - } - - UIAttribute* width = ui_attribute_from_group(element_group, UI_ATTRIBUTE_TYPE_DIMENSION_WIDTH); - UIAttribute* height = ui_attribute_from_group(element_group, UI_ATTRIBUTE_TYPE_DIMENSION_HEIGHT); - UIAttribute* align_h = ui_attribute_from_group(element_group, UI_ATTRIBUTE_TYPE_ALIGN_H); - UIAttribute* align_v = ui_attribute_from_group(element_group, UI_ATTRIBUTE_TYPE_ALIGN_V); - UIAttribute* text = ui_attribute_from_group(element_group, UI_ATTRIBUTE_TYPE_CONTENT); - UIAttribute* size = ui_attribute_from_group(element_group, UI_ATTRIBUTE_TYPE_FONT_SIZE); - UIAttribute* color_index = ui_attribute_from_group(element_group, UI_ATTRIBUTE_TYPE_FONT_COLOR); - - // @todo Above we only handle the default values, what about state dependent values like hover, active? - // Simply check the state here and load the child_entries based on the state - // However, for that we need the current state of the button... should this be in a separate button object, - // that also holds position information for hover checks etc. Or should that state be stored in the theme data? - // Right now we could make these checks right here anyway but in the future we don't want to update the rendering data - // every frame if we don't have to. We don't want immediate mode! We only want to update the UI if there is a change. - // If a change (or state change like hover) triggers a complete update of all elements or just a sub region update - // remains TBD - - int32 start = *index; - - vertex_rect_border_create( - vertices, index, zindex, - x->value_float, y->value_float, width->value_float, height->value_float, 1, UI_ALIGN_H_LEFT, UI_ALIGN_V_BOTTOM, - 12, 0.0f, 0.0f - ); - - vertex_rect_create( - vertices, index, zindex, - x->value_float + 1, y->value_float + 1, width->value_float - 2, height->value_float - 2, UI_ALIGN_H_LEFT, UI_ALIGN_V_BOTTOM, - 14, 0.0f, 0.0f - ); - - zindex = nextafterf(zindex, INFINITY); - - vertex_text_create( - vertices, index, zindex, - x->value_float, y->value_float, width->value_float, height->value_float, align_h->value_int, align_v->value_int, - theme->font, text->value_str, size->value_float, color_index->value_float - ); - - element->vertex_count = *index - start; - memcpy(element->vertices, vertices + start, sizeof(Vertex3DTextureColorIndex) * element->vertex_count); -} - - -#endif \ No newline at end of file diff --git a/gpuapi/opengl/OpenglWin32.h b/gpuapi/opengl/OpenglWin32.h index 061784d..148f73e 100644 --- a/gpuapi/opengl/OpenglWin32.h +++ b/gpuapi/opengl/OpenglWin32.h @@ -858,6 +858,7 @@ void opengl_init(Window* window, int32 multisample = 0) opengl_init_wgl(); + // @question Why do we do the GetDC here? Couldn't we do it in UtilsWindows.h window->hdc = GetDC(window->hwnd); set_pixel_format(window->hdc, multisample); diff --git a/hash/Crc.h b/hash/Crc.h new file mode 100644 index 0000000..8beaa5e --- /dev/null +++ b/hash/Crc.h @@ -0,0 +1,76 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_HASH_CRC_H +#define TOS_HASH_CRC_H + +#include "../stdlib/Types.h" +#include "../architecture/Intrinsics.h" + +inline +uint32 crc32_software_u8(const byte* data, size_t length) { + uint32 crc = 0xFFFFFFFF; + + // Standard CRC-32 polynomial + uint32 polynomial = 0xEDB88320; + + for (size_t i = 0; i < length; ++i) { + crc ^= data[i]; + for (byte bit = 0; bit < 8; ++bit) { + crc = (crc >> 1); + + if (crc & 1) { + crc ^= polynomial; + } + } + } + + return crc; +} + +inline +uint32 crc32_intrin_u8(const byte* data, size_t length) { + uint32 crc = 0xFFFFFFFF; + for (size_t i = 0; i < length; ++i) { + crc = intrin_crc32_u8(crc, data[i]); + } + + return crc; +} + +inline +uint32 crc32_intrin_u16(const uint16* data, size_t length) { + uint32 crc = 0xFFFFFFFF; + for (size_t i = 0; i < length; ++i) { + crc = intrin_crc32_u16(crc, data[i]); + } + + return crc; +} + +inline +uint32 crc32_intrin_u32(const uint32* data, size_t length) { + uint32 crc = 0xFFFFFFFF; + for (size_t i = 0; i < length; ++i) { + crc = intrin_crc32_u32(crc, data[i]); + } + + return crc; +} + +inline +uint32 crc32_intrin_u64(const uint64* data, size_t length) { + uint64 crc = 0xFFFFFFFF; + for (size_t i = 0; i < length; ++i) { + crc = intrin_crc32_u64(crc, data[i]); + } + + return crc; +} + +#endif \ No newline at end of file diff --git a/hash/GeneralHash.h b/hash/GeneralHash.h index 7538742..5bd39e7 100644 --- a/hash/GeneralHash.h +++ b/hash/GeneralHash.h @@ -222,4 +222,18 @@ uint64 hash_ejb_seeded(const char* str, int32 seed) return (hash % PRIME2) ^ (seed + (seed << 6) + (seed >> 2));; } +inline +uint32 intrin_hash(uint64 a, uint64 b = 0) +{ + uint8 seed[16] = { + 0xaa, 0x9b, 0xbd, 0xb8, 0xa1, 0x98, 0xac, 0x3f, 0x1f, 0x94, 0x07, 0xb3, 0x8c, 0x27, 0x93, 0x69, + }; + + __m128i hash = _mm_set_epi64x(a, b); + hash = _mm_aesdec_si128(hash, _mm_loadu_si128((__m128i *) seed)); + hash = _mm_aesdec_si128(hash, _mm_loadu_si128((__m128i *) seed)); + + return _mm_extract_epi32(hash, 0); +} + #endif \ No newline at end of file diff --git a/image/Image.cpp b/image/Image.cpp index 068922a..5f80a7c 100644 --- a/image/Image.cpp +++ b/image/Image.cpp @@ -18,7 +18,7 @@ #include "Bitmap.h" #include "Png.h" -void image_from_file(Image* image, const char* path, RingMemory* ring) +void image_from_file(Image* __restrict image, const char* __restrict path, RingMemory* __restrict ring) { FileBody file; file_read(path, &file, ring); @@ -32,7 +32,7 @@ void image_from_file(Image* image, const char* path, RingMemory* ring) } } -void image_flip_vertical(RingMemory* ring, Image* image) +void image_flip_vertical(RingMemory* __restrict ring, Image* __restrict image) { uint32 stride = image->width * sizeof(uint32); byte* temp = ring_get_memory(ring, image->pixel_count * sizeof(uint32)); @@ -66,7 +66,7 @@ int32 image_data_size(const Image* image) } inline -uint32 image_header_from_data(const byte* data, Image* image) +uint32 image_header_from_data(const byte* __restrict data, Image* __restrict image) { const byte* start = data; @@ -84,7 +84,7 @@ uint32 image_header_from_data(const byte* data, Image* image) return (int32) (data - start); } -uint32 image_from_data(const byte* data, Image* image) +uint32 image_from_data(const byte* __restrict data, Image* __restrict image) { const byte* pos = data; pos += image_header_from_data(data, image); @@ -97,7 +97,7 @@ uint32 image_from_data(const byte* data, Image* image) } inline -uint32 image_header_to_data(const Image* image, byte* data) +uint32 image_header_to_data(const Image* __restrict image, byte* __restrict data) { byte* start = data; @@ -113,7 +113,7 @@ uint32 image_header_to_data(const Image* image, byte* data) return (int32) (data - start); } -uint32 image_to_data(const Image* image, byte* data) +uint32 image_to_data(const Image* __restrict image, byte* __restrict data) { byte* pos = data; pos += image_header_to_data(image, data); diff --git a/localization/Language.h b/localization/Language.h index 94ed864..e2b3f7c 100644 --- a/localization/Language.h +++ b/localization/Language.h @@ -7,12 +7,14 @@ #define LANGUAGE_VERSION 1 +// Size is limited to 4GB struct Language { - // WARNING: the actual start of data is data -= sizeof(count); see file loading below + // WARNING: the actual start of data is data -= sizeof(Language); see file loading below + // The reason for this is we store the Language struct in the beginning of the data/file byte* data; int32 count; - int64 size; + int32 size; char** lang; }; @@ -27,7 +29,7 @@ void language_from_file_txt( // count elements language->count = 1; - int64 len = 0; + int32 len = 0; byte* data = file.content; @@ -65,7 +67,7 @@ int32 language_data_size(const Language* language) return (int32) (language->size + sizeof(language->count) + sizeof(language->size) - + language->count * sizeof(uint64) + + language->count * sizeof(uint32) ); } @@ -92,12 +94,12 @@ int32 language_from_data( // Load pointers/offsets for (int32 i = 0; i < language->count; ++i) { - *pos_lang++ = (char *) (start + SWAP_ENDIAN_LITTLE(*((uint64 *) pos))); - pos += sizeof(uint64); + *pos_lang++ = (char *) (start + SWAP_ENDIAN_LITTLE(*((uint32 *) pos))); + pos += sizeof(uint32); } memcpy( - language->data + language->count * sizeof(uint64), + language->data + language->count * sizeof(uint32), pos, language->size ); @@ -123,14 +125,14 @@ int32 language_to_data( // Save pointers for (int32 i = 0; i < language->count; ++i) { - *((uint64 *) pos) = SWAP_ENDIAN_LITTLE(pos - start); - pos += sizeof(uint64); + *((uint32 *) pos) = SWAP_ENDIAN_LITTLE((uint32) ((uintptr_t) pos - (uintptr_t) start)); + pos += sizeof(uint32); } // Save actual strings memcpy( pos, - language->data + language->count * sizeof(uint64), + language->data + language->count * sizeof(uint32), language->size ); diff --git a/log/Debug.cpp b/log/Debug.cpp index e19bcaf..1851989 100644 --- a/log/Debug.cpp +++ b/log/Debug.cpp @@ -9,13 +9,8 @@ #include "../utils/StringUtils.h" #include "../utils/TestUtils.h" #include "../thread/Atomic.h" - -// Required for rdtsc(); -#if _WIN32 - #include -#else - #include -#endif +#include "../architecture/Intrinsics.h" +#include "../compiler/CompilerUtils.h" global_persist DebugContainer* debug_container = NULL; @@ -93,7 +88,7 @@ void log_to_file() inline void update_timing_stat(uint32 stat, const char* function) { - uint64 new_tick_count = __rdtsc(); + uint64 new_tick_count = intrin_timestamp_counter(); TimingStat* timing_stat = &debug_container->perf_stats[stat]; @@ -109,14 +104,14 @@ inline void update_timing_stat_start(uint32 stat, const char*) { spinlock_start(&debug_container->perf_stats_spinlock); - debug_container->perf_stats[stat].old_tick_count = __rdtsc(); + debug_container->perf_stats[stat].old_tick_count = intrin_timestamp_counter(); spinlock_end(&debug_container->perf_stats_spinlock); } inline void update_timing_stat_end(uint32 stat, const char* function) { - uint64 new_tick_count = __rdtsc(); + uint64 new_tick_count = intrin_timestamp_counter(); TimingStat* timing_stat = &debug_container->perf_stats[stat]; @@ -131,7 +126,7 @@ void update_timing_stat_end(uint32 stat, const char* function) inline void update_timing_stat_end_continued(uint32 stat, const char* function) { - uint64 new_tick_count = __rdtsc(); + uint64 new_tick_count = intrin_timestamp_counter(); TimingStat* timing_stat = &debug_container->perf_stats[stat]; @@ -241,7 +236,7 @@ void debug_memory_log(uintptr_t start, uint64 size, int32 type, const char* func dmr->start = start - mem->start; dmr->size = size; - dmr->time = __rdtsc(); + dmr->time = intrin_timestamp_counter(); dmr->function_name = function; if (type < 0 && mem->usage < size * -type) { @@ -273,7 +268,7 @@ void debug_memory_reserve(uintptr_t start, uint64 size, int32 type, const char* dmr->start = start - mem->start; dmr->size = size; - dmr->time = __rdtsc(); + dmr->time = intrin_timestamp_counter(); dmr->function_name = function; } @@ -307,7 +302,7 @@ void debug_memory_reset() } // We remove debug information that are "older" than 1GHz - uint64 time = __rdtsc() - 1 * GHZ; + uint64 time = intrin_timestamp_counter() - 1 * GHZ; for (uint64 i = 0; i < debug_container->dmc.memory_element_idx; ++i) { for (int32 j = 0; j < DEBUG_MEMORY_RANGE_MAX; ++j) { diff --git a/log/Debug.h b/log/Debug.h index 79ef15a..bb7e43a 100644 --- a/log/Debug.h +++ b/log/Debug.h @@ -32,6 +32,18 @@ #define LOG_DATA_ARRAY 5 +#ifndef DEBUG_COUNTER + #define DEBUG_COUNTER 1 + enum DebugCounter { + DEBUG_COUNTER_MEM_ALLOC, + + DEBUG_COUNTER_DRIVE_READ, + DEBUG_COUNTER_DRIVE_WRITE, + + DEBUG_COUNTER_SIZE + }; +#endif + enum LogDataType { LOG_DATA_NONE, LOG_DATA_VOID, @@ -86,6 +98,8 @@ struct DebugContainer { // Used to log general int values (e.g. counter for draw calls etc.) int64* counter; + // We are not using FileHandle here since that would require us to include more files + // These files in return require Debug.h #if _WIN32 HANDLE log_fp; #elif __linux__ diff --git a/math/Evaluator.h b/math/Evaluator.h index 3d7a544..c00f2d6 100644 --- a/math/Evaluator.h +++ b/math/Evaluator.h @@ -11,6 +11,7 @@ #include "../stdlib/Types.h" #include "../utils/StringUtils.h" +#include "../compiler/CompilerUtils.h" #include #include @@ -106,6 +107,7 @@ f32 evaluator_apply_operator(char op, f32 a, f32 b) { return a / b; default: { UNREACHABLE(); + return 0; } } } diff --git a/math/matrix/MatrixFloat32.h b/math/matrix/MatrixFloat32.h index eda2a07..67a4322 100644 --- a/math/matrix/MatrixFloat32.h +++ b/math/matrix/MatrixFloat32.h @@ -13,12 +13,7 @@ #include #include #include "../../utils/TestUtils.h" - -#if ARM - #include "../../stdlib/IntrinsicsArm.h" -#else - #include "../../stdlib/Intrinsics.h" -#endif +#include "../../architecture/Intrinsics.h" // @todo Implement intrinsic versions! @@ -29,7 +24,7 @@ inline void vec2_normalize(f32* __restrict x, f32* __restrict y) { - f32 d = oms_rsqrt((*x) * (*x) + (*y) * (*y)); + f32 d = intrin_rsqrt_f32((*x) * (*x) + (*y) * (*y)); *x *= d; *y *= d; @@ -113,7 +108,7 @@ f32 vec3_length(v3_f32* vec) inline void vec3_normalize(f32* __restrict x, f32* __restrict y, f32* __restrict z) { - f32 d = oms_rsqrt((*x) * (*x) + (*y) * (*y) + (*z) * (*z)); + f32 d = intrin_rsqrt_f32((*x) * (*x) + (*y) * (*y) + (*z) * (*z)); *x *= d; *y *= d; @@ -123,7 +118,7 @@ void vec3_normalize(f32* __restrict x, f32* __restrict y, f32* __restrict z) inline void vec3_normalize(v3_f32* vec) { - f32 d = oms_rsqrt(vec->x * vec->x + vec->y * vec->y + vec->z * vec->z); + f32 d = intrin_rsqrt_f32(vec->x * vec->x + vec->y * vec->y + vec->z * vec->z); vec->x *= d; vec->y *= d; @@ -204,7 +199,7 @@ f32 vec3_dot(const v3_f32* a, const v3_f32* b) { void vec4_normalize(f32* __restrict x, f32* __restrict y, f32* __restrict z, f32* __restrict w) { - f32 d = oms_rsqrt((*x) * (*x) + (*y) * (*y) + (*z) * (*z) + (*w) * (*w)); + f32 d = intrin_rsqrt_f32((*x) * (*x) + (*y) * (*y) + (*z) * (*z) + (*w) * (*w)); *x *= d; *y *= d; diff --git a/memory/BufferMemory.h b/memory/BufferMemory.h index e560fb7..1794458 100644 --- a/memory/BufferMemory.h +++ b/memory/BufferMemory.h @@ -13,6 +13,7 @@ #include "../stdlib/Types.h" #include "../utils/EndianUtils.h" #include "../utils/TestUtils.h" +#include "../log/Log.h" #include "../log/DebugMemory.h" #include "../system/Allocator.h" diff --git a/memory/ChunkMemory.h b/memory/ChunkMemory.h index fd0ea05..678b45f 100644 --- a/memory/ChunkMemory.h +++ b/memory/ChunkMemory.h @@ -14,6 +14,7 @@ #include "../utils/TestUtils.h" #include "../utils/EndianUtils.h" #include "../utils/BitUtils.h" +#include "../log/Log.h" #include "../log/DebugMemory.h" #include "BufferMemory.h" #include "../system/Allocator.h" @@ -125,7 +126,7 @@ void chunk_free(ChunkMemory* buf) } inline -uint32 chunk_id_from_memory(ChunkMemory* buf, byte* pos) { +uint32 chunk_id_from_memory(const ChunkMemory* buf, const byte* pos) { return (uint32) ((uintptr_t) pos - (uintptr_t) buf->memory) / buf->chunk_size; } diff --git a/memory/Queue.h b/memory/Queue.h index e93bcdd..635aa2f 100644 --- a/memory/Queue.h +++ b/memory/Queue.h @@ -192,7 +192,7 @@ bool queue_dequeue(Queue* queue, byte* data) inline bool queue_dequeue_atomic(Queue* queue, byte* data) { - if (atomic_get_acquire_release((volatile uint64 *) &queue->head) == (uint64) queue->tail) { + if ((uint64) atomic_get_acquire_release((void **) &queue->head) == (uint64) queue->tail) { return false; } diff --git a/memory/RingMemory.h b/memory/RingMemory.h index 49a53eb..d98152c 100644 --- a/memory/RingMemory.h +++ b/memory/RingMemory.h @@ -17,6 +17,7 @@ #include "../utils/TestUtils.h" #include "BufferMemory.h" +#include "../log/Log.h" #include "../log/DebugMemory.h" #include "../thread/Atomic.h" #include "../thread/Semaphore.h" @@ -270,7 +271,7 @@ bool ring_commit_safe_atomic(const RingMemory* ring, uint64 size, uint32 aligned uint64 max_mem_required = size + aligned * 2; // @todo consider to switch to uintptr_t - uint64 tail = atomic_get_relaxed((uint64 *) &ring->tail); + uint64 tail = (uint64) atomic_get_relaxed((void **) &ring->tail); // This doesn't have to be atomic since we assume single producer/consumer and a commit is performed by the consumer uint64 head = (uint64) ring->head; diff --git a/models/chat/ChatType.h b/models/chat/ChatType.h index c94a07a..ec5694e 100644 --- a/models/chat/ChatType.h +++ b/models/chat/ChatType.h @@ -9,18 +9,24 @@ #ifndef TOS_MODELS_CHAT_TYPE_H #define TOS_MODELS_CHAT_TYPE_H -enum ChatType { - CHAT_TYPE_MIXED = 1, - CHAT_TYPE_LOCAL = 2, - CHAT_TYPE_GLOBAL = 4, - CHAT_TYPE_PLAYER = 8, - CHAT_TYPE_GROUP = 16, - CHAT_TYPE_GUILD = 32, - CHAT_TYPE_AUCTION_HOUSE = 64, - CHAT_TYPE_TRADE = 128, - CHAT_TYPE_PRIVATE = 256, // e.g. direct messages, also used in raid finders etc. - CHAT_TYPE_FRIENDS = 512, - CHAT_TYPE_CHAT_ROOM = 1024 +#include "../../stdlib/Types.h" + +// NOT the message type, just where the message is sent to/from +enum ChatType : uint16 { + CHAT_TYPE_MIXED = 1 << 0, + CHAT_TYPE_LOCAL = 1 << 1, + CHAT_TYPE_GLOBAL = 1 << 2, + CHAT_TYPE_SERVER = 1 << 3, + CHAT_TYPE_PLAYER = 1 << 4, + CHAT_TYPE_GROUP = 1 << 5, + CHAT_TYPE_GUILD = 1 << 6, + CHAT_TYPE_AUCTION_HOUSE = 1 << 7, + CHAT_TYPE_TRADE = 1 << 8, // When trading with someone + CHAT_TYPE_PRIVATE = 1 << 9, // When chatting with someone in private (DM) + CHAT_TYPE_FRIENDS = 1 << 10, + CHAT_TYPE_CHAT_ROOM = 1 << 11, // Specific chat channels + CHAT_TYPE_CHAT_LFG = 1 << 12, // LFG finder + CHAT_TYPE_PVP = 1 << 13, // Also Guild vs. Guild }; #endif \ No newline at end of file diff --git a/object/Mesh.h b/object/Mesh.h index 36edfd3..87820de 100644 --- a/object/Mesh.h +++ b/object/Mesh.h @@ -16,6 +16,7 @@ #include "../utils/EndianUtils.h" #include "../utils/StringUtils.h" #include "../stdlib/Simd.h" +#include "../compiler/CompilerUtils.h" #define MESH_VERSION 1 @@ -72,13 +73,13 @@ void mesh_from_file_txt( file_read(path, &file, ring); ASSERT_SIMPLE(file.size); - char* pos = (char *) file.content; + const char* pos = (char *) file.content; // move past the version string pos += 8; // @todo us version for different handling - int32 version = strtol(pos, &pos, 10); ++pos; + int32 version = strtol(pos, (char **) &pos, 10); ++pos; int32 object_index = 0; int32 group_index = 0; @@ -179,9 +180,9 @@ void mesh_from_file_txt( mesh->vertex_type |= VERTEX_TYPE_POSITION; } - vertices[vertex_count * 3] = strtof(pos, &pos); ++pos; - vertices[vertex_count * 3 + 1] = strtof(pos, &pos); ++pos; - vertices[vertex_count * 3 + 2] = strtof(pos, &pos); ++pos; + vertices[vertex_count * 3] = strtof(pos, (char **) &pos); ++pos; + vertices[vertex_count * 3 + 1] = strtof(pos, (char **) &pos); ++pos; + vertices[vertex_count * 3 + 2] = strtof(pos, (char **) &pos); ++pos; // has color information // @todo Move to own case statement // 'co' @@ -190,13 +191,13 @@ void mesh_from_file_txt( mesh->vertex_type |= VERTEX_TYPE_COLOR; } - vertices[vertex_count * 12 + 8] = strtof(pos, &pos); ++pos; - vertices[vertex_count * 12 + 9] = strtof(pos, &pos); ++pos; - vertices[vertex_count * 12 + 10] = strtof(pos, &pos); ++pos; + vertices[vertex_count * 12 + 8] = strtof(pos, (char **) &pos); ++pos; + vertices[vertex_count * 12 + 9] = strtof(pos, (char **) &pos); ++pos; + vertices[vertex_count * 12 + 10] = strtof(pos, (char **) &pos); ++pos; // handle optional alpha [a] if (*pos != '\n' && pos[1] != ' ' && pos[1] != '\n') { - vertices[vertex_count * 12 + 11] = strtof(pos, &pos); ++pos; + vertices[vertex_count * 12 + 11] = strtof(pos, (char **) &pos); ++pos; } else { vertices[vertex_count * 12 + 11] = 1.0f; } @@ -208,30 +209,30 @@ void mesh_from_file_txt( } break; case 2: { // 'vn' - normals[normal_count * 3] = strtof(pos, &pos); ++pos; - normals[normal_count * 3 + 1] = strtof(pos, &pos); ++pos; - normals[normal_count * 3 + 2] = strtof(pos, &pos); ++pos; + normals[normal_count * 3] = strtof(pos, (char **) &pos); ++pos; + normals[normal_count * 3 + 1] = strtof(pos, (char **) &pos); ++pos; + normals[normal_count * 3 + 2] = strtof(pos, (char **) &pos); ++pos; ++normal_count; } break; case 3: { // 'vt' - tex_coords[tex_coord_count * 2] = strtof(pos, &pos); ++pos; - tex_coords[tex_coord_count * 2 + 1] = strtof(pos, &pos); ++pos; + tex_coords[tex_coord_count * 2] = strtof(pos, (char **) &pos); ++pos; + tex_coords[tex_coord_count * 2 + 1] = strtof(pos, (char **) &pos); ++pos; ++tex_coord_count; } break; case 4: { // 'vp' - strtof(pos, &pos); ++pos; + strtof(pos, (char **) &pos); ++pos; // handle optional [v] if (*pos != '\n' && pos[1] != ' ' && pos[1] != '\n') { - strtof(pos, &pos); ++pos; + strtof(pos, (char **) &pos); ++pos; // handle optional [w] if (*pos != '\n' && pos[1] != ' ' && pos[1] != '\n') { - strtof(pos, &pos); ++pos; + strtof(pos, (char **) &pos); ++pos; } } } break; @@ -248,12 +249,12 @@ void mesh_from_file_txt( } break; case 6: { // 's' - strtol(pos, &pos, 10); ++pos; + strtol(pos, (char **) &pos, 10); ++pos; } break; case 7: { // 'f' int32 ftype = 0; - char* tmp = pos; + const char* tmp = pos; while (*tmp != ' ') { if (*tmp++ == '/') { ++ftype; @@ -275,33 +276,33 @@ void mesh_from_file_txt( face_type = VERTEX_TYPE_POSITION; } - faces[(face_count * max_blocks * 1) + block] = strtol(pos, &pos, 10) - 1; ++pos; + faces[(face_count * max_blocks * 1) + block] = strtol(pos, (char **) &pos, 10) - 1; ++pos; } else if (ftype == 1) { // v1/vt1 v2/vt2 v3/vt3 ... if (face_count == 0) { face_type = VERTEX_TYPE_POSITION | VERTEX_TYPE_TEXTURE_COORD; } - faces[(face_count * max_blocks * 2) + block * 2] = strtol(pos, &pos, 10) - 1; ++pos; - faces[(face_count * max_blocks * 2) + block * 2 + 1] = strtol(pos, &pos, 10) - 1; ++pos; + faces[(face_count * max_blocks * 2) + block * 2] = strtol(pos, (char **) &pos, 10) - 1; ++pos; + faces[(face_count * max_blocks * 2) + block * 2 + 1] = strtol(pos, (char **) &pos, 10) - 1; ++pos; } else if (ftype == 2) { // v1/vt1/vn1 v2/vt2/vn2 v3/vt3/vn3 ... if (face_count == 0) { face_type = VERTEX_TYPE_POSITION | VERTEX_TYPE_TEXTURE_COORD | VERTEX_TYPE_NORMAL; } - faces[(face_count * max_blocks * 3) + block * 3] = strtol(pos, &pos, 10) - 1; ++pos; - faces[(face_count * max_blocks * 3) + block * 3 + 1] = strtol(pos, &pos, 10) - 1; ++pos; - faces[(face_count * max_blocks * 3) + block * 3 + 2] = strtol(pos, &pos, 10) - 1; ++pos; + faces[(face_count * max_blocks * 3) + block * 3] = strtol(pos, (char **) &pos, 10) - 1; ++pos; + faces[(face_count * max_blocks * 3) + block * 3 + 1] = strtol(pos, (char **) &pos, 10) - 1; ++pos; + faces[(face_count * max_blocks * 3) + block * 3 + 2] = strtol(pos, (char **) &pos, 10) - 1; ++pos; } else if (ftype == 3) { // v1//vn1 v2//vn2 v3//vn3 ... if (face_count == 0) { face_type = VERTEX_TYPE_POSITION | VERTEX_TYPE_NORMAL; } - faces[(face_count * max_blocks * 2) + block * 2] = strtol(pos, &pos, 10) - 1; ++pos; + faces[(face_count * max_blocks * 2) + block * 2] = strtol(pos, (char **) &pos, 10) - 1; ++pos; ++pos; - faces[(face_count * max_blocks * 2) + block * 2 + 1] = strtol(pos, &pos, 10) - 1; ++pos; + faces[(face_count * max_blocks * 2) + block * 2 + 1] = strtol(pos, (char **) &pos, 10) - 1; ++pos; } ++block; @@ -323,7 +324,7 @@ void mesh_from_file_txt( case 9: { //l while (*pos != '\0' && *pos != '\n') { - strtol(pos, &pos, 10); ++pos; + strtol(pos, (char **) &pos, 10); ++pos; } } break; case 10: { diff --git a/object/Vertex.h b/object/Vertex.h index 5cf7cef..ce7aab1 100644 --- a/object/Vertex.h +++ b/object/Vertex.h @@ -25,14 +25,9 @@ struct Vertex3DNormal { struct Vertex3DTextureColor { v3_f32 position; - v2_f32 tex_coord; - v4_f32 color; -}; -struct Vertex3DTextureColorIndex { - v3_f32 position; - v2_f32 tex_coord; - f32 color; + // If negative = color, positive = texture + v2_f32 texture_color; }; struct Vertex3DColorIndex { diff --git a/platform/linux/FileUtils.cpp b/platform/linux/FileUtils.cpp index 5e312e2..c4af4be 100644 --- a/platform/linux/FileUtils.cpp +++ b/platform/linux/FileUtils.cpp @@ -224,29 +224,33 @@ void file_read(const char* path, FileBody* file, RingMemory* ring) { return; } - struct stat file_stat; - if (fstat(fp, &file_stat) == -1) { - close(fp); - file->size = 0; - file->content = NULL; + if (file->size == 0) { + struct stat file_stat; + if (fstat(fp, &file_stat) == -1) { + close(fp); + file->size = 0; + file->content = NULL; - return; - } + return; + } - if (file_stat.st_size > MAX_UINT32) { - close(fp); - file->size = 0; - file->content = NULL; + if (file_stat.st_size > MAX_UINT32) { + close(fp); + file->size = 0; + file->content = NULL; - return; + return; + } + + file->size = file_stat.st_size + 1; } if (ring != NULL) { - file->content = ring_get_memory(ring, file_stat.st_size); + file->content = ring_get_memory(ring, file->size); } - ssize_t bytes_read = read(fp, file->content, file_stat.st_size); - if (bytes_read != file_stat.st_size) { + ssize_t bytes_read = read(fp, file->content, file->size - 1); + if (bytes_read != file->size) { close(fp); file->content = NULL; file->size = 0; @@ -262,6 +266,59 @@ void file_read(const char* path, FileBody* file, RingMemory* ring) { close(fp); } +// This function uses a couple of temporary/internal variables to keep track of state and data for consecutive calls +// The alternative would be to correct the file position after almost every call using seek which is very inefficient. +// Since the mentality of this function is to be called consecutively we do it this way. +bool file_read_line( + FileHandle fp, + char* line_buffer, size_t buffer_size, + char internal_buffer[512], ssize_t* internal_buffer_size, char** internal_pos +) { + if (!(*internal_pos)) { + *internal_pos = internal_buffer; + } + + size_t line_filled = 0; + + while (line_filled < buffer_size - 1) { + // Refill the internal buffer if empty + if (*internal_pos == internal_buffer + *internal_buffer_size) { + *internal_buffer_size = read(fp, internal_buffer, 512); + if (*internal_buffer_size <= 0) { + line_buffer[line_filled] = '\0'; + + return line_filled > 0; + } + + *internal_pos = internal_buffer; + } + + char current_char = **internal_pos; + ++(*internal_pos); + + // Handle line endings (\n, \r, \r\n, \n\r) + if (current_char == '\n' || current_char == '\r') { + if ((*internal_pos < internal_buffer + *internal_buffer_size) + && (**internal_pos == '\n' || **internal_pos == '\r') + && **internal_pos != current_char + ) { + ++(*internal_pos); + } + + line_buffer[line_filled] = '\0'; + + // Successfully read a line + return true; + } + + line_buffer[line_filled++] = current_char; + } + + line_buffer[line_filled] = '\0'; + + return true; +} + inline bool file_write(const char* path, const FileBody* file) { int32 fd; diff --git a/platform/linux/Library.cpp b/platform/linux/Library.cpp index 1f25039..603b88b 100644 --- a/platform/linux/Library.cpp +++ b/platform/linux/Library.cpp @@ -17,10 +17,8 @@ #include "../../stdlib/Types.h" #include "../../utils/StringUtils.h" -#include "UtilsLinux.h" #include "../../system/Library.h" - -// @todo Rename file to Library.cpp +#include "UtilsLinux.h" inline bool library_load(Library* lib) @@ -28,7 +26,8 @@ bool library_load(Library* lib) char dst[PATH_MAX]; str_concat_new(dst, lib->dir, lib->dst); - #if DEBUG + // In debug mode, we create a copy at runtime, so we can recompile & reload it + #if DEBUG || INTERNAL char src[PATH_MAX]; size_t dst_len = strlen(dst); @@ -43,7 +42,7 @@ bool library_load(Library* lib) if (lib->handle) { dlclose(lib->handle); lib->handle = NULL; - usleep(100000); // 100 ms + usleep(100000); // 100 ms } // @question we might want RTLD_NOW? diff --git a/platform/linux/Library.h b/platform/linux/Library.h new file mode 100644 index 0000000..6350038 --- /dev/null +++ b/platform/linux/Library.h @@ -0,0 +1,14 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_PLATFORM_LINUX_LIBRARY_H +#define TOS_PLATFORM_LINUX_LIBRARY_H + +typedef void* LibraryHandle; + +#endif \ No newline at end of file diff --git a/platform/linux/SystemInfo.cpp b/platform/linux/SystemInfo.cpp index 321d3ea..639bd7e 100644 --- a/platform/linux/SystemInfo.cpp +++ b/platform/linux/SystemInfo.cpp @@ -16,6 +16,7 @@ #include "../../stdlib/Types.h" #include "../../system/SystemInfo.h" #include "../../architecture/CpuInfo.cpp" +#include "../../system/FileUtils.cpp" #include #include @@ -34,14 +35,15 @@ uint64 system_private_memory_usage() uint64 system_app_memory_usage() { - FILE* fp = fopen("/proc/self/smaps", "r"); - if (!fp) { - return 0; - } - uint64 total_size = 0; + + FileHandle fp = file_read_handle("/proc/self/smaps"); char line[256]; - while (fgets(line, sizeof(line), fp)) { + char internal_buffer[512]; + ssize_t internal_buffer_size = 0; + char* internal_pos = NULL; + + while (file_read_line(fp, line, sizeof(line), internal_buffer, &internal_buffer_size, &internal_pos)) { if (str_compare(line, "Private_Dirty:", sizeof("Private_Dirty:") - 1) == 0) { uint64 private_dirty; if (sscanf(line, "Private_Dirty: %lu kB", &private_dirty) == 1) { @@ -50,7 +52,7 @@ uint64 system_app_memory_usage() } } - fclose(fp); + file_close_handle(fp); return total_size; } @@ -70,22 +72,18 @@ uint16 system_country_code() } void mainboard_info_get(MainboardInfo* info) { - info->name[63] = '\0'; - info->serial_number[63] = '\0'; + FileBody file; - FILE *fp; + file.content = info->name; + file.size = sizeof(info->name); + file_read("/sys/class/dmi/id/board_name", &file); - fp = fopen("/sys/class/dmi/id/board_name", "r"); - if (fp) { - fgets(info->name, 64, fp); - fclose(fp); - } + file.content = info->serial_number; + file.size = sizeof(info->serial_number); + file_read("/sys/class/dmi/id/board_serial", &file); - fp = fopen("/sys/class/dmi/id/board_serial", "r"); - if (fp) { - fgets(info->serial_number, 64, fp); - fclose(fp); - } + info->name[sizeof(info->name) - 1] = '\0'; + info->serial_number[sizeof(info->serial_number) - 1] = '\0'; info->name[strcspn(info->name, "\n")] = '\0'; info->serial_number[strcspn(info->serial_number, "\n")] = '\0'; @@ -96,28 +94,23 @@ int32 network_info_get(NetworkInfo* info) { struct stat st; int32 i = 0; + FileBody file; + for (i = 0; i < 4; i++) { sprintf_fast(path, "/sys/class/net/eth%d", i); if (stat(path, &st) == 0) { // Read MAC address sprintf_fast(path, "/sys/class/net/eth%d/address", i); - FILE *mac_file = fopen(path, "r"); - if (mac_file) { - fscanf(mac_file, "%s", info[i].mac); - fclose(mac_file); - } + file.content = info[i].mac; + file.size = sizeof(info[i].mac); + file_read(path, &file); // Read interface name sprintf_fast(path, "/sys/class/net/eth%d/ifindex", i); - FILE *index_file = fopen(path, "r"); - if (index_file) { - fscanf(index_file, "%s", info[i].slot); - fclose(index_file); - } - - info[i].mac[23] = '\0'; - info[i].slot[63] = '\0'; + file.content = info[i].slot; + file.size = sizeof(info[i].slot); + file_read(path, &file); } } @@ -125,14 +118,13 @@ int32 network_info_get(NetworkInfo* info) { } void cpu_info_get(CpuInfo* info) { - FILE* fp = fopen("/proc/cpuinfo", "r"); - if (!fp) { - return; - } - + FileHandle fp = file_read_handle("/proc/cpuinfo"); char line[256]; + char internal_buffer[512]; + ssize_t internal_buffer_size = 0; + char* internal_pos = NULL; - while (fgets(line, sizeof(line), fp)) { + while (file_read_line(fp, line, sizeof(line), internal_buffer, &internal_buffer_size, &internal_pos)) { if (str_compare(line, "vendor_id", 9) == 0) { sscanf(line, "vendor_id : %s", info->vendor); } else if (str_compare(line, "model", 5) == 0) { @@ -146,7 +138,7 @@ void cpu_info_get(CpuInfo* info) { } } - fclose(fp); + file_close_handle(fp); info->family = 0; info->page_size = 4096; // Assuming standard page size of 4KB in Linux @@ -160,21 +152,21 @@ void os_info_get(OSInfo* info) { } void ram_info_get(RamInfo* info) { - FILE* fp = fopen("/proc/meminfo", "r"); - if (fp == NULL) { - return; - } - - char line[256]; uint32 total_memory = 0; - while (fgets(line, sizeof(line), fp)) { + FileHandle fp = file_read_handle("/proc/meminfo"); + char line[256]; + char internal_buffer[512]; + ssize_t internal_buffer_size = 0; + char* internal_pos = NULL; + + while (file_read_line(fp, line, sizeof(line), internal_buffer, &internal_buffer_size, &internal_pos)) { if (sscanf(line, "MemTotal: %u kB", &total_memory) == 1) { break; } } - fclose(fp); + file_close_handle(fp); // Convert memory from kB to MB info->memory = total_memory / 1024; @@ -209,32 +201,6 @@ uint32 gpu_info_get(GpuInfo* info) { return count; } - -void display_info_get_primary(DisplayInfo* info) { - FILE* fp = popen("xrandr --current", "r"); - if (fp == NULL) { - return; - } - - char line[256]; - while (fgets(line, sizeof(line), fp)) { - if (strstr(line, "primary")) { - // Example of a line containing display info: "HDMI-1 connected 1920x1080+0+0 60.00*+" - char name[64]; - uint32 width, height, hz; - if (sscanf(line, "%s connected %dx%d+%*d+%*d %d", name, &width, &height, &hz) == 4) { - str_copy_short(info->name, name); - info->width = width; - info->height = height; - info->hz = hz; - } - break; - } - } - - fclose(fp); -} - uint32 display_info_get(DisplayInfo* info) { FILE* fp = popen("xrandr --current", "r"); if (fp == NULL) { @@ -254,6 +220,7 @@ uint32 display_info_get(DisplayInfo* info) { info[count].width = width; info[count].height = height; info[count].hz = hz; + info[count].is_primary = strstr(line, "primary"); count++; } } diff --git a/platform/linux/threading/Atomic.h b/platform/linux/threading/Atomic.h index 943472c..dfbbbcf 100644 --- a/platform/linux/threading/Atomic.h +++ b/platform/linux/threading/Atomic.h @@ -9,1208 +9,8 @@ #ifndef TOS_PLATFORM_LINUX_THREADING_ATOMIC_H #define TOS_PLATFORM_LINUX_THREADING_ATOMIC_H -#include -#include "../../../stdlib/Types.h" - -inline -void atomic_set_relaxed(void** target, void* value) -{ - __atomic_store_n(target, value, __ATOMIC_RELAXED); -} - -inline -void* atomic_get_relaxed(void** target) -{ - return __atomic_load_n(target, __ATOMIC_RELAXED); -} - -inline -void atomic_set_relaxed(volatile int32* value, int32 new_value) -{ - __atomic_store_n(value, new_value, __ATOMIC_RELAXED); -} - -inline -void atomic_set_relaxed(volatile int64* value, int64 new_value) -{ - __atomic_store_n(value, new_value, __ATOMIC_RELAXED); -} - -inline -int32 atomic_fetch_set_relaxed(volatile int32* value, int32 new_value) -{ - return __atomic_exchange_n(value, new_value, __ATOMIC_RELAXED); -} - -inline -int64 atomic_fetch_set_relaxed(volatile int64* value, int64 new_value) -{ - return __atomic_exchange_n(value, new_value, __ATOMIC_RELAXED); -} - -inline -void atomic_get_relaxed(volatile byte* value, byte data[16]) -{ - __atomic_store((volatile __int128 *) value, (__int128 *) data, __ATOMIC_RELAXED); -} - -inline -int32 atomic_get_relaxed(volatile int32* value) -{ - return __atomic_load_n((int32 *) value, __ATOMIC_RELAXED); -} - -inline -int64 atomic_get_relaxed(volatile int64* value) -{ - return __atomic_load_n((int64 *) value, __ATOMIC_RELAXED); -} - -inline -void atomic_get_relaxed(volatile byte* value, byte data[16]) -{ - __atomic_load((volatile __int128 *) value, (__int128 *) data, __ATOMIC_RELAXED); -} - -inline -void atomic_increment_relaxed(volatile int32* value) -{ - __atomic_add_fetch(value, 1, __ATOMIC_RELAXED); -} - -inline -void atomic_decrement_relaxed(volatile int32* value) -{ - __atomic_sub_fetch(value, 1, __ATOMIC_RELAXED); -} - -inline -void atomic_increment_relaxed(volatile int64* value) -{ - __atomic_add_fetch(value, 1, __ATOMIC_RELAXED); -} - -inline -void atomic_decrement_relaxed(volatile int64* value) -{ - __atomic_sub_fetch(value, 1, __ATOMIC_RELAXED); -} - -inline -void atomic_add_relaxed(volatile int32* value, int32 increment) -{ - __atomic_add_fetch(value, increment, __ATOMIC_RELAXED); -} - -inline -void atomic_sub_relaxed(volatile int32* value, int32 decrement) -{ - __atomic_sub_fetch(value, decrement, __ATOMIC_RELAXED); -} - -inline -void atomic_add_relaxed(volatile int64* value, int64 increment) -{ - __atomic_add_fetch(value, increment, __ATOMIC_RELAXED); -} - -inline -void atomic_sub_relaxed(volatile int64* value, int64 decrement) -{ - __atomic_sub_fetch(value, decrement, __ATOMIC_RELAXED); -} - -inline -int32 atomic_compare_exchange_weak_relaxed(volatile int32* value, int32* expected, int32 desired) -{ - __atomic_compare_exchange_n(value, expected, desired, 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED); - return *expected; -} - -inline -int32 atomic_fetch_add_relaxed(volatile int32* value, int32 operand) -{ - return __atomic_add_fetch(value, operand, __ATOMIC_RELAXED); -} - -inline -int32 atomic_fetch_sub_relaxed(volatile int32* value, int32 operand) -{ - return __atomic_sub_fetch(value, operand, __ATOMIC_RELAXED); -} - -inline -int64 atomic_fetch_add_relaxed(volatile int64* value, int64 operand) -{ - return __atomic_add_fetch(value, operand, __ATOMIC_RELAXED); -} - -inline -int64 atomic_fetch_sub_relaxed(volatile int64* value, int64 operand) -{ - return __atomic_sub_fetch(value, operand, __ATOMIC_RELAXED); -} - -inline -void atomic_set_relaxed(volatile uint32* value, uint32 new_value) -{ - __atomic_store_n(value, new_value, __ATOMIC_RELAXED); -} - -inline -void atomic_set_relaxed(volatile uint64* value, uint64 new_value) -{ - __atomic_store_n(value, new_value, __ATOMIC_RELAXED); -} - -inline -uint32 atomic_fetch_set_relaxed(volatile uint32* value, uint32 new_value) -{ - return __atomic_exchange_n(value, new_value, __ATOMIC_RELAXED); -} - -inline -uint64 atomic_fetch_set_relaxed(volatile uint64* value, uint64 new_value) -{ - return __atomic_exchange_n(value, new_value, __ATOMIC_RELAXED); -} - -inline -void atomic_get_relaxed(volatile byte* value, byte data[16]) -{ - __atomic_store((volatile __uint128 *) value, (__uint128 *) data, __ATOMIC_RELAXED); -} - -inline -uint32 atomic_get_relaxed(volatile uint32* value) -{ - return __atomic_load_n((uint32 *) value, __ATOMIC_RELAXED); -} - -inline -uint64 atomic_get_relaxed(volatile uint64* value) -{ - return __atomic_load_n((uint64 *) value, __ATOMIC_RELAXED); -} - -inline -void atomic_increment_relaxed(volatile uint32* value) -{ - __atomic_add_fetch(value, 1, __ATOMIC_RELAXED); -} - -inline -void atomic_decrement_relaxed(volatile uint32* value) -{ - __atomic_sub_fetch(value, 1, __ATOMIC_RELAXED); -} - -inline -void atomic_increment_relaxed(volatile uint64* value) -{ - __atomic_add_fetch(value, 1, __ATOMIC_RELAXED); -} - -inline -void atomic_decrement_relaxed(volatile uint64* value) -{ - __atomic_sub_fetch(value, 1, __ATOMIC_RELAXED); -} - -inline -void atomic_add_relaxed(volatile uint32* value, uint32 increment) -{ - __atomic_add_fetch(value, increment, __ATOMIC_RELAXED); -} - -inline -void atomic_sub_relaxed(volatile uint32* value, uint32 decrement) -{ - __atomic_sub_fetch(value, decrement, __ATOMIC_RELAXED); -} - -inline -uint32 atomic_compare_exchange_weak_relaxed(volatile uint32* value, uint32* expected, uint32 desired) -{ - __atomic_compare_exchange_n(value, expected, desired, 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED); - return *expected; -} - -inline -uint32 atomic_fetch_add_relaxed(volatile uint32* value, uint32 operand) -{ - return __atomic_add_fetch(value, operand, __ATOMIC_RELAXED); -} - -inline -uint32 atomic_fetch_sub_relaxed(volatile uint32* value, uint32 operand) -{ - return __atomic_sub_fetch(value, operand, __ATOMIC_RELAXED); -} - -inline -uint64 atomic_fetch_add_relaxed(volatile uint64* value, uint64 operand) -{ - return __atomic_add_fetch(value, operand, __ATOMIC_RELAXED); -} - -inline -uint64 atomic_fetch_sub_relaxed(volatile uint64* value, uint64 operand) -{ - return __atomic_sub_fetch(value, operand, __ATOMIC_RELAXED); -} - -inline -void atomic_and_relaxed(volatile uint32* value, uint32 mask) -{ - __atomic_fetch_and(value, mask, __ATOMIC_RELAXED); -} - -inline -void atomic_and_relaxed(volatile int32* value, int32 mask) -{ - __atomic_fetch_and(value, mask, __ATOMIC_RELAXED); -} - -inline -void atomic_and_relaxed(volatile uint64* value, uint64 mask) -{ - __atomic_fetch_and(value, mask, __ATOMIC_RELAXED); -} - -inline -void atomic_and_relaxed(volatile int64* value, int64 mask) -{ - __atomic_fetch_and(value, mask, __ATOMIC_RELAXED); -} - -inline -void atomic_or_relaxed(volatile uint32* value, uint32 mask) -{ - __atomic_fetch_or(value, mask, __ATOMIC_RELAXED); -} - -inline -void atomic_or_relaxed(volatile int32* value, int32 mask) -{ - __atomic_fetch_or(value, mask, __ATOMIC_RELAXED); -} - -inline -void atomic_or_relaxed(volatile uint64* value, uint64 mask) -{ - __atomic_fetch_or(value, mask, __ATOMIC_RELAXED); -} - -inline -void atomic_or_relaxed(volatile int64* value, int64 mask) -{ - __atomic_fetch_or(value, mask, __ATOMIC_RELAXED); -} - -inline -void atomic_set_acquire(void** target, void* value) -{ - __atomic_store_n(target, value, __ATOMIC_ACQUIRE); -} - -inline -void* atomic_get_acquire(void** target) -{ - return __atomic_load_n(target, __ATOMIC_ACQUIRE); -} - -inline -void atomic_set_acquire(volatile int32* value, int32 new_value) -{ - __atomic_store_n(value, new_value, __ATOMIC_ACQUIRE); -} - -inline -void atomic_set_acquire(volatile int64* value, int64 new_value) -{ - __atomic_store_n(value, new_value, __ATOMIC_ACQUIRE); -} - -inline -int32 atomic_fetch_set_acquire(volatile int32* value, int32 new_value) -{ - return __atomic_exchange_n(value, new_value, __ATOMIC_ACQUIRE); -} - -inline -int64 atomic_fetch_set_acquire(volatile int64* value, int64 new_value) -{ - return __atomic_exchange_n(value, new_value, __ATOMIC_ACQUIRE); -} - -inline -void atomic_get_acquire(volatile byte* value, byte data[16]) -{ - __atomic_store((volatile __int128 *) value, (__int128 *) data, __ATOMIC_ACQUIRE); -} - -inline -int32 atomic_get_acquire(volatile int32* value) -{ - return __atomic_load_n((int32 *) value, __ATOMIC_ACQUIRE); -} - -inline -int64 atomic_get_acquire(volatile int64* value) -{ - return __atomic_load_n((int64 *) value, __ATOMIC_ACQUIRE); -} - -inline -void atomic_get_acquire(volatile byte* value, byte data[16]) -{ - __atomic_load((volatile __int128 *) value, (__int128 *) data, __ATOMIC_ACQUIRE); -} - -inline -void atomic_increment_acquire(volatile int32* value) -{ - __atomic_add_fetch(value, 1, __ATOMIC_ACQUIRE); -} - -inline -void atomic_decrement_acquire(volatile int32* value) -{ - __atomic_sub_fetch(value, 1, __ATOMIC_ACQUIRE); -} - -inline -void atomic_increment_acquire(volatile int64* value) -{ - __atomic_add_fetch(value, 1, __ATOMIC_ACQUIRE); -} - -inline -void atomic_decrement_acquire(volatile int64* value) -{ - __atomic_sub_fetch(value, 1, __ATOMIC_ACQUIRE); -} - -inline -void atomic_add_acquire(volatile int32* value, int32 increment) -{ - __atomic_add_fetch(value, increment, __ATOMIC_ACQUIRE); -} - -inline -void atomic_sub_acquire(volatile int32* value, int32 decrement) -{ - __atomic_sub_fetch(value, decrement, __ATOMIC_ACQUIRE); -} - -inline -void atomic_add_acquire(volatile int64* value, int64 increment) -{ - __atomic_add_fetch(value, increment, __ATOMIC_ACQUIRE); -} - -inline -void atomic_sub_acquire(volatile int64* value, int64 decrement) -{ - __atomic_sub_fetch(value, decrement, __ATOMIC_ACQUIRE); -} - -inline -int32 atomic_compare_exchange_weak_acquire(volatile int32* value, int32* expected, int32 desired) -{ - __atomic_compare_exchange_n(value, expected, desired, 0, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE); - return *expected; -} - -inline -int32 atomic_fetch_add_acquire(volatile int32* value, int32 operand) -{ - return __atomic_add_fetch(value, operand, __ATOMIC_ACQUIRE); -} - -inline -int32 atomic_fetch_sub_acquire(volatile int32* value, int32 operand) -{ - return __atomic_sub_fetch(value, operand, __ATOMIC_ACQUIRE); -} - -inline -int64 atomic_fetch_add_acquire(volatile int64* value, int64 operand) -{ - return __atomic_add_fetch(value, operand, __ATOMIC_ACQUIRE); -} - -inline -int64 atomic_fetch_sub_acquire(volatile int64* value, int64 operand) -{ - return __atomic_sub_fetch(value, operand, __ATOMIC_ACQUIRE); -} - -inline -void atomic_set_acquire(volatile uint32* value, uint32 new_value) -{ - __atomic_store_n(value, new_value, __ATOMIC_ACQUIRE); -} - -inline -void atomic_set_acquire(volatile uint64* value, uint64 new_value) -{ - __atomic_store_n(value, new_value, __ATOMIC_ACQUIRE); -} - -inline -uint32 atomic_fetch_set_acquire(volatile uint32* value, uint32 new_value) -{ - return __atomic_exchange_n(value, new_value, __ATOMIC_ACQUIRE); -} - -inline -uint64 atomic_fetch_set_acquire(volatile uint64* value, uint64 new_value) -{ - return __atomic_exchange_n(value, new_value, __ATOMIC_ACQUIRE); -} - -inline -void atomic_get_acquire(volatile byte* value, byte data[16]) -{ - __atomic_store((volatile __uint128 *) value, (__uint128 *) data, __ATOMIC_ACQUIRE); -} - -inline -uint32 atomic_get_acquire(volatile uint32* value) -{ - return __atomic_load_n((uint32 *) value, __ATOMIC_ACQUIRE); -} - -inline -uint64 atomic_get_acquire(volatile uint64* value) -{ - return __atomic_load_n((uint64 *) value, __ATOMIC_ACQUIRE); -} - -inline -void atomic_increment_acquire(volatile uint32* value) -{ - __atomic_add_fetch(value, 1, __ATOMIC_ACQUIRE); -} - -inline -void atomic_decrement_acquire(volatile uint32* value) -{ - __atomic_sub_fetch(value, 1, __ATOMIC_ACQUIRE); -} - -inline -void atomic_increment_acquire(volatile uint64* value) -{ - __atomic_add_fetch(value, 1, __ATOMIC_ACQUIRE); -} - -inline -void atomic_decrement_acquire(volatile uint64* value) -{ - __atomic_sub_fetch(value, 1, __ATOMIC_ACQUIRE); -} - -inline -void atomic_add_acquire(volatile uint32* value, uint32 increment) -{ - __atomic_add_fetch(value, increment, __ATOMIC_ACQUIRE); -} - -inline -void atomic_sub_acquire(volatile uint32* value, uint32 decrement) -{ - __atomic_sub_fetch(value, decrement, __ATOMIC_ACQUIRE); -} - -inline -uint32 atomic_compare_exchange_weak_acquire(volatile uint32* value, uint32* expected, uint32 desired) -{ - __atomic_compare_exchange_n(value, expected, desired, 0, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE); - return *expected; -} - -inline -uint32 atomic_fetch_add_acquire(volatile uint32* value, uint32 operand) -{ - return __atomic_add_fetch(value, operand, __ATOMIC_ACQUIRE); -} - -inline -uint32 atomic_fetch_sub_acquire(volatile uint32* value, uint32 operand) -{ - return __atomic_sub_fetch(value, operand, __ATOMIC_ACQUIRE); -} - -inline -uint64 atomic_fetch_add_acquire(volatile uint64* value, uint64 operand) -{ - return __atomic_add_fetch(value, operand, __ATOMIC_ACQUIRE); -} - -inline -uint64 atomic_fetch_sub_acquire(volatile uint64* value, uint64 operand) -{ - return __atomic_sub_fetch(value, operand, __ATOMIC_ACQUIRE); -} - -inline -void atomic_and_acquire(volatile uint32* value, uint32 mask) -{ - __atomic_fetch_and(value, mask, __ATOMIC_ACQUIRE); -} - -inline -void atomic_and_acquire(volatile int32* value, int32 mask) -{ - __atomic_fetch_and(value, mask, __ATOMIC_ACQUIRE); -} - -inline -void atomic_and_acquire(volatile uint64* value, uint64 mask) -{ - __atomic_fetch_and(value, mask, __ATOMIC_ACQUIRE); -} - -inline -void atomic_and_acquire(volatile int64* value, int64 mask) -{ - __atomic_fetch_and(value, mask, __ATOMIC_ACQUIRE); -} - -inline -void atomic_or_acquire(volatile uint32* value, uint32 mask) -{ - __atomic_fetch_or(value, mask, __ATOMIC_ACQUIRE); -} - -inline -void atomic_or_acquire(volatile int32* value, int32 mask) -{ - __atomic_fetch_or(value, mask, __ATOMIC_ACQUIRE); -} - -inline -void atomic_or_acquire(volatile uint64* value, uint64 mask) -{ - __atomic_fetch_or(value, mask, __ATOMIC_ACQUIRE); -} - -inline -void atomic_or_acquire(volatile int64* value, int64 mask) -{ - __atomic_fetch_or(value, mask, __ATOMIC_ACQUIRE); -} - -inline -void atomic_set_release(void** target, void* value) -{ - __atomic_store_n(target, value, __ATOMIC_RELEASE); -} - -inline -void* atomic_get_release(void** target) -{ - return __atomic_load_n(target, __ATOMIC_RELEASE); -} - -inline -void atomic_set_release(volatile int32* value, int32 new_value) -{ - __atomic_store_n(value, new_value, __ATOMIC_RELEASE); -} - -inline -void atomic_set_release(volatile int64* value, int64 new_value) -{ - __atomic_store_n(value, new_value, __ATOMIC_RELEASE); -} - -inline -int32 atomic_fetch_set_release(volatile int32* value, int32 new_value) -{ - return __atomic_exchange_n(value, new_value, __ATOMIC_RELEASE); -} - -inline -int64 atomic_fetch_set_release(volatile int64* value, int64 new_value) -{ - return __atomic_exchange_n(value, new_value, __ATOMIC_RELEASE); -} - -inline -void atomic_get_release(volatile byte* value, byte data[16]) -{ - __atomic_store((volatile __int128 *) value, (__int128 *) data, __ATOMIC_RELEASE); -} - -inline -int32 atomic_get_release(volatile int32* value) -{ - return __atomic_load_n((int32 *) value, __ATOMIC_RELEASE); -} - -inline -int64 atomic_get_release(volatile int64* value) -{ - return __atomic_load_n((int64 *) value, __ATOMIC_RELEASE); -} - -inline -void atomic_get_release(volatile byte* value, byte data[16]) -{ - __atomic_load((volatile __int128 *) value, (__int128 *) data, __ATOMIC_RELEASE); -} - -inline -void atomic_increment_release(volatile int32* value) -{ - __atomic_add_fetch(value, 1, __ATOMIC_RELEASE); -} - -inline -void atomic_decrement_release(volatile int32* value) -{ - __atomic_sub_fetch(value, 1, __ATOMIC_RELEASE); -} - -inline -void atomic_increment_release(volatile int64* value) -{ - __atomic_add_fetch(value, 1, __ATOMIC_RELEASE); -} - -inline -void atomic_decrement_release(volatile int64* value) -{ - __atomic_sub_fetch(value, 1, __ATOMIC_RELEASE); -} - -inline -void atomic_add_release(volatile int32* value, int32 increment) -{ - __atomic_add_fetch(value, increment, __ATOMIC_RELEASE); -} - -inline -void atomic_sub_release(volatile int32* value, int32 decrement) -{ - __atomic_sub_fetch(value, decrement, __ATOMIC_RELEASE); -} - -inline -void atomic_add_release(volatile int64* value, int64 increment) -{ - __atomic_add_fetch(value, increment, __ATOMIC_RELEASE); -} - -inline -void atomic_sub_release(volatile int64* value, int64 decrement) -{ - __atomic_sub_fetch(value, decrement, __ATOMIC_RELEASE); -} - -inline -int32 atomic_compare_exchange_weak_release(volatile int32* value, int32* expected, int32 desired) -{ - __atomic_compare_exchange_n(value, expected, desired, 0, __ATOMIC_RELEASE, __ATOMIC_RELEASE); - return *expected; -} - -inline -int32 atomic_fetch_add_release(volatile int32* value, int32 operand) -{ - return __atomic_add_fetch(value, operand, __ATOMIC_RELEASE); -} - -inline -int32 atomic_fetch_sub_release(volatile int32* value, int32 operand) -{ - return __atomic_sub_fetch(value, operand, __ATOMIC_RELEASE); -} - -inline -int64 atomic_fetch_add_release(volatile int64* value, int64 operand) -{ - return __atomic_add_fetch(value, operand, __ATOMIC_RELEASE); -} - -inline -int64 atomic_fetch_sub_release(volatile int64* value, int64 operand) -{ - return __atomic_sub_fetch(value, operand, __ATOMIC_RELEASE); -} - -inline -void atomic_set_release(volatile uint32* value, uint32 new_value) -{ - __atomic_store_n(value, new_value, __ATOMIC_RELEASE); -} - -inline -void atomic_set_release(volatile uint64* value, uint64 new_value) -{ - __atomic_store_n(value, new_value, __ATOMIC_RELEASE); -} - -inline -uint32 atomic_fetch_set_release(volatile uint32* value, uint32 new_value) -{ - return __atomic_exchange_n(value, new_value, __ATOMIC_RELEASE); -} - -inline -uint64 atomic_fetch_set_release(volatile uint64* value, uint64 new_value) -{ - return __atomic_exchange_n(value, new_value, __ATOMIC_RELEASE); -} - -inline -void atomic_get_release(volatile byte* value, byte data[16]) -{ - __atomic_store((volatile __uint128 *) value, (__uint128 *) data, __ATOMIC_RELEASE); -} - -inline -uint32 atomic_get_release(volatile uint32* value) -{ - return __atomic_load_n((uint32 *) value, __ATOMIC_RELEASE); -} - -inline -uint64 atomic_get_release(volatile uint64* value) -{ - return __atomic_load_n((uint64 *) value, __ATOMIC_RELEASE); -} - -inline -void atomic_increment_release(volatile uint32* value) -{ - __atomic_add_fetch(value, 1, __ATOMIC_RELEASE); -} - -inline -void atomic_decrement_release(volatile uint32* value) -{ - __atomic_sub_fetch(value, 1, __ATOMIC_RELEASE); -} - -inline -void atomic_increment_release(volatile uint64* value) -{ - __atomic_add_fetch(value, 1, __ATOMIC_RELEASE); -} - -inline -void atomic_decrement_release(volatile uint64* value) -{ - __atomic_sub_fetch(value, 1, __ATOMIC_RELEASE); -} - -inline -void atomic_add_release(volatile uint32* value, uint32 increment) -{ - __atomic_add_fetch(value, increment, __ATOMIC_RELEASE); -} - -inline -void atomic_sub_release(volatile uint32* value, uint32 decrement) -{ - __atomic_sub_fetch(value, decrement, __ATOMIC_RELEASE); -} - -inline -uint32 atomic_compare_exchange_weak_release(volatile uint32* value, uint32* expected, uint32 desired) -{ - __atomic_compare_exchange_n(value, expected, desired, 0, __ATOMIC_RELEASE, __ATOMIC_RELEASE); - return *expected; -} - -inline -uint32 atomic_fetch_add_release(volatile uint32* value, uint32 operand) -{ - return __atomic_add_fetch(value, operand, __ATOMIC_RELEASE); -} - -inline -uint32 atomic_fetch_sub_release(volatile uint32* value, uint32 operand) -{ - return __atomic_sub_fetch(value, operand, __ATOMIC_RELEASE); -} - -inline -uint64 atomic_fetch_add_release(volatile uint64* value, uint64 operand) -{ - return __atomic_add_fetch(value, operand, __ATOMIC_RELEASE); -} - -inline -uint64 atomic_fetch_sub_release(volatile uint64* value, uint64 operand) -{ - return __atomic_sub_fetch(value, operand, __ATOMIC_RELEASE); -} - -inline -void atomic_and_release(volatile uint32* value, uint32 mask) -{ - __atomic_fetch_and(value, mask, __ATOMIC_RELEASE); -} - -inline -void atomic_and_release(volatile int32* value, int32 mask) -{ - __atomic_fetch_and(value, mask, __ATOMIC_RELEASE); -} - -inline -void atomic_and_release(volatile uint64* value, uint64 mask) -{ - __atomic_fetch_and(value, mask, __ATOMIC_RELEASE); -} - -inline -void atomic_and_release(volatile int64* value, int64 mask) -{ - __atomic_fetch_and(value, mask, __ATOMIC_RELEASE); -} - -inline -void atomic_or_release(volatile uint32* value, uint32 mask) -{ - __atomic_fetch_or(value, mask, __ATOMIC_RELEASE); -} - -inline -void atomic_or_release(volatile int32* value, int32 mask) -{ - __atomic_fetch_or(value, mask, __ATOMIC_RELEASE); -} - -inline -void atomic_or_release(volatile uint64* value, uint64 mask) -{ - __atomic_fetch_or(value, mask, __ATOMIC_RELEASE); -} - -inline -void atomic_or_release(volatile int64* value, int64 mask) -{ - __atomic_fetch_or(value, mask, __ATOMIC_RELEASE); -} - -inline -void atomic_set_acquire_release(void** target, void* value) -{ - __atomic_store_n(target, value, __ATOMIC_SEQ_CST); -} - -inline -void* atomic_get_acquire_release(void** target) -{ - return __atomic_load_n(target, __ATOMIC_SEQ_CST); -} - -inline -void atomic_set_acquire_release(volatile int32* value, int32 new_value) -{ - __atomic_store_n(value, new_value, __ATOMIC_SEQ_CST); -} - -inline -void atomic_set_acquire_release(volatile int64* value, int64 new_value) -{ - __atomic_store_n(value, new_value, __ATOMIC_SEQ_CST); -} - -inline -int32 atomic_fetch_set_acquire_release(volatile int32* value, int32 new_value) -{ - return __atomic_exchange_n(value, new_value, __ATOMIC_SEQ_CST); -} - -inline -int64 atomic_fetch_set_acquire_release(volatile int64* value, int64 new_value) -{ - return __atomic_exchange_n(value, new_value, __ATOMIC_SEQ_CST); -} - -inline -void atomic_get_acquire_release(volatile byte* value, byte data[16]) -{ - __atomic_store((volatile __int128 *) value, (__int128 *) data, __ATOMIC_SEQ_CST); -} - -inline -int32 atomic_get_acquire_release(volatile int32* value) -{ - return __atomic_load_n((int32 *) value, __ATOMIC_SEQ_CST); -} - -inline -int64 atomic_get_acquire_release(volatile int64* value) -{ - return __atomic_load_n((int64 *) value, __ATOMIC_SEQ_CST); -} - -inline -void atomic_get_acquire_release(volatile byte* value, byte data[16]) -{ - __atomic_load((volatile __int128 *) value, (__int128 *) data, __ATOMIC_SEQ_CST); -} - -inline -void atomic_increment_acquire_release(volatile int32* value) -{ - __atomic_add_fetch(value, 1, __ATOMIC_SEQ_CST); -} - -inline -void atomic_decrement_acquire_release(volatile int32* value) -{ - __atomic_sub_fetch(value, 1, __ATOMIC_SEQ_CST); -} - -inline -void atomic_increment_acquire_release(volatile int64* value) -{ - __atomic_add_fetch(value, 1, __ATOMIC_SEQ_CST); -} - -inline -void atomic_decrement_acquire_release(volatile int64* value) -{ - __atomic_sub_fetch(value, 1, __ATOMIC_SEQ_CST); -} - -inline -void atomic_add_acquire_release(volatile int32* value, int32 increment) -{ - __atomic_add_fetch(value, increment, __ATOMIC_SEQ_CST); -} - -inline -void atomic_sub_acquire_release(volatile int32* value, int32 decrement) -{ - __atomic_sub_fetch(value, decrement, __ATOMIC_SEQ_CST); -} - -inline -void atomic_add_acquire_release(volatile int64* value, int64 increment) -{ - __atomic_add_fetch(value, increment, __ATOMIC_SEQ_CST); -} - -inline -void atomic_sub_acquire_release(volatile int64* value, int64 decrement) -{ - __atomic_sub_fetch(value, decrement, __ATOMIC_SEQ_CST); -} - -inline -int32 atomic_compare_exchange_weak_acquire_release(volatile int32* value, int32* expected, int32 desired) -{ - __atomic_compare_exchange_n(value, expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); - return *expected; -} - -inline -int32 atomic_fetch_add_acquire_release(volatile int32* value, int32 operand) -{ - return __atomic_add_fetch(value, operand, __ATOMIC_SEQ_CST); -} - -inline -int32 atomic_fetch_sub_acquire_release(volatile int32* value, int32 operand) -{ - return __atomic_sub_fetch(value, operand, __ATOMIC_SEQ_CST); -} - -inline -int64 atomic_fetch_add_acquire_release(volatile int64* value, int64 operand) -{ - return __atomic_add_fetch(value, operand, __ATOMIC_SEQ_CST); -} - -inline -int64 atomic_fetch_sub_acquire_release(volatile int64* value, int64 operand) -{ - return __atomic_sub_fetch(value, operand, __ATOMIC_SEQ_CST); -} - -inline -void atomic_set_acquire_release(volatile uint32* value, uint32 new_value) -{ - __atomic_store_n(value, new_value, __ATOMIC_SEQ_CST); -} - -inline -void atomic_set_acquire_release(volatile uint64* value, uint64 new_value) -{ - __atomic_store_n(value, new_value, __ATOMIC_SEQ_CST); -} - -inline -uint32 atomic_fetch_set_acquire_release(volatile uint32* value, uint32 new_value) -{ - return __atomic_exchange_n(value, new_value, __ATOMIC_SEQ_CST); -} - -inline -uint64 atomic_fetch_set_acquire_release(volatile uint64* value, uint64 new_value) -{ - return __atomic_exchange_n(value, new_value, __ATOMIC_SEQ_CST); -} - -inline -void atomic_get_acquire_release(volatile byte* value, byte data[16]) -{ - __atomic_store((volatile __uint128 *) value, (__uint128 *) data, __ATOMIC_SEQ_CST); -} - -inline -uint32 atomic_get_acquire_release(volatile uint32* value) -{ - return __atomic_load_n((uint32 *) value, __ATOMIC_SEQ_CST); -} - -inline -uint64 atomic_get_acquire_release(volatile uint64* value) -{ - return __atomic_load_n((uint64 *) value, __ATOMIC_SEQ_CST); -} - -inline -void atomic_increment_acquire_release(volatile uint32* value) -{ - __atomic_add_fetch(value, 1, __ATOMIC_SEQ_CST); -} - -inline -void atomic_decrement_acquire_release(volatile uint32* value) -{ - __atomic_sub_fetch(value, 1, __ATOMIC_SEQ_CST); -} - -inline -void atomic_increment_acquire_release(volatile uint64* value) -{ - __atomic_add_fetch(value, 1, __ATOMIC_SEQ_CST); -} - -inline -void atomic_decrement_acquire_release(volatile uint64* value) -{ - __atomic_sub_fetch(value, 1, __ATOMIC_SEQ_CST); -} - -inline -void atomic_add_acquire_release(volatile uint32* value, uint32 increment) -{ - __atomic_add_fetch(value, increment, __ATOMIC_SEQ_CST); -} - -inline -void atomic_sub_acquire_release(volatile uint32* value, uint32 decrement) -{ - __atomic_sub_fetch(value, decrement, __ATOMIC_SEQ_CST); -} - -inline -uint32 atomic_compare_exchange_weak_acquire_release(volatile uint32* value, uint32* expected, uint32 desired) -{ - __atomic_compare_exchange_n(value, expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); - return *expected; -} - -inline -uint32 atomic_fetch_add_acquire_release(volatile uint32* value, uint32 operand) -{ - return __atomic_add_fetch(value, operand, __ATOMIC_SEQ_CST); -} - -inline -uint32 atomic_fetch_sub_acquire_release(volatile uint32* value, uint32 operand) -{ - return __atomic_sub_fetch(value, operand, __ATOMIC_SEQ_CST); -} - -inline -uint64 atomic_fetch_add_acquire_release(volatile uint64* value, uint64 operand) -{ - return __atomic_add_fetch(value, operand, __ATOMIC_SEQ_CST); -} - -inline -uint64 atomic_fetch_sub_acquire_release(volatile uint64* value, uint64 operand) -{ - return __atomic_sub_fetch(value, operand, __ATOMIC_SEQ_CST); -} - -inline -void atomic_and_acquire_release(volatile uint32* value, uint32 mask) -{ - __atomic_fetch_and(value, mask, __ATOMIC_SEQ_CST); -} - -inline -void atomic_and_acquire_release(volatile int32* value, int32 mask) -{ - __atomic_fetch_and(value, mask, __ATOMIC_SEQ_CST); -} - -inline -void atomic_and_acquire_release(volatile uint64* value, uint64 mask) -{ - __atomic_fetch_and(value, mask, __ATOMIC_SEQ_CST); -} - -inline -void atomic_and_acquire_release(volatile int64* value, int64 mask) -{ - __atomic_fetch_and(value, mask, __ATOMIC_SEQ_CST); -} - -inline -void atomic_or_acquire_release(volatile uint32* value, uint32 mask) -{ - __atomic_fetch_or(value, mask, __ATOMIC_SEQ_CST); -} - -inline -void atomic_or_acquire_release(volatile int32* value, int32 mask) -{ - __atomic_fetch_or(value, mask, __ATOMIC_SEQ_CST); -} - -inline -void atomic_or_acquire_release(volatile uint64* value, uint64 mask) -{ - __atomic_fetch_or(value, mask, __ATOMIC_SEQ_CST); -} - -inline -void atomic_or_acquire_release(volatile int64* value, int64 mask) -{ - __atomic_fetch_or(value, mask, __ATOMIC_SEQ_CST); -} - - -// Check out the intrinsic functions fence_memory and fence_write -// These are much faster and could accomplish what you are doing -inline -void atomic_fence_acquire() -{ - __atomic_thread_fence(__ATOMIC_ACQUIRE); -} - -// Check out the intrinsic functions fence_memory and fence_write -// These are much faster and could accomplish what you are doing -inline -void atomic_fence_release() -{ - __atomic_thread_fence(__ATOMIC_RELEASE); -} +#if __GNUC__ + #include "../../../compiler/gcc/Atomic.h" +#endif #endif \ No newline at end of file diff --git a/platform/win32/FileUtils.cpp b/platform/win32/FileUtils.cpp index 07da482..ee1e561 100644 --- a/platform/win32/FileUtils.cpp +++ b/platform/win32/FileUtils.cpp @@ -176,20 +176,24 @@ file_read(const char* path, FileBody* file, RingMemory* ring = NULL) return; } - LARGE_INTEGER size; - if (!GetFileSizeEx(fp, &size)) { - CloseHandle(fp); - file->content = NULL; + if (file->size == 0) { + LARGE_INTEGER size; + if (!GetFileSizeEx(fp, &size)) { + CloseHandle(fp); + file->content = NULL; - return; + return; + } + + file->size = size.QuadPart + 1; } if (ring != NULL) { - file->content = ring_get_memory(ring, size.QuadPart + 1); + file->content = ring_get_memory(ring, file->size); } - DWORD bytes; - if (!ReadFile(fp, file->content, (uint32) size.QuadPart, &bytes, NULL)) { + DWORD bytes_read; + if (!ReadFile(fp, file->content, (uint32) file->size - 1, &bytes_read, NULL)) { CloseHandle(fp); file->content = NULL; @@ -198,12 +202,13 @@ file_read(const char* path, FileBody* file, RingMemory* ring = NULL) CloseHandle(fp); - file->content[bytes] = '\0'; - file->size = size.QuadPart; + file->content[bytes_read] = '\0'; + file->size = bytes_read + 1; - LOG_INCREMENT_BY(DEBUG_COUNTER_DRIVE_READ, bytes); + LOG_INCREMENT_BY(DEBUG_COUNTER_DRIVE_READ, bytes_read); } +// @question Do we really need length? we have file.size we could use as we do in a function above inline void file_read(const char* path, FileBody* file, uint64 offset, uint64 length = MAX_UINT64, RingMemory* ring = NULL) { @@ -272,8 +277,8 @@ void file_read(const char* path, FileBody* file, uint64 offset, uint64 length = return; } - DWORD bytes; - if (!ReadFile(fp, file->content, (uint32) read_length, &bytes, NULL)) { + DWORD bytes_read; + if (!ReadFile(fp, file->content, (uint32) read_length, &bytes_read, NULL)) { CloseHandle(fp); file->content = NULL; @@ -282,10 +287,10 @@ void file_read(const char* path, FileBody* file, uint64 offset, uint64 length = CloseHandle(fp); - file->content[bytes] = '\0'; - file->size = bytes; + file->content[bytes_read] = '\0'; + file->size = bytes_read; - LOG_INCREMENT_BY(DEBUG_COUNTER_DRIVE_READ, bytes); + LOG_INCREMENT_BY(DEBUG_COUNTER_DRIVE_READ, bytes_read); } inline @@ -326,18 +331,70 @@ void file_read(FileHandle fp, FileBody* file, uint64 offset = 0, uint64 length = return; } - DWORD bytes; - if (!ReadFile(fp, file->content, (uint32) read_length, &bytes, NULL)) { + DWORD bytes_read; + if (!ReadFile(fp, file->content, (uint32) read_length, &bytes_read, NULL)) { file->content = NULL; ASSERT_SIMPLE(false); return; } - file->content[bytes] = '\0'; - file->size = bytes; + file->content[bytes_read] = '\0'; + file->size = bytes_read; - LOG_INCREMENT_BY(DEBUG_COUNTER_DRIVE_READ, bytes); + LOG_INCREMENT_BY(DEBUG_COUNTER_DRIVE_READ, bytes_read); +} + +inline +bool file_read_line( + FileHandle fp, + char* line_buffer, size_t buffer_size, + char internal_buffer[512], ssize_t* internal_buffer_size, char** internal_pos +) { + if (!(*internal_pos)) { + *internal_pos = internal_buffer; + } + + size_t line_filled = 0; + + while (line_filled < buffer_size - 1) { + // Refill the internal buffer if empty + if (*internal_pos == internal_buffer + *internal_buffer_size) { + if (!ReadFile(fp, internal_buffer, 512, (DWORD *) internal_buffer_size, NULL) + || *internal_buffer_size == 0 + ) { + line_buffer[line_filled] = '\0'; + + return line_filled > 0; + } + + *internal_pos = internal_buffer; + } + + char current_char = **internal_pos; + ++(*internal_pos); + + // Handle line endings (\n, \r, \r\n, \n\r) + if (current_char == '\n' || current_char == '\r') { + if ((*internal_pos < internal_buffer + *internal_buffer_size) + && (**internal_pos == '\n' || **internal_pos == '\r') + && **internal_pos != current_char + ) { + ++(*internal_pos); + } + + line_buffer[line_filled] = '\0'; + + // Successfully read a line + return true; + } + + line_buffer[line_filled++] = current_char; + } + + line_buffer[line_filled] = '\0'; + + return true; } inline uint64 diff --git a/platform/win32/Library.cpp b/platform/win32/Library.cpp index 06953e8..1ccc00d 100644 --- a/platform/win32/Library.cpp +++ b/platform/win32/Library.cpp @@ -18,15 +18,14 @@ #include "../../utils/StringUtils.h" #include "../../system/Library.h" -// @todo Rename file to Library.cpp - inline bool library_load(Library* lib) { char dst[MAX_PATH]; str_concat_new(dst, lib->dir, lib->dst); - #if DEBUG + // In debug mode, we create a copy at runtime, so we can recompile & reload it + #if DEBUG || INTERNAL char src[MAX_PATH]; size_t dst_len = strlen(dst); diff --git a/platform/win32/Library.h b/platform/win32/Library.h new file mode 100644 index 0000000..16bbd26 --- /dev/null +++ b/platform/win32/Library.h @@ -0,0 +1,16 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_PLATFORM_WIN32_LIBRARY_H +#define TOS_PLATFORM_WIN32_LIBRARY_H + +#include + +typedef HMODULE LibraryHandle; + +#endif \ No newline at end of file diff --git a/platform/win32/SystemInfo.cpp b/platform/win32/SystemInfo.cpp index e0963f0..4aad4f2 100644 --- a/platform/win32/SystemInfo.cpp +++ b/platform/win32/SystemInfo.cpp @@ -30,6 +30,7 @@ #include // @performance Do we really need all these libs, can't we simplify that?! +// At least we should dynamically load them, this way the application won't crash if the lib doesn't exist #include #pragma comment(lib, "Advapi32.lib") #pragma comment(lib, "wbemuuid.lib") @@ -94,8 +95,8 @@ uint16 system_country_code() } void mainboard_info_get(MainboardInfo* info) { - info->name[63] = '\0'; - info->serial_number[63] = '\0'; + info->name[sizeof(info->name) - 1] = '\0'; + info->serial_number[sizeof(info->serial_number) - 1] = '\0'; HRESULT hres; @@ -214,8 +215,6 @@ void mainboard_info_get(MainboardInfo* info) { if (SUCCEEDED(hr)) { wchar_to_char(vtProp.bstrVal); sprintf_fast(info->serial_number, sizeof(info->serial_number), "%s", vtProp.bstrVal); - info->serial_number[64] = '\0'; - VariantClear(&vtProp); } @@ -227,6 +226,9 @@ void mainboard_info_get(MainboardInfo* info) { pLoc->Release(); pEnumerator->Release(); CoUninitialize(); + + info->name[sizeof(info->name) - 1] = '\0'; + info->serial_number[sizeof(info->serial_number) - 1] = '\0'; } int32 network_info_get(NetworkInfo* info) { @@ -368,7 +370,7 @@ uint32 gpu_info_get(GpuInfo* info) { } uint32 i = 0; - while (pFactory->EnumAdapters(i, &pAdapter) != DXGI_ERROR_NOT_FOUND && i < 2) { + while (pFactory->EnumAdapters(i, &pAdapter) != DXGI_ERROR_NOT_FOUND && i < 3) { hr = pAdapter->GetDesc(&adapterDesc); if (FAILED(hr)) { pAdapter->Release(); @@ -388,33 +390,6 @@ uint32 gpu_info_get(GpuInfo* info) { return i; } -void display_info_get_primary(DisplayInfo* info) { - DISPLAY_DEVICEA device; - DEVMODEA mode; - - device.cb = sizeof(DISPLAY_DEVICEA); - - uint32_t i = 0; - while (EnumDisplayDevicesA(NULL, i, &device, 0)) { - ++i; - - if (!(device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)) { - continue; - } - - mode.dmSize = sizeof(mode); - - if (EnumDisplaySettingsA(device.DeviceName, ENUM_CURRENT_SETTINGS, &mode)) { - str_copy_short(info->name, device.DeviceName); - info->width = mode.dmPelsWidth; - info->height = mode.dmPelsHeight; - info->hz = mode.dmDisplayFrequency; - } - - break; - } -} - uint32 display_info_get(DisplayInfo* info) { DISPLAY_DEVICEA device; DEVMODEA mode; @@ -431,6 +406,7 @@ uint32 display_info_get(DisplayInfo* info) { info[i].width = mode.dmPelsWidth; info[i].height = mode.dmPelsHeight; info[i].hz = mode.dmDisplayFrequency; + info[i].is_primary = (bool) (device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE); } ++i; diff --git a/platform/win32/UtilsWindows.h b/platform/win32/UtilsWindows.h index 737c1d0..4b54a3e 100644 --- a/platform/win32/UtilsWindows.h +++ b/platform/win32/UtilsWindows.h @@ -145,6 +145,7 @@ void window_open(Window* window) void window_close(Window* window) { CloseWindow(window->hwnd); + DestroyWindow(window->hwnd); } #endif \ No newline at end of file diff --git a/platform/win32/threading/Atomic.h b/platform/win32/threading/Atomic.h index 0f89740..6b02eda 100644 --- a/platform/win32/threading/Atomic.h +++ b/platform/win32/threading/Atomic.h @@ -9,1488 +9,251 @@ #ifndef TOS_PLATFORM_WIN32_THREADING_ATOMIC_H #define TOS_PLATFORM_WIN32_THREADING_ATOMIC_H -#include #include "../../../stdlib/Types.h" +#include // WARNING: Windows doesn't really have relaxed, release, acquire function on x86_64. // You can see that by checking out how they are defined -inline -void atomic_set_relaxed(void** target, void* new_pointer) -{ - InterlockedExchangePointerNoFence(target, new_pointer); -} - -inline -void* atomic_get_relaxed(void** target) -{ - return InterlockedCompareExchangePointerNoFence(target, NULL, NULL); -} - -inline -void atomic_set_relaxed(volatile int32* value, int32 new_value) -{ - InterlockedExchangeNoFence((long *) value, new_value); -} - -inline -void atomic_set_relaxed(volatile int64* value, int64 new_value) -{ - InterlockedExchangeNoFence64((LONG64 *) value, (LONG64) new_value); -} - -inline -void atomic_set_relaxed(volatile f32* value, f32 new_value) -{ - InterlockedExchangeNoFence((long *) value, (long) new_value); -} - -inline -void atomic_set_relaxed(volatile f64* value, f64 new_value) -{ - InterlockedExchangeNoFence64((LONG64 *) value, (LONG64) new_value); -} - -inline -int32 atomic_fetch_set_relaxed(volatile int32* value, int32 new_value) -{ - return (int32) InterlockedExchangeNoFence((long *) value, new_value); -} - -inline -int64 atomic_fetch_set_relaxed(volatile int64* value, int64 new_value) -{ - return (int64) InterlockedExchangeNoFence64((LONG64 *) value, (LONG64) new_value); -} - -inline -void atomic_set_relaxed(volatile byte* value, const byte new_value[16]) -{ - int64* value64 = (int64*) value; - const int64* new_value64 = (const int64*) new_value; - - int64 expected_low, expected_high; - - do { - expected_low = value64[0]; - expected_high = value64[1]; - } while ( - !InterlockedCompareExchange128( - (volatile long long *) value, - new_value64[1], - new_value64[0], - &expected_low - ) - ); -} - -inline -int32 atomic_get_relaxed(volatile int32* value) -{ - return (int32) InterlockedCompareExchangeNoFence((long *) value, 0, 0); -} - -inline -int64 atomic_get_relaxed(volatile int64* value) -{ - return (int64) InterlockedCompareExchangeNoFence64((LONG64 *) value, 0, 0); -} - -inline -f32 atomic_get_relaxed(volatile f32* value) -{ - return (f32) InterlockedCompareExchangeNoFence((long *) value, 0, 0); -} - -inline -f64 atomic_get_relaxed(volatile f64* value) -{ - return (f64) InterlockedCompareExchangeNoFence64((LONG64 *) value, 0, 0); -} - -inline -void atomic_get_relaxed(volatile byte* value, byte data[16]) -{ - InterlockedCompareExchange128((volatile long long *) value, 0, 0, (long long *) data); -} - -inline -void atomic_increment_relaxed(volatile int32* value) -{ - InterlockedIncrementNoFence((long *) value); -} - -inline -void atomic_decrement_relaxed(volatile int32* value) -{ - InterlockedDecrementNoFence((long *) value); -} - -inline -void atomic_increment_relaxed(volatile int64* value) -{ - InterlockedIncrementNoFence64((LONG64 *) value); -} - -inline -void atomic_decrement_relaxed(volatile int64* value) -{ - InterlockedDecrementNoFence64((LONG64 *) value); -} - -inline -void atomic_add_relaxed(volatile int32* value, int32 increment) -{ - InterlockedAddNoFence((long *) value, increment); -} - -inline -void atomic_sub_relaxed(volatile int32* value, int32 decrement) -{ - InterlockedAddNoFence((long *) value, -decrement); -} - -inline -void atomic_add_relaxed(volatile int64* value, int64 increment) -{ - InterlockedAddNoFence64((LONG64 *) value, (LONG64) increment); -} - -inline -void atomic_sub_relaxed(volatile int64* value, int64 decrement) -{ - InterlockedAddNoFence64((LONG64 *) value, -((LONG64) decrement)); -} - -inline -f32 atomic_compare_exchange_weak_relaxed(volatile f32* value, f32* expected, f32 desired) -{ - return (f32) InterlockedCompareExchangeNoFence((long *) value, (long) desired, (long) *expected); -} - -inline -f64 atomic_compare_exchange_weak_relaxed(volatile f64* value, f64* expected, f64 desired) -{ - return (f64) InterlockedCompareExchangeNoFence64((LONG64 *) value, (LONG64) desired, (LONG64) *expected); -} - -inline -int32 atomic_compare_exchange_weak_relaxed(volatile int32* value, int32* expected, int32 desired) -{ - return (int32) InterlockedCompareExchangeNoFence((long *) value, desired, *expected); -} - -inline -int64 atomic_compare_exchange_weak_relaxed(volatile int64* value, int64* expected, int64 desired) -{ - return (int64) InterlockedCompareExchangeNoFence64((LONG64 *) value, (LONG64) desired, (LONG64) *expected); -} - -inline -int32 atomic_fetch_add_relaxed(volatile int32* value, int32 operand) -{ - return (int32) InterlockedExchangeAddNoFence((long *) value, operand); -} - -inline -int32 atomic_fetch_sub_relaxed(volatile int32* value, int32 operand) -{ - return (int32) InterlockedExchangeSubtract((unsigned long *) value, operand); -} - -inline -int64 atomic_fetch_add_relaxed(volatile int64* value, int64 operand) -{ - return (int64) InterlockedExchangeAddNoFence64((LONG64 *) value, (LONG64) operand); -} - -inline -int64 atomic_fetch_sub_relaxed(volatile int64* value, int64 operand) -{ - return (int64) InterlockedExchangeAdd64((LONG64 *) value, -((LONG64) operand)); -} - -inline -void atomic_set_relaxed(volatile uint32* value, uint32 new_value) -{ - InterlockedExchangeNoFence((long *) value, new_value); -} - -inline -void atomic_set_relaxed(volatile uint64* value, uint64 new_value) -{ - InterlockedExchangeNoFence64((LONG64 *) value, (LONG64) new_value); -} - -inline -uint32 atomic_fetch_set_relaxed(volatile uint32* value, uint32 new_value) -{ - return (uint32) InterlockedExchangeNoFence((long *) value, new_value); -} - -inline -uint64 atomic_fetch_set_relaxed(volatile uint64* value, uint64 new_value) -{ - return (uint64) InterlockedExchangeNoFence64((LONG64 *) value, (LONG64) new_value); -} - -inline -uint32 atomic_get_relaxed(volatile uint32* value) -{ - return (uint32) InterlockedCompareExchangeNoFence((long *) value, 0, 0); -} - -inline -uint64 atomic_get_relaxed(volatile uint64* value) -{ - return (uint64) InterlockedCompareExchangeNoFence64((LONG64 *) value, 0, 0); -} - -inline -void atomic_increment_relaxed(volatile uint32* value) -{ - InterlockedIncrementNoFence((long *) value); -} - -inline -void atomic_decrement_relaxed(volatile uint32* value) -{ - InterlockedDecrementNoFence((long *) value); -} - -inline -void atomic_increment_relaxed(volatile uint64* value) -{ - InterlockedIncrementNoFence64((LONG64 *) value); -} - -inline -void atomic_decrement_relaxed(volatile uint64* value) -{ - InterlockedDecrementNoFence64((LONG64 *) value); -} - -inline -void atomic_add_relaxed(volatile uint32* value, uint32 increment) -{ - InterlockedAddNoFence((long *) value, increment); -} - -inline -void atomic_sub_relaxed(volatile uint32* value, uint32 decrement) -{ - InterlockedAddNoFence((long *) value, -1 * ((int32) decrement)); -} - -inline -void atomic_add_relaxed(volatile uint64* value, uint64 increment) -{ - InterlockedAddNoFence64((LONG64 *) value, (LONG64) increment); -} - -inline -void atomic_sub_relaxed(volatile uint64* value, uint64 decrement) -{ - InterlockedAddNoFence64((LONG64 *) value, -((LONG64) decrement)); -} - -inline -uint32 atomic_compare_exchange_weak_relaxed(volatile uint32* value, uint32* expected, uint32 desired) -{ - return (uint32) InterlockedCompareExchangeNoFence((long *) value, desired, *expected); -} - -inline -uint64 atomic_compare_exchange_weak_relaxed(volatile uint64* value, uint64* expected, uint64 desired) -{ - return (uint64) InterlockedCompareExchangeNoFence64((LONG64 *) value, (LONG64) desired, (LONG64) *expected); -} - -inline -uint32 atomic_fetch_add_relaxed(volatile uint32* value, uint32 operand) -{ - return (uint32) InterlockedExchangeAddNoFence((long *) value, operand); -} - -inline -uint32 atomic_fetch_sub_relaxed(volatile uint32* value, uint32 operand) -{ - return (uint32) InterlockedExchangeSubtract((unsigned long *) value, operand); -} - -inline -uint64 atomic_fetch_add_relaxed(volatile uint64* value, uint64 operand) -{ - return (uint64) InterlockedExchangeAddNoFence64((LONG64 *) value, (LONG64) operand); -} - -inline -uint64 atomic_fetch_sub_relaxed(volatile uint64* value, uint64 operand) -{ - return (uint64) InterlockedExchangeAdd64((LONG64 *) value, -((LONG64) operand)); -} - -inline -void atomic_and_relaxed(volatile uint32* value, uint32 mask) -{ - InterlockedAndNoFence((volatile LONG *) value, mask); -} - -inline -void atomic_and_relaxed(volatile int32* value, int32 mask) -{ - InterlockedAndNoFence((volatile LONG *) value, (LONG)mask); -} - -inline -void atomic_and_relaxed(volatile uint64* value, uint64 mask) -{ - InterlockedAnd64NoFence((volatile LONG64 *) value, mask); -} - -inline -void atomic_and_relaxed(volatile int64* value, int64 mask) -{ - InterlockedAnd64NoFence((volatile LONG64 *) value, (LONG64) mask); -} - -inline -void atomic_or_relaxed(volatile uint32* value, uint32 mask) -{ - InterlockedOrNoFence((volatile LONG *) value, mask); -} - -inline -void atomic_or_relaxed(volatile int32* value, int32 mask) -{ - InterlockedOrNoFence((volatile LONG *) value, (LONG)mask); -} - -inline -void atomic_or_relaxed(volatile uint64* value, uint64 mask) -{ - InterlockedOr64NoFence((volatile LONG64 *) value, mask); -} - -inline -void atomic_or_relaxed(volatile int64* value, int64 mask) -{ - InterlockedOr64NoFence((volatile LONG64 *) value, mask); -} - -inline -void atomic_set_acquire(void** target, void* new_pointer) -{ - InterlockedExchangePointerAcquire(target, new_pointer); -} - -inline -void* atomic_get_acquire(void** target) -{ - return InterlockedCompareExchangePointerAcquire(target, NULL, NULL); -} - -inline -void atomic_set_acquire(volatile int32* value, int32 new_value) -{ - InterlockedExchangeAcquire((long *) value, new_value); -} - -inline -void atomic_set_acquire(volatile int64* value, int64 new_value) -{ - InterlockedExchangeAcquire64((LONG64 *) value, (LONG64) new_value); -} - -inline -void atomic_set_acquire(volatile f32* value, f32 new_value) -{ - InterlockedExchangeAcquire((long *) value, (long) new_value); -} - -inline -void atomic_set_acquire(volatile f64* value, f64 new_value) -{ - InterlockedExchangeAcquire64((LONG64 *) value, (LONG64) new_value); -} - -inline -int32 atomic_fetch_set_acquire(volatile int32* value, int32 new_value) -{ - return (int32) InterlockedExchangeAcquire((long *) value, new_value); -} - -inline -int64 atomic_fetch_set_acquire(volatile int64* value, int64 new_value) -{ - return (int64) InterlockedExchangeAcquire64((LONG64 *) value, (LONG64) new_value); -} - -inline -void atomic_set_acquire(volatile byte* value, const byte new_value[16]) -{ - int64* value64 = (int64*) value; - const int64* new_value64 = (const int64*) new_value; - - int64 expected_low, expected_high; - - do { - expected_low = value64[0]; - expected_high = value64[1]; - } while ( - !InterlockedCompareExchange128( - (volatile long long *) value, - new_value64[1], - new_value64[0], - &expected_low - ) - ); -} - -inline -int32 atomic_get_acquire(volatile int32* value) -{ - return (int32) InterlockedCompareExchangeAcquire((long *) value, 0, 0); -} - -inline -int64 atomic_get_acquire(volatile int64* value) -{ - return (int64) InterlockedCompareExchangeAcquire64((LONG64 *) value, 0, 0); -} - -inline -f32 atomic_get_acquire(volatile f32* value) -{ - return (f32) InterlockedCompareExchangeAcquire((long *) value, 0, 0); -} - -inline -f64 atomic_get_acquire(volatile f64* value) -{ - return (f64) InterlockedCompareExchangeAcquire64((LONG64 *) value, 0, 0); -} - -inline -void atomic_get_acquire(volatile byte* value, byte data[16]) -{ - InterlockedCompareExchange128((volatile long long *) value, 0, 0, (long long *) data); -} - -inline -void atomic_increment_acquire(volatile int32* value) -{ - InterlockedIncrementAcquire((long *) value); -} - -inline -void atomic_decrement_acquire(volatile int32* value) -{ - InterlockedDecrementAcquire((long *) value); -} - -inline -void atomic_increment_acquire(volatile int64* value) -{ - InterlockedIncrementAcquire64((LONG64 *) value); -} - -inline -void atomic_decrement_acquire(volatile int64* value) -{ - InterlockedDecrementAcquire64((LONG64 *) value); -} - -inline -void atomic_add_acquire(volatile int32* value, int32 increment) -{ - InterlockedAddAcquire((long *) value, increment); -} - -inline -void atomic_sub_acquire(volatile int32* value, int32 decrement) -{ - InterlockedAddAcquire((long *) value, -decrement); -} - -inline -void atomic_add_acquire(volatile int64* value, int64 increment) -{ - InterlockedAddAcquire64((LONG64 *) value, (LONG64) increment); -} - -inline -void atomic_sub_acquire(volatile int64* value, int64 decrement) -{ - InterlockedAddAcquire64((LONG64 *) value, -1 * ((LONG64) decrement)); -} - -inline -f32 atomic_compare_exchange_weak_acquire(volatile f32* value, f32* expected, f32 desired) -{ - return (f32) InterlockedCompareExchangeAcquire((long *) value, (long) desired, (long) *expected); -} - -inline -f64 atomic_compare_exchange_weak_acquire(volatile f64* value, f64* expected, f64 desired) -{ - return (f64) InterlockedCompareExchangeAcquire64((LONG64 *) value, (LONG64) desired, (LONG64) *expected); -} - -inline -int32 atomic_compare_exchange_weak_acquire(volatile int32* value, int32* expected, int32 desired) -{ - return (int32) InterlockedCompareExchangeAcquire((long *) value, desired, *expected); -} - -inline -int64 atomic_compare_exchange_weak_acquire(volatile int64* value, int64* expected, int64 desired) -{ - return (int64) InterlockedCompareExchangeAcquire64((LONG64 *) value, (LONG64) desired, (LONG64) *expected); -} - -inline -int32 atomic_fetch_add_acquire(volatile int32* value, int32 operand) -{ - return (int32) InterlockedExchangeAddAcquire((long *) value, operand); -} - -inline -int32 atomic_fetch_sub_acquire(volatile int32* value, int32 operand) -{ - return (int32) InterlockedExchangeSubtract((unsigned long *) value, operand); -} - -inline -int64 atomic_fetch_add_acquire(volatile int64* value, int64 operand) -{ - return (int64) InterlockedExchangeAdd64((LONG64 *) value, -((LONG64) operand)); -} - -inline -int64 atomic_fetch_sub_acquire(volatile int64* value, int64 operand) -{ - return (int64) InterlockedExchangeAdd64((LONG64 *) value, -((LONG64) operand)); -} - -inline -void atomic_set_acquire(volatile uint32* value, uint32 new_value) -{ - InterlockedExchangeAcquire((long *) value, new_value); -} - -inline -void atomic_set_acquire(volatile uint64* value, uint64 new_value) -{ - InterlockedExchangeAcquire64((LONG64 *) value, (LONG64) new_value); -} - -inline -uint32 atomic_fetch_set_acquire(volatile uint32* value, uint32 new_value) -{ - return (uint32) InterlockedExchangeAcquire((long *) value, new_value); -} - -inline -uint64 atomic_fetch_set_acquire(volatile uint64* value, uint64 new_value) -{ - return (uint64) InterlockedExchangeAcquire64((LONG64 *) value, (LONG64) new_value); -} - -inline -uint32 atomic_get_acquire(volatile uint32* value) -{ - return (uint32) InterlockedCompareExchangeAcquire((long *) value, 0, 0); -} - -inline -uint64 atomic_get_acquire(volatile uint64* value) -{ - return (uint64) InterlockedCompareExchangeAcquire64((LONG64 *) value, 0, 0); -} - -inline -void atomic_increment_acquire(volatile uint32* value) -{ - InterlockedIncrementAcquire((long *) value); -} - -inline -void atomic_decrement_acquire(volatile uint32* value) -{ - InterlockedDecrementAcquire((long *) value); -} - -inline -void atomic_increment_acquire(volatile uint64* value) -{ - InterlockedIncrementAcquire64((LONG64 *) value); -} - -inline -void atomic_decrement_acquire(volatile uint64* value) -{ - InterlockedDecrementAcquire64((LONG64 *) value); -} - -inline -void atomic_add_acquire(volatile uint32* value, uint32 increment) -{ - InterlockedAddAcquire((long *) value, increment); -} - -inline -void atomic_sub_acquire(volatile uint32* value, uint32 decrement) -{ - InterlockedAddAcquire((long *) value, -1 * ((int32) decrement)); -} - -inline -void atomic_add_acquire(volatile uint64* value, uint64 increment) -{ - InterlockedAddAcquire64((LONG64 *) value, (LONG64) increment); -} - -inline -void atomic_sub_acquire(volatile uint64* value, uint64 decrement) -{ - InterlockedAddAcquire64((LONG64 *) value, -((LONG64) decrement)); -} - -inline -uint32 atomic_compare_exchange_weak_acquire(volatile uint32* value, uint32* expected, uint32 desired) -{ - return (uint32) InterlockedCompareExchangeAcquire((long *) value, desired, *expected); -} - -inline -uint64 atomic_compare_exchange_weak_acquire(volatile uint64* value, uint64* expected, uint64 desired) -{ - return (uint64) InterlockedCompareExchangeAcquire64((LONG64 *) value, (LONG64) desired, (LONG64) *expected); -} - -inline -uint32 atomic_fetch_add_acquire(volatile uint32* value, uint32 operand) -{ - return (uint32) InterlockedExchangeAddAcquire((long *) value, operand); -} - -inline -uint32 atomic_fetch_sub_acquire(volatile uint32* value, uint32 operand) -{ - return (uint32) InterlockedExchangeSubtract((unsigned long *) value, (long) operand); -} - -inline -uint64 atomic_fetch_add_acquire(volatile uint64* value, uint64 operand) -{ - return (uint64) InterlockedExchangeAddAcquire64((LONG64 *) value, (LONG64) operand); -} - -inline -uint64 atomic_fetch_sub_acquire(volatile uint64* value, uint64 operand) -{ - return (uint64) InterlockedExchangeAdd64((LONG64 *) value, -((LONG64) operand)); -} - -inline -void atomic_and_acquire(volatile uint32* value, uint32 mask) -{ - InterlockedAndAcquire((volatile LONG *) value, mask); -} - -inline -void atomic_and_acquire(volatile int32* value, int32 mask) -{ - InterlockedAndAcquire((volatile LONG *) value, (LONG)mask); -} - -inline -void atomic_and_acquire(volatile uint64* value, uint64 mask) -{ - InterlockedAnd64Acquire((volatile LONG64 *) value, mask); -} - -inline -void atomic_and_acquire(volatile int64* value, int64 mask) -{ - InterlockedAnd64Acquire((volatile LONG64 *) value, mask); -} - -inline -void atomic_or_acquire(volatile uint32* value, uint32 mask) -{ - InterlockedOrAcquire((volatile LONG *) value, mask); -} - -inline -void atomic_or_acquire(volatile int32* value, int32 mask) -{ - InterlockedOrAcquire((volatile LONG *) value, (LONG)mask); -} - -inline -void atomic_or_acquire(volatile uint64* value, uint64 mask) -{ - InterlockedOr64Acquire((volatile LONG64 *) value, mask); -} - -inline -void atomic_or_acquire(volatile int64* value, int64 mask) -{ - InterlockedOr64Acquire((volatile LONG64 *) value, mask); -} - -inline -void atomic_set_release(void** target, void* new_pointer) -{ - InterlockedExchangePointer(target, new_pointer); -} - -inline -void* atomic_get_release(void** target) -{ - return InterlockedCompareExchangePointerRelease(target, NULL, NULL); -} - -inline -void atomic_set_release(volatile int32* value, int32 new_value) -{ - InterlockedExchange((long *) value, new_value); -} - -inline -void atomic_set_release(volatile int64* value, int64 new_value) -{ - InterlockedExchange64((LONG64 *) value, (LONG64) new_value); -} - -inline -void atomic_set_release(volatile f32* value, f32 new_value) -{ - InterlockedExchange((long *) value, (long) new_value); -} - -inline -void atomic_set_release(volatile f64* value, f64 new_value) -{ - InterlockedExchange64((LONG64 *) value, (LONG64) new_value); -} - -inline -int32 atomic_fetch_set_release(volatile int32* value, int32 new_value) -{ - return (int32) InterlockedExchange((long *) value, new_value); -} - -inline -int64 atomic_fetch_set_release(volatile int64* value, int64 new_value) -{ - return (int64) InterlockedExchange64((LONG64 *) value, (LONG64) new_value); -} - -inline -void atomic_set_release(volatile byte* value, const byte new_value[16]) -{ - int64* value64 = (int64*) value; - const int64* new_value64 = (const int64*) new_value; - - int64 expected_low, expected_high; - - do { - expected_low = value64[0]; - expected_high = value64[1]; - } while ( - !InterlockedCompareExchange128( - (volatile long long *) value, - new_value64[1], - new_value64[0], - &expected_low - ) - ); -} - -inline -int32 atomic_get_release(volatile int32* value) -{ - return (int32) InterlockedCompareExchangeRelease((long *) value, 0, 0); -} - -inline -int64 atomic_get_release(volatile int64* value) -{ - return (int64) InterlockedCompareExchangeRelease64((LONG64 *) value, 0, 0); -} - -inline -f32 atomic_get_release(volatile f32* value) -{ - return (f32) InterlockedCompareExchangeRelease((long *) value, 0, 0); -} - -inline -f64 atomic_get_release(volatile f64* value) -{ - return (f64) InterlockedCompareExchangeRelease64((LONG64 *) value, 0, 0); -} - -inline -void atomic_get_release(volatile byte* value, byte data[16]) -{ - InterlockedCompareExchange128((volatile long long *) value, 0, 0, (long long *) data); -} - -inline -void atomic_increment_release(volatile int32* value) -{ - InterlockedIncrementRelease((long *) value); -} - -inline -void atomic_decrement_release(volatile int32* value) -{ - InterlockedDecrementRelease((long *) value); -} - -inline -void atomic_increment_release(volatile int64* value) -{ - InterlockedIncrementRelease64((LONG64 *) value); -} - -inline -void atomic_decrement_release(volatile int64* value) -{ - InterlockedDecrementRelease64((LONG64 *) value); -} - -inline -void atomic_add_release(volatile int32* value, int32 increment) -{ - InterlockedAddRelease((long *) value, increment); -} - -inline -void atomic_sub_release(volatile int32* value, int32 decrement) -{ - InterlockedAddRelease((long *) value, -decrement); -} - -inline -void atomic_add_release(volatile int64* value, int64 increment) -{ - InterlockedAddRelease64((LONG64 *) value, (LONG64) increment); -} - -inline -void atomic_sub_release(volatile int64* value, int64 decrement) -{ - InterlockedAddRelease64((LONG64 *) value, -((LONG64) decrement)); -} - -inline -f32 atomic_compare_exchange_weak_release(volatile f32* value, f32* expected, f32 desired) -{ - return (f32) InterlockedCompareExchangeRelease((long *) value, (long) desired, (long) *expected); -} - -inline -f64 atomic_compare_exchange_weak_release(volatile f64* value, f64* expected, f64 desired) -{ - return (f64) InterlockedCompareExchangeRelease64((LONG64 *) value, (LONG64) desired, (LONG64) *expected); -} - -inline -int32 atomic_compare_exchange_weak_release(volatile int32* value, int32* expected, int32 desired) -{ - return (int32) InterlockedCompareExchangeRelease((long *) value, desired, *expected); -} - -inline -int64 atomic_compare_exchange_weak_release(volatile int64* value, int64* expected, int64 desired) -{ - return (int64) InterlockedCompareExchangeRelease64((LONG64 *) value, (LONG64) desired, (LONG64) *expected); -} - -inline -int32 atomic_fetch_add_release(volatile int32* value, int32 operand) -{ - return (int32) InterlockedExchangeAddRelease((long *) value, operand); -} - -inline -int32 atomic_fetch_sub_release(volatile int32* value, int32 operand) -{ - return (int32) InterlockedExchangeSubtract((unsigned long *) value, operand); -} - -inline -int64 atomic_fetch_add_release(volatile int64* value, int64 operand) -{ - return (int64) InterlockedExchangeAdd64((LONG64 *) value, -((LONG64) operand)); -} - -inline -int64 atomic_fetch_sub_release(volatile int64* value, int64 operand) -{ - return (int64) InterlockedExchangeAdd64((LONG64 *) value, -((LONG64) operand)); -} - -inline -void atomic_set_release(volatile uint32* value, uint32 new_value) -{ - InterlockedExchange((long *) value, new_value); -} - -inline -void atomic_set_release(volatile uint64* value, uint64 new_value) -{ - InterlockedExchange64((LONG64 *) value, (LONG64) new_value); -} - -inline -uint32 atomic_fetch_set_release(volatile uint32* value, uint32 new_value) -{ - return (uint32) InterlockedExchange((long *) value, new_value); -} - -inline -uint64 atomic_fetch_set_release(volatile uint64* value, uint64 new_value) -{ - return (uint64) InterlockedExchange64((LONG64 *) value, (LONG64) new_value); -} - -inline -uint32 atomic_get_release(volatile uint32* value) -{ - return (uint32) InterlockedCompareExchangeRelease((long *) value, 0, 0); -} - -inline -uint64 atomic_get_release(volatile uint64* value) -{ - return (uint64) InterlockedCompareExchangeRelease64((LONG64 *) value, 0, 0); -} - -inline -void atomic_increment_release(volatile uint32* value) -{ - InterlockedIncrementRelease((long *) value); -} - -inline -void atomic_decrement_release(volatile uint32* value) -{ - InterlockedDecrementRelease((long *) value); -} - -inline -void atomic_increment_release(volatile uint64* value) -{ - InterlockedIncrementRelease64((LONG64 *) value); -} - -inline -void atomic_decrement_release(volatile uint64* value) -{ - InterlockedDecrementRelease64((LONG64 *) value); -} - -inline -void atomic_add_release(volatile uint32* value, uint32 increment) -{ - InterlockedAddRelease((long *) value, increment); -} - -inline -void atomic_sub_release(volatile uint32* value, uint32 decrement) -{ - InterlockedAddRelease((long *) value, -1 * ((int32) decrement)); -} - -inline -void atomic_add_release(volatile uint64* value, uint64 increment) -{ - InterlockedAddRelease64((LONG64 *) value, (LONG64) increment); -} - -inline -void atomic_sub_release(volatile uint64* value, uint64 decrement) -{ - InterlockedAddRelease64((LONG64 *) value, -((LONG64) decrement)); -} - -inline -uint32 atomic_compare_exchange_weak_release(volatile uint32* value, uint32* expected, uint32 desired) -{ - return (uint32) InterlockedCompareExchangeRelease((long *) value, desired, *expected); -} - -inline -uint64 atomic_compare_exchange_weak_release(volatile uint64* value, uint64* expected, uint64 desired) -{ - return (uint64) InterlockedCompareExchangeRelease64((LONG64 *) value, (LONG64) desired, (LONG64) *expected); -} - -inline -uint32 atomic_fetch_add_release(volatile uint32* value, uint32 operand) -{ - return (uint32) InterlockedExchangeAddRelease((long *) value, operand); -} - -inline -uint32 atomic_fetch_sub_release(volatile uint32* value, uint32 operand) -{ - return (uint32) InterlockedExchangeSubtract((unsigned long *) value, (long) operand); -} - -inline -uint64 atomic_fetch_add_release(volatile uint64* value, uint64 operand) -{ - return (uint64) InterlockedExchangeAddRelease64((LONG64 *) value, (LONG64) operand); -} - -inline -uint64 atomic_fetch_sub_release(volatile uint64* value, uint64 operand) -{ - return (uint64) InterlockedExchangeAdd64((LONG64 *) value, -((LONG64) operand)); -} - -inline -void atomic_and_release(volatile uint32* value, uint32 mask) -{ - InterlockedAndRelease((volatile LONG *) value, mask); -} - -inline -void atomic_and_release(volatile int32* value, int32 mask) -{ - InterlockedAndRelease((volatile LONG *) value, (LONG)mask); -} - -inline -void atomic_and_release(volatile uint64* value, uint64 mask) -{ - InterlockedAnd64Release((volatile LONG64 *) value, mask); -} - -inline -void atomic_and_release(volatile int64* value, int64 mask) -{ - InterlockedAnd64Release((volatile LONG64 *) value, mask); -} - -inline -void atomic_or_release(volatile uint32* value, uint32 mask) -{ - InterlockedOrRelease((volatile LONG *) value, mask); -} - -inline -void atomic_or_release(volatile int32* value, int32 mask) -{ - InterlockedOrRelease((volatile LONG *) value, (LONG)mask); -} - -inline -void atomic_or_release(volatile uint64* value, uint64 mask) -{ - InterlockedOr64Release((volatile LONG64 *) value, mask); -} - -inline -void atomic_or_release(volatile int64* value, int64 mask) -{ - InterlockedOr64Release((volatile LONG64 *) value, mask); -} - -inline -void atomic_set_acquire_release(void** target, void* new_pointer) -{ - InterlockedExchangePointer(target, new_pointer); -} - -inline -void* atomic_get_acquire_release(void** target) -{ - return InterlockedCompareExchangePointer(target, NULL, NULL); -} - -inline -void atomic_set_acquire_release(volatile int32* value, int32 new_value) -{ - InterlockedExchange((long *) value, new_value); -} - -inline -void atomic_set_acquire_release(volatile int64* value, int64 new_value) -{ - InterlockedExchange64((LONG64 *) value, (LONG64) new_value); -} - -inline -void atomic_set_acquire_release(volatile f32* value, f32 new_value) -{ - InterlockedExchange((long *) value, (long) new_value); -} - -inline -void atomic_set_acquire_release(volatile f64* value, f64 new_value) -{ - InterlockedExchange64((LONG64 *) value, (LONG64) new_value); -} - -inline -int32 atomic_fetch_set_acquire_release(volatile int32* value, int32 new_value) -{ - return (int32) InterlockedExchange((long *) value, new_value); -} - -inline -int64 atomic_fetch_set_acquire_release(volatile int64* value, int64 new_value) -{ - return (int64) InterlockedExchange64((LONG64 *) value, (LONG64) new_value); -} - -inline -void atomic_set_acquire_release(volatile byte* value, const byte new_value[16]) -{ - int64* value64 = (int64*) value; - const int64* new_value64 = (const int64*) new_value; - - int64 expected_low, expected_high; - - do { - expected_low = value64[0]; - expected_high = value64[1]; - } while ( - !InterlockedCompareExchange128( - (volatile long long *) value, - new_value64[1], - new_value64[0], - &expected_low - ) - ); -} - -inline -int32 atomic_get_acquire_release(volatile int32* value) -{ - return (int32) InterlockedCompareExchange((long *) value, 0, 0); -} - -inline -int64 atomic_get_acquire_release(volatile int64* value) -{ - return (int64) InterlockedCompareExchange64((LONG64 *) value, 0, 0); -} - -inline -f32 atomic_get_acquire_release(volatile f32* value) -{ - return (f32) InterlockedCompareExchange((long *) value, 0, 0); -} - -inline -f64 atomic_get_acquire_release(volatile f64* value) -{ - return (f64) InterlockedCompareExchange64((LONG64 *) value, 0, 0); -} - -inline -void atomic_get_acquire_release(volatile byte* value, byte data[16]) -{ - InterlockedCompareExchange128((volatile long long *) value, 0, 0, (long long *) data); -} - -inline -void atomic_increment_acquire_release(volatile int32* value) -{ - InterlockedIncrement((long *) value); -} - -inline -void atomic_decrement_acquire_release(volatile int32* value) -{ - InterlockedDecrement((long *) value); -} - -inline -void atomic_increment_acquire_release(volatile int64* value) -{ - InterlockedIncrement64((LONG64 *) value); -} - -inline -void atomic_decrement_acquire_release(volatile int64* value) -{ - InterlockedDecrement64((LONG64 *) value); -} - -inline -void atomic_add_acquire_release(volatile int32* value, int32 increment) -{ - InterlockedAdd((long *) value, increment); -} - -inline -void atomic_sub_acquire_release(volatile int32* value, int32 decrement) -{ - InterlockedAdd((long *) value, -decrement); -} - -inline -void atomic_add_acquire_release(volatile int64* value, int64 increment) -{ - InterlockedAdd64((LONG64 *) value, (LONG64) increment); -} - -inline -void atomic_sub_acquire_release(volatile int64* value, int64 decrement) -{ - InterlockedAdd64((LONG64 *) value, -((LONG64) decrement)); -} - -inline -f32 atomic_compare_exchange_weak_acquire_release(volatile f32* value, f32* expected, f32 desired) -{ - return (f32) InterlockedCompareExchange((long *) value, (long) desired, (long) *expected); -} - -inline -f64 atomic_compare_exchange_weak_acquire_release(volatile f64* value, f64* expected, f64 desired) -{ - return (f64) InterlockedCompareExchange64((LONG64 *) value, (LONG64) desired, (LONG64) *expected); -} - -inline -int32 atomic_compare_exchange_weak_acquire_release(volatile int32* value, int32* expected, int32 desired) -{ - return (int32) InterlockedCompareExchange((long *) value, desired, *expected); -} - -inline -int64 atomic_compare_exchange_weak_acquire_release(volatile int64* value, int64* expected, int64 desired) -{ - return (int64) InterlockedCompareExchange64((LONG64 *) value, (LONG64) desired, (LONG64) *expected); -} - -inline -int32 atomic_fetch_add_acquire_release(volatile int32* value, int32 operand) -{ - return (int32) InterlockedExchangeAdd((long *) value, operand); -} - -inline -int32 atomic_fetch_sub_acquire_release(volatile int32* value, int32 operand) -{ - int32 ret = (int32) InterlockedExchangeSubtract((unsigned long *) value, operand); - - return ret; -} - -inline -int64 atomic_fetch_add_acquire_release(volatile int64* value, int64 operand) -{ - int64 ret = (int64) InterlockedExchangeAdd64((LONG64 *) value, -((LONG64) operand)); - - return ret; -} - -inline -int64 atomic_fetch_sub_acquire_release(volatile int64* value, int64 operand) -{ - int64 ret = (int64) InterlockedExchangeAdd64((LONG64 *) value, -((LONG64) operand)); - - return ret; -} - -inline -void atomic_set_acquire_release(volatile uint32* value, uint32 new_value) -{ - InterlockedExchange((long *) value, new_value); -} - -inline -void atomic_set_acquire_release(volatile uint64* value, uint64 new_value) -{ - InterlockedExchange64((LONG64 *) value, (LONG64) new_value); -} - -inline -uint32 atomic_fetch_set_acquire_release(volatile uint32* value, uint32 new_value) -{ - return (uint32) InterlockedExchange((long *) value, new_value); -} - -inline -uint64 atomic_fetch_set_acquire_release(volatile uint64* value, uint64 new_value) -{ - return (uint64) InterlockedExchange64((LONG64 *) value, (LONG64) new_value); -} - -inline -uint32 atomic_get_acquire_release(volatile uint32* value) -{ - return (uint32) InterlockedCompareExchange((long *) value, 0, 0); -} - -inline -uint64 atomic_get_acquire_release(volatile uint64* value) -{ - return (uint64) InterlockedCompareExchange64((LONG64 *) value, 0, 0); -} - -inline -void atomic_increment_acquire_release(volatile uint32* value) -{ - InterlockedIncrement((long *) value); -} - -inline -void atomic_decrement_acquire_release(volatile uint32* value) -{ - InterlockedDecrement((long *) value); -} - -inline -void atomic_increment_acquire_release(volatile uint64* value) -{ - InterlockedIncrement64((LONG64 *) value); -} - -inline -void atomic_decrement_acquire_release(volatile uint64* value) -{ - InterlockedDecrement64((LONG64 *) value); -} - -inline -void atomic_add_acquire_release(volatile uint32* value, uint32 increment) -{ - InterlockedAdd((long *) value, increment); -} - -inline -void atomic_sub_acquire_release(volatile uint32* value, uint32 decrement) -{ - InterlockedAdd((long *) value, -1 * ((int32) decrement)); -} - -inline -void atomic_add_acquire_release(volatile uint64* value, uint64 increment) -{ - InterlockedAdd64((LONG64 *) value, (LONG64) increment); -} - -inline -void atomic_sub_acquire_release(volatile uint64* value, uint64 decrement) -{ - InterlockedAdd64((LONG64 *) value, -((LONG64) decrement)); -} - -inline -uint32 atomic_compare_exchange_weak_acquire_release(volatile uint32* value, uint32* expected, uint32 desired) -{ - return (uint32) InterlockedCompareExchange((long *) value, desired, *expected); -} - -inline -uint64 atomic_compare_exchange_weak_acquire_release(volatile uint64* value, uint64* expected, uint64 desired) -{ - return (uint64) InterlockedCompareExchange64((LONG64 *) value, (LONG64) desired, (LONG64) *expected); -} - -inline -uint32 atomic_fetch_add_acquire_release(volatile uint32* value, uint32 operand) -{ - return (uint32) InterlockedExchangeAdd((long *) value, operand); -} - -inline -uint32 atomic_fetch_sub_acquire_release(volatile uint32* value, uint32 operand) -{ - uint32 ret = (uint32) InterlockedExchangeSubtract((unsigned long *) value, (long) operand); - - return ret; -} - -inline -uint64 atomic_fetch_add_acquire_release(volatile uint64* value, uint64 operand) -{ - return (uint64) InterlockedExchangeAdd64((LONG64 *) value, (LONG64) operand); -} - -inline -uint64 atomic_fetch_sub_acquire_release(volatile uint64* value, uint64 operand) -{ - uint64 ret = (uint64) InterlockedExchangeAdd64((LONG64 *) value, -((LONG64) operand)); - - return ret; -} - -inline -void atomic_and_acquire_release(volatile uint32* value, uint32 mask) -{ - InterlockedAnd((volatile LONG *) value, mask); -} - -inline -void atomic_and_acquire_release(volatile int32* value, int32 mask) -{ - InterlockedAnd((volatile LONG *) value, (LONG)mask); -} - -inline -void atomic_and_acquire_release(volatile uint64* value, uint64 mask) -{ - InterlockedAnd64((volatile LONG64 *) value, mask); -} - -inline -void atomic_and_acquire_release(volatile int64* value, int64 mask) -{ - InterlockedAnd64((volatile LONG64 *) value, mask); -} - -inline -void atomic_or_acquire_release(volatile uint32* value, uint32 mask) -{ - InterlockedOr((volatile LONG *) value, mask); -} - -inline -void atomic_or_acquire_release(volatile int32* value, int32 mask) -{ - InterlockedOr((volatile LONG *) value, (LONG)mask); -} - -inline -void atomic_or_acquire_release(volatile uint64* value, uint64 mask) -{ - InterlockedOr64((volatile LONG64 *) value, mask); -} - -inline -void atomic_or_acquire_release(volatile int64* value, int64 mask) -{ - InterlockedOr64((volatile LONG64 *) value, mask); -} +// We need the following helper types to "cast" between float and long. +// We can't just perform a "normal" cast since that re-interprets the bits. We need to maintain the bits +typedef union { f32 f; LONG l; } _atomic_32; +typedef union { f64 f; LONG64 l; } _atomic_64; + +inline void atomic_set_relaxed(void** target, void* new_pointer) { InterlockedExchangePointerNoFence(target, new_pointer); } +inline void* atomic_get_relaxed(void** target) { return InterlockedCompareExchangePointerNoFence(target, NULL, NULL); } +inline void atomic_set_relaxed(volatile int32* value, int32 new_value) { InterlockedExchangeNoFence((long *) value, new_value); } +inline void atomic_set_relaxed(volatile int64* value, int64 new_value) { InterlockedExchangeNoFence64((LONG64 *) value, (LONG64) new_value); } +inline void atomic_set_relaxed(volatile f32* value, f32 new_value) { _atomic_32 temp = {.f = new_value}; InterlockedExchangeNoFence((long *) value, (long) temp.l); } +inline void atomic_set_relaxed(volatile f64* value, f64 new_value) { _atomic_64 temp = {.f = new_value}; InterlockedExchangeNoFence64((LONG64 *) value, (LONG64) temp.l); } +inline int32 atomic_fetch_set_relaxed(volatile int32* value, int32 new_value) { return (int32) InterlockedExchangeNoFence((long *) value, new_value); } +inline int64 atomic_fetch_set_relaxed(volatile int64* value, int64 new_value) { return (int64) InterlockedExchangeNoFence64((LONG64 *) value, (LONG64) new_value); } +inline int32 atomic_get_relaxed(volatile int32* value) { return (int32) InterlockedCompareExchangeNoFence((long *) value, 0, 0); } +inline int64 atomic_get_relaxed(volatile int64* value) { return (int64) InterlockedCompareExchangeNoFence64((LONG64 *) value, 0, 0); } +inline f32 atomic_get_relaxed(volatile f32* value) { _atomic_32 temp = {.l = InterlockedCompareExchangeNoFence((long *) value, 0, 0)}; return temp.f; } +inline f64 atomic_get_relaxed(volatile f64* value) { _atomic_64 temp = {.l = InterlockedCompareExchangeNoFence64((LONG64 *) value, 0, 0)}; return temp.f; } +inline void atomic_increment_relaxed(volatile int32* value) { InterlockedIncrementNoFence((long *) value); } +inline void atomic_decrement_relaxed(volatile int32* value) { InterlockedDecrementNoFence((long *) value); } +inline void atomic_increment_relaxed(volatile int64* value) { InterlockedIncrementNoFence64((LONG64 *) value); } +inline void atomic_decrement_relaxed(volatile int64* value) { InterlockedDecrementNoFence64((LONG64 *) value); } +inline void atomic_add_relaxed(volatile int32* value, int32 increment) { InterlockedAddNoFence((long *) value, increment); } +inline void atomic_sub_relaxed(volatile int32* value, int32 decrement) { InterlockedAddNoFence((long *) value, -decrement); } +inline void atomic_add_relaxed(volatile int64* value, int64 increment) { InterlockedAddNoFence64((LONG64 *) value, (LONG64) increment); } +inline void atomic_sub_relaxed(volatile int64* value, int64 decrement) { InterlockedAddNoFence64((LONG64 *) value, -((LONG64) decrement)); } +inline f32 atomic_compare_exchange_weak_relaxed(volatile f32* value, f32* expected, f32 desired) { _atomic_32 temp = {.l = InterlockedCompareExchangeNoFence((long *) value, (long) desired, (long) *expected) }; return temp.f; } +inline f64 atomic_compare_exchange_weak_relaxed(volatile f64* value, f64* expected, f64 desired) { _atomic_64 temp = {.l = InterlockedCompareExchangeNoFence64((LONG64 *) value, (LONG64) desired, (LONG64) *expected) }; return temp.f; } +inline int32 atomic_compare_exchange_weak_relaxed(volatile int32* value, int32* expected, int32 desired) { return (int32) InterlockedCompareExchangeNoFence((long *) value, desired, *expected); } +inline int64 atomic_compare_exchange_weak_relaxed(volatile int64* value, int64* expected, int64 desired) { return (int64) InterlockedCompareExchangeNoFence64((LONG64 *) value, (LONG64) desired, (LONG64) *expected); } +inline int32 atomic_fetch_add_relaxed(volatile int32* value, int32 operand) { return (int32) InterlockedExchangeAddNoFence((long *) value, operand); } +inline int32 atomic_fetch_sub_relaxed(volatile int32* value, int32 operand) { return (int32) InterlockedExchangeAddNoFence((unsigned long *) value, -((long) operand)); } +inline int64 atomic_fetch_add_relaxed(volatile int64* value, int64 operand) { return (int64) InterlockedExchangeAddNoFence64((LONG64 *) value, (LONG64) operand); } +inline int64 atomic_fetch_sub_relaxed(volatile int64* value, int64 operand) { return (int64) InterlockedExchangeAdd64((LONG64 *) value, -((LONG64) operand)); } +inline void atomic_set_relaxed(volatile uint32* value, uint32 new_value) { InterlockedExchangeNoFence((long *) value, new_value); } +inline void atomic_set_relaxed(volatile uint64* value, uint64 new_value) { InterlockedExchangeNoFence64((LONG64 *) value, (LONG64) new_value); } +inline uint32 atomic_fetch_set_relaxed(volatile uint32* value, uint32 new_value) { return (uint32) InterlockedExchangeNoFence((long *) value, new_value); } +inline uint64 atomic_fetch_set_relaxed(volatile uint64* value, uint64 new_value) { return (uint64) InterlockedExchangeNoFence64((LONG64 *) value, (LONG64) new_value); } +inline uint32 atomic_get_relaxed(volatile uint32* value) { return (uint32) InterlockedCompareExchangeNoFence((long *) value, 0, 0); } +inline uint64 atomic_get_relaxed(volatile uint64* value) { return (uint64) InterlockedCompareExchangeNoFence64((LONG64 *) value, 0, 0); } +inline void atomic_increment_relaxed(volatile uint32* value) { InterlockedIncrementNoFence((long *) value); } +inline void atomic_decrement_relaxed(volatile uint32* value) { InterlockedDecrementNoFence((long *) value); } +inline void atomic_increment_relaxed(volatile uint64* value) { InterlockedIncrementNoFence64((LONG64 *) value); } +inline void atomic_decrement_relaxed(volatile uint64* value) { InterlockedDecrementNoFence64((LONG64 *) value); } +inline void atomic_add_relaxed(volatile uint32* value, uint32 increment) { InterlockedAddNoFence((long *) value, increment); } +inline void atomic_sub_relaxed(volatile uint32* value, uint32 decrement) { InterlockedAddNoFence((long *) value, -1 * ((int32) decrement)); } +inline void atomic_add_relaxed(volatile uint64* value, uint64 increment) { InterlockedAddNoFence64((LONG64 *) value, (LONG64) increment); } +inline void atomic_sub_relaxed(volatile uint64* value, uint64 decrement) { InterlockedAddNoFence64((LONG64 *) value, -((LONG64) decrement)); } +inline uint32 atomic_compare_exchange_weak_relaxed(volatile uint32* value, uint32* expected, uint32 desired) { return (uint32) InterlockedCompareExchangeNoFence((long *) value, desired, *expected); } +inline uint64 atomic_compare_exchange_weak_relaxed(volatile uint64* value, uint64* expected, uint64 desired) { return (uint64) InterlockedCompareExchangeNoFence64((LONG64 *) value, (LONG64) desired, (LONG64) *expected); } +inline uint32 atomic_fetch_add_relaxed(volatile uint32* value, uint32 operand) { return (uint32) InterlockedExchangeAddNoFence((long *) value, operand); } +inline uint32 atomic_fetch_sub_relaxed(volatile uint32* value, uint32 operand) { return (uint32) InterlockedExchangeAddNoFence((unsigned long *) value, -((long) operand)); } +inline uint64 atomic_fetch_add_relaxed(volatile uint64* value, uint64 operand) { return (uint64) InterlockedExchangeAddNoFence64((LONG64 *) value, (LONG64) operand); } +inline uint64 atomic_fetch_sub_relaxed(volatile uint64* value, uint64 operand) { return (uint64) InterlockedExchangeAdd64((LONG64 *) value, -((LONG64) operand)); } +inline void atomic_and_relaxed(volatile uint32* value, uint32 mask) { InterlockedAndNoFence((volatile LONG *) value, mask); } +inline void atomic_and_relaxed(volatile int32* value, int32 mask) { InterlockedAndNoFence((volatile LONG *) value, (LONG)mask); } +inline void atomic_and_relaxed(volatile uint64* value, uint64 mask) { InterlockedAnd64NoFence((volatile LONG64 *) value, mask); } +inline void atomic_and_relaxed(volatile int64* value, int64 mask) { InterlockedAnd64NoFence((volatile LONG64 *) value, mask); } +inline void atomic_or_relaxed(volatile uint32* value, uint32 mask) { InterlockedOrNoFence((volatile LONG *) value, mask); } +inline void atomic_or_relaxed(volatile int32* value, int32 mask) { InterlockedOrNoFence((volatile LONG *) value, (LONG)mask); } +inline void atomic_or_relaxed(volatile uint64* value, uint64 mask) { InterlockedOr64NoFence((volatile LONG64 *) value, mask); } +inline void atomic_or_relaxed(volatile int64* value, int64 mask) { InterlockedOr64NoFence((volatile LONG64 *) value, mask); } + +inline void atomic_set_acquire(void** target, void* new_pointer) { InterlockedExchangePointerAcquire(target, new_pointer); } +inline void* atomic_get_acquire(void** target) { return InterlockedCompareExchangePointerAcquire(target, NULL, NULL); } +inline void atomic_set_acquire(volatile int32* value, int32 new_value) { InterlockedExchangeAcquire((long *) value, new_value); } +inline void atomic_set_acquire(volatile int64* value, int64 new_value) { InterlockedExchangeAcquire64((LONG64 *) value, (LONG64) new_value); } +inline void atomic_set_acquire(volatile f32* value, f32 new_value) { _atomic_32 temp = {.f = new_value}; InterlockedExchangeAcquire((long *) value, (long) temp.l); } +inline void atomic_set_acquire(volatile f64* value, f64 new_value) { _atomic_64 temp = {.f = new_value}; InterlockedExchangeAcquire64((LONG64 *) value, (LONG64) temp.l); } +inline int32 atomic_fetch_set_acquire(volatile int32* value, int32 new_value) { return (int32) InterlockedExchangeAcquire((long *) value, new_value); } +inline int64 atomic_fetch_set_acquire(volatile int64* value, int64 new_value) { return (int64) InterlockedExchangeAcquire64((LONG64 *) value, (LONG64) new_value); } +inline int32 atomic_get_acquire(volatile int32* value) { return (int32) InterlockedCompareExchangeAcquire((long *) value, 0, 0); } +inline int64 atomic_get_acquire(volatile int64* value) { return (int64) InterlockedCompareExchangeAcquire64((LONG64 *) value, 0, 0); } +inline f32 atomic_get_acquire(volatile f32* value) { _atomic_32 temp = {.l = InterlockedCompareExchangeAcquire((long *) value, 0, 0)}; return temp.f; } +inline f64 atomic_get_acquire(volatile f64* value) { _atomic_64 temp = {.l = InterlockedCompareExchangeAcquire64((LONG64 *) value, 0, 0)}; return temp.f; } +inline void atomic_increment_acquire(volatile int32* value) { InterlockedIncrementAcquire((long *) value); } +inline void atomic_decrement_acquire(volatile int32* value) { InterlockedDecrementAcquire((long *) value); } +inline void atomic_increment_acquire(volatile int64* value) { InterlockedIncrementAcquire64((LONG64 *) value); } +inline void atomic_decrement_acquire(volatile int64* value) { InterlockedDecrementAcquire64((LONG64 *) value); } +inline void atomic_add_acquire(volatile int32* value, int32 increment) { InterlockedAddAcquire((long *) value, increment); } +inline void atomic_sub_acquire(volatile int32* value, int32 decrement) { InterlockedAddAcquire((long *) value, -decrement); } +inline void atomic_add_acquire(volatile int64* value, int64 increment) { InterlockedAddAcquire64((LONG64 *) value, (LONG64) increment); } +inline void atomic_sub_acquire(volatile int64* value, int64 decrement) { InterlockedAddAcquire64((LONG64 *) value, -((LONG64) decrement)); } +inline f32 atomic_compare_exchange_weak_acquire(volatile f32* value, f32* expected, f32 desired) { _atomic_32 temp = {.l = InterlockedCompareExchangeAcquire((long *) value, (long) desired, (long) *expected) }; return temp.f; } +inline f64 atomic_compare_exchange_weak_acquire(volatile f64* value, f64* expected, f64 desired) { _atomic_64 temp = {.l = InterlockedCompareExchangeAcquire64((LONG64 *) value, (LONG64) desired, (LONG64) *expected) }; return temp.f; } +inline int32 atomic_compare_exchange_weak_acquire(volatile int32* value, int32* expected, int32 desired) { return (int32) InterlockedCompareExchangeAcquire((long *) value, desired, *expected); } +inline int64 atomic_compare_exchange_weak_acquire(volatile int64* value, int64* expected, int64 desired) { return (int64) InterlockedCompareExchangeAcquire64((LONG64 *) value, (LONG64) desired, (LONG64) *expected); } +inline int32 atomic_fetch_add_acquire(volatile int32* value, int32 operand) { return (int32) InterlockedExchangeAddAcquire((long *) value, operand); } +inline int32 atomic_fetch_sub_acquire(volatile int32* value, int32 operand) { return (int32) InterlockedExchangeAddAcquire((unsigned long *) value, -((long) operand)); } +inline int64 atomic_fetch_add_acquire(volatile int64* value, int64 operand) { return (int64) InterlockedExchangeAddAcquire64((LONG64 *) value, (LONG64) operand); } +inline int64 atomic_fetch_sub_acquire(volatile int64* value, int64 operand) { return (int64) InterlockedExchangeAdd64((LONG64 *) value, -((LONG64) operand)); } +inline void atomic_set_acquire(volatile uint32* value, uint32 new_value) { InterlockedExchangeAcquire((long *) value, new_value); } +inline void atomic_set_acquire(volatile uint64* value, uint64 new_value) { InterlockedExchangeAcquire64((LONG64 *) value, (LONG64) new_value); } +inline uint32 atomic_fetch_set_acquire(volatile uint32* value, uint32 new_value) { return (uint32) InterlockedExchangeAcquire((long *) value, new_value); } +inline uint64 atomic_fetch_set_acquire(volatile uint64* value, uint64 new_value) { return (uint64) InterlockedExchangeAcquire64((LONG64 *) value, (LONG64) new_value); } +inline uint32 atomic_get_acquire(volatile uint32* value) { return (uint32) InterlockedCompareExchangeAcquire((long *) value, 0, 0); } +inline uint64 atomic_get_acquire(volatile uint64* value) { return (uint64) InterlockedCompareExchangeAcquire64((LONG64 *) value, 0, 0); } +inline void atomic_increment_acquire(volatile uint32* value) { InterlockedIncrementAcquire((long *) value); } +inline void atomic_decrement_acquire(volatile uint32* value) { InterlockedDecrementAcquire((long *) value); } +inline void atomic_increment_acquire(volatile uint64* value) { InterlockedIncrementAcquire64((LONG64 *) value); } +inline void atomic_decrement_acquire(volatile uint64* value) { InterlockedDecrementAcquire64((LONG64 *) value); } +inline void atomic_add_acquire(volatile uint32* value, uint32 increment) { InterlockedAddAcquire((long *) value, increment); } +inline void atomic_sub_acquire(volatile uint32* value, uint32 decrement) { InterlockedAddAcquire((long *) value, -1 * ((int32) decrement)); } +inline void atomic_add_acquire(volatile uint64* value, uint64 increment) { InterlockedAddAcquire64((LONG64 *) value, (LONG64) increment); } +inline void atomic_sub_acquire(volatile uint64* value, uint64 decrement) { InterlockedAddAcquire64((LONG64 *) value, -((LONG64) decrement)); } +inline uint32 atomic_compare_exchange_weak_acquire(volatile uint32* value, uint32* expected, uint32 desired) { return (uint32) InterlockedCompareExchangeAcquire((long *) value, desired, *expected); } +inline uint64 atomic_compare_exchange_weak_acquire(volatile uint64* value, uint64* expected, uint64 desired) { return (uint64) InterlockedCompareExchangeAcquire64((LONG64 *) value, (LONG64) desired, (LONG64) *expected); } +inline uint32 atomic_fetch_add_acquire(volatile uint32* value, uint32 operand) { return (uint32) InterlockedExchangeAddAcquire((long *) value, operand); } +inline uint32 atomic_fetch_sub_acquire(volatile uint32* value, uint32 operand) { return (uint32) InterlockedExchangeAddAcquire((unsigned long *) value, -((long) operand)); } +inline uint64 atomic_fetch_add_acquire(volatile uint64* value, uint64 operand) { return (uint64) InterlockedExchangeAddAcquire64((LONG64 *) value, (LONG64) operand); } +inline uint64 atomic_fetch_sub_acquire(volatile uint64* value, uint64 operand) { return (uint64) InterlockedExchangeAdd64((LONG64 *) value, -((LONG64) operand)); } +inline void atomic_and_acquire(volatile uint32* value, uint32 mask) { InterlockedAndAcquire((volatile LONG *) value, mask); } +inline void atomic_and_acquire(volatile int32* value, int32 mask) { InterlockedAndAcquire((volatile LONG *) value, (LONG)mask); } +inline void atomic_and_acquire(volatile uint64* value, uint64 mask) { InterlockedAnd64Acquire((volatile LONG64 *) value, mask); } +inline void atomic_and_acquire(volatile int64* value, int64 mask) { InterlockedAnd64Acquire((volatile LONG64 *) value, mask); } +inline void atomic_or_acquire(volatile uint32* value, uint32 mask) { InterlockedOrAcquire((volatile LONG *) value, mask); } +inline void atomic_or_acquire(volatile int32* value, int32 mask) { InterlockedOrAcquire((volatile LONG *) value, (LONG)mask); } +inline void atomic_or_acquire(volatile uint64* value, uint64 mask) { InterlockedOr64Acquire((volatile LONG64 *) value, mask); } +inline void atomic_or_acquire(volatile int64* value, int64 mask) { InterlockedOr64Acquire((volatile LONG64 *) value, mask); } + +inline void atomic_set_release(void** target, void* new_pointer) { InterlockedExchangePointer(target, new_pointer); } +inline void* atomic_get_release(void** target) { return InterlockedCompareExchangePointerRelease(target, NULL, NULL); } +inline void atomic_set_release(volatile int32* value, int32 new_value) { InterlockedExchange((long *) value, new_value); } +inline void atomic_set_release(volatile int64* value, int64 new_value) { InterlockedExchange64((LONG64 *) value, (LONG64) new_value); } +inline void atomic_set_release(volatile f32* value, f32 new_value) { _atomic_32 temp = {.f = new_value}; InterlockedExchange((long *) value, (long) temp.l); } +inline void atomic_set_release(volatile f64* value, f64 new_value) { _atomic_64 temp = {.f = new_value}; InterlockedExchange64((LONG64 *) value, (LONG64) temp.l); } +inline int32 atomic_fetch_set_release(volatile int32* value, int32 new_value) { return (int32) InterlockedExchange((long *) value, new_value); } +inline int64 atomic_fetch_set_release(volatile int64* value, int64 new_value) { return (int64) InterlockedExchange64((LONG64 *) value, (LONG64) new_value); } +inline int32 atomic_get_release(volatile int32* value) { return (int32) InterlockedCompareExchangeRelease((long *) value, 0, 0); } +inline int64 atomic_get_release(volatile int64* value) { return (int64) InterlockedCompareExchangeRelease64((LONG64 *) value, 0, 0); } +inline f32 atomic_get_release(volatile f32* value) { _atomic_32 temp = {.l = InterlockedCompareExchangeRelease((long *) value, 0, 0)}; return temp.f; } +inline f64 atomic_get_release(volatile f64* value) { _atomic_64 temp = {.l = InterlockedCompareExchangeRelease64((LONG64 *) value, 0, 0)}; return temp.f; } +inline void atomic_increment_release(volatile int32* value) { InterlockedIncrementRelease((long *) value); } +inline void atomic_decrement_release(volatile int32* value) { InterlockedDecrementRelease((long *) value); } +inline void atomic_increment_release(volatile int64* value) { InterlockedIncrementRelease64((LONG64 *) value); } +inline void atomic_decrement_release(volatile int64* value) { InterlockedDecrementRelease64((LONG64 *) value); } +inline void atomic_add_release(volatile int32* value, int32 increment) { InterlockedAddRelease((long *) value, increment); } +inline void atomic_sub_release(volatile int32* value, int32 decrement) { InterlockedAddRelease((long *) value, -decrement); } +inline void atomic_add_release(volatile int64* value, int64 increment) { InterlockedAddRelease64((LONG64 *) value, (LONG64) increment); } +inline void atomic_sub_release(volatile int64* value, int64 decrement) { InterlockedAddRelease64((LONG64 *) value, -((LONG64) decrement)); } +inline f32 atomic_compare_exchange_weak_release(volatile f32* value, f32* expected, f32 desired) { _atomic_32 temp = {.l = InterlockedCompareExchangeRelease((long *) value, (long) desired, (long) *expected) }; return temp.f; } +inline f64 atomic_compare_exchange_weak_release(volatile f64* value, f64* expected, f64 desired) { _atomic_64 temp = {.l = InterlockedCompareExchangeRelease64((LONG64 *) value, (LONG64) desired, (LONG64) *expected) }; return temp.f; } +inline int32 atomic_compare_exchange_weak_release(volatile int32* value, int32* expected, int32 desired) { return (int32) InterlockedCompareExchangeRelease((long *) value, desired, *expected); } +inline int64 atomic_compare_exchange_weak_release(volatile int64* value, int64* expected, int64 desired) { return (int64) InterlockedCompareExchangeRelease64((LONG64 *) value, (LONG64) desired, (LONG64) *expected); } +inline int32 atomic_fetch_add_release(volatile int32* value, int32 operand) { return (int32) InterlockedExchangeAddRelease((long *) value, operand); } +inline int32 atomic_fetch_sub_release(volatile int32* value, int32 operand) { return (int32) InterlockedExchangeAddRelease((unsigned long *) value, -((long) operand)); } +inline int64 atomic_fetch_add_release(volatile int64* value, int64 operand) { return (int64) InterlockedExchangeAddRelease64((LONG64 *) value, (LONG64) operand); } +inline int64 atomic_fetch_sub_release(volatile int64* value, int64 operand) { return (int64) InterlockedExchangeAdd64((LONG64 *) value, -((LONG64) operand)); } +inline void atomic_set_release(volatile uint32* value, uint32 new_value) { InterlockedExchange((long *) value, new_value); } +inline void atomic_set_release(volatile uint64* value, uint64 new_value) { InterlockedExchange64((LONG64 *) value, (LONG64) new_value); } +inline uint32 atomic_fetch_set_release(volatile uint32* value, uint32 new_value) { return (uint32) InterlockedExchange((long *) value, new_value); } +inline uint64 atomic_fetch_set_release(volatile uint64* value, uint64 new_value) { return (uint64) InterlockedExchange64((LONG64 *) value, (LONG64) new_value); } +inline uint32 atomic_get_release(volatile uint32* value) { return (uint32) InterlockedCompareExchangeRelease((long *) value, 0, 0); } +inline uint64 atomic_get_release(volatile uint64* value) { return (uint64) InterlockedCompareExchangeRelease64((LONG64 *) value, 0, 0); } +inline void atomic_increment_release(volatile uint32* value) { InterlockedIncrementRelease((long *) value); } +inline void atomic_decrement_release(volatile uint32* value) { InterlockedDecrementRelease((long *) value); } +inline void atomic_increment_release(volatile uint64* value) { InterlockedIncrementRelease64((LONG64 *) value); } +inline void atomic_decrement_release(volatile uint64* value) { InterlockedDecrementRelease64((LONG64 *) value); } +inline void atomic_add_release(volatile uint32* value, uint32 increment) { InterlockedAddRelease((long *) value, increment); } +inline void atomic_sub_release(volatile uint32* value, uint32 decrement) { InterlockedAddRelease((long *) value, -1 * ((int32) decrement)); } +inline void atomic_add_release(volatile uint64* value, uint64 increment) { InterlockedAddRelease64((LONG64 *) value, (LONG64) increment); } +inline void atomic_sub_release(volatile uint64* value, uint64 decrement) { InterlockedAddRelease64((LONG64 *) value, -((LONG64) decrement)); } +inline uint32 atomic_compare_exchange_weak_release(volatile uint32* value, uint32* expected, uint32 desired) { return (uint32) InterlockedCompareExchangeRelease((long *) value, desired, *expected); } +inline uint64 atomic_compare_exchange_weak_release(volatile uint64* value, uint64* expected, uint64 desired) { return (uint64) InterlockedCompareExchangeRelease64((LONG64 *) value, (LONG64) desired, (LONG64) *expected); } +inline uint32 atomic_fetch_add_release(volatile uint32* value, uint32 operand) { return (uint32) InterlockedExchangeAddRelease((long *) value, operand); } +inline uint32 atomic_fetch_sub_release(volatile uint32* value, uint32 operand) { return (uint32) InterlockedExchangeAddRelease((unsigned long *) value, -((long) operand)); } +inline uint64 atomic_fetch_add_release(volatile uint64* value, uint64 operand) { return (uint64) InterlockedExchangeAddRelease64((LONG64 *) value, (LONG64) operand); } +inline uint64 atomic_fetch_sub_release(volatile uint64* value, uint64 operand) { return (uint64) InterlockedExchangeAdd64((LONG64 *) value, -((LONG64) operand)); } +inline void atomic_and_release(volatile uint32* value, uint32 mask) { InterlockedAndRelease((volatile LONG *) value, mask); } +inline void atomic_and_release(volatile int32* value, int32 mask) { InterlockedAndRelease((volatile LONG *) value, (LONG)mask); } +inline void atomic_and_release(volatile uint64* value, uint64 mask) { InterlockedAnd64Release((volatile LONG64 *) value, mask); } +inline void atomic_and_release(volatile int64* value, int64 mask) { InterlockedAnd64Release((volatile LONG64 *) value, mask); } +inline void atomic_or_release(volatile uint32* value, uint32 mask) { InterlockedOrRelease((volatile LONG *) value, mask); } +inline void atomic_or_release(volatile int32* value, int32 mask) { InterlockedOrRelease((volatile LONG *) value, (LONG)mask); } +inline void atomic_or_release(volatile uint64* value, uint64 mask) { InterlockedOr64Release((volatile LONG64 *) value, mask); } +inline void atomic_or_release(volatile int64* value, int64 mask) { InterlockedOr64Release((volatile LONG64 *) value, mask); } + +inline void atomic_set_acquire_release(void** target, void* new_pointer) { InterlockedExchangePointer(target, new_pointer); } +inline void* atomic_get_acquire_release(void** target) { return InterlockedCompareExchangePointer(target, NULL, NULL); } +inline void atomic_set_acquire_release(volatile int32* value, int32 new_value) { InterlockedExchange((long *) value, new_value); } +inline void atomic_set_acquire_release(volatile int64* value, int64 new_value) { InterlockedExchange64((LONG64 *) value, (LONG64) new_value); } +inline void atomic_set_acquire_release(volatile f32* value, f32 new_value) { _atomic_32 temp = {.f = new_value}; InterlockedExchange((long *) value, (long) temp.l); } +inline void atomic_set_acquire_release(volatile f64* value, f64 new_value) { _atomic_64 temp = {.f = new_value}; InterlockedExchange64((LONG64 *) value, (LONG64) temp.l); } +inline int32 atomic_fetch_set_acquire_release(volatile int32* value, int32 new_value) { return (int32) InterlockedExchange((long *) value, new_value); } +inline int64 atomic_fetch_set_acquire_release(volatile int64* value, int64 new_value) { return (int64) InterlockedExchange64((LONG64 *) value, (LONG64) new_value); } +inline int32 atomic_get_acquire_release(volatile int32* value) { return (int32) InterlockedCompareExchange((long *) value, 0, 0); } +inline int64 atomic_get_acquire_release(volatile int64* value) { return (int64) InterlockedCompareExchange64((LONG64 *) value, 0, 0); } +inline f32 atomic_get_acquire_release(volatile f32* value) { _atomic_32 temp = {.l = InterlockedCompareExchange((long *) value, 0, 0)}; return temp.f; } +inline f64 atomic_get_acquire_release(volatile f64* value) { _atomic_64 temp = {.l = InterlockedCompareExchange64((LONG64 *) value, 0, 0)}; return temp.f; } +inline void atomic_increment_acquire_release(volatile int32* value) { InterlockedIncrement((long *) value); } +inline void atomic_decrement_acquire_release(volatile int32* value) { InterlockedDecrement((long *) value); } +inline void atomic_increment_acquire_release(volatile int64* value) { InterlockedIncrement64((LONG64 *) value); } +inline void atomic_decrement_acquire_release(volatile int64* value) { InterlockedDecrement64((LONG64 *) value); } +inline void atomic_add_acquire_release(volatile int32* value, int32 increment) { InterlockedAdd((long *) value, increment); } +inline void atomic_sub_acquire_release(volatile int32* value, int32 decrement) { InterlockedAdd((long *) value, -decrement); } +inline void atomic_add_acquire_release(volatile int64* value, int64 increment) { InterlockedAdd64((LONG64 *) value, (LONG64) increment); } +inline void atomic_sub_acquire_release(volatile int64* value, int64 decrement) { InterlockedAdd64((LONG64 *) value, -((LONG64) decrement)); } +inline f32 atomic_compare_exchange_weak_acquire_release(volatile f32* value, f32* expected, f32 desired) { _atomic_32 temp = {.l = InterlockedCompareExchange((long *) value, (long) desired, (long) *expected) }; return temp.f; } +inline f64 atomic_compare_exchange_weak_acquire_release(volatile f64* value, f64* expected, f64 desired) { _atomic_64 temp = {.l = InterlockedCompareExchange64((LONG64 *) value, (LONG64) desired, (LONG64) *expected) }; return temp.f; } +inline int32 atomic_compare_exchange_weak_acquire_release(volatile int32* value, int32* expected, int32 desired) { return (int32) InterlockedCompareExchange((long *) value, desired, *expected); } +inline int64 atomic_compare_exchange_weak_acquire_release(volatile int64* value, int64* expected, int64 desired) { return (int64) InterlockedCompareExchange64((LONG64 *) value, (LONG64) desired, (LONG64) *expected); } +inline int32 atomic_fetch_add_acquire_release(volatile int32* value, int32 operand) { return (int32) InterlockedExchangeAdd((long *) value, operand); } +inline int32 atomic_fetch_sub_acquire_release(volatile int32* value, int32 operand) { return (int32) InterlockedExchangeAdd((unsigned long *) value, -((long) operand)); } +inline int64 atomic_fetch_add_acquire_release(volatile int64* value, int64 operand) { return (int64) InterlockedExchangeAdd64((LONG64 *) value, (LONG64) operand); } +inline int64 atomic_fetch_sub_acquire_release(volatile int64* value, int64 operand) { return (int64) InterlockedExchangeAdd64((LONG64 *) value, -((LONG64) operand)); } +inline void atomic_set_acquire_release(volatile uint32* value, uint32 new_value) { InterlockedExchange((long *) value, new_value); } +inline void atomic_set_acquire_release(volatile uint64* value, uint64 new_value) { InterlockedExchange64((LONG64 *) value, (LONG64) new_value); } +inline uint32 atomic_fetch_set_acquire_release(volatile uint32* value, uint32 new_value) { return (uint32) InterlockedExchange((long *) value, new_value); } +inline uint64 atomic_fetch_set_acquire_release(volatile uint64* value, uint64 new_value) { return (uint64) InterlockedExchange64((LONG64 *) value, (LONG64) new_value); } +inline uint32 atomic_get_acquire_release(volatile uint32* value) { return (uint32) InterlockedCompareExchange((long *) value, 0, 0); } +inline uint64 atomic_get_acquire_release(volatile uint64* value) { return (uint64) InterlockedCompareExchange64((LONG64 *) value, 0, 0); } +inline void atomic_increment_acquire_release(volatile uint32* value) { InterlockedIncrement((long *) value); } +inline void atomic_decrement_acquire_release(volatile uint32* value) { InterlockedDecrement((long *) value); } +inline void atomic_increment_acquire_release(volatile uint64* value) { InterlockedIncrement64((LONG64 *) value); } +inline void atomic_decrement_acquire_release(volatile uint64* value) { InterlockedDecrement64((LONG64 *) value); } +inline void atomic_add_acquire_release(volatile uint32* value, uint32 increment) { InterlockedAdd((long *) value, increment); } +inline void atomic_sub_acquire_release(volatile uint32* value, uint32 decrement) { InterlockedAdd((long *) value, -1 * ((int32) decrement)); } +inline void atomic_add_acquire_release(volatile uint64* value, uint64 increment) { InterlockedAdd64((LONG64 *) value, (LONG64) increment); } +inline void atomic_sub_acquire_release(volatile uint64* value, uint64 decrement) { InterlockedAdd64((LONG64 *) value, -((LONG64) decrement)); } +inline uint32 atomic_compare_exchange_weak_acquire_release(volatile uint32* value, uint32* expected, uint32 desired) { return (uint32) InterlockedCompareExchange((long *) value, desired, *expected); } +inline uint64 atomic_compare_exchange_weak_acquire_release(volatile uint64* value, uint64* expected, uint64 desired) { return (uint64) InterlockedCompareExchange64((LONG64 *) value, (LONG64) desired, (LONG64) *expected); } +inline uint32 atomic_fetch_add_acquire_release(volatile uint32* value, uint32 operand) { return (uint32) InterlockedExchangeAdd((long *) value, operand); } +inline uint32 atomic_fetch_sub_acquire_release(volatile uint32* value, uint32 operand) { return (uint32) InterlockedExchangeAdd((unsigned long *) value, -((long) operand)); } +inline uint64 atomic_fetch_add_acquire_release(volatile uint64* value, uint64 operand) { return (uint64) InterlockedExchangeAdd64((LONG64 *) value, (LONG64) operand); } +inline uint64 atomic_fetch_sub_acquire_release(volatile uint64* value, uint64 operand) { return (uint64) InterlockedExchangeAdd64((LONG64 *) value, -((LONG64) operand)); } +inline void atomic_and_acquire_release(volatile uint32* value, uint32 mask) { InterlockedAnd((volatile LONG *) value, mask); } +inline void atomic_and_acquire_release(volatile int32* value, int32 mask) { InterlockedAnd((volatile LONG *) value, (LONG)mask); } +inline void atomic_and_acquire_release(volatile uint64* value, uint64 mask) { InterlockedAnd64((volatile LONG64 *) value, mask); } +inline void atomic_and_acquire_release(volatile int64* value, int64 mask) { InterlockedAnd64((volatile LONG64 *) value, mask); } +inline void atomic_or_acquire_release(volatile uint32* value, uint32 mask) { InterlockedOr((volatile LONG *) value, mask); } +inline void atomic_or_acquire_release(volatile int32* value, int32 mask) { InterlockedOr((volatile LONG *) value, (LONG)mask); } +inline void atomic_or_acquire_release(volatile uint64* value, uint64 mask) { InterlockedOr64((volatile LONG64 *) value, mask); } +inline void atomic_or_acquire_release(volatile int64* value, int64 mask) { InterlockedOr64((volatile LONG64 *) value, mask); } // Check out the intrinsic functions fence_memory and fence_write // These are much faster and could accomplish what you are doing -inline -void atomic_fence_acquire() -{ - MemoryBarrier(); -} +#define atomic_fence_acquire() MemoryBarrier(); // Check out the intrinsic functions fence_memory and fence_write // These are much faster and could accomplish what you are doing -inline -void atomic_fence_release() -{ - MemoryBarrier(); -} +#define atomic_fence_release() MemoryBarrier(); #endif \ No newline at end of file diff --git a/stdlib/HashMap.h b/stdlib/HashMap.h index 2ee5305..e61a5b5 100644 --- a/stdlib/HashMap.h +++ b/stdlib/HashMap.h @@ -15,59 +15,54 @@ #include "../memory/BufferMemory.h" #include "../memory/ChunkMemory.h" #include "../utils/StringUtils.h" +#include "../stdlib/Simd.h" -// WARNING Length of 28 used to ensure perfect padding with element_id and key -#define HASH_MAP_MAX_KEY_LENGTH 28 +// If a hash key is longer than the max key length, we use the last N characters of that key +// The key length is currently chosen to result in 32 byte size for the common case: HashEntryInt32 +#define HASH_MAP_MAX_KEY_LENGTH 26 ///////////////////////////// // string key ///////////////////////////// struct HashEntryInt32 { - uint32 element_id; char key[HASH_MAP_MAX_KEY_LENGTH]; - HashEntryInt32* next; + uint16 next; int32 value; }; struct HashEntryInt64 { - uint32 element_id; char key[HASH_MAP_MAX_KEY_LENGTH]; - HashEntryInt64* next; + uint16 next; int64 value; }; struct HashEntryUIntPtr { - uint32 element_id; char key[HASH_MAP_MAX_KEY_LENGTH]; - HashEntryUIntPtr* next; + uint16 next; uintptr_t value; }; struct HashEntryVoidP { - uint32 element_id; char key[HASH_MAP_MAX_KEY_LENGTH]; - HashEntryVoidP* next; + uint16 next; void* value; }; struct HashEntryFloat { - uint32 element_id; char key[HASH_MAP_MAX_KEY_LENGTH]; - HashEntryFloat* next; + uint16 next; f32 value; }; struct HashEntryStr { - uint32 element_id; char key[HASH_MAP_MAX_KEY_LENGTH]; - HashEntryStr* next; + uint16 next; char value[HASH_MAP_MAX_KEY_LENGTH]; }; struct HashEntry { - uint32 element_id; char key[HASH_MAP_MAX_KEY_LENGTH]; - HashEntry* next; + uint16 next; byte* value; }; @@ -75,56 +70,53 @@ struct HashEntry { // int key ///////////////////////////// struct HashEntryInt32KeyInt32 { - uint32 element_id; int32 key; - HashEntryInt32KeyInt32* next; + uint16 next; int32 value; }; struct HashEntryInt64KeyInt32 { - uint32 element_id; int32 key; - HashEntryInt64KeyInt32* next; + uint16 next; int64 value; }; struct HashEntryUIntPtrKeyInt32 { - uint32 element_id; int32 key; - HashEntryUIntPtrKeyInt32* next; + uint16 next; uintptr_t value; }; struct HashEntryVoidPKeyInt32 { - uint32 element_id; int32 key; - HashEntryVoidPKeyInt32* next; + uint16 next; void* value; }; struct HashEntryFloatKeyInt32 { - uint32 element_id; int32 key; - HashEntryFloatKeyInt32* next; + uint16 next; f32 value; }; struct HashEntryStrKeyInt32 { - uint32 element_id; int32 key; - HashEntryStrKeyInt32* next; + uint16 next; char value[HASH_MAP_MAX_KEY_LENGTH]; }; struct HashEntryKeyInt32 { - uint32 element_id; int32 key; - HashEntryKeyInt32* next; + uint16 next; byte* value; }; +// HashMaps are limited to 4GB in total size struct HashMap { - void** table; + // Values are 1-indexed/offset since 0 means not used/found + uint16* table; + + // @todo We might want to align the ChunkMemory memory to 8byte, currently it's either 4 or 8 byte depending on the length ChunkMemory buf; }; @@ -133,13 +125,12 @@ void hashmap_create(HashMap* hm, int32 count, int32 element_size, RingMemory* ri { byte* data = ring_get_memory( ring, - count * (sizeof(void *) + element_size) - + CEIL_DIV(count, 64) * sizeof(hm->buf.free), - 0, true + count * (sizeof(uint16) + element_size) + + CEIL_DIV(count, 64) * sizeof(hm->buf.free) ); - hm->table = (void **) data; - chunk_init(&hm->buf, data + sizeof(void *) * count, count, element_size, 8); + hm->table = (uint16 *) data; + chunk_init(&hm->buf, data + sizeof(uint16) * count, count, element_size, 8); LOG_LEVEL_2("Created HashMap for %n elements with %n B per element = %n B", {{LOG_DATA_INT32, &count}, {LOG_DATA_INT32, &element_size}, {LOG_DATA_UINT64, &hm->buf.size}}); } @@ -149,12 +140,12 @@ void hashmap_create(HashMap* hm, int32 count, int32 element_size, BufferMemory* { byte* data = buffer_get_memory( buf, - count * (sizeof(void *) + element_size) + count * (sizeof(uint16) + element_size) + CEIL_DIV(count, 64) * sizeof(hm->buf.free) ); - hm->table = (void **) data; - chunk_init(&hm->buf, data + sizeof(void *) * count, count, element_size, 8); + hm->table = (uint16 *) data; + chunk_init(&hm->buf, data + sizeof(uint16) * count, count, element_size, 8); LOG_LEVEL_2("Created HashMap for %n elements with %n B per element = %n B", {{LOG_DATA_INT32, &count}, {LOG_DATA_INT32, &element_size}, {LOG_DATA_UINT64, &hm->buf.size}}); } @@ -162,12 +153,18 @@ void hashmap_create(HashMap* hm, int32 count, int32 element_size, BufferMemory* // WARNING: element_size = element size + remaining HashEntry data size void hashmap_create(HashMap* hm, int32 count, int32 element_size, byte* buf) { - hm->table = (void **) buf; - chunk_init(&hm->buf, buf + sizeof(void *) * count, count, element_size, 8); + hm->table = (uint16 *) buf; + chunk_init(&hm->buf, buf + sizeof(uint16) * count, count, element_size, 8); LOG_LEVEL_2("Created HashMap for %n elements with %n B per element = %n B", {{LOG_DATA_INT32, &count}, {LOG_DATA_INT32, &element_size}, {LOG_DATA_UINT64, &hm->buf.size}}); } +void hashmap_update_data_pointer(HashMap* hm, byte* data) +{ + hm->table = (uint16 *) data; + hm->buf.memory = data + sizeof(uint16) * hm->buf.count; +} + // Calculates how large a hashmap will be inline int64 hashmap_size(int count, int32 element_size) @@ -180,7 +177,7 @@ int64 hashmap_size(int count, int32 element_size) inline int64 hashmap_size(const HashMap* hm) { - return hm->buf.count * sizeof(hm->table) + hm->buf.size; + return hm->buf.count * sizeof(uint16) + hm->buf.size; } ///////////////////////////// @@ -191,7 +188,6 @@ void hashmap_insert(HashMap* hm, const char* key, int32 value) { int32 element = chunk_reserve(&hm->buf, 1); HashEntryInt32* entry = (HashEntryInt32 *) chunk_get_element(&hm->buf, element, true); - entry->element_id = element; // Ensure key length str_move_to_pos(&key, -HASH_MAP_MAX_KEY_LENGTH); @@ -199,17 +195,17 @@ void hashmap_insert(HashMap* hm, const char* key, int32 value) { entry->key[HASH_MAP_MAX_KEY_LENGTH - 1] = '\0'; entry->value = value; - entry->next = NULL; + entry->next = 0; if (hm->table[index]) { - HashEntryInt32* tmp = (HashEntryInt32 *) hm->table[index]; + HashEntryInt32* tmp = (HashEntryInt32 *) chunk_get_element(&hm->buf, hm->table[index] - 1, false); while(tmp->next) { - tmp = tmp->next; + tmp = (HashEntryInt32 *) chunk_get_element(&hm->buf, tmp->next - 1, false); } - tmp->next = entry; + tmp->next = (uint16) (element + 1); } else { - hm->table[index] = entry; + hm->table[index] = (uint16) (element + 1); } } @@ -218,7 +214,6 @@ void hashmap_insert(HashMap* hm, const char* key, int64 value) { int32 element = chunk_reserve(&hm->buf, 1); HashEntryInt64* entry = (HashEntryInt64 *) chunk_get_element(&hm->buf, element, true); - entry->element_id = element; // Ensure key length str_move_to_pos(&key, -HASH_MAP_MAX_KEY_LENGTH); @@ -226,17 +221,17 @@ void hashmap_insert(HashMap* hm, const char* key, int64 value) { entry->key[HASH_MAP_MAX_KEY_LENGTH - 1] = '\0'; entry->value = value; - entry->next = NULL; + entry->next = 0; if (hm->table[index]) { - HashEntryInt64* tmp = (HashEntryInt64 *) hm->table[index]; + HashEntryInt64* tmp = (HashEntryInt64 *) chunk_get_element(&hm->buf, hm->table[index] - 1, false); while(tmp->next) { - tmp = tmp->next; + tmp = (HashEntryInt64 *) chunk_get_element(&hm->buf, tmp->next - 1, false); } - tmp->next = entry; + tmp->next = (uint16) (element + 1); } else { - hm->table[index] = entry; + hm->table[index] = (uint16) (element + 1); } } @@ -245,7 +240,6 @@ void hashmap_insert(HashMap* hm, const char* key, uintptr_t value) { int32 element = chunk_reserve(&hm->buf, 1); HashEntryUIntPtr* entry = (HashEntryUIntPtr *) chunk_get_element(&hm->buf, element, true); - entry->element_id = element; // Ensure key length str_move_to_pos(&key, -HASH_MAP_MAX_KEY_LENGTH); @@ -253,17 +247,17 @@ void hashmap_insert(HashMap* hm, const char* key, uintptr_t value) { entry->key[HASH_MAP_MAX_KEY_LENGTH - 1] = '\0'; entry->value = value; - entry->next = NULL; + entry->next = 0; if (hm->table[index]) { - HashEntryUIntPtr* tmp = (HashEntryUIntPtr *) hm->table[index]; + HashEntryUIntPtr* tmp = (HashEntryUIntPtr *) chunk_get_element(&hm->buf, hm->table[index] - 1, false); while(tmp->next) { - tmp = tmp->next; + tmp = (HashEntryUIntPtr *) chunk_get_element(&hm->buf, tmp->next - 1, false); } - tmp->next = entry; + tmp->next = (uint16) (element + 1); } else { - hm->table[index] = entry; + hm->table[index] = (uint16) (element + 1); } } @@ -272,7 +266,6 @@ void hashmap_insert(HashMap* hm, const char* key, void* value) { int32 element = chunk_reserve(&hm->buf, 1); HashEntryVoidP* entry = (HashEntryVoidP *) chunk_get_element(&hm->buf, element, true); - entry->element_id = element; // Ensure key length str_move_to_pos(&key, -HASH_MAP_MAX_KEY_LENGTH); @@ -280,17 +273,17 @@ void hashmap_insert(HashMap* hm, const char* key, void* value) { entry->key[HASH_MAP_MAX_KEY_LENGTH - 1] = '\0'; entry->value = value; - entry->next = NULL; + entry->next = 0; if (hm->table[index]) { - HashEntryVoidP* tmp = (HashEntryVoidP *) hm->table[index]; + HashEntryVoidP* tmp = (HashEntryVoidP *) chunk_get_element(&hm->buf, hm->table[index] - 1, false); while(tmp->next) { - tmp = tmp->next; + tmp = (HashEntryVoidP *) chunk_get_element(&hm->buf, tmp->next - 1, false); } - tmp->next = entry; + tmp->next = (uint16) (element + 1); } else { - hm->table[index] = entry; + hm->table[index] = (uint16) (element + 1); } } @@ -299,7 +292,6 @@ void hashmap_insert(HashMap* hm, const char* key, f32 value) { int32 element = chunk_reserve(&hm->buf, 1); HashEntryFloat* entry = (HashEntryFloat *) chunk_get_element(&hm->buf, element, true); - entry->element_id = element; // Ensure key length str_move_to_pos(&key, -HASH_MAP_MAX_KEY_LENGTH); @@ -307,17 +299,17 @@ void hashmap_insert(HashMap* hm, const char* key, f32 value) { entry->key[HASH_MAP_MAX_KEY_LENGTH - 1] = '\0'; entry->value = value; - entry->next = NULL; + entry->next = 0; if (hm->table[index]) { - HashEntryFloat* tmp = (HashEntryFloat *) hm->table[index]; + HashEntryFloat* tmp = (HashEntryFloat *) chunk_get_element(&hm->buf, hm->table[index] - 1, false); while(tmp->next) { - tmp = tmp->next; + tmp = (HashEntryFloat *) chunk_get_element(&hm->buf, tmp->next - 1, false); } - tmp->next = entry; + tmp->next = (uint16) (element + 1); } else { - hm->table[index] = entry; + hm->table[index] = (uint16) (element + 1); } } @@ -326,7 +318,6 @@ void hashmap_insert(HashMap* hm, const char* key, const char* value) { int32 element = chunk_reserve(&hm->buf, 1); HashEntryStr* entry = (HashEntryStr *) chunk_get_element(&hm->buf, element, true); - entry->element_id = element; // Ensure key length str_move_to_pos(&key, -HASH_MAP_MAX_KEY_LENGTH); @@ -336,17 +327,17 @@ void hashmap_insert(HashMap* hm, const char* key, const char* value) { str_copy_short(entry->value, value, HASH_MAP_MAX_KEY_LENGTH); entry->value[HASH_MAP_MAX_KEY_LENGTH - 1] = '\0'; - entry->next = NULL; + entry->next = 0; if (hm->table[index]) { - HashEntryStr* tmp = (HashEntryStr *) hm->table[index]; + HashEntryStr* tmp = (HashEntryStr *) chunk_get_element(&hm->buf, hm->table[index] - 1, false); while(tmp->next) { - tmp = tmp->next; + tmp = (HashEntryStr *) chunk_get_element(&hm->buf, tmp->next - 1, false); } - tmp->next = entry; + tmp->next = (uint16) (element + 1); } else { - hm->table[index] = entry; + hm->table[index] = (uint16) (element + 1); } } @@ -355,7 +346,6 @@ HashEntry* hashmap_insert(HashMap* hm, const char* key, byte* value) { int32 element = chunk_reserve(&hm->buf, 1); HashEntry* entry = (HashEntry *) chunk_get_element(&hm->buf, element, true); - entry->element_id = element; entry->value = (byte *) entry + sizeof(HashEntry); @@ -366,17 +356,17 @@ HashEntry* hashmap_insert(HashMap* hm, const char* key, byte* value) { memcpy(entry->value, value, hm->buf.chunk_size - sizeof(HashEntry)); - entry->next = NULL; + entry->next = 0; if (hm->table[index]) { - HashEntry* tmp = (HashEntry *) hm->table[index]; + HashEntry* tmp = (HashEntry *) chunk_get_element(&hm->buf, hm->table[index] - 1, false); while(tmp->next) { - tmp = tmp->next; + tmp = (HashEntry *) chunk_get_element(&hm->buf, tmp->next - 1, false); } - tmp->next = entry; + tmp->next = (uint16) (element + 1); } else { - hm->table[index] = entry; + hm->table[index] = (uint16) (element + 1); } return entry; @@ -387,7 +377,6 @@ HashEntry* hashmap_reserve(HashMap* hm, const char* key) { int32 element = chunk_reserve(&hm->buf, 1); HashEntry* entry = (HashEntry *) chunk_get_element(&hm->buf, element, true); - entry->element_id = element; entry->value = (byte *) entry + sizeof(HashEntry); @@ -396,17 +385,17 @@ HashEntry* hashmap_reserve(HashMap* hm, const char* key) { str_copy_short(entry->key, key, HASH_MAP_MAX_KEY_LENGTH); entry->key[HASH_MAP_MAX_KEY_LENGTH - 1] = '\0'; - entry->next = NULL; + entry->next = 0; if (hm->table[index]) { - HashEntry* tmp = (HashEntry *) hm->table[index]; + HashEntry* tmp = (HashEntry *) chunk_get_element(&hm->buf, hm->table[index] - 1, false); while(tmp->next) { - tmp = tmp->next; + tmp = (HashEntry *) chunk_get_element(&hm->buf, tmp->next - 1, false); } - tmp->next = entry; + tmp->next = (uint16) (element + 1); } else { - hm->table[index] = entry; + hm->table[index] = (uint16) (element + 1); } return entry; @@ -416,7 +405,7 @@ HashEntry* hashmap_reserve(HashMap* hm, const char* key) { HashEntry* hashmap_get_reserve(HashMap* hm, const char* key) { uint64 index = hash_djb2(key) % hm->buf.count; - HashEntry* entry = (HashEntry *) hm->table[index]; + HashEntry* entry = (HashEntry *) chunk_get_element(&hm->buf, hm->table[index] - 1, false); while (entry != NULL) { if (str_compare(entry->key, key, HASH_MAP_MAX_KEY_LENGTH) == 0) { @@ -424,16 +413,15 @@ HashEntry* hashmap_get_reserve(HashMap* hm, const char* key) return entry; } - if (((HashEntry *) entry->next) == NULL) { + if (!entry->next) { break; } - entry = (HashEntry *) entry->next; + entry = (HashEntry *) chunk_get_element(&hm->buf, entry->next - 1, false); } int32 element = chunk_reserve(&hm->buf, 1); HashEntry* entry_new = (HashEntry *) chunk_get_element(&hm->buf, element, true); - entry_new->element_id = element; entry_new->value = (byte *) entry_new + sizeof(HashEntry); @@ -443,17 +431,29 @@ HashEntry* hashmap_get_reserve(HashMap* hm, const char* key) entry_new->key[HASH_MAP_MAX_KEY_LENGTH - 1] = '\0'; if (entry) { - entry->next = entry_new; + entry->next = (uint16) (element + 1); } else { - hm->table[index] = entry_new; + hm->table[index] = (uint16) (element + 1); } return entry_new; } -HashEntry* hashmap_get_entry(const HashMap* hm, const char* key) { +inline +HashEntry* hashmap_get_entry_by_index(HashMap* hm, uint32 index) +{ + return hm->table[index] ? (HashEntry *) chunk_get_element(&hm->buf, hm->table[index] - 1, false) : NULL; +} + +inline +HashEntry* hashmap_get_entry_by_element(HashMap* hm, uint32 element) +{ + return (HashEntry *) chunk_get_element(&hm->buf, element - 1, false); +} + +HashEntry* hashmap_get_entry(HashMap* hm, const char* key) { uint64 index = hash_djb2(key) % hm->buf.count; - HashEntry* entry = (HashEntry *) hm->table[index]; + HashEntry* entry = (HashEntry *) chunk_get_element(&hm->buf, hm->table[index] - 1, false); while (entry != NULL) { if (str_compare(entry->key, key, HASH_MAP_MAX_KEY_LENGTH) == 0) { @@ -461,17 +461,42 @@ HashEntry* hashmap_get_entry(const HashMap* hm, const char* key) { return entry; } - entry = (HashEntry *) entry->next; + entry = (HashEntry *) chunk_get_element(&hm->buf, entry->next - 1, false); } return NULL; } +uint32 hashmap_get_element(const HashMap* hm, const char* key) { + uint64 index = hash_djb2(key) % hm->buf.count; + const HashEntry* entry = (const HashEntry *) chunk_get_element((ChunkMemory *) &hm->buf, hm->table[index] - 1, false); + + uint32 element_id = hm->table[index]; + + while (entry != NULL) { + if (str_compare(entry->key, key, HASH_MAP_MAX_KEY_LENGTH) == 0) { + DEBUG_MEMORY_READ((uintptr_t) entry, sizeof(HashEntry)); + return element_id; + } + + element_id = entry->next; + entry = (const HashEntry *) chunk_get_element((ChunkMemory *) &hm->buf, entry->next - 1, false); + } + + return 0; +} + +inline +uint32 hashmap_get_element_by_entry(const HashMap* hm, const HashEntry* entry) +{ + return chunk_id_from_memory(&hm->buf, (byte *) entry) + 1; +} + // This function only saves one step (omission of the hash function) // The reason for this is in some cases we can use compile time hashing -HashEntry* hashmap_get_entry(const HashMap* hm, const char* key, uint64 hash) { +HashEntry* hashmap_get_entry(HashMap* hm, const char* key, uint64 hash) { hash %= hm->buf.count; - HashEntry* entry = (HashEntry *) hm->table[hash]; + HashEntry* entry = (HashEntry *) chunk_get_element(&hm->buf, hm->table[hash] - 1, false); while (entry != NULL) { if (str_compare(entry->key, key, HASH_MAP_MAX_KEY_LENGTH) == 0) { @@ -479,7 +504,7 @@ HashEntry* hashmap_get_entry(const HashMap* hm, const char* key, uint64 hash) { return entry; } - entry = (HashEntry *) entry->next; + entry = (HashEntry *) chunk_get_element(&hm->buf, entry->next - 1, false); } return NULL; @@ -490,9 +515,11 @@ HashEntry* hashmap_get_entry(const HashMap* hm, const char* key, uint64 hash) { // Maybe we create a nother hashmap that is doubly linked void hashmap_remove(HashMap* hm, const char* key) { uint64 index = hash_djb2(key) % hm->buf.count; - HashEntry* entry = (HashEntry *) hm->table[index]; + HashEntry* entry = (HashEntry *) chunk_get_element(&hm->buf, hm->table[index] - 1, false); HashEntry* prev = NULL; + uint32 element_id = hm->table[index]; + while (entry != NULL) { if (str_compare(entry->key, key, HASH_MAP_MAX_KEY_LENGTH) == 0) { if (prev == NULL) { @@ -501,13 +528,14 @@ void hashmap_remove(HashMap* hm, const char* key) { prev->next = entry->next; } - chunk_free_elements(&hm->buf, entry->element_id); + chunk_free_elements(&hm->buf, element_id - 1); return; } + element_id = entry->next; prev = entry; - entry = entry->next; + entry = (HashEntry *) chunk_get_element(&hm->buf, entry->next - 1, false); } } @@ -519,21 +547,20 @@ void hashmap_insert(HashMap* hm, int32 key, int32 value) { int32 element = chunk_reserve(&hm->buf, 1); HashEntryInt32KeyInt32* entry = (HashEntryInt32KeyInt32 *) chunk_get_element(&hm->buf, element, true); - entry->element_id = element; entry->key = key; entry->value = value; - entry->next = NULL; + entry->next = 0; if (hm->table[index]) { - HashEntryInt32KeyInt32* tmp = (HashEntryInt32KeyInt32 *) hm->table[index]; + HashEntryInt32KeyInt32* tmp = (HashEntryInt32KeyInt32 *) chunk_get_element(&hm->buf, hm->table[index] - 1, false); while(tmp->next) { - tmp = tmp->next; + tmp = (HashEntryInt32KeyInt32 *) chunk_get_element(&hm->buf, tmp->next - 1, false); } - tmp->next = entry; + tmp->next = (uint16) (element + 1); } else { - hm->table[index] = entry; + hm->table[index] = (uint16) (element + 1); } } @@ -542,21 +569,20 @@ void hashmap_insert(HashMap* hm, int32 key, int64 value) { int32 element = chunk_reserve(&hm->buf, 1); HashEntryInt64KeyInt32* entry = (HashEntryInt64KeyInt32 *) chunk_get_element(&hm->buf, element, true); - entry->element_id = element; entry->key = key; entry->value = value; - entry->next = NULL; + entry->next = 0; if (hm->table[index]) { - HashEntryInt64KeyInt32* tmp = (HashEntryInt64KeyInt32 *) hm->table[index]; + HashEntryInt64KeyInt32* tmp = (HashEntryInt64KeyInt32 *) chunk_get_element(&hm->buf, hm->table[index] - 1, false); while(tmp->next) { - tmp = tmp->next; + tmp = (HashEntryInt64KeyInt32 *) chunk_get_element(&hm->buf, tmp->next - 1, false); } - tmp->next = entry; + tmp->next = (uint16) (element + 1); } else { - hm->table[index] = entry; + hm->table[index] = (uint16) (element + 1); } } @@ -565,21 +591,20 @@ void hashmap_insert(HashMap* hm, int32 key, uintptr_t value) { int32 element = chunk_reserve(&hm->buf, 1); HashEntryUIntPtrKeyInt32* entry = (HashEntryUIntPtrKeyInt32 *) chunk_get_element(&hm->buf, element, true); - entry->element_id = element; entry->key = key; entry->value = value; - entry->next = NULL; + entry->next = 0; if (hm->table[index]) { - HashEntryUIntPtrKeyInt32* tmp = (HashEntryUIntPtrKeyInt32 *) hm->table[index]; + HashEntryUIntPtrKeyInt32* tmp = (HashEntryUIntPtrKeyInt32 *) chunk_get_element(&hm->buf, hm->table[index] - 1, false); while(tmp->next) { - tmp = tmp->next; + tmp = (HashEntryUIntPtrKeyInt32 *) chunk_get_element(&hm->buf, tmp->next - 1, false); } - tmp->next = entry; + tmp->next = (uint16) (element + 1); } else { - hm->table[index] = entry; + hm->table[index] = (uint16) (element + 1); } } @@ -588,21 +613,20 @@ void hashmap_insert(HashMap* hm, int32 key, void* value) { int32 element = chunk_reserve(&hm->buf, 1); HashEntryVoidPKeyInt32* entry = (HashEntryVoidPKeyInt32 *) chunk_get_element(&hm->buf, element, true); - entry->element_id = element; entry->key = key; entry->value = value; - entry->next = NULL; + entry->next = 0; if (hm->table[index]) { - HashEntryVoidPKeyInt32* tmp = (HashEntryVoidPKeyInt32 *) hm->table[index]; + HashEntryVoidPKeyInt32* tmp = (HashEntryVoidPKeyInt32 *) chunk_get_element(&hm->buf, hm->table[index] - 1, false); while(tmp->next) { - tmp = tmp->next; + tmp = (HashEntryVoidPKeyInt32 *) chunk_get_element(&hm->buf, tmp->next - 1, false); } - tmp->next = entry; + tmp->next = (uint16) (element + 1); } else { - hm->table[index] = entry; + hm->table[index] = (uint16) (element + 1); } } @@ -611,21 +635,20 @@ void hashmap_insert(HashMap* hm, int32 key, f32 value) { int32 element = chunk_reserve(&hm->buf, 1); HashEntryFloatKeyInt32* entry = (HashEntryFloatKeyInt32 *) chunk_get_element(&hm->buf, element, true); - entry->element_id = element; entry->key = key; entry->value = value; - entry->next = NULL; + entry->next = 0; if (hm->table[index]) { - HashEntryFloatKeyInt32* tmp = (HashEntryFloatKeyInt32 *) hm->table[index]; + HashEntryFloatKeyInt32* tmp = (HashEntryFloatKeyInt32 *) chunk_get_element(&hm->buf, hm->table[index] - 1, false); while(tmp->next) { - tmp = tmp->next; + tmp = (HashEntryFloatKeyInt32 *) chunk_get_element(&hm->buf, tmp->next - 1, false); } - tmp->next = entry; + tmp->next = (uint16) (element + 1); } else { - hm->table[index] = entry; + hm->table[index] = (uint16) (element + 1); } } @@ -634,24 +657,23 @@ void hashmap_insert(HashMap* hm, int32 key, const char* value) { int32 element = chunk_reserve(&hm->buf, 1); HashEntryStrKeyInt32* entry = (HashEntryStrKeyInt32 *) chunk_get_element(&hm->buf, element, true); - entry->element_id = element; entry->key = key; str_copy_short(entry->value, value, HASH_MAP_MAX_KEY_LENGTH); entry->value[HASH_MAP_MAX_KEY_LENGTH - 1] = '\0'; - entry->next = NULL; + entry->next = 0; if (hm->table[index]) { - HashEntryStrKeyInt32* tmp = (HashEntryStrKeyInt32 *) hm->table[index]; + HashEntryStrKeyInt32* tmp = (HashEntryStrKeyInt32 *) chunk_get_element(&hm->buf, hm->table[index] - 1, false); while(tmp->next) { - tmp = tmp->next; + tmp = (HashEntryStrKeyInt32 *) chunk_get_element(&hm->buf, tmp->next - 1, false); } - tmp->next = entry; + tmp->next = (uint16) (element + 1); } else { - hm->table[index] = entry; + hm->table[index] = (uint16) (element + 1); } } @@ -660,30 +682,29 @@ void hashmap_insert(HashMap* hm, int32 key, byte* value) { int32 element = chunk_reserve(&hm->buf, 1); HashEntryKeyInt32* entry = (HashEntryKeyInt32 *) chunk_get_element(&hm->buf, element, true); - entry->element_id = element; entry->key = key; entry->value = (byte *) entry + sizeof(HashEntryKeyInt32); memcpy(entry->value, value, hm->buf.chunk_size - sizeof(HashEntryKeyInt32)); - entry->next = NULL; + entry->next = 0; if (hm->table[index]) { - HashEntryKeyInt32* tmp = (HashEntryKeyInt32 *) hm->table[index]; + HashEntryKeyInt32* tmp = (HashEntryKeyInt32 *) chunk_get_element(&hm->buf, hm->table[index] - 1, false); while(tmp->next) { - tmp = tmp->next; + tmp = (HashEntryKeyInt32 *) chunk_get_element(&hm->buf, tmp->next - 1, false); } - tmp->next = entry; + tmp->next = (uint16) (element + 1); } else { - hm->table[index] = entry; + hm->table[index] = (uint16) (element + 1); } } -HashEntryKeyInt32* hashmap_get_entry(const HashMap* hm, int32 key) { +HashEntryKeyInt32* hashmap_get_entry(HashMap* hm, int32 key) { uint64 index = key % hm->buf.count; - HashEntryKeyInt32* entry = (HashEntryKeyInt32 *) hm->table[index]; + HashEntryKeyInt32* entry = (HashEntryKeyInt32 *) chunk_get_element(&hm->buf, hm->table[index] - 1, false); while (entry != NULL) { if (entry->key == key) { @@ -699,9 +720,9 @@ HashEntryKeyInt32* hashmap_get_entry(const HashMap* hm, int32 key) { // This function only saves one step (omission of the hash function) // The reason for this is in some cases we can use compile time hashing -HashEntryKeyInt32* hashmap_get_entry(const HashMap* hm, int32 key, uint64 hash) { +HashEntryKeyInt32* hashmap_get_entry(HashMap* hm, int32 key, uint64 hash) { hash %= hm->buf.count; - HashEntryKeyInt32* entry = (HashEntryKeyInt32 *) hm->table[hash]; + HashEntryKeyInt32* entry = (HashEntryKeyInt32 *) chunk_get_element(&hm->buf, hm->table[hash] - 1, false); while (entry != NULL) { if (entry->key == key) { @@ -720,9 +741,11 @@ HashEntryKeyInt32* hashmap_get_entry(const HashMap* hm, int32 key, uint64 hash) // Maybe we create a nother hashmap that is doubly linked void hashmap_remove(HashMap* hm, int32 key) { uint64 index = key % hm->buf.count; - HashEntryKeyInt32* entry = (HashEntryKeyInt32 *) hm->table[index]; + HashEntryKeyInt32* entry = (HashEntryKeyInt32 *) chunk_get_element(&hm->buf, hm->table[index] - 1, false); HashEntryKeyInt32* prev = NULL; + uint32 element_id = hm->table[index]; + while (entry != NULL) { if (entry->key == key) { if (prev == NULL) { @@ -731,13 +754,14 @@ void hashmap_remove(HashMap* hm, int32 key) { prev->next = entry->next; } - chunk_free_elements(&hm->buf, entry->element_id); + chunk_free_elements(&hm->buf, element_id - 1); return; } + element_id = entry->next; prev = entry; - entry = entry->next; + entry = (HashEntryKeyInt32 *) chunk_get_element(&hm->buf, entry->next - 1, false); } } @@ -746,26 +770,27 @@ int32 hashmap_value_size(const HashMap* hm) { return (uint32) ( hm->buf.chunk_size - - sizeof(uint32) // element id - sizeof(char) * HASH_MAP_MAX_KEY_LENGTH // key - - sizeof(uintptr_t) // next pointer + - sizeof(uint16) // next element ); } -// @question Shouldn't we also store the hashmap count, chunk size etc? Currently not done and expected to be correctly initialized. +// @question Shouldn't we also store the chunk size etc? Currently not done and expected to be correctly initialized. inline -int64 hashmap_dump(const HashMap* hm, byte* data) +int64 hashmap_dump(const HashMap* hm, byte* data, int32 steps = 8) { *((uint32 *) data) = SWAP_ENDIAN_LITTLE(hm->buf.count); data += sizeof(hm->buf.count); - // Dump the table content where the elements are relative indices/pointers - for (int32 i = 0; i < hm->buf.count; ++i) { - *((uint64 *) data) = hm->table[i] - ? SWAP_ENDIAN_LITTLE((uintptr_t) hm->table[i] - (uintptr_t) hm->buf.memory) - : 0ULL; - } - data += sizeof(uint64) * hm->buf.count; + // Dump the table content + memcpy(data, hm->table, sizeof(uint16) * hm->buf.count); + SWAP_ENDIAN_LITTLE_SIMD( + (uint16 *) data, + (uint16 *) data, + sizeof(uint16) * hm->buf.count / 2, // everything is 2 bytes -> super easy to swap + steps + ); + data += sizeof(uint16) * hm->buf.count; // @bug what if Int32 key? int32 value_size = hashmap_value_size(hm); @@ -778,21 +803,13 @@ int64 hashmap_dump(const HashMap* hm, byte* data) if (hm->buf.free[free_index] & (1ULL << bit_index)) { HashEntry* entry = (HashEntry *) chunk_get_element((ChunkMemory *) &hm->buf, i); - // element_id - *((uint32 *) data) = SWAP_ENDIAN_LITTLE(entry->element_id); - data += sizeof(entry->element_id); - // key memcpy(data, entry->key, sizeof(entry->key)); data += sizeof(entry->key); - // next pointer - if (entry->next) { - *((uint64 *) data) = SWAP_ENDIAN_LITTLE((uintptr_t) entry->next - (uintptr_t) hm->buf.memory); - } else { - memset(data, 0, sizeof(uint64)); - } - data += sizeof(uint64); + // next "pointer" + *((uint16 *) data) = SWAP_ENDIAN_LITTLE(entry->next); + data += sizeof(entry->next); // We just assume that 4 or 8 bytes = int -> endian handling if (value_size == 4) { @@ -820,25 +837,26 @@ int64 hashmap_dump(const HashMap* hm, byte* data) memcpy(data, hm->buf.free, sizeof(uint64) * CEIL_DIV(hm->buf.count, 64)); return sizeof(hm->buf.count) // hash map count = buffer count - + hm->buf.count * sizeof(uint64) // table content + + hm->buf.count * sizeof(uint16) // table content + hm->buf.size; // hash map content + free array } // WARNING: Requires hashmap_create first inline -int64 hashmap_load(HashMap* hm, const byte* data) +int64 hashmap_load(HashMap* hm, const byte* data, int32 steps = 8) { uint64 count = SWAP_ENDIAN_LITTLE(*((uint32 *) data)); - data += sizeof(uint32); + data += sizeof(uint16); // Load the table content - for (uint32 i = 0; i < count; ++i) { - uint64 offset = SWAP_ENDIAN_LITTLE(*((uint64 *) data)); - data += sizeof(offset); - - // the first element has no offset! - hm->table[i] = offset || i == 0 ? hm->buf.memory + offset : NULL; - } + memcpy(hm->table, data, sizeof(uint16) * count); + SWAP_ENDIAN_LITTLE_SIMD( + (uint32 *) hm->table, + (uint32 *) hm->table, + sizeof(uint16) * count / 4, // everything is 4 bytes -> super easy to swap + steps + ); + data += sizeof(uint16) * count; // This loop here is why it is important to already have an initialized hashmap // @question Do we maybe want to change this and not require an initalized hashmap? @@ -856,16 +874,11 @@ int64 hashmap_load(HashMap* hm, const byte* data) chunk_iterate_start(&hm->buf, chunk_id) HashEntry* entry = (HashEntry *) chunk_get_element((ChunkMemory *) &hm->buf, chunk_id); - // element id - entry->element_id = SWAP_ENDIAN_LITTLE(entry->element_id); - // key is already loaded with the memcpy // @question Do we even want to use memcpy? We are re-checking all the values here anyways - // next pointer - if (entry->next) { - entry->next = (HashEntry *) (hm->buf.memory + SWAP_ENDIAN_LITTLE((uint64) entry->next)); - } + // next "pointer" + entry->next = SWAP_ENDIAN_LITTLE(entry->next); if (value_size == 4) { ((HashEntryInt32 *) entry)->value = SWAP_ENDIAN_LITTLE(((HashEntryInt32 *) entry)->value); @@ -878,7 +891,7 @@ int64 hashmap_load(HashMap* hm, const byte* data) // How many bytes was read from data return sizeof(hm->buf.count) // hash map count = buffer count - + hm->buf.count * sizeof(uint64) // table content + + hm->buf.count * sizeof(uint16) // table content + hm->buf.size; } diff --git a/stdlib/Intrinsics.h b/stdlib/Intrinsics.h deleted file mode 100644 index 55cf99b..0000000 --- a/stdlib/Intrinsics.h +++ /dev/null @@ -1,89 +0,0 @@ -/** - * Jingga - * - * @copyright Jingga - * @license OMS License 2.0 - * @version 1.0.0 - * @link https://jingga.app - */ -#ifndef TOS_STDLIB_INTRINSICS_H -#define TOS_STDLIB_INTRINSICS_H - -#include -#include - -#if __linux__ - #include - #include -#endif - -#include "Types.h" - -inline f32 oms_sqrt(f32 a) { return _mm_cvtss_f32(_mm_sqrt_ss(_mm_set_ss(a))); } -inline f64 oms_sqrt(f64 a) -{ - __m128d temp =_mm_set_sd(a); - - return _mm_cvtsd_f64(_mm_sqrt_sd(temp, temp)); -} - -inline f32 oms_rsqrt(f32 a) { return _mm_cvtss_f32(_mm_rsqrt_ss(_mm_set_ss(a))); } -inline f64 oms_rsqrt(f64 a) -{ - __m128d temp =_mm_set_sd(a); - - return _mm_cvtsd_f64( - _mm_div_sd( - _mm_set_sd(1.0), - _mm_sqrt_sd(temp, temp) - ) - ); -} - -inline f32 oms_round(f32 a) -{ - return _mm_cvtss_f32( - _mm_round_ss(_mm_setzero_ps(), _mm_set_ss(a), (_MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC))); -} - -inline uint32 round_to_int(f32 a) { return (uint32) _mm_cvtss_si32(_mm_set_ss(a)); } - -inline f32 oms_floor(f32 a) { return _mm_cvtss_f32(_mm_floor_ss(_mm_setzero_ps(), _mm_set_ss(a))); } - -inline f32 oms_ceil(f32 a) { return _mm_cvtss_f32(_mm_ceil_ss(_mm_setzero_ps(), _mm_set_ss(a))); } - -inline uint32 oms_hash(uint64 a, uint64 b = 0) -{ - uint8 seed[16] = { - 0xaa, 0x9b, 0xbd, 0xb8, 0xa1, 0x98, 0xac, 0x3f, 0x1f, 0x94, 0x07, 0xb3, 0x8c, 0x27, 0x93, 0x69, - }; - - __m128i hash = _mm_set_epi64x(a, b); - hash = _mm_aesdec_si128(hash, _mm_loadu_si128((__m128i *) seed)); - hash = _mm_aesdec_si128(hash, _mm_loadu_si128((__m128i *) seed)); - - return _mm_extract_epi32(hash, 0); -} - -inline void oms_fence_memory() -{ - _mm_mfence(); -} - -inline void oms_fence_write() -{ - _mm_sfence(); -} - -inline void oms_fence_load() -{ - _mm_lfence(); -} - -inline -void oms_invalidate_cache(void* address) -{ - _mm_clflush(address); -} - -#endif \ No newline at end of file diff --git a/stdlib/IntrinsicsArm.h b/stdlib/IntrinsicsArm.h deleted file mode 100644 index c88d18b..0000000 --- a/stdlib/IntrinsicsArm.h +++ /dev/null @@ -1,92 +0,0 @@ -/** - * Jingga - * - * @copyright Jingga - * @license OMS License 2.0 - * @version 1.0.0 - * @link https://jingga.app - */ -#ifndef TOS_STDLIB_INTRINSICS_ARM_H -#define TOS_STDLIB_INTRINSICS_ARM_H - -#include -#include - -inline float oms_sqrt(float a) { - svfloat32_t input = svdup_f32(a); - svfloat32_t result = svsqrt_f32(input); - - return svget1_f32(result); -} - -inline double oms_sqrt(double a) { - svfloat64_t input = svdup_f64(a); - svfloat64_t result = svsqrt_f64(input); - - return svget1_f64(result); -} - -inline float oms_rsqrt(float a) { - svfloat32_t input = svdup_f32(a); - svfloat32_t result = svrsqrte_f32(input); - - return svget1_f32(result); -} - -inline double oms_rsqrt(double a) { - svfloat64_t input = svdup_f64(a); - svfloat64_t result = svrsqrte_f64(input); - - return svget1_f64(result); -} - -inline float oms_round(float a) { - svfloat32_t input = svdup_f32(a); - svfloat32_t result = svrndn_f32(input); - - return svget1_f32(result); -} - -inline uint32_t round_to_int(float a) { - svfloat32_t input = svdup_f32(a); - svint32_t result = svcvtn_f32_s32(input, SVE_32B); - - return svget1_s32(result); -} - -inline float oms_floor(float a) { - svfloat32_t input = svdup_f32(a); - svfloat32_t result = svfloor_f32(input); - - return svget1_f32(result); -} - -inline float oms_ceil(float a) { - svfloat32_t input = svdup_f32(a); - svfloat32_t result = svceil_f32(input); - - return svget1_f32(result); -} - -inline void oms_fence_memory() -{ - __dmb(0xF); -} - -inline void oms_fence_write() -{ - __dmb(0xB); -} - -inline void oms_fence_load() -{ - __dmb(0x7); -} - -inline -void oms_invalidate_cache(void* address) -{ - asm volatile("dc ivac, %0" : : "r"(address) : "memory"); -} - -#endif \ No newline at end of file diff --git a/stdlib/PerfectHashMap.h b/stdlib/PerfectHashMap.h index bdea724..0620dd6 100644 --- a/stdlib/PerfectHashMap.h +++ b/stdlib/PerfectHashMap.h @@ -14,9 +14,9 @@ #include "../hash/GeneralHash.h" #include "../memory/RingMemory.h" -typedef uint64 (*perfect_hash_function)(const char* key, int32 seed); +typedef uint64 (*PerfectHashFunction)(const char* key, int32 seed); -const perfect_hash_function PERFECT_HASH_FUNCTIONS[] = { +const PerfectHashFunction PERFECT_HASH_FUNCTIONS[] = { hash_djb2_seeded, hash_sdbm_seeded, hash_lose_lose_seeded, @@ -27,91 +27,50 @@ const perfect_hash_function PERFECT_HASH_FUNCTIONS[] = { }; struct PerfectHashEntryInt32 { - int64 element_id; char key[HASH_MAP_MAX_KEY_LENGTH]; int32 value; }; struct PerfectHashEntryInt64 { - int64 element_id; char key[HASH_MAP_MAX_KEY_LENGTH]; int64 value; }; struct PerfectHashEntryUIntPtr { - int64 element_id; char key[HASH_MAP_MAX_KEY_LENGTH]; uintptr_t value; }; struct PerfectHashEntryVoidP { - int64 element_id; char key[HASH_MAP_MAX_KEY_LENGTH]; void* value; }; struct PerfectHashEntryFloat { - int64 element_id; char key[HASH_MAP_MAX_KEY_LENGTH]; f32 value; }; struct PerfectHashEntryStr { - int64 element_id; char key[HASH_MAP_MAX_KEY_LENGTH]; char value[HASH_MAP_MAX_KEY_LENGTH]; }; struct PerfectHashEntry { - int64 element_id; char key[HASH_MAP_MAX_KEY_LENGTH]; byte* value; }; struct PerfectHashMap { int32 hash_seed; - perfect_hash_function hash_function; - int32 entry_size; + PerfectHashFunction hash_function; + uint32 entry_size; - int32 map_size; + uint32 map_size; byte* hash_entries; }; -bool set_perfect_hashmap(PerfectHashMap* hm, const char** keys, int32 key_count, perfect_hash_function hash_func, int32 seed_tries, RingMemory* ring) -{ - int32* indices = (int32 *) ring_get_memory(ring, hm->map_size * sizeof(int32), 4); - bool is_unique = false; - - int32 seed; - int32 c = 0; - - while (!is_unique && c < seed_tries) { - is_unique = true; - seed = rand(); - memset(indices, 0, hm->map_size * sizeof(int32)); - - for (int32 j = 0; j < key_count; ++j) { - int32 index = hash_func(keys[j], seed) % hm->map_size; - if (indices[index]) { - is_unique = false; - break; - } else { - indices[index] = 1; - } - } - - ++c; - } - - if (is_unique) { - hm->hash_seed = seed; - hm->hash_function = hash_func; - } - - return is_unique; -} - -bool perfect_hashmap_find_perfect_hash(PerfectHashMap* hm, const char** keys, int32 key_count, int32 seed_trys, RingMemory* ring) +PerfectHashMap* perfect_hashmap_prepare(PerfectHashMap* hm, const char** keys, int32 key_count, int32 seed_trys, RingMemory* ring) { int32* indices = (int32 *) ring_get_memory(ring, hm->map_size * sizeof(int32), 4); bool is_unique = false; @@ -141,22 +100,12 @@ bool perfect_hashmap_find_perfect_hash(PerfectHashMap* hm, const char** keys, in if (is_unique) { hm->hash_seed = seed; hm->hash_function = PERFECT_HASH_FUNCTIONS[i]; + + return hm; } } - return is_unique; -} - -// WARNING: element_size = element size + remaining HashEntry data size -void perfect_hashmap_create(PerfectHashMap* hm, int32 count, int32 element_size, RingMemory* ring) -{ - hm->map_size = count; - hm->entry_size = element_size; - hm->hash_entries = ring_get_memory( - ring, - count * element_size, - 0, true - ); + return NULL; } // WARNING: element_size = element size + remaining HashEntry data size @@ -169,6 +118,8 @@ void perfect_hashmap_create(PerfectHashMap* hm, int32 count, int32 element_size, count * element_size, 0, true ); + + LOG_LEVEL_2("Created PerfectHashMap for %n elements with %n B per element", {{LOG_DATA_INT32, &count}, {LOG_DATA_INT32, &element_size}}); } // WARNING: element_size = element size + remaining HashEntry data size @@ -177,6 +128,8 @@ void perfect_hashmap_create(PerfectHashMap* hm, int32 count, int32 element_size, hm->map_size = count; hm->entry_size = element_size; hm->hash_entries = buf; + + LOG_LEVEL_2("Created PerfectHashMap for %n elements with %n B per element", {{LOG_DATA_INT32, &count}, {LOG_DATA_INT32, &element_size}}); } // Calculates how large a hashmap will be @@ -196,7 +149,6 @@ inline void perfect_hashmap_insert(PerfectHashMap* hm, const char* key, int32 value) { int32 index = hm->hash_function(key, hm->hash_seed) % hm->map_size; PerfectHashEntryInt32* entry = (PerfectHashEntryInt32 *) (hm->hash_entries + hm->entry_size * index); - entry->element_id = index; str_copy_short(entry->key, key); entry->value = value; } @@ -205,7 +157,6 @@ inline void perfect_hashmap_insert(PerfectHashMap* hm, const char* key, int64 value) { int32 index = hm->hash_function(key, hm->hash_seed) % hm->map_size; PerfectHashEntryInt64* entry = (PerfectHashEntryInt64 *) (hm->hash_entries + hm->entry_size * index); - entry->element_id = index; str_copy_short(entry->key, key); entry->value = value; } @@ -214,7 +165,6 @@ inline void perfect_hashmap_insert(PerfectHashMap* hm, const char* key, uintptr_t value) { int32 index = hm->hash_function(key, hm->hash_seed) % hm->map_size; PerfectHashEntryUIntPtr* entry = (PerfectHashEntryUIntPtr *) (hm->hash_entries + hm->entry_size * index); - entry->element_id = index; str_copy_short(entry->key, key); entry->value = value; } @@ -223,7 +173,6 @@ inline void perfect_hashmap_insert(PerfectHashMap* hm, const char* key, void* value) { int32 index = hm->hash_function(key, hm->hash_seed) % hm->map_size; PerfectHashEntryVoidP* entry = (PerfectHashEntryVoidP *) (hm->hash_entries + hm->entry_size * index); - entry->element_id = index; str_copy_short(entry->key, key); entry->value = value; } @@ -232,7 +181,6 @@ inline void perfect_hashmap_insert(PerfectHashMap* hm, const char* key, f32 value) { int32 index = hm->hash_function(key, hm->hash_seed) % hm->map_size; PerfectHashEntryFloat* entry = (PerfectHashEntryFloat *) (hm->hash_entries + hm->entry_size * index); - entry->element_id = index; str_copy_short(entry->key, key); entry->value = value; } @@ -241,7 +189,6 @@ inline void perfect_hashmap_insert(PerfectHashMap* hm, const char* key, const char* value) { int32 index = hm->hash_function(key, hm->hash_seed) % hm->map_size; PerfectHashEntryStr* entry = (PerfectHashEntryStr *) (hm->hash_entries + hm->entry_size * index); - entry->element_id = index; str_copy_short(entry->key, key); memcpy(entry->value, value, HASH_MAP_MAX_KEY_LENGTH); } @@ -250,7 +197,6 @@ inline void perfect_hashmap_insert(PerfectHashMap* hm, const char* key, byte* value) { int32 index = hm->hash_function(key, hm->hash_seed) % hm->map_size; PerfectHashEntryStr* entry = (PerfectHashEntryStr *) (hm->hash_entries + hm->entry_size * index); - entry->element_id = index; str_copy_short(entry->key, key); memcpy(entry->value, value, hm->entry_size - sizeof(PerfectHashEntry)); } @@ -260,7 +206,7 @@ PerfectHashEntry* perfect_hashmap_get_entry(const PerfectHashMap* hm, const char int32 index = hm->hash_function(key, hm->hash_seed) % hm->map_size; PerfectHashEntry* entry = (PerfectHashEntry *) (hm->hash_entries + hm->entry_size * index); - return *entry->key == '\0' ? NULL : entry; + return str_compare(entry->key, key) == 0 ? entry : NULL; } inline @@ -268,7 +214,12 @@ void perfect_hashmap_delete_entry(PerfectHashMap* hm, const char* key) { int32 index = hm->hash_function(key, hm->hash_seed) % hm->map_size; PerfectHashEntry* entry = (PerfectHashEntry *) (hm->hash_entries + hm->entry_size * index); - // This depends on where we check if an element exists (if we change perfect_hashmap_get_entry this also needs changing) + if (str_compare(entry->key, key) != 0) { + return; + } + + // This depends on where we check if an element exists + // If we change perfect_hashmap_get_entry this also needs changing *entry->key = '\0'; } @@ -329,30 +280,30 @@ int64 perfect_hashmap_load(PerfectHashMap* hm, const byte* data) inline bool perfect_hashmap_from_hashmap(PerfectHashMap* phm, const HashMap* hm, int32 seed_trys, RingMemory* ring) { - char** keys = (char **) ring_get_memory(ring, sizeof(char *) * hm->buf.count, 8); + const char** keys = (char **) ring_get_memory(ring, sizeof(char *) * hm->buf.count, 8); // Find all keys int32 key_index = 0; for (int32 i = 0; i < hm->buf.count; ++i) { - HashEntry* entry = (HashEntry *) hm->table[i]; + const HashEntry* entry = (HashEntry *) hashmap_get_entry_by_index((HashMap *) hm, i); while (entry != NULL) { keys[key_index++] = entry->key; - entry = (HashEntry *) entry->next; + entry = (HashEntry *) hashmap_get_entry_by_element((HashMap *) hm, entry->next); } } // Check if we can turn it into a perfect hash map - bool is_perfect = perfect_hashmap_find_perfect_hash(phm, (char **) keys, key_index, seed_trys, ring); + PerfectHashMap* is_perfect = perfect_hashmap_prepare(phm, keys, key_index, seed_trys, ring); if (!is_perfect) { return false; } // Fill perfect hash map for (int32 i = 0; i < hm->buf.count; ++i) { - HashEntry* entry = (HashEntry *) hm->table[i]; + const HashEntry* entry = (HashEntry *) hashmap_get_entry_by_index((HashMap *) hm, i); while (entry != NULL) { perfect_hashmap_insert(phm, entry->key, entry->value); - entry = (HashEntry *) entry->next; + entry = (HashEntry *) hashmap_get_entry_by_element((HashMap *) hm, entry->next); } } diff --git a/stdlib/Simd.h b/stdlib/Simd.h index 7335348..1a00f26 100644 --- a/stdlib/Simd.h +++ b/stdlib/Simd.h @@ -12,6 +12,7 @@ #if __aarch64__ #else + // @todo Should get moved to architecture/x86/simd directory #include "simd/SIMD_F32.h" #include "simd/SIMD_F64.h" #include "simd/SIMD_I8.h" diff --git a/stdlib/Types.h b/stdlib/Types.h index 89f533e..80c72ba 100644 --- a/stdlib/Types.h +++ b/stdlib/Types.h @@ -6,30 +6,14 @@ * @version 1.0.0 * @link https://jingga.app */ -#ifndef TOS_TYPES_H -#define TOS_TYPES_H +#ifndef TOS_STDLIB_TYPES_H +#define TOS_STDLIB_TYPES_H #include #ifdef _MSC_VER #include - - #define PACKED_STRUCT __pragma(pack(push, 1)) - #define UNPACKED_STRUCT __pragma(pack(pop)) typedef SSIZE_T ssize_t; - - #define UNREACHABLE() __assume(0) -#else - #define PACKED_STRUCT __attribute__((__packed__)) - #define UNPACKED_STRUCT ((void) 0) - - #define UNREACHABLE() __builtin_unreachable() -#endif - -#if _WIN32 - #define EXPORT_LIB extern "C" __declspec(dllexport) -#elif __linux__ - #define EXPORT_LIB extern "C" __attribute__((visibility("default"))) #endif #define ARRAY_COUNT(a) (sizeof(a) / sizeof((a)[0])) diff --git a/system/Library.h b/system/Library.h index 48b314c..7ad50a7 100644 --- a/system/Library.h +++ b/system/Library.h @@ -12,22 +12,20 @@ #include "../stdlib/Types.h" #if _WIN32 - #include + #include "../platform/win32/Library.h" +#elif __linux__ + #include "../platform/linux/Library.h" #endif struct Library { - #if _WIN32 - HMODULE handle; - #elif __linux__ - void* handle; - #endif + LibraryHandle handle; bool is_valid; char dir[MAX_PATH]; char dst[64]; - #if DEBUG + #if DEBUG || INTERNAL uint64 last_load; #endif diff --git a/system/SystemInfo.cpp b/system/SystemInfo.cpp index bc6a35a..de85d55 100644 --- a/system/SystemInfo.cpp +++ b/system/SystemInfo.cpp @@ -53,15 +53,16 @@ void system_info_render(char* buf, const SystemInfo* info) { "==============\n" "Name: %s\n" "VRAM: %d\n" "Name: %s\n" "VRAM: %d\n" + "Name: %s\n" "VRAM: %d\n" "\n" "Display:\n" "==============\n" - "Name: %s\n" "Width: %d\n" "Height: %d\n" "Hz: %d\n" - "Name: %s\n" "Width: %d\n" "Height: %d\n" "Hz: %d\n" - "Name: %s\n" "Width: %d\n" "Height: %d\n" "Hz: %d\n" - "Name: %s\n" "Width: %d\n" "Height: %d\n" "Hz: %d\n" - "Name: %s\n" "Width: %d\n" "Height: %d\n" "Hz: %d\n" - "Name: %s\n" "Width: %d\n" "Height: %d\n" "Hz: %d\n" + "Name: %s " "Width: %d " "Height: %d " "Hz: %d " "Primary: %d\n" + "Name: %s " "Width: %d " "Height: %d " "Hz: %d " "Primary: %d\n" + "Name: %s " "Width: %d " "Height: %d " "Hz: %d " "Primary: %d\n" + "Name: %s " "Width: %d " "Height: %d " "Hz: %d " "Primary: %d\n" + "Name: %s " "Width: %d " "Height: %d " "Hz: %d " "Primary: %d\n" + "Name: %s " "Width: %d " "Height: %d " "Hz: %d " "Primary: %d\n" "\n" "RAM:\n" "==============\n" @@ -80,12 +81,13 @@ void system_info_render(char* buf, const SystemInfo* info) { info->cpu.features, info->gpu[0].name, info->gpu[0].vram, info->gpu_count < 2 ? "" : info->gpu[1].name, info->gpu_count < 2 ? 0 : info->gpu[1].vram, - info->display[0].name, info->display[0].width, info->display[0].height, info->display[0].hz, - info->display_count < 2 ? "" : info->display[1].name, info->display_count < 2 ? 0 : info->display[1].width, info->display_count < 2 ? 0 : info->display[1].height, info->display_count < 2 ? 0 : info->display[1].hz, - info->display_count < 3 ? "" : info->display[2].name, info->display_count < 3 ? 0 : info->display[2].width, info->display_count < 3 ? 0 : info->display[2].height, info->display_count < 3 ? 0 : info->display[2].hz, - info->display_count < 4 ? "" : info->display[3].name, info->display_count < 4 ? 0 : info->display[3].width, info->display_count < 4 ? 0 : info->display[3].height, info->display_count < 4 ? 0 : info->display[3].hz, - info->display_count < 5 ? "" : info->display[4].name, info->display_count < 5 ? 0 : info->display[4].width, info->display_count < 5 ? 0 : info->display[4].height, info->display_count < 5 ? 0 : info->display[4].hz, - info->display_count < 6 ? "" : info->display[5].name, info->display_count < 6 ? 0 : info->display[5].width, info->display_count < 6 ? 0 : info->display[5].height, info->display_count < 6 ? 0 : info->display[5].hz, + info->gpu_count < 3 ? "" : info->gpu[2].name, info->gpu_count < 3 ? 0 : info->gpu[2].vram, + info->display[0].name, info->display[0].width, info->display[0].height, info->display[0].hz, info->display[0].is_primary, + info->display_count < 2 ? "" : info->display[1].name, info->display_count < 2 ? 0 : info->display[1].width, info->display_count < 2 ? 0 : info->display[1].height, info->display_count < 2 ? 0 : info->display[1].hz, info->display_count < 2 ? 0 : info->display[1].is_primary, + info->display_count < 3 ? "" : info->display[2].name, info->display_count < 3 ? 0 : info->display[2].width, info->display_count < 3 ? 0 : info->display[2].height, info->display_count < 3 ? 0 : info->display[2].hz, info->display_count < 3 ? 0 : info->display[2].is_primary, + info->display_count < 4 ? "" : info->display[3].name, info->display_count < 4 ? 0 : info->display[3].width, info->display_count < 4 ? 0 : info->display[3].height, info->display_count < 4 ? 0 : info->display[3].hz, info->display_count < 4 ? 0 : info->display[3].is_primary, + info->display_count < 5 ? "" : info->display[4].name, info->display_count < 5 ? 0 : info->display[4].width, info->display_count < 5 ? 0 : info->display[4].height, info->display_count < 5 ? 0 : info->display[4].hz, info->display_count < 5 ? 0 : info->display[4].is_primary, + info->display_count < 6 ? "" : info->display[5].name, info->display_count < 6 ? 0 : info->display[5].width, info->display_count < 6 ? 0 : info->display[5].height, info->display_count < 6 ? 0 : info->display[5].hz, info->display_count < 6 ? 0 : info->display[5].is_primary, info->ram.memory ); } @@ -99,7 +101,6 @@ void system_info_get(SystemInfo* info) ram_info_get(&info->ram); info->gpu_count = gpu_info_get(info->gpu); info->display_count = display_info_get(info->display); - display_info_get_primary(&info->display_primary); info->language = system_language_code(); } diff --git a/system/SystemInfo.h b/system/SystemInfo.h index 39c6576..283d8a3 100644 --- a/system/SystemInfo.h +++ b/system/SystemInfo.h @@ -45,6 +45,7 @@ struct DisplayInfo { int32 width; int32 height; int32 hz; + bool is_primary; }; struct SystemInfo { @@ -57,10 +58,9 @@ struct SystemInfo { CpuInfo cpu; RamInfo ram; - GpuInfo gpu[2]; + GpuInfo gpu[3]; int32 gpu_count; - DisplayInfo display_primary; DisplayInfo display[6]; int32 display_count; diff --git a/thread/ThreadJob.h b/thread/ThreadJob.h index 592a74d..9c31279 100644 --- a/thread/ThreadJob.h +++ b/thread/ThreadJob.h @@ -20,7 +20,7 @@ typedef void (*ThreadPoolJobFunc)(void*); struct PoolWorker { int32 id; - volatile int32 state; + int32 state; void* arg; void* result; RingMemory ring; @@ -29,7 +29,7 @@ struct PoolWorker { }; struct Worker { - volatile int32 state; + int32 state; pthread_t thread; }; diff --git a/thread/ThreadPool.h b/thread/ThreadPool.h index 6026034..8ed6cd2 100644 --- a/thread/ThreadPool.h +++ b/thread/ThreadPool.h @@ -34,7 +34,7 @@ struct ThreadPool { int32 size; int32 state; - uint32 id_counter; + int32 id_counter; }; static THREAD_RETURN thread_pool_worker(void* arg) @@ -120,7 +120,7 @@ void thread_pool_wait(ThreadPool* pool) void thread_pool_destroy(ThreadPool* pool) { // This sets the queue to empty - atomic_set_acquire((void **) &pool->work_queue.tail, (void **) &pool->work_queue.head); + atomic_set_acquire((void **) &pool->work_queue.tail, pool->work_queue.head); // This sets the state to "shutdown" atomic_set_release(&pool->state, 1); diff --git a/ui/UIAnimation.h b/ui/UIAnimation.h index 0c572e3..74d24ef 100644 --- a/ui/UIAnimation.h +++ b/ui/UIAnimation.h @@ -4,20 +4,38 @@ #include "../stdlib/Types.h" #include "../animation/AnimationEaseType.h" -#define UI_ANIMATION_ACTIVE_FLAG 0x80000000 - struct UIAnimationState { - uint64 start; - uint32 duration; + // When did the animation start? + uint32 start; + // Element specific use (e.g. cursor uses 0/1 for visible/invisible for blinking) // The highest bit indicates if the animation is active or not - int32 state; - AnimationEaseType anim_type; + int16 state; + + // What is our last keyframe for reference? + byte keyframe; + + // Currently active animation + byte active_animation; }; struct UIAnimation { - uint32 duration; + // For which transition is this animation used? + UIStyleType style_old; + UIStyleType style_new; + + // This allows for a maximum duration of 65536ms = 65.536s + uint16 duration; AnimationEaseType anim_type; + + // The last keyframe is always the style associated with style_new + // This means that with 0 keyframes and a duration of 'Xs' the animation is interpolated between style_old and style_new + // In other words the keyframes below only define ADDITIONAL steps in between style_old and style_new + // The keyframes are defined in the theme file + byte keyframe_count; + + // The dynamic array containing the offsets into the keyframes come directly after UIAnimation + // UIElementDetail* keyframes; }; #endif \ No newline at end of file diff --git a/ui/UIButton.h b/ui/UIButton.h index bb571cb..0b8d5ff 100644 --- a/ui/UIButton.h +++ b/ui/UIButton.h @@ -2,6 +2,12 @@ #define TOS_UI_BUTTON_H #include "../stdlib/Types.h" +#include "attribute/UIAttribute.h" +#include "attribute/UIAttributeDimension.h" +#include "UIStyleType.h" +#include "UILayout.h" +#include "UIElement.h" +#include "../math/Evaluator.h" struct UIButtonState { }; @@ -10,4 +16,42 @@ struct UIButton { }; +void ui_button_state_serialize(const UIButtonState* __restrict state, byte** __restrict pos) +{ + +} + +void ui_button_state_unserialize(UIButtonState* __restrict state, const byte** __restrict pos) +{ + +} + +void ui_button_state_populate(const UIAttributeGroup* __restrict group, UIButtonState* __restrict state) +{ + +} + +void ui_button_element_serialize(const UIButton* __restrict details, byte** __restrict pos) +{ + +} + +void ui_button_element_unserialize(UIButton* __restrict details, const byte** __restrict pos) +{ + +} + +void ui_button_element_populate( + const UIAttributeGroup* __restrict group, + UIElement* __restrict element, + UIStyleType style_type, + EvaluatorVariable* __restrict variables +) { +} + +int32 ui_button_element_update(UILayout* layout, UIElement* element) +{ + return 0; +} + #endif \ No newline at end of file diff --git a/ui/UICursor.h b/ui/UICursor.h index 9abe87f..770562d 100644 --- a/ui/UICursor.h +++ b/ui/UICursor.h @@ -2,12 +2,24 @@ #define TOS_UI_CURSOR_H #include "../stdlib/Types.h" +#include "attribute/UIAttributeDimension.h" +#include "UILayout.h" +#include "UIElement.h" struct UICursorState { }; struct UICursor { - + UIAttributeDimension dimension; + byte opacity; // 1 byte alpha channel }; +int32 ui_cursor_element_update(UILayout* layout, UIElement* element) +{ + UICursor* input = (UICursor *) (layout->data + element->style_types[element->style_new]); + UICursorState* state = (UICursorState *) (layout->data + element->state); + + return 0; +} + #endif \ No newline at end of file diff --git a/ui/UIElement.h b/ui/UIElement.h index 44012ea..3d35492 100644 --- a/ui/UIElement.h +++ b/ui/UIElement.h @@ -2,11 +2,14 @@ #define TOS_UI_ELEMENT_H #include "../stdlib/Types.h" +#include "UIStyleType.h" +#include "UIAnimation.h" enum UIElementType : byte { UI_ELEMENT_TYPE_BUTTON, UI_ELEMENT_TYPE_SELECT, UI_ELEMENT_TYPE_INPUT, + UI_ELEMENT_TYPE_LABEL, UI_ELEMENT_TYPE_TEXTAREA, UI_ELEMENT_TYPE_IMAGE, UI_ELEMENT_TYPE_TEXT, @@ -24,22 +27,92 @@ enum UIElementState : byte { UI_ELEMENT_STATE_VISIBLE = 1 << 1, UI_ELEMENT_STATE_FOCUSED = 1 << 2, UI_ELEMENT_STATE_CLICKABLE = 1 << 3, + + // Are we currently in an animation? + // @question Do we even need this? Can't we just use the animation state (start == 0) UI_ELEMENT_STATE_ANIMATION = 1 << 4, + + // Flag to indicate that the element changed + // Just checking style_old and style_new is not enough, since we may have an ongoing animation + // We also need to be able to check the parent element in case the parent element changed position + // -> we also need to change position of all child elements (parent sets this flag for all child elements) + UI_ELEMENT_STATE_CHANGED = 1 << 5, }; +// All pointer like variables are uint32 offset values +// This allows us to copy the data around temp memory without loss of reference +// For arrays we position the data after the UIElement struct UIElement { // @see UIElementState byte state_flag; UIElementType type; + // Used to keep track of the current state (= _old) and the next state or state we are transitioning into UIStyleType style_old; UIStyleType style_new; - UIElement* parent; - void* state; - void* details[UI_STYLE_TYPE_SIZE]; + // Used for grouping ui elements (e.g. const ui elements, fairly static elements, dynamic elements) + byte category; + + f32 zindex; + + // Some elements need information from their parent element + // @question Do we even need this? When rendering we always start at the root and go down + // This means we could easily pass the parent element as a parameter in the function call + // Maybe we still want this in case we ever want to call individual elements? + uint32 parent; + + ////////////////////////////////////// + // Sub info + ////////////////////////////////////// + + // Every element can have a fixed state, which is element type specific + // This state is shared across all style_type (see below) + uint32 state; + + // Every element can have multiple implementations for different states (e.g. hover, focus, ...) + // These implementations are also element type specific and can be found in here + uint32 style_types[UI_STYLE_TYPE_SIZE]; + + // A UIElement can have child elements (e.g. a Window has labels, buttons, etc...) uint16 children_count; - UIElement** children; + + // The children array comes directly after UIElement + // uint32* children; + + ////////////////////////////////////// + // Animations + ////////////////////////////////////// + + // A UIElement can have animations + // e.g. when switching between styles/states or simply repeating animations like hover animations + // @question Should this even be here or should this be in the state of the element? + UIAnimationState animation_state; + + // The animation count is defined in the theme file + uint16 animation_count; + + // Location where the animation information is stored + // We cannot put it at the end of this UIElement since the length is only known by the theme + uint32 animations; + + // The animations array comes directly after the children array + // This means: UIElement + children_count * sizeof(uint32) + // uint32* animations; + + ////////////////////////////////////// + // Cache + ////////////////////////////////////// + + // We cache the last UI element rendering for re-use in the next frame + // @question There might be custom UI elements which need more than 2^16 vertices + uint16 vertex_count; + + // The max vertex count is defined in the theme file + uint16 vertex_count_max; + + // Offset into the vertex array (NOT in bytes but in vertices) + uint32 vertices_active; }; #endif \ No newline at end of file diff --git a/ui/UIElementType.h b/ui/UIElementType.h index c506bd3..135b9fe 100644 --- a/ui/UIElementType.h +++ b/ui/UIElementType.h @@ -3,6 +3,7 @@ #include #include "../stdlib/Types.h" +#include "../compiler/CompilerUtils.h" #include "UIButton.h" #include "UISelect.h" #include "UIInput.h" @@ -46,6 +47,7 @@ int32 ui_element_type_size(UIElementType e) return sizeof(UICursor); default: { UNREACHABLE(); + return 0; } } } @@ -80,6 +82,7 @@ int32 ui_element_state_size(UIElementType e) return sizeof(UICursorState); default: { UNREACHABLE(); + return 0; } } } diff --git a/ui/UIInput.h b/ui/UIInput.h index 595edde..8bda970 100644 --- a/ui/UIInput.h +++ b/ui/UIInput.h @@ -3,15 +3,21 @@ #include "../stdlib/Types.h" #include "../camera/Camera.h" +#include "attribute/UIAttribute.h" #include "attribute/UIAttributeBorder.h" #include "attribute/UIAttributeShadow.h" -#include "attribute/UIAttributeFont.h" #include "attribute/UIAttributeBackground.h" #include "attribute/UIAttributeDimension.h" #include "UIAnimation.h" #include "UIStyleType.h" #include "UIElement.h" +#include "UICursor.h" +#include "UIWindow.h" +#include "UIPanel.h" +#include "UILayout.h" #include "../math/Evaluator.h" +#include "../gpuapi/RenderUtils.h" +#include "../object/Vertex.h" enum UIInputType : byte { UI_INPUT_TYPE_TEXT, @@ -22,11 +28,8 @@ enum UIInputType : byte { }; struct UIInputState { - char content[512]; - char* content_ref; uint16 cursor_pos_x; uint16 cursor_pos_y; - UIAnimationState animation; UIInputType type; int32 min_value; int32 max_value; @@ -38,66 +41,213 @@ struct UIInput { byte opacity; // 1 byte alpha channel byte padding; - // Animation used to get into this style - UIAnimation animation; - - UIAttributeFont font; UIAttributeBackground background; - UIAttributeBorder border; UIAttributeShadow shadow_outer; UIAttributeShadow shadow_inner; }; -void ui_input_state_populate(const UIAttributeGroup* group, UIInputState* state) { - for (int32 i = 0; i < group->attribute_size; ++i) { - switch (group->attributes[i].attribute_id) { +void ui_input_state_serialize(const UIInputState* __restrict state, byte** __restrict pos) +{ + *((uint16 *) *pos) = SWAP_ENDIAN_LITTLE(state->cursor_pos_x); + *pos += sizeof(state->cursor_pos_x); + + *((uint16 *) *pos) = SWAP_ENDIAN_LITTLE(state->cursor_pos_y); + *pos += sizeof(state->cursor_pos_y); + + **pos = state->type; + *pos += sizeof(state->type); + + *((int32 *) *pos) = SWAP_ENDIAN_LITTLE(state->min_value); + *pos += sizeof(state->min_value); + + *((int32 *) *pos) = SWAP_ENDIAN_LITTLE(state->max_value); + *pos += sizeof(state->max_value); + + *((uint16 *) *pos) = SWAP_ENDIAN_LITTLE(state->max_input_length); + *pos += sizeof(state->max_input_length); +} + +void ui_input_state_unserialize(UIInputState* __restrict state, const byte** __restrict pos) +{ + state->cursor_pos_x = SWAP_ENDIAN_LITTLE(*((uint16 *) *pos)); + *pos += sizeof(state->cursor_pos_x); + + state->cursor_pos_y = SWAP_ENDIAN_LITTLE(*((uint16 *) *pos)); + *pos += sizeof(state->cursor_pos_y); + + state->type = (UIInputType) **pos; + *pos += sizeof(state->type); + + state->min_value = SWAP_ENDIAN_LITTLE(*((int32 *) *pos)); + *pos += sizeof(state->min_value); + + state->max_value = SWAP_ENDIAN_LITTLE(*((int32 *) *pos)); + *pos += sizeof(state->max_value); + + state->max_input_length = SWAP_ENDIAN_LITTLE(*((uint16 *) *pos)); + *pos += sizeof(state->max_input_length); +} + +void ui_input_state_populate(const UIAttributeGroup* __restrict group, UIInputState* __restrict state) { + + UIAttribute* attributes = (UIAttribute *) (group + 1); + for (int32 i = 0; i < group->attribute_count; ++i) { + switch (attributes[i].attribute_id) { case UI_ATTRIBUTE_TYPE_TYPE: { - state->type = (UIInputType) group->attributes[i].value_int; + state->type = (UIInputType) attributes[i].value_int; } break; case UI_ATTRIBUTE_TYPE_MIN_VALUE: { - state->min_value = group->attributes[i].value_int; + state->min_value = attributes[i].value_int; } break; case UI_ATTRIBUTE_TYPE_MAX_VALUE: { - state->max_value = group->attributes[i].value_int; + state->max_value = attributes[i].value_int; } break; case UI_ATTRIBUTE_TYPE_MAX_INPUT_LENGTH: { - state->max_input_length = (uint16) group->attributes[i].value_int; + state->max_input_length = (uint16) attributes[i].value_int; } break; + default: {} } } } +void ui_input_element_serialize(const UIInput* __restrict details, byte** __restrict pos) +{ + ui_attr_dimension_serialize(&details->dimension, pos); + + **pos = details->opacity; + *pos += sizeof(details->opacity); + + **pos = details->padding; + *pos += sizeof(details->padding); + + ui_attr_background_serialize(&details->background, pos); + ui_attr_border_serialize(&details->border, pos); + ui_attr_shadow_serialize(&details->shadow_outer, pos); + ui_attr_shadow_serialize(&details->shadow_inner, pos); +} + +void ui_input_element_unserialize(UIInput* __restrict details, const byte** __restrict pos) +{ + ui_attr_dimension_unserialize(&details->dimension, pos); + + details->opacity = **pos; + *pos += sizeof(details->opacity); + + details->padding = **pos; + *pos += sizeof(details->padding); + + ui_attr_background_unserialize(&details->background, pos); + ui_attr_border_unserialize(&details->border, pos); + ui_attr_shadow_unserialize(&details->shadow_outer, pos); + ui_attr_shadow_unserialize(&details->shadow_inner, pos); +} + void ui_input_element_populate( - const UIAttributeGroup* group, - UIElement* element, - UIStyleType style_type, - EvaluatorVariable* variables + UILayout* layout, + const UIAttributeGroup* __restrict group, + UIInput* __restrict input, + UIElement* parent, + EvaluatorVariable* __restrict variables ) { - if (element->parent) { + if (parent) { // @bug How to ensure that the parent is initialized before the child element // Currently the order of the initialization depends on the theme file, NOT the layout file // We could fix it by loading the style based on the layout order but this would result in many misses when looking up styles // The reason for these misses are, that often only 1-2 style_types exist per element - UIInput* parent = (UIInput *) element->parent->details[UI_STYLE_TYPE_DEFAULT]; - variables[2].value = parent->dimension.dimension.x; - variables[3].value = parent->dimension.dimension.y; - variables[4].value = parent->dimension.dimension.width; - variables[5].value = parent->dimension.dimension.height; + + v4_f32* parent_dimension; + switch (parent->type) { + case UI_ELEMENT_TYPE_VIEW_WINDOW: { + UIWindow* parent_window = (UIWindow *) (layout->data + parent->style_types[UI_STYLE_TYPE_ACTIVE]); + parent_dimension = &parent_window->dimension.dimension; + } break; + case UI_ELEMENT_TYPE_VIEW_PANEL: { + UIPanel* parent_window = (UIPanel *) (layout->data + parent->style_types[UI_STYLE_TYPE_ACTIVE]); + parent_dimension = &parent_window->dimension.dimension; + } break; + default: + UNREACHABLE(); + parent_dimension = NULL; + } + + variables[2].value = parent_dimension->x; + variables[3].value = parent_dimension->y; + variables[4].value = parent_dimension->width; + variables[5].value = parent_dimension->height; } - UIInput* e = (UIInput *) element->details[style_type]; + UIAttribute* attributes = (UIAttribute *) (group + 1); + // First set all values, which we can set immediately - for (int32 i = 0; i < group->attribute_size; ++i) { - switch (group->attributes[i].attribute_id) { + for (int32 i = 0; i < group->attribute_count; ++i) { + switch (attributes->attribute_id) { case UI_ATTRIBUTE_TYPE_DIMENSION_X: case UI_ATTRIBUTE_TYPE_DIMENSION_WIDTH: case UI_ATTRIBUTE_TYPE_DIMENSION_Y: case UI_ATTRIBUTE_TYPE_DIMENSION_HEIGHT: { - ui_theme_assign_dimension(&e->dimension, &group->attributes[i], 6, variables); + ui_theme_assign_dimension(&input->dimension, attributes, 6, variables); } break; } } } +int32 ui_input_element_update(UILayout* layout, UIElement* element) +{ + UIInput* input = (UIInput *) (layout->data + element->style_types[element->style_new]); + UIInputState* state = (UIInputState *) (layout->data + element->state); + + int32 idx = 0; + f32 zindex = element->zindex; + + v4_f32 dimension = input->dimension.dimension; + + // Border + if (input->border.thickness) { + idx += vertex_rect_create( + layout->vertices_active + element->vertices_active, zindex, + dimension, input->dimension.alignment, + input->border.color + ); + + // Adjusting dimension based on border + // border is part of width/height + dimension.x += input->border.thickness; + dimension.y += input->border.thickness; + dimension.width -= input->border.thickness; + dimension.height -= input->border.thickness; + + zindex = nextafterf(zindex, INFINITY); + } + + // Background + if (input->background.background_color) { + idx += vertex_rect_create( + layout->vertices_active + element->vertices_active + idx, zindex, + dimension, input->dimension.alignment, + input->background.background_color + ); + + zindex = nextafterf(zindex, INFINITY); + } + + // Cursor + HashEntryInt32* cursor_entry = (HashEntryInt32 *) hashmap_get_entry(&layout->hash_map, "cursor"); + if (cursor_entry) { + UIElement* cursor_element = (UIElement *) (layout->data + cursor_entry->value); + // This requires the cursor position is already updated wherever we handle the input update (on_enter, on_leave) + idx += ui_cursor_element_update(layout, cursor_element); + + memcpy( + layout->vertices_active + element->vertices_active + idx, + layout->vertices_active + cursor_element->vertices_active, + cursor_element->vertex_count * sizeof(*(layout->vertices_active)) + ); + } + + element->vertex_count = (uint16) idx; + + return idx; +} + #endif \ No newline at end of file diff --git a/ui/UILabel.h b/ui/UILabel.h index e2f5b7d..b94677d 100644 --- a/ui/UILabel.h +++ b/ui/UILabel.h @@ -2,12 +2,69 @@ #define TOS_UI_LABEL_H #include "../stdlib/Types.h" +#include "attribute/UIAttributeFont.h" +#include "attribute/UIAttributeDimension.h" +#include "UIStyleType.h" +#include "UIElement.h" +#include "UITheme.h" +#include "UILayout.h" +#include "../object/Vertex.h" struct UILabelState { + char* content; }; struct UILabel { - + UIAttributeDimension dimension; + byte opacity; // 1 byte alpha channel + UIAttributeFont font; }; +void ui_label_state_serialize(const UILabelState* __restrict state, byte** __restrict pos) +{ + +} + +void ui_label_state_unserialize(UILabelState* __restrict state, const byte** __restrict pos) +{ + +} + +void ui_label_state_populate(const UIAttributeGroup* __restrict group, UILabelState* __restrict state) +{ + +} + +void ui_label_element_serialize(const UILabel* __restrict details, byte** __restrict pos) +{ + +} + +void ui_label_element_unserialize(UILabel* __restrict details, const byte** __restrict pos) +{ + +} + +void ui_label_element_populate( + const UIAttributeGroup* __restrict group, + UIElement* __restrict element, + UIStyleType style_type, + EvaluatorVariable* __restrict variables +) { +} + +int32 ui_label_element_update(UILayout* layout, UIElement* element) +{ + UILabel* label = (UILabel *) (layout->data + element->style_types[element->style_new]); + UILabelState* state = (UILabelState *) (layout->data + element->state); + + return vertex_text_create( + layout->vertices_active + element->vertices_active, element->zindex, + label->dimension.dimension, label->font.alignment, + layout->font, state->content, + label->font.size, label->font.color, + label->font.weight + ).z; +} + #endif \ No newline at end of file diff --git a/ui/UILayout.cpp b/ui/UILayout.cpp new file mode 100644 index 0000000..b076212 --- /dev/null +++ b/ui/UILayout.cpp @@ -0,0 +1,847 @@ +#ifndef TOS_UI_LAYOUT_C +#define TOS_UI_LAYOUT_C + +#include +#include "../stdlib/Types.h" +#include "../stdlib/HashMap.h" +#include "../asset/Asset.h" +#include "../camera/Camera.h" +#include "../system/FileUtils.cpp" +#include "../compiler/CompilerUtils.h" + +#include "UILayout.h" +#include "UITheme.h" +#include "UIElement.h" +#include "UIElementType.h" +#include "UIInput.h" +#include "UILabel.h" + +// Doesn't change the position of pos outside of the function, since lookahead +static +void ui_layout_count_direct_children(UIElement* __restrict element, const char* __restrict pos, int32 parent_level) +{ + // Find amount of child elements + // We have to perform a lookahead since this determins the size of our children array + uint16 direct_child_elements = 0; + + int32 level = 0; + while (*pos != '\0') { + while (*pos == ' ' || *pos == '\t') { + ++pos; + ++level; + } + + if (level > parent_level + 4) { + // This element is a childrens child and not a direct child + continue; + } else if (level <= parent_level || !str_is_alphanum(*pos)) { + // We are no longer inside of element + break; + } + + ++direct_child_elements; + str_move_past(&pos, '\n'); + } + + element->children_count = direct_child_elements; +} + +static +void ui_layout_assign_children( + UILayout* __restrict layout, + UIElement* __restrict element, + const char* __restrict pos, + int32 parent_level +) { + int32 current_child_pos = 0; + + char block_name[28]; + + int32 level = 0; + while (*pos != '\0') { + while (*pos == ' ' || *pos == '\t') { + ++pos; + ++level; + } + + if (level > parent_level + 4) { + // This element is a childrens child and not a direct child + continue; + } else if (level <= parent_level) { + // We are no longer inside of element + break; + } + + str_copy_move_until(&pos, block_name, ":"); + str_move_past(&pos, '\n'); + + // Children array (located after the UIElement) + uint32* children = (uint32 *) (element + 1); + + // Set child offset + HashEntryInt32* child_entry = (HashEntryInt32 *) hashmap_get_entry(&layout->hash_map, block_name); + children[current_child_pos] = child_entry->value; + + // Create a reference to the parent element for the child element + UIElement* child_element = (UIElement *) (layout->data + child_entry->value); + child_element->parent = (uint32) ((uintptr_t) element - (uintptr_t) layout->data); + + ++current_child_pos; + } +} + +// WARNING: theme needs to have memory already reserved and assigned to data +void layout_from_file_txt( + UILayout* __restrict layout, + const char* __restrict path, + RingMemory* ring +) { + FileBody file; + file_read(path, &file, ring); + ASSERT_SIMPLE(file.size); + + const char* pos = (char *) file.content; + + // move past the version string + pos += 8; + + // Use version for different handling + int32 version = strtol(pos, (char **) &pos, 10); ++pos; + + // 1. Iteration: We have to find how many elements are defined in the layout file. + // Therefore we have to do an initial iteration + // We start at 1 since we always have a root element + int32 temp_element_count = 1; + while (*pos != '\0') { + // Skip all white spaces + str_skip_empty(&pos); + + ++temp_element_count; + + // Go to the next line + str_move_past(&pos, '\n'); + } + + // 2. Iteration: Fill HashMap + // @performance This is probably horrible since we are not using a perfect hashing function (1 hash -> 1 index) + // I wouldn't be surprised if we have a 50% hash overlap (2 hashes -> 1 index) + hashmap_create(&layout->hash_map, temp_element_count, sizeof(HashEntryInt32), layout->data); + int64 hm_size = hashmap_size(&layout->hash_map); + + pos = (char *) file.content; + + // move past version string + str_move_past(&pos, '\n'); + + char block_name[28]; + char block_type[28]; + + // We store the UIElement and associated data after the hashmap + byte* element_data = layout->data + hm_size; + + // Create root element + UIElement* root = (UIElement *) element_data; + hashmap_insert(&layout->hash_map, ":root", element_data - layout->data); + ui_layout_count_direct_children(root, pos, -4); + + // NOTE: The root element cannot have any animations or vertices + element_data += sizeof(UIElement) + sizeof(uint32) * root->children_count; + + int32 level; + while (*pos != '\0') { + if (*pos == '\n') { + ++pos; + continue; + } + + level = 0; + while (*pos == ' ' || *pos == '\t') { + ++pos; + ++level; + } + + if (*pos == '\n' || *pos == '\0') { + continue; + } + + str_copy_move_until(&pos, block_name, ":"); ++pos; + str_copy_move_until(&pos, block_type, " \r\n"); + str_move_past(&pos, '\n'); + + // Insert new element + UIElement* element = (UIElement *) element_data; + hashmap_insert(&layout->hash_map, block_name, (int32) ((uintptr_t) element_data - (uintptr_t) layout->data)); + + element->type = (UIElementType) ui_element_type_to_id(block_type); + + // The children array is dynamic in size and comes directly after the UIElement + ui_layout_count_direct_children(element, pos, level); + + element_data += sizeof(UIElement) + + sizeof(uint32) * element->children_count; // Children offsets come after the UIElement + + // We put the state data after this element + element->state = (uint32) ((uintptr_t) element_data - (uintptr_t) layout->data); + element_data += ui_element_state_size(element->type); + + // We put the active element data after this element + element->style_types[UI_STYLE_TYPE_ACTIVE] = (uint32) ((uintptr_t) element_data - (uintptr_t) layout->data); + // @performance We should probably make sure the data is nicely aligned here + element_data += ui_element_type_size(element->type); + + // We put the default element data after this element + // Depending on the theme we will have also additional styles (e.g. :active, :hidden, ...) + element->style_types[UI_STYLE_TYPE_DEFAULT] = (uint32) ((uintptr_t) element_data - (uintptr_t) layout->data); + // @performance We should probably make sure the data is nicely aligned here + element_data += ui_element_type_size(element->type); + } + + // 3. Iteration: Create child references + pos = (char *) file.content; + + // move past version string + str_move_past(&pos, '\n'); + + while (*pos != '\0') { + if (*pos == '\n') { + ++pos; + continue; + } + + level = 0; + while (*pos == ' ' || *pos == '\t') { + ++pos; + ++level; + } + + if (*pos == '\n' || *pos == '\0') { + continue; + } + + str_copy_move_until(&pos, block_name, ":"); + str_move_past(&pos, '\n'); + + UIElement* element = (UIElement *) (layout->data + ((HashEntryInt32 *) hashmap_get_entry(&layout->hash_map, block_name))->value); + ui_layout_assign_children(layout, element, pos, level); + + // ui_layout_assign_children doesn't move the pos pointer + str_move_past(&pos, '\n'); + } + + // 4. Iteration: Create root child references + pos = (char *) file.content; + + // move past version string + str_move_past(&pos, '\n'); + + uint32* root_children = (uint32 *) (root + 1); + + int32 child = 0; + while (*pos != '\0') { + if (*pos == '\n') { + ++pos; + continue; + } + + if (*pos == ' ' || *pos == '\t') { + str_move_past(&pos, '\n'); + continue; + } + + str_copy_move_until(&pos, block_name, ":"); + str_move_past(&pos, '\n'); + root_children[child++] = ((HashEntryInt32 *) hashmap_get_entry(&layout->hash_map, block_name))->value; + } +} + +static +void ui_layout_serialize_element_state(UIElementType type, const void* __restrict state, byte** __restrict pos) { + switch (type) { + case UI_ELEMENT_TYPE_INPUT: { + ui_input_state_serialize((UIInputState *) state, pos); + } break; + } +} + +static +void ui_layout_serialize_element_detail(UIElementType type, const void* __restrict details, byte** __restrict pos) { + switch (type) { + case UI_ELEMENT_TYPE_INPUT: { + ui_input_element_serialize((UIInput *) details, pos); + } break; + } +} + +static +void ui_layout_serialize_element( + HashEntryInt32* entry, + byte* data, + byte** pos, + const byte* start +) { + // @performance Are we sure the data is nicely aligned? + // Probably depends on the from_txt function and the start of layout->data + UIElement* element = (UIElement *) (data + entry->value); + + **pos = element->state_flag; + *pos += sizeof(element->state_flag); + + **pos = element->type; + *pos += sizeof(element->type); + + **pos = element->style_old; + *pos += sizeof(element->style_old); + + **pos = element->style_new; + *pos += sizeof(element->style_new); + + *((uint32 *) *pos) = SWAP_ENDIAN_LITTLE(element->parent); + *pos += sizeof(element->parent); + + *((uint32 *) *pos) = SWAP_ENDIAN_LITTLE(element->state); + *pos += sizeof(element->state); + + // Details + for (int32 i = 0; i < UI_STYLE_TYPE_SIZE; ++i) { + *((uint32 *) *pos) = SWAP_ENDIAN_LITTLE(element->style_types[i]); + *pos += sizeof(element->style_types[i]); + } + + *((uint16 *) *pos) = SWAP_ENDIAN_LITTLE(element->children_count); + *pos += sizeof(element->children_count); + + /* We don't save the animation state since that is always 0 in the file + memset(*pos, 0, sizeof(element->animation_state)); + *pos += sizeof(element->animation_state); + */ + + *((uint16 *) *pos) = SWAP_ENDIAN_LITTLE(element->animation_count); + *pos += sizeof(element->animation_count); + + *((uint32 *) *pos) = SWAP_ENDIAN_LITTLE(element->animations); + *pos += sizeof(element->animations); + + *((uint16 *) *pos) = SWAP_ENDIAN_LITTLE(element->vertex_count); + *pos += sizeof(element->vertex_count); + + *((uint32 *) *pos) = SWAP_ENDIAN_LITTLE(element->vertices_active); + *pos += sizeof(element->vertices_active); + + // Output dynamic length content directly after UIElement + // + // WARNING: The data ordering in our output data is not necessarily the same as in memory ESPECIALLY for animations + // However, we can simply reconstruct the memory order by reversing the logic + // + // @todo We could optimize the memory layout of our data 9e.g. ->style_types, children, ... to be more packed + // At this point we may have this data available now (if we save a cached version = layout+theme) + // Obviously, this won't have an effect on the current run-tim but would make the memory layout nicer on the next load + // It would be kind of a self-optimizing ui layout system :). + // Of course, updating the reference values (uint32) will be challenging since the file pos will still not be the same as the offset due to alignment and padding + // We would probably need a helper_offset value that gets passed around also as parameter of this function + ////////////////////////////////////// + + // Children array + uint32* children = (uint32 *) (element + 1); + for (int32 i = 0; i < element->children_count; ++i) { + *((uint32 *) *pos) = SWAP_ENDIAN_LITTLE(children[i]); + *pos += sizeof(*children); + } + + // State element data e.g. UIInputState + ui_layout_serialize_element_state(element->type, data + element->state, pos); + + // detailed element data/style_types e.g. UIInput + // When you create a layout this is should only contain the default style type + // BUT we also support layout caching where a fully parsed layout+theme can be saved and loaded + // This is very fast since now we don't need to build the layout based on the theme as long as the theme and window dimensions didn't change + for (int32 i = 0; i < UI_STYLE_TYPE_SIZE; ++i) { + if (!element->style_types[i]) { + continue; + } + + ui_layout_serialize_element_detail(element->type, data + element->style_types[i], pos); + } + + UIAnimation* animations = (UIAnimation *) (data + element->animations); + int32 element_style_type_size = ui_element_type_size(element->type); + + for (int32 i = 0; i < element->animation_count; ++i) { + **pos = animations[i].style_old; + *pos += sizeof(animations[i].style_old); + + **pos = animations[i].style_new; + *pos += sizeof(animations[i].style_new); + + *((uint16 *) *pos) = SWAP_ENDIAN_LITTLE(animations[i].duration); + *pos += sizeof(animations[i].duration); + + **pos = animations[i].anim_type; + *pos += sizeof(animations[i].anim_type); + + **pos = animations[i].keyframe_count; + *pos += sizeof(animations[i].keyframe_count); + + // The keyframes are the element detail information (e.g. UIInput) and they are located after the respective Animation definition + byte* keyframes = (byte *) (&animations[i] + 1); + for (int32 j = 0; j < animations[i].keyframe_count; ++j) { + ui_layout_serialize_element_detail(element->type, keyframes + j * element_style_type_size, pos); + } + } +} + +int32 layout_to_data( + const UILayout* __restrict layout, + byte* __restrict data +) { + byte* pos = data; + byte* max_pos = data; + + // version + *((int32 *) pos) = SWAP_ENDIAN_LITTLE(UI_LAYOUT_VERSION); + pos += sizeof(int32); + + // hashmap + byte* start = pos; + pos += hashmap_dump(&layout->hash_map, pos); + + // UIElement data + for (uint32 i = 0; i < layout->hash_map.buf.count; ++i) { + HashEntryInt32* entry = (HashEntryInt32 *) hashmap_get_entry_by_index((HashMap *) &layout->hash_map, i); + if (!entry) { + continue; + } + + pos = start + entry->value; + ui_layout_serialize_element(entry, layout->data, &pos, start); + if (pos > max_pos) { + max_pos = pos; + } + + // save all the next elements + while (entry->next) { + pos = start + entry->value; + ui_layout_serialize_element(entry, layout->data, &pos, start); + if (pos > max_pos) { + max_pos = pos; + } + entry = (HashEntryInt32 *) hashmap_get_entry_by_element((HashMap *) &layout->hash_map, entry->next); + } + } + + return (int32) (max_pos - data); +} + +static +void ui_layout_unserialize_element_state(UIElementType type, void* __restrict state, const byte** __restrict pos) { + switch (type) { + case UI_ELEMENT_TYPE_INPUT: { + ui_input_state_unserialize((UIInputState *) state, pos); + } break; + } +} + +static +void ui_layout_unserialize_element_detail(UIElementType type, void* __restrict details, const byte** __restrict pos) { + switch (type) { + case UI_ELEMENT_TYPE_INPUT: { + ui_input_element_unserialize((UIInput *) details, pos); + } break; + } +} + +static +void ui_layout_parse_element(HashEntryInt32* entry, byte* data, const byte** pos) +{ + // @performance Are we sure the data is nicely aligned? + // Probably depends on the from_txt function and the start of layout->data + UIElement* element = (UIElement *) (data + entry->value); + + element->state_flag = **pos; + *pos += sizeof(element->state_flag); + + element->type = (UIElementType) **pos; + *pos += sizeof(element->type); + + element->style_old = (UIStyleType) **pos; + *pos += sizeof(element->style_old); + + element->style_new = (UIStyleType) **pos; + *pos += sizeof(element->style_new); + + element->parent = SWAP_ENDIAN_LITTLE(*((uint32 *) *pos)); + *pos += sizeof(element->parent); + + element->state = SWAP_ENDIAN_LITTLE(*((uint32 *) *pos)); + *pos += sizeof(element->state); + + // Details + for (int32 i = 0; i < UI_STYLE_TYPE_SIZE; ++i) { + element->style_types[i] = SWAP_ENDIAN_LITTLE(*((uint32 *) *pos)); + *pos += sizeof(element->style_types[i]); + } + + element->children_count = SWAP_ENDIAN_LITTLE(*((uint16 *) *pos)); + *pos += sizeof(element->children_count); + + // @question Do we really have to do that? Shouldn't the animation_state data be 0 anyways or could there be garbage values? + memset(&element->animation_state, 0, sizeof(element->animation_state)); + + element->animation_count = SWAP_ENDIAN_LITTLE(*((uint16 *) *pos)); + *pos += sizeof(element->animation_count); + + element->animations = SWAP_ENDIAN_LITTLE(*((uint32 *) *pos)); + *pos += sizeof(element->animations); + + element->vertex_count = SWAP_ENDIAN_LITTLE(*((uint16 *) *pos)); + *pos += sizeof(element->vertex_count); + + // @bug this needs to be changed? + element->vertices_active = SWAP_ENDIAN_LITTLE(*((uint32 *) *pos)); + *pos += sizeof(element->vertices_active); + + // Load dynamic length content + // Some of the content belongs directly after the element but some of it belongs at very specific offsets + // The reason for that is that the offsets are stored e.g. in element->state + // The memory is fragmented since a lot of the information is split up in different files (layout file and theme file) + // Therefor, we cannot create a nice memory layout when loading a layout+theme + // + // @question Can we optimize the memory layout to a less fragmented version? + // One solution could be to combine layout file and theme file. In that case we always know the correct element count + // Or see the serialization function for more comments + ////////////////////////////////////// + + // Children array + uint32* children = (uint32 *) (element + 1); + for (int32 i = 0; i < element->children_count; ++i) { + children[i] = SWAP_ENDIAN_LITTLE(*((uint32 *) *pos)); + *pos += sizeof(*children); + } + + // State element data e.g. UIInputState + ui_layout_unserialize_element_state(element->type, data + element->state, pos); + + // detailed element data/style_types e.g. UIInput + for (int32 i = 0; i < UI_STYLE_TYPE_SIZE; ++i) { + if (!element->style_types[i]) { + continue; + } + + ui_layout_unserialize_element_detail(element->type, data + element->style_types[i], pos); + } + + UIAnimation* animations = (UIAnimation *) (data + element->animations); + int32 element_style_type_size = ui_element_type_size(element->type); + + for (int32 i = 0; i < element->animation_count; ++i) { + animations[i].style_old = (UIStyleType) **pos; + *pos += sizeof(animations[i].style_old); + + animations[i].style_new = (UIStyleType) **pos; + *pos += sizeof(animations[i].style_new); + + animations[i].duration = SWAP_ENDIAN_LITTLE(*((uint16 *) *pos)); + *pos += sizeof(animations[i].duration); + + animations[i].anim_type = (AnimationEaseType) **pos; + *pos += sizeof(animations[i].anim_type); + + animations[i].keyframe_count = **pos; + *pos += sizeof(animations[i].keyframe_count); + + // The keyframes are the element detail information (e.g. UIInput) and they are located after the respective Animation definition + byte* keyframes = (byte *) (&animations[i] + 1); + for (int32 j = 0; j < animations[i].keyframe_count; ++j) { + ui_layout_unserialize_element_detail(element->type, keyframes + j * element_style_type_size, pos); + } + } +} + +// The size of layout->data should be the file size + a bunch of additional data for additional theme dependent "UIElements->style_types". +// Yes, this means we have a little too much data but not by a lot +int32 layout_from_data( + const byte* __restrict data, + UILayout* __restrict layout +) { + const byte* pos = data; + const byte* max_pos = pos; + + int32 version = *((int32 *) pos); + pos += sizeof(version); + + // Prepare hashmap (incl. reserve memory) by initializing it the same way we originally did + // Of course we still need to populate the data using hashmap_load() + hashmap_create(&layout->hash_map, (int32) SWAP_ENDIAN_LITTLE(*((uint32 *) pos)), sizeof(HashEntryInt32), layout->data); + + const byte* start = data; + pos += hashmap_load(&layout->hash_map, pos); + + // layout data + for (int32 i = 0; i < layout->hash_map.buf.count; ++i) { + HashEntryInt32* entry = (HashEntryInt32 *) hashmap_get_entry_by_index(&layout->hash_map, i); + if (!entry) { + continue; + } + + pos = start + entry->value; + ui_layout_parse_element(entry, layout->data, &pos); + if (pos > max_pos) { + max_pos = pos; + } + + // save all the next elements + while (entry->next) { + pos = start + entry->value; + ui_layout_parse_element(entry, layout->data, &pos); + if (pos > max_pos) { + max_pos = pos; + } + entry = (HashEntryInt32 *) hashmap_get_entry_by_element(&layout->hash_map, entry->next); + } + } + + layout->layout_size = (uint32) (max_pos - data); + + return (int32) layout->layout_size; +} + +// @performance Implement a way to only load a specific element and all its children +// This way we can re-load specific elements on change and we could also greatly reduce the setup time by ignoring ui elements that are rarely visible + +void layout_from_theme( + UILayout* __restrict layout, + const UIThemeStyle* __restrict theme, + const Camera* __restrict camera +) { + EvaluatorVariable variables[] = { + { "vw", (f32) camera->viewport_width }, + { "vh", (f32) camera->viewport_height }, + { "px", 0.0 }, // Placeholder for parent values + { "py", 0.0 }, // Placeholder for parent values + { "pw", 0.0 }, // Placeholder for parent values + { "ph", 0.0 }, // Placeholder for parent values + }; + + // @todo Handle animations + // @todo Handle vertices_active offset + + layout->font = theme->font; + + // Current position where we can the different sub elements (e.g. :hover, :active, ...) + // We make sure that the offset is a multiple of 8 bytes for better alignment + uint32 dynamic_pos = ROUND_TO_NEAREST(layout->layout_size, 8); + + // We first need to handle the default element -> iterate all elements but only handle the default style + for (int32 i = 0; i < theme->hash_map.buf.count; ++i) { + HashEntryInt32* style_entry = (HashEntryInt32 *) hashmap_get_entry_by_index((HashMap *) &theme->hash_map, i); + if (!style_entry) { + continue; + } + + // We don't handle special styles here, only the default one + if (strchr(style_entry->key, ':')) { + continue; + } + + HashEntryInt32* entry = (HashEntryInt32 *) hashmap_get_entry(&layout->hash_map, style_entry->key); + if (!entry) { + // Couldn't find the base element + continue; + } + + // Populate default element + UIElement* element = (UIElement *) (layout->data + entry->value); + UIAttributeGroup* group = (UIAttributeGroup *) (theme->data + style_entry->value); + UIElement* parent = element->parent ? (UIElement *) (layout->data + element->parent) : NULL; + + // @todo Continue implementation + switch (element->type) { + case UI_ELEMENT_TYPE_INPUT: { + ui_input_state_populate(group, (UIInputState *) (layout->data + element->state)); + ui_input_element_populate( + layout, + group, + (UIInput *) (layout->data + element->style_types[UI_STYLE_TYPE_DEFAULT]), + parent, + variables + ); + } break; + } + } + + // We iterate every style + // 1. Fill default element if it is default style + // 2. Create and fill new element if it isn't default style (e.g. :hover) + for (int32 i = 0; i < theme->hash_map.buf.count; ++i) { + HashEntryInt32* style_entry = (HashEntryInt32 *) hashmap_get_entry_by_index((HashMap *) &theme->hash_map, i); + if (!style_entry) { + continue; + } + + // We only handle special styles here, not the default one + char* special = strchr(style_entry->key, ':'); + if (!special) { + // The default element was already handled outside this loop + continue; + } + + UIStyleType style_type = (UIStyleType) ui_style_type_to_id(special); + + char pure_name[HASH_MAP_MAX_KEY_LENGTH]; + str_copy_until(style_entry->key, pure_name, ':'); + + HashEntryInt32* entry = (HashEntryInt32 *) hashmap_get_entry(&layout->hash_map, pure_name); + if (!entry) { + // Couldn't find the base element + continue; + } + + UIElement* element = (UIElement *) (layout->data + entry->value); + + // Doesn't exist (usually the first load, but exists when we resize our window) + if (!element->style_types[style_type]) { + element->style_types[style_type] = dynamic_pos; + dynamic_pos += ui_element_type_size(element->type); + } + + // The style inherits from the default style/element + memcpy( + layout->data + element->style_types[style_type], + layout->data + element->style_types[UI_STYLE_TYPE_DEFAULT], + ui_element_type_size(element->type) + ); + + // Populate element style_types + UIAttributeGroup* group = (UIAttributeGroup *) (theme->data + style_entry->value); + UIElement* parent = element->parent ? (UIElement *) (layout->data + element->parent) : NULL; + + // @todo Continue implementation + switch (element->type) { + case UI_ELEMENT_TYPE_INPUT: { + ui_input_element_populate( + layout, + group, + (UIInput *) (layout->data + element->style_types[style_type]), + parent, + variables + ); + } break; + } + } +} + +void ui_layout_update(UILayout* layout, UIElement* element) { + if (element->style_new != element->style_old + && (element->state_flag & UI_ELEMENT_STATE_CHANGED) + && (element->state_flag & UI_ELEMENT_STATE_ANIMATION) + ) { + // @todo Even if an animation is ongoing we might not want to update if the last step is < n ms ago + switch (element->type) { + case UI_ELEMENT_TYPE_BUTTON: { + + } break; + case UI_ELEMENT_TYPE_SELECT: { + + } break; + case UI_ELEMENT_TYPE_INPUT: { + ui_input_element_update(layout, element); + } break; + case UI_ELEMENT_TYPE_LABEL: { + ui_label_element_update(layout, element); + } break; + case UI_ELEMENT_TYPE_TEXT: { + + } break; + case UI_ELEMENT_TYPE_TEXTAREA: { + + } break; + case UI_ELEMENT_TYPE_IMAGE: { + + } break; + case UI_ELEMENT_TYPE_LINK: { + + } break; + case UI_ELEMENT_TYPE_TABLE: { + + } break; + case UI_ELEMENT_TYPE_VIEW_WINDOW: { + + } break; + case UI_ELEMENT_TYPE_VIEW_PANEL: { + + } break; + case UI_ELEMENT_TYPE_VIEW_TAB: { + + } break; + case UI_ELEMENT_TYPE_CURSOR: { + + } break; + default: + UNREACHABLE(); + } + } +} + +void ui_layout_update_dfs(UILayout* layout, UIElement* element, byte category = 0) { + if (element->category == category) { + ui_layout_update(layout, element); + } + + uint32* children = (uint32 *) (element + 1); + for (int32 i = 0; i < element->children_count; ++i) { + ui_layout_update(layout, (UIElement *) (layout->data + children[i])); + } +} + +uint32 ui_layout_render_dfs( + UILayout* layout, + UIElement* element, Vertex3DTextureColor* __restrict vertices, + byte category = 0 +) { + uint32 vertex_count = 0; + + if (element->category == category) { + memcpy(vertices, layout->vertices_active + element->vertices_active, sizeof(*vertices) * element->vertex_count); + vertices += element->vertex_count; + vertex_count += element->vertex_count; + } + + for (int32 i = 0; i < element->children_count; ++i) { + uint32 child_vertex_count = ui_layout_render_dfs(layout, element, vertices, category); + vertices += child_vertex_count; + vertex_count += child_vertex_count; + } + + return vertex_count; +} + +uint32 ui_layout_update_render_dfs( + UILayout* layout, + UIElement* __restrict element, Vertex3DTextureColor* __restrict vertices, + byte category = 0 +) { + uint32 vertex_count = 0; + + if (element->category == category) { + ui_layout_update(layout, element); + + memcpy(vertices, layout->vertices_active + element->vertices_active, sizeof(*vertices) * element->vertex_count); + vertices += element->vertex_count; + vertex_count += element->vertex_count; + } + + for (int32 i = 0; i < element->children_count; ++i) { + uint32 child_vertex_count = ui_layout_update_render_dfs(layout, element, vertices, category); + vertices += child_vertex_count; + vertex_count += child_vertex_count; + } + + return vertex_count; +} + +inline +uint32 layout_element_from_location(UILayout* layout, uint16 x, uint16 y) +{ + return layout->ui_chroma_codes[layout->width * y / 4 + x / 4]; +} + +#endif \ No newline at end of file diff --git a/ui/UILayout.h b/ui/UILayout.h index 7f894fe..1252263 100644 --- a/ui/UILayout.h +++ b/ui/UILayout.h @@ -5,13 +5,8 @@ #include "../stdlib/Types.h" #include "../stdlib/HashMap.h" #include "../asset/Asset.h" -#include "../camera/Camera.h" - -#include "../system/FileUtils.cpp" - -#include "UITheme.h" -#include "UIElement.h" -#include "UIElementType.h" +#include "../font/Font.h" +#include "../object/Vertex.h" #define UI_LAYOUT_VERSION 1 @@ -27,6 +22,9 @@ struct UILayout { // Contains all UI elements also dynamic ones (e.g. movable windows) uint32* ui_chroma_codes; + // @question Maybe we should have an array of fonts (e.g. allow up to 3 fonts per layout?) + Font* font; + // Used to directly find element by name // The values are pointers to the UIElements // @todo Should be a perfect hash map @@ -36,7 +34,7 @@ struct UILayout { // Only the size of the fixed layout, doesn't include the theme specific data uint32 layout_size; - // Total possible size + // Total possible size (hard limited to 4 GB) uint32 data_size; // Holds the ui elements @@ -44,11 +42,16 @@ struct UILayout { // 1. HashMap data (points to 2.a.) // 2. UIElements (default) // a. General UIElement - // b. Element specific state - // c. Element specific style + // b. Children array (uint32) + // c. Element specific state + // d. Element specific active style (very important for animations) + // e. Element specific default style (not the other styles) // 3. Additional UI styles (see c.), dynamically created when the theme is loaded // We effectively create a tree in data where the individual elements can get directly accessed through the hashmap - byte* data; + // WARNING: This memory is shared between different layouts + // 1. When we load a new layout we assign a temp memory buffer to this pointer + // 2. Once we are ready to switch the scene we copy the temporary memory into this data pointer + byte* data; // Owner of the actual data // Changes on a as needed basis uint32 vertex_size_static; @@ -67,527 +70,15 @@ struct UILayout { uint32 vertex_size; // @question Should we maybe also hold the font atlas asset here AND the color palette? + + // Cache for elements to be used for rendering + // This is very similar to the currently rendered UI output but may have some empty space between elements + // The reason for this is that some elements may need different vertex counts for different states (e.g. input field) + // WARNING: This memory is shared between different layouts + // @performance Maybe we could use this also for rendering by setting free vertices and elements currently hidden to 0 + // This would allow us to effectively remove the ui_asset + uint32 active_vertex_size; + Vertex3DTextureColor* vertices_active; // Not the data owner (see data above) }; -void count_direct_child_elements(UIElement* element, const char* pos, int32 parent_level) -{ - // Find amount of child elements - // We have to perform a lookahead since this determins the since this determines the size of our current element - uint16 direct_child_elements = 0; - - int32 level = 0; - while (*pos != '\0') { - while (*pos == ' ' || *pos == '\t') { - ++pos; - ++level; - } - - if (level > parent_level + 4) { - // This element is a childrens child and not a direct child - continue; - } else if (level <= parent_level) { - // We are no longer inside of element - break; - } - } - - element->children_count = direct_child_elements; -} - -void assign_child_elements(UILayout* layout, UIElement* element, char* pos, int32 parent_level) { - int32 current_child_pos = 0; - - char block_name[28]; - - int32 level = 0; - while (*pos != '\0') { - while (*pos == ' ' || *pos == '\t') { - ++pos; - ++level; - } - - if (level > parent_level + 4) { - // This element is a childrens child and not a direct child - continue; - } else if (level <= parent_level) { - // We are no longer inside of element - break; - } - - str_copy_move_until(&pos, block_name, ":"); - str_move_past(&pos, '\n'); - - element->children[current_child_pos] = (UIElement *) ( - layout->data - + ((HashEntryInt64 *) hashmap_get_entry(&layout->hash_map, block_name))->value - ); - - element->children[current_child_pos]->parent = element; - - ++current_child_pos; - } -} - -// WARNING: theme needs to have memory already reserved and assigned to data -void layout_from_file_txt( - UILayout* layout, - const char* path, - RingMemory* ring -) { - FileBody file; - file_read(path, &file, ring); - ASSERT_SIMPLE(file.size); - - char* pos = (char *) file.content; - - // move past the version string - pos += 8; - - // Use version for different handling - int32 version = strtol(pos, &pos, 10); ++pos; - - // 1. Iteration: We have to find how many elements are defined in the layout file. - // Therefore we have to do an initial iteration - int32 temp_element_count = 0; - while (*pos != '\0') { - // Skip all white spaces - str_skip_empty(&pos); - - ++temp_element_count; - - // Go to the next line - str_move_past(&pos, '\n'); - } - - // 2. Iteration: Fill HashMap - // @performance This is probably horrible since we are not using a perfect hashing function (1 hash -> 1 index) - // I wouldn't be surprised if we have a 50% hash overlap (2 hashes -> 1 index) - hashmap_create(&layout->hash_map, temp_element_count, sizeof(HashEntryVoidP), layout->data); - int64 hm_size = hashmap_size(&layout->hash_map); - - pos = (char *) file.content; - - // move past version string - str_move_past(&pos, '\n'); - - char block_name[28]; - char block_type[28]; - - byte* element_data = layout->data + hm_size; - - int32 level; - while (*pos != '\0') { - if (*pos == '\n') { - ++pos; - continue; - } - - level = 0; - while (*pos == ' ' || *pos == '\t') { - ++pos; - ++level; - } - - if (*pos == '\n' || *pos == '\0') { - continue; - } - - str_copy_move_until(&pos, block_name, ":"); ++pos; - str_copy_move_until(&pos, block_type, " \r\n"); - str_move_past(&pos, '\n'); - - UIElement* element = (UIElement *) element_data; - element->type = (UIElementType) ui_element_type_to_id(block_type); - element->children = (UIElement **) (element_data + sizeof(UIElement)); - count_direct_child_elements(element, pos, level); - - // Every UIElement can have child elements, we need to store the pointers to those elements - element_data += sizeof(UIElement) + sizeof(UIElement*) * element->children_count; - - // We also put the state data after this element - element->state = element_data; - element_data += ui_element_state_size(element->type); - - // We also put the default element data after this element - // Depending on the theme we will have also additional styles (e.g. :active, :hidden, ...) - element->details[0] = element_data; - - // @performance We should probably make sure the data is nicely aligned here - element_data += ui_element_type_size(element->type); - - // Insert new element - hashmap_insert(&layout->hash_map, block_name, element_data - layout->data); - } - - // 3. Iteration: Create child references - pos = (char *) file.content; - - // move past version string - str_move_past(&pos, '\n'); - - while (*pos != '\0') { - if (*pos == '\n') { - ++pos; - continue; - } - - level = 0; - while (*pos == ' ' || *pos == '\t') { - ++pos; - ++level; - } - - if (*pos == '\n' || *pos == '\0') { - continue; - } - - str_copy_move_until(&pos, block_name, ":"); - str_move_past(&pos, '\n'); - - UIElement* element = (UIElement *) (layout->data + ((HashEntryInt64 *) hashmap_get_entry(&layout->hash_map, block_name))->value); - assign_child_elements(layout, element, pos, level); - } -} - -static inline -void ui_layout_serialize_element(HashEntryInt64* entry, byte* data, byte** pos, const byte* start) -{ - // @performance Are we sure the data is nicely aligned? - // Probably depends on the from_txt function and the start of layout->data - UIElement* element = (UIElement *) (data + entry->value); - - **pos = element->state_flag; - *pos += sizeof(element->state_flag); - - **pos = element->type; - *pos += sizeof(element->type); - - **pos = element->style_old; - *pos += sizeof(element->style_old); - - **pos = element->style_new; - *pos += sizeof(element->style_new); - - // Parent - if (element->parent) { - *((uint64 *) *pos) = SWAP_ENDIAN_LITTLE((uint64) ((uintptr_t) element->parent - (uintptr_t) data)); - } else { - memset(*pos, 0, sizeof(uint64)); - } - - *pos += sizeof(uint64); - - // State - if (element->state) { - *((uint64 *) *pos) = SWAP_ENDIAN_LITTLE((uint64) ((uintptr_t) element->state - (uintptr_t) data)); - } else { - memset(*pos, 0, sizeof(uint64)); - } - - *pos += sizeof(uint64); - - // Details - for (int32 j = 0; j < UI_STYLE_TYPE_SIZE; ++j) { - if (element->details[j]) { - *((uint64 *) *pos) = SWAP_ENDIAN_LITTLE((uint64) ((uintptr_t) element->details[j] - (uintptr_t) data)); - } else { - memset(*pos, 0, sizeof(uint64)); - } - - *pos += sizeof(uint64); - } - - *((uint16 *) *pos) = SWAP_ENDIAN_LITTLE(element->children_count); - *pos += sizeof(element->children_count); - - for (int32 j = 0; j < element->children_count; ++j) { - *((uint64 *) *pos) = SWAP_ENDIAN_LITTLE((uint64) ((uintptr_t) element->children[j] - (uintptr_t) data)); - *pos += sizeof(uint64); - } - - // @performance, shouldn't it just be memset for both elements? - // state element data e.g. UIInputState - memcpy(*pos, element->state, ui_element_state_size(element->type)); - *pos += ui_element_state_size(element->type); - - // detailed element data e.g. UIInput - memcpy(*pos, element->details[0], ui_element_type_size(element->type)); - *pos += ui_element_type_size(element->type); -} - -int32 layout_to_data( - const UILayout* layout, - byte* data -) { - byte* pos = data; - byte* max_pos = data; - - // version - *((int32 *) pos) = SWAP_ENDIAN_LITTLE(UI_LAYOUT_VERSION); - pos += sizeof(int32); - - // hashmap - byte* start = pos; - pos += hashmap_dump(&layout->hash_map, pos); - - // UIElement data - for (uint32 i = 0; i < layout->hash_map.buf.count; ++i) { - if (!layout->hash_map.table[i]) { - continue; - } - - HashEntryInt64* entry = (HashEntryInt64 *) layout->hash_map.table[i]; - - pos = start + entry->value; - ui_layout_serialize_element(entry, layout->data, &pos, start); - if (pos > max_pos) { - max_pos = pos; - } - - // save all the next elements - while (entry->next) { - pos = start + entry->value; - ui_layout_serialize_element(entry, layout->data, &pos, start); - if (pos > max_pos) { - max_pos = pos; - } - entry = entry->next; - } - } - - return (int32) (max_pos - data); -} - -static inline -void ui_layout_parse_element(HashEntryInt64* entry, byte* data, const byte** pos) -{ - // @performance Are we sure the data is nicely aligned? - // Probably depends on the from_txt function and the start of layout->data - - // Change offset to pointer - entry->value = (uintptr_t) data + entry->value; - - UIElement* element = (UIElement *) entry->value; - - element->state_flag = **pos; - *pos += sizeof(element->state_flag); - - element->type = (UIElementType) **pos; - *pos += sizeof(element->type); - - element->style_old = (UIStyleType) **pos; - *pos += sizeof(element->style_old); - - element->style_new = (UIStyleType) **pos; - *pos += sizeof(element->style_new); - - // Parent - uint64 temp = SWAP_ENDIAN_LITTLE(*((uint64 *) *pos)); - element->parent = temp - ? (UIElement *) (data + temp) - : NULL; - - *pos += sizeof(uint64); - - // State - temp = SWAP_ENDIAN_LITTLE(*((uint64 *) *pos)); - element->state = temp - ? data + temp - : NULL; - - *pos += sizeof(uint64); - - // Details - for (int32 j = 0; j < UI_STYLE_TYPE_SIZE; ++j) { - temp = SWAP_ENDIAN_LITTLE(*((uint64 *) *pos)); - element->details[j] = temp - ? data + temp - : NULL; - - *pos += sizeof(uint64); - } - - element->children_count = SWAP_ENDIAN_LITTLE(*((uint16 *) *pos)); - *pos += sizeof(element->children_count); - - for (int32 j = 0; j < element->children_count; ++j) { - temp = SWAP_ENDIAN_LITTLE(*((uint64 *) *pos)); - element->children[j] = temp - ? (UIElement *) (data + temp) - : NULL; // this should never happen since the children_count only gets incremented if it has a child - - if (element->children[j]) { - element->children[j]->parent = element; - } - - *pos += sizeof(uint64); - } - - // @performance, shouldn't it just be memset for both elements? - // state element data e.g. UIInput - memcpy(element->state, *pos, ui_element_state_size(element->type)); - *pos += ui_element_state_size(element->type); - - // detailed element data e.g. UIInput - memcpy(element->details[0], *pos, ui_element_type_size(element->type)); - *pos += ui_element_type_size(element->type); -} - -// The size of layout->data should be the file size + a bunch of additional data for additional theme dependent "UIElements->details". -// Yes, this means we have a little too much data but not by a lot -int32 layout_from_data( - const byte* data, - UILayout* layout -) { - const byte* pos = data; - const byte* max_pos = pos; - - int32 version = *((int32 *) pos); - pos += sizeof(version); - - // Prepare hashmap (incl. reserve memory) by initializing it the same way we originally did - // Of course we still need to populate the data using hashmap_load() - // The value is a int64 (because this is the value of the chunk buffer size but the hashmap only allows int32) - hashmap_create(&layout->hash_map, (int32) SWAP_ENDIAN_LITTLE(*((uint64 *) pos)), sizeof(HashEntryInt64), layout->data); - - const byte* start = data; - pos += hashmap_load(&layout->hash_map, pos); - - // layout data - for (int32 i = 0; i < layout->hash_map.buf.count; ++i) { - if (!layout->hash_map.table[i]) { - continue; - } - - HashEntryInt64* entry = (HashEntryInt64 *) layout->hash_map.table[i]; - - pos = start + entry->value; - ui_layout_parse_element(entry, layout->data, &pos); - if (pos > max_pos) { - max_pos = pos; - } - - // save all the next elements - while (entry->next) { - pos = start + entry->value; - ui_layout_parse_element(entry, layout->data, &pos); - if (pos > max_pos) { - max_pos = pos; - } - entry = entry->next; - } - } - - layout->layout_size = (uint32) (max_pos - data); - - return (int32) layout->layout_size; -} - -// @performance Implement a way to only load a specific element and all its children -// This way we can re-load specific elements on change and we could also greatly reduce the setup time by ignoring ui elements that are rarely visible - -void layout_from_theme( - UILayout* layout, - const UIThemeStyle* theme, - const Camera* camera -) { - EvaluatorVariable variables[] = { - { "vw", (f32) camera->viewport_width }, - { "vh", (f32) camera->viewport_height }, - { "px", 0.0 }, // Placeholder for parent values - { "py", 0.0 }, // Placeholder for parent values - { "pw", 0.0 }, // Placeholder for parent values - { "ph", 0.0 }, // Placeholder for parent values - }; - - // Current position where we can the different sub elements (e.g. :hover, :active, ...) - byte* dynamic_pos = layout->data + layout->layout_size; - - // We first need to handle the default element -> iterate all elements but only handle the default style - // @todo do here - for (int32 i = 0; i < theme->hash_map.buf.count; ++i) { - if (!theme->hash_map.table[i]) { - continue; - } - - HashEntryUIntPtr* style_entry = (HashEntryUIntPtr *) theme->hash_map.table[i]; - - // We don't handle special styles here, only the default one - if (strchr(style_entry->key, ':')) { - continue; - } - - HashEntry* entry = hashmap_get_entry(&layout->hash_map, style_entry->key); - if (!entry) { - // Couldn't even find the base element - continue; - } - - // Populate default element - UIElement* element = (UIElement *) entry->value; - UIAttributeGroup* group = (UIAttributeGroup *) style_entry->value; - - switch (element->type) { - case UI_ELEMENT_TYPE_INPUT: { - ui_input_state_populate(group, (UIInputState *) element->state); - ui_input_element_populate(group, element, UI_STYLE_TYPE_DEFAULT, variables); - } break; - } - } - - // We iterate every style - // 1. Fill default element if it is default style - // 2. Create and fill new element if it isn't default style (e.g. :hover) - for (int32 i = 0; i < theme->hash_map.buf.count; ++i) { - if (!theme->hash_map.table[i]) { - continue; - } - - HashEntryUIntPtr* style_entry = (HashEntryUIntPtr *) theme->hash_map.table[i]; - - // We only handle special styles here, not the default one - char* special = strchr(style_entry->key, ':'); - if (!special) { - // The default element was already handled outside this loop - continue; - } - - UIStyleType style_type = (UIStyleType) ui_style_type_to_id(special); - - char pure_name[HASH_MAP_MAX_KEY_LENGTH]; - str_copy_until(style_entry->key, pure_name, ':'); - - HashEntry* entry = hashmap_get_entry(&layout->hash_map, pure_name); - if (!entry) { - // Couldn't even find the base element - continue; - } - - UIElement* element = (UIElement *) entry->value; - - // Doesn't exist (usually the first load, but exists when we resize our window) - if (!element->details[style_type]) { - element->details[style_type] = dynamic_pos; - dynamic_pos += ui_element_type_size(element->type); - } - - // The style inherits from the default element - memcpy(element->details[style_type], element->details[0], ui_element_type_size(element->type)); - - // Populate element details - UIAttributeGroup* group = (UIAttributeGroup *) style_entry->value; - switch (element->type) { - case UI_ELEMENT_TYPE_INPUT: { - ui_input_element_populate(group, element, style_type, variables); - } break; - } - } -} - -inline -uint32 layout_element_from_location(UILayout* layout, uint16 x, uint16 y) -{ - return layout->ui_chroma_codes[layout->width * y / 4 + x / 4]; -} - #endif \ No newline at end of file diff --git a/ui/UIPanel.h b/ui/UIPanel.h index eb2d872..dc04112 100644 --- a/ui/UIPanel.h +++ b/ui/UIPanel.h @@ -2,12 +2,13 @@ #define TOS_UI_PANEL_H #include "../stdlib/Types.h" +#include "attribute/UIAttributeDimension.h" struct UIPanelState { }; struct UIPanel { - + UIAttributeDimension dimension; }; #endif \ No newline at end of file diff --git a/ui/UIStyleType.h b/ui/UIStyleType.h index 0bb5a40..0b1074a 100644 --- a/ui/UIStyleType.h +++ b/ui/UIStyleType.h @@ -4,9 +4,14 @@ #include "../stdlib/Types.h" enum UIStyleType : byte { - UI_STYLE_TYPE_DEFAULT, // = :visible - UI_STYLE_TYPE_HIDDEN, - UI_STYLE_TYPE_ACTIVE, // e.g. input + // This can be the same as one of the style_types below but doesn't have to be + // The most common situation where this is different is for animations + // In case of animations we often perform interpolations so the active style is different from ANY defined style since it is dynamically calculated based on the time + UI_STYLE_TYPE_ACTIVE, + + UI_STYLE_TYPE_DEFAULT, + UI_STYLE_TYPE_HIDDEN, // e.g. useful as starting position for slide-in/blend-in etc. animations + UI_STYLE_TYPE_FOCUS, // e.g. input UI_STYLE_TYPE_DISABLED, // disabled form elements UI_STYLE_TYPE_HOVER, // e.g. button UI_STYLE_TYPE_MANUAL, @@ -16,19 +21,19 @@ enum UIStyleType : byte { constexpr int32 ui_style_type_to_id(const char* str) { - if (str_compare(":hidden", str) == 0) { + if (*str == '\0') { + return UI_STYLE_TYPE_DEFAULT; + } else if (str_compare(":hid", str, 4) == 0) { return UI_STYLE_TYPE_HIDDEN; - } else if (str_compare(":active", str) == 0) { - return UI_STYLE_TYPE_ACTIVE; - } else if (str_compare(":diabled", str) == 0) { + } else if (str_compare(":foc", str, 4) == 0) { + return UI_STYLE_TYPE_FOCUS; + } else if (str_compare(":dis", str, 4) == 0) { return UI_STYLE_TYPE_DISABLED; - } else if (str_compare(":hover", str) == 0) { + } else if (str_compare(":hov", str, 4) == 0) { return UI_STYLE_TYPE_HOVER; - } else if (str_compare(":manual", str) == 0) { + } else { return UI_STYLE_TYPE_MANUAL; } - - return -1; } #endif \ No newline at end of file diff --git a/ui/UITheme.h b/ui/UITheme.h index 485c89d..bf2d117 100644 --- a/ui/UITheme.h +++ b/ui/UITheme.h @@ -24,34 +24,37 @@ struct UIThemeStyle { // The hashmap contains the offset where the respective style can be found // @performance Switch to perfect hash map HashMap hash_map; + + uint32 data_size; byte* data; - // It feels weird that this is here, especially considering we could have multiple fonts + // @question It feels weird that this is here, especially considering we could have multiple fonts + // Maybe we should have an array of fonts (e.g. allow up to 3 fonts per theme?) Font* font; }; inline UIAttributeGroup* theme_style_group(UIThemeStyle* theme, const char* group_name) { - HashEntryInt64* entry = (HashEntryInt64 *) hashmap_get_entry(&theme->hash_map, group_name); + HashEntryInt32* entry = (HashEntryInt32 *) hashmap_get_entry(&theme->hash_map, group_name); if (!entry) { ASSERT_SIMPLE(false); return NULL; } - return (UIAttributeGroup *) entry->value; + return (UIAttributeGroup *) (theme->data + entry->value); } inline UIAttributeGroup* theme_style_group(UIThemeStyle* theme, const char* group_name, int32 group_id) { - HashEntryInt64* entry = (HashEntryInt64 *) hashmap_get_entry(&theme->hash_map, group_name, group_id); + HashEntryInt32* entry = (HashEntryInt32 *) hashmap_get_entry(&theme->hash_map, group_name, group_id); if (!entry) { ASSERT_SIMPLE(false); return NULL; } - return (UIAttributeGroup *) entry->value; + return (UIAttributeGroup *) (theme->data + entry->value); } static inline @@ -83,13 +86,13 @@ void theme_from_file_txt( file_read(path, &file, ring); ASSERT_SIMPLE(file.size); - char* pos = (char *) file.content; + const char* pos = (char *) file.content; // move past the version string pos += 8; // Use version for different handling - int32 version = strtol(pos, &pos, 10); ++pos; + int32 version = strtol(pos, (char **) &pos, 10); ++pos; // We have to find how many groups are defined in the theme file. // Therefore we have to do an initial iteration @@ -109,7 +112,7 @@ void theme_from_file_txt( // @performance This is probably horrible since we are not using a perfect hashing function (1 hash -> 1 index) // I wouldn't be surprised if we have a 50% hash overlap (2 hashes -> 1 index) - hashmap_create(&theme->hash_map, temp_group_count, sizeof(HashEntryInt64), theme->data); + hashmap_create(&theme->hash_map, temp_group_count, sizeof(HashEntryInt32), theme->data); int64 data_offset = hashmap_size(&theme->hash_map); UIAttributeGroup* temp_group = NULL; @@ -153,15 +156,14 @@ void theme_from_file_txt( if (temp_group) { // Before we insert a new group we have to sort the attributes // since this makes searching them later on more efficient. - qsort(temp_group->attributes, temp_group->attribute_size, sizeof(UIAttribute), compare_by_attribute_id); + qsort(temp_group + 1, temp_group->attribute_count, sizeof(UIAttribute), compare_by_attribute_id); } // Insert new group hashmap_insert(&theme->hash_map, block_name, data_offset); temp_group = (UIAttributeGroup *) (theme->data + data_offset); - temp_group->attribute_size = 0; - temp_group->attributes = (UIAttribute *) (theme->data + data_offset + sizeof(UIAttributeGroup)); + temp_group->attribute_count = 0; data_offset += sizeof(UIAttributeGroup); } @@ -182,65 +184,65 @@ void theme_from_file_txt( // Again, currently this if check is redundant but it wasn't in the past and we may need it again in the future. if (block_name[0] == '#' || block_name[0] == '.') { // Named block + UIAttribute* attribute_reference = (UIAttribute *) (temp_group + 1); memcpy( - temp_group->attributes + temp_group->attribute_size, + attribute_reference + temp_group->attribute_count, &attribute, sizeof(attribute) ); data_offset += sizeof(attribute); - ++temp_group->attribute_size; + ++temp_group->attribute_count; } str_move_to(&pos, '\n'); } // We still need to sort the last group - qsort(temp_group->attributes, temp_group->attribute_size, sizeof(UIAttribute), compare_by_attribute_id); + qsort(temp_group + 1, temp_group->attribute_count, sizeof(UIAttribute), compare_by_attribute_id); } static inline -void ui_theme_parse_group(HashEntryInt64* entry, byte* data, const byte** pos) +void ui_theme_parse_group(HashEntryInt32* entry, byte* data, const byte** pos) { // @performance Are we sure the data is nicely aligned? // Probably depends on the from_txt function and the start of theme->data - // Change offset to pointer - entry->value = (uintptr_t) data + entry->value; + UIAttributeGroup* group = (UIAttributeGroup *) data + entry->value; - UIAttributeGroup* group = (UIAttributeGroup *) entry->value; + group->attribute_count = SWAP_ENDIAN_LITTLE(*((int32 *) *pos)); + *pos += sizeof(group->attribute_count); - group->attribute_size = SWAP_ENDIAN_LITTLE(*((int32 *) *pos)); - *pos += sizeof(group->attribute_size); + UIAttribute* attribute_reference = (UIAttribute *) (group + 1); - for (uint32 j = 0; j < group->attribute_size; ++j) { - group->attributes[j].attribute_id = (UIAttributeType) SWAP_ENDIAN_LITTLE(*((uint16 *) *pos)); - *pos += sizeof(group->attributes[j].attribute_id); + for (uint32 j = 0; j < group->attribute_count; ++j) { + attribute_reference[j].attribute_id = (UIAttributeType) SWAP_ENDIAN_LITTLE(*((uint16 *) *pos)); + *pos += sizeof(attribute_reference[j].attribute_id); - group->attributes[j].datatype = *((UIAttributeDataType *) *pos); - *pos += sizeof(group->attributes[j].datatype); + attribute_reference[j].datatype = *((UIAttributeDataType *) *pos); + *pos += sizeof(attribute_reference[j].datatype); - if (group->attributes[j].datatype == UI_ATTRIBUTE_DATA_TYPE_INT) { - group->attributes[j].value_int = SWAP_ENDIAN_LITTLE(*((int32 *) *pos)); - *pos += sizeof(group->attributes[j].value_int); - } else if (group->attributes[j].datatype == UI_ATTRIBUTE_DATA_TYPE_INT) { - group->attributes[j].value_float = SWAP_ENDIAN_LITTLE(*((f32 *) *pos)); - *pos += sizeof(group->attributes[j].value_float); - } else if (group->attributes[j].datatype == UI_ATTRIBUTE_DATA_TYPE_STR) { - memcpy(group->attributes[j].value_str, *pos, sizeof(group->attributes[j].value_str)); - *pos += sizeof(group->attributes[j].value_str); - } else if (group->attributes[j].datatype == UI_ATTRIBUTE_DATA_TYPE_V4_F32) { - group->attributes[j].value_v4_f32.x = SWAP_ENDIAN_LITTLE(*((f32 *) *pos)); - *pos += sizeof(group->attributes[j].value_v4_f32.x); + if (attribute_reference[j].datatype == UI_ATTRIBUTE_DATA_TYPE_INT) { + attribute_reference[j].value_int = SWAP_ENDIAN_LITTLE(*((int32 *) *pos)); + *pos += sizeof(attribute_reference[j].value_int); + } else if (attribute_reference[j].datatype == UI_ATTRIBUTE_DATA_TYPE_INT) { + attribute_reference[j].value_float = SWAP_ENDIAN_LITTLE(*((f32 *) *pos)); + *pos += sizeof(attribute_reference[j].value_float); + } else if (attribute_reference[j].datatype == UI_ATTRIBUTE_DATA_TYPE_STR) { + memcpy(attribute_reference[j].value_str, *pos, sizeof(attribute_reference[j].value_str)); + *pos += sizeof(attribute_reference[j].value_str); + } else if (attribute_reference[j].datatype == UI_ATTRIBUTE_DATA_TYPE_V4_F32) { + attribute_reference[j].value_v4_f32.x = SWAP_ENDIAN_LITTLE(*((f32 *) *pos)); + *pos += sizeof(attribute_reference[j].value_v4_f32.x); - group->attributes[j].value_v4_f32.y = SWAP_ENDIAN_LITTLE(*((f32 *) *pos)); - *pos += sizeof(group->attributes[j].value_v4_f32.y); + attribute_reference[j].value_v4_f32.y = SWAP_ENDIAN_LITTLE(*((f32 *) *pos)); + *pos += sizeof(attribute_reference[j].value_v4_f32.y); - group->attributes[j].value_v4_f32.z = SWAP_ENDIAN_LITTLE(*((f32 *) *pos)); - *pos += sizeof(group->attributes[j].value_v4_f32.z); + attribute_reference[j].value_v4_f32.z = SWAP_ENDIAN_LITTLE(*((f32 *) *pos)); + *pos += sizeof(attribute_reference[j].value_v4_f32.z); - group->attributes[j].value_v4_f32.w = SWAP_ENDIAN_LITTLE(*((f32 *) *pos)); - *pos += sizeof(group->attributes[j].value_v4_f32.w); + attribute_reference[j].value_v4_f32.w = SWAP_ENDIAN_LITTLE(*((f32 *) *pos)); + *pos += sizeof(attribute_reference[j].value_v4_f32.w); } } } @@ -261,8 +263,8 @@ void ui_theme_parse_group(HashEntryInt64* entry, byte* data, const byte** pos) // The size of theme->data should be the file size. // Yes, this means we have a little too much data but not by a lot int32 theme_from_data( - const byte* data, - UIThemeStyle* theme + const byte* __restrict data, + UIThemeStyle* __restrict theme ) { const byte* pos = data; const byte* max_pos = data; @@ -273,7 +275,7 @@ int32 theme_from_data( // Prepare hashmap (incl. reserve memory) by initializing it the same way we originally did // Of course we still need to populate the data using hashmap_load() // The value is a int64 (because this is the value of the chunk buffer size but the hashmap only allows int32) - hashmap_create(&theme->hash_map, (int32) SWAP_ENDIAN_LITTLE(*((uint64 *) pos)), sizeof(HashEntryInt64), theme->data); + hashmap_create(&theme->hash_map, (int32) SWAP_ENDIAN_LITTLE(*((uint32 *) pos)), sizeof(HashEntryInt32), theme->data); const byte* start = theme->hash_map.buf.memory; pos += hashmap_load(&theme->hash_map, pos); @@ -281,12 +283,11 @@ int32 theme_from_data( // theme data // Layout: first load the size of the group, then load the individual attributes for (int32 i = 0; i < theme->hash_map.buf.count; ++i) { - if (!theme->hash_map.table[i]) { + HashEntryInt32* entry = (HashEntryInt32 *) hashmap_get_entry_by_index((HashMap *) &theme->hash_map, i); + if (!entry) { continue; } - HashEntryInt64* entry = (HashEntryInt64 *) theme->hash_map.table[i]; - // This way we now could access the data directly without the silly theme->data + entry->value calc. pos = start + entry->value; ui_theme_parse_group(entry, theme->data, &pos); @@ -301,7 +302,7 @@ int32 theme_from_data( if (pos > max_pos) { max_pos = pos; } - entry = entry->next; + entry = (HashEntryInt32 *) hashmap_get_entry_by_element((HashMap *) &theme->hash_map, entry->next); } } @@ -312,7 +313,7 @@ int32 theme_from_data( // Not every group has all the attributes (most likely only a small subset) // However, an accurate calculation is probably too slow and not needed most of the time inline -int64 theme_data_size(const UIThemeStyle* theme) +int64 theme_data_size_max(const UIThemeStyle* theme) { return hashmap_size(&theme->hash_map) + theme->hash_map.buf.count * UI_ATTRIBUTE_TYPE_SIZE * sizeof(UIAttribute); @@ -320,43 +321,45 @@ int64 theme_data_size(const UIThemeStyle* theme) // @todo Why do even need **pos, shouldn't it just be *pos static inline -void ui_theme_serialize_group(HashEntryInt64* entry, byte* data, byte** pos, const byte* start) +void ui_theme_serialize_group(const HashEntryInt32* entry, byte* data, byte** pos, const byte* start) { // @performance Are we sure the data is nicely aligned? // Probably depends on the from_txt function and the start of theme->data UIAttributeGroup* group = (UIAttributeGroup *) (data + entry->value); - *((int32 *) *pos) = SWAP_ENDIAN_LITTLE(group->attribute_size); - *pos += sizeof(group->attribute_size); + *((int32 *) *pos) = SWAP_ENDIAN_LITTLE(group->attribute_count); + *pos += sizeof(group->attribute_count); - for (uint32 j = 0; j < group->attribute_size; ++j) { - *((uint16 *) *pos) = SWAP_ENDIAN_LITTLE(group->attributes[j].attribute_id); - *pos += sizeof(group->attributes[j].attribute_id); + UIAttribute* attribute_reference = (UIAttribute *) (group + 1); - *((byte *) *pos) = group->attributes[j].datatype; - *pos += sizeof(group->attributes[j].datatype); + for (uint32 j = 0; j < group->attribute_count; ++j) { + *((uint16 *) *pos) = SWAP_ENDIAN_LITTLE(attribute_reference[j].attribute_id); + *pos += sizeof(attribute_reference[j].attribute_id); - if (group->attributes[j].datatype == UI_ATTRIBUTE_DATA_TYPE_INT) { - *((int32 *) *pos) = SWAP_ENDIAN_LITTLE(group->attributes[j].value_int); - *pos += sizeof(group->attributes[j].value_int); - } else if (group->attributes[j].datatype == UI_ATTRIBUTE_DATA_TYPE_INT) { - *((f32 *) *pos) = SWAP_ENDIAN_LITTLE(group->attributes[j].value_float); - *pos += sizeof(group->attributes[j].value_float); - } else if (group->attributes[j].datatype == UI_ATTRIBUTE_DATA_TYPE_STR) { - memcpy(*pos, group->attributes[j].value_str, sizeof(group->attributes[j].value_str)); - *pos += sizeof(group->attributes[j].value_str); - } else if (group->attributes[j].datatype == UI_ATTRIBUTE_DATA_TYPE_V4_F32) { - *((f32 *) *pos) = SWAP_ENDIAN_LITTLE(group->attributes[j].value_v4_f32.x); - *pos += sizeof(group->attributes[j].value_v4_f32.x); + *((byte *) *pos) = attribute_reference[j].datatype; + *pos += sizeof(attribute_reference[j].datatype); - *((f32 *) *pos) = SWAP_ENDIAN_LITTLE(group->attributes[j].value_v4_f32.y); - *pos += sizeof(group->attributes[j].value_v4_f32.y); + if (attribute_reference[j].datatype == UI_ATTRIBUTE_DATA_TYPE_INT) { + *((int32 *) *pos) = SWAP_ENDIAN_LITTLE(attribute_reference[j].value_int); + *pos += sizeof(attribute_reference[j].value_int); + } else if (attribute_reference[j].datatype == UI_ATTRIBUTE_DATA_TYPE_INT) { + *((f32 *) *pos) = SWAP_ENDIAN_LITTLE(attribute_reference[j].value_float); + *pos += sizeof(attribute_reference[j].value_float); + } else if (attribute_reference[j].datatype == UI_ATTRIBUTE_DATA_TYPE_STR) { + memcpy(*pos, attribute_reference[j].value_str, sizeof(attribute_reference[j].value_str)); + *pos += sizeof(attribute_reference[j].value_str); + } else if (attribute_reference[j].datatype == UI_ATTRIBUTE_DATA_TYPE_V4_F32) { + *((f32 *) *pos) = SWAP_ENDIAN_LITTLE(attribute_reference[j].value_v4_f32.x); + *pos += sizeof(attribute_reference[j].value_v4_f32.x); - *((f32 *) *pos) = SWAP_ENDIAN_LITTLE(group->attributes[j].value_v4_f32.z); - *pos += sizeof(group->attributes[j].value_v4_f32.z); + *((f32 *) *pos) = SWAP_ENDIAN_LITTLE(attribute_reference[j].value_v4_f32.y); + *pos += sizeof(attribute_reference[j].value_v4_f32.y); - *((f32 *) *pos) = SWAP_ENDIAN_LITTLE(group->attributes[j].value_v4_f32.w); - *pos += sizeof(group->attributes[j].value_v4_f32.w); + *((f32 *) *pos) = SWAP_ENDIAN_LITTLE(attribute_reference[j].value_v4_f32.z); + *pos += sizeof(attribute_reference[j].value_v4_f32.z); + + *((f32 *) *pos) = SWAP_ENDIAN_LITTLE(attribute_reference[j].value_v4_f32.w); + *pos += sizeof(attribute_reference[j].value_v4_f32.w); } } } @@ -377,8 +380,8 @@ void ui_theme_serialize_group(HashEntryInt64* entry, byte* data, byte** pos, con // attributes ... int32 theme_to_data( - const UIThemeStyle* theme, - byte* data + const UIThemeStyle* __restrict theme, + byte* __restrict data ) { byte* pos = data; byte* max_pos = data; @@ -394,12 +397,11 @@ int32 theme_to_data( // theme data // Layout: first save the size of the group, then save the individual attributes for (uint32 i = 0; i < theme->hash_map.buf.count; ++i) { - if (!theme->hash_map.table[i]) { + const HashEntryInt32* entry = (HashEntryInt32 *) hashmap_get_entry_by_index((HashMap *) &theme->hash_map, i); + if (!entry) { continue; } - HashEntryInt64* entry = (HashEntryInt64 *) theme->hash_map.table[i]; - pos = start + entry->value; ui_theme_serialize_group(entry, theme->data, &pos, start); if (pos > max_pos) { @@ -413,7 +415,7 @@ int32 theme_to_data( if (pos > max_pos) { max_pos = pos; } - entry = entry->next; + entry = (HashEntryInt32 *) hashmap_get_entry_by_element((HashMap *) &theme->hash_map, entry->next); } } diff --git a/ui/UIWindow.h b/ui/UIWindow.h index 014a285..1feb77b 100644 --- a/ui/UIWindow.h +++ b/ui/UIWindow.h @@ -6,6 +6,7 @@ #include "attribute/UIAttributeShadow.h" #include "attribute/UIAttributeFont.h" #include "attribute/UIAttributeBackground.h" +#include "attribute/UIAttributeDimension.h" #include "UIAnimation.h" #include "UIStyleType.h" @@ -13,7 +14,7 @@ struct UIWindowState { }; struct UIWindow { - v4_int16 dimension; + UIAttributeDimension dimension; UIAnimation animation; byte padding; byte alignment; diff --git a/ui/attribute/UIAttribute.h b/ui/attribute/UIAttribute.h index 736f221..f7a3267 100644 --- a/ui/attribute/UIAttribute.h +++ b/ui/attribute/UIAttribute.h @@ -4,6 +4,7 @@ #include "../../stdlib/Types.h" #include "../../utils/StringUtils.h" #include "../../math/Evaluator.h" +#include "../../compiler/CompilerUtils.h" #include "UIAttributeType.h" #include "UIAttributeDimension.h" @@ -29,27 +30,31 @@ struct UIAttribute { }; struct UIAttributeGroup { - int32 attribute_size; - UIAttribute* attributes; + int32 attribute_count; + // We don't use a pointer since this would prevent us from copying around the main data owner + // The UIAttribute values come directly after UIAttributeGroup (e.g. group + 1 in memory) + //UIAttribute* attributes; }; UIAttribute* ui_attribute_from_group(UIAttributeGroup* group, UIAttributeType type) { - if (!group->attributes) { + if (!group->attribute_count) { return NULL; } int32 left = 0; int32 right = type; + UIAttribute* attributes = (UIAttribute *) (group + 1); + // Binary search since attributes are sorted by attribute_id // @performance Consider Eytzinger while (left <= right) { int32 mid = left + (right - left) / 2; - if (group->attributes[mid].attribute_id == type) { - return &group->attributes[mid]; - } else if (group->attributes[mid].attribute_id < type) { + if (attributes[mid].attribute_id == type) { + return &attributes[mid]; + } else if (attributes[mid].attribute_id < type) { left = mid + 1; } else { right = mid - 1; @@ -70,6 +75,8 @@ int32 ui_attribute_type_to_id(const char* attribute_name) return UI_ATTRIBUTE_TYPE_DIMENSION_WIDTH; } else if (str_compare(attribute_name, "height") == 0) { return UI_ATTRIBUTE_TYPE_DIMENSION_HEIGHT; + } else if (str_compare(attribute_name, "overflow") == 0) { + return UI_ATTRIBUTE_TYPE_DIMENSION_OVERFLOW; } else if (str_compare(attribute_name, "font_name") == 0) { return UI_ATTRIBUTE_TYPE_FONT_NAME; } else if (str_compare(attribute_name, "font_color") == 0) { diff --git a/ui/attribute/UIAttributeBackground.h b/ui/attribute/UIAttributeBackground.h index 3575447..87e10fa 100644 --- a/ui/attribute/UIAttributeBackground.h +++ b/ui/attribute/UIAttributeBackground.h @@ -13,9 +13,29 @@ enum UIBackgroundStyle : byte { struct UIAttributeBackground { UIBackgroundStyle background_style; union { - void* background_image; + uint32 background_image; uint32 background_color; }; }; +inline +void ui_attr_background_serialize(const UIAttributeBackground* __restrict bg, byte** __restrict pos) +{ + **pos = bg->background_style; + *pos += sizeof(bg->background_style); + + *((uint32 *) *pos) = SWAP_ENDIAN_LITTLE(bg->background_color); + *pos += sizeof(bg->background_color); +} + +inline +void ui_attr_background_unserialize(UIAttributeBackground* __restrict bg, const byte** __restrict pos) +{ + bg->background_style = (UIBackgroundStyle) **pos; + *pos += sizeof(bg->background_style); + + bg->background_color = SWAP_ENDIAN_LITTLE(*((uint32 *) *pos)); + *pos += sizeof(bg->background_color); +} + #endif \ No newline at end of file diff --git a/ui/attribute/UIAttributeBorder.h b/ui/attribute/UIAttributeBorder.h index f2d78d5..4892e79 100644 --- a/ui/attribute/UIAttributeBorder.h +++ b/ui/attribute/UIAttributeBorder.h @@ -9,4 +9,24 @@ struct UIAttributeBorder { uint32 color; }; +inline +void ui_attr_border_serialize(const UIAttributeBorder* __restrict border, byte** __restrict pos) +{ + *((uint16 *) *pos) = SWAP_ENDIAN_LITTLE(border->thickness); + *pos += sizeof(border->thickness); + + *((uint32 *) *pos) = SWAP_ENDIAN_LITTLE(border->color); + *pos += sizeof(border->color); +} + +inline +void ui_attr_border_unserialize(UIAttributeBorder* __restrict border, const byte** __restrict pos) +{ + border->thickness = SWAP_ENDIAN_LITTLE(*((uint16 *) *pos)); + *pos += sizeof(border->thickness); + + border->color = SWAP_ENDIAN_LITTLE(*((uint32 *) *pos)); + *pos += sizeof(border->color); +} + #endif \ No newline at end of file diff --git a/ui/attribute/UIAttributeDimension.h b/ui/attribute/UIAttributeDimension.h index 07a8929..267dae1 100644 --- a/ui/attribute/UIAttributeDimension.h +++ b/ui/attribute/UIAttributeDimension.h @@ -53,4 +53,34 @@ struct UIAttributeDimension { */ }; +inline +void ui_attr_dimension_serialize(const UIAttributeDimension* __restrict dim, byte** __restrict pos) +{ + **pos = dim->flag; + *pos += sizeof(dim->flag); + + **pos = dim->alignment; + *pos += sizeof(dim->alignment); + + for (int32 i = 0; i < 4; ++i) { + *((f32 *) *pos) = SWAP_ENDIAN_LITTLE(dim->dimension.vec[i]); + *pos += sizeof(dim->dimension.vec[i]); + } +} + +inline +void ui_attr_dimension_unserialize(UIAttributeDimension* __restrict dim, const byte** __restrict pos) +{ + dim->flag = **pos; + *pos += sizeof(dim->flag); + + dim->alignment = **pos; + *pos += sizeof(dim->alignment); + + for (int32 i = 0; i < 4; ++i) { + dim->dimension.vec[i] = SWAP_ENDIAN_LITTLE(*((f32 *) *pos)); + *pos += sizeof(dim->dimension.vec[i]); + } +} + #endif \ No newline at end of file diff --git a/ui/attribute/UIAttributeFont.h b/ui/attribute/UIAttributeFont.h index 5844c43..0132cdb 100644 --- a/ui/attribute/UIAttributeFont.h +++ b/ui/attribute/UIAttributeFont.h @@ -14,6 +14,7 @@ struct UIAttributeFont { f32 weight; UIAttributeShadow shadow_outer; byte decoration; + byte alignment; // @todo family? }; diff --git a/ui/attribute/UIAttributeShadow.h b/ui/attribute/UIAttributeShadow.h index 4e4e400..6d2fbe4 100644 --- a/ui/attribute/UIAttributeShadow.h +++ b/ui/attribute/UIAttributeShadow.h @@ -10,4 +10,36 @@ struct UIAttributeShadow { byte offset; }; +inline +void ui_attr_shadow_serialize(const UIAttributeShadow* __restrict shadow, byte** __restrict pos) +{ + *((f32 *) *pos) = SWAP_ENDIAN_LITTLE(shadow->angle); + *pos += sizeof(shadow->angle); + + *((uint32 *) *pos) = SWAP_ENDIAN_LITTLE(shadow->color); + *pos += sizeof(shadow->color); + + **pos = shadow->fade; + *pos += sizeof(shadow->fade); + + **pos = shadow->offset; + *pos += sizeof(shadow->offset); +} + +inline +void ui_attr_shadow_unserialize(UIAttributeShadow* __restrict shadow, const byte** __restrict pos) +{ + shadow->angle = SWAP_ENDIAN_LITTLE(*((f32 *) *pos)); + *pos += sizeof(shadow->angle); + + shadow->color = SWAP_ENDIAN_LITTLE(*((uint32 *) *pos)); + *pos += sizeof(shadow->color); + + shadow->fade = **pos; + *pos += sizeof(shadow->fade); + + shadow->offset = **pos; + *pos += sizeof(shadow->offset); +} + #endif \ No newline at end of file diff --git a/ui/attribute/UIAttributeType.h b/ui/attribute/UIAttributeType.h index 34f9ed8..1ee571b 100644 --- a/ui/attribute/UIAttributeType.h +++ b/ui/attribute/UIAttributeType.h @@ -17,6 +17,10 @@ enum UIAttributeType : uint16 { UI_ATTRIBUTE_TYPE_DIMENSION_WIDTH, UI_ATTRIBUTE_TYPE_DIMENSION_HEIGHT, + // Allows elements to overflow their parent while still positioned relative to their parent element + // e.g. Text in a button (e.g. a cooldown timer of a skill could be positioned below a button) + UI_ATTRIBUTE_TYPE_DIMENSION_OVERFLOW, + UI_ATTRIBUTE_TYPE_CONTENT, UI_ATTRIBUTE_TYPE_CONTENT_ALIGN_H, UI_ATTRIBUTE_TYPE_CONTENT_ALIGN_V, diff --git a/utils/PerformanceProfiler.h b/utils/PerformanceProfiler.h index 84a2bf1..17c635f 100644 --- a/utils/PerformanceProfiler.h +++ b/utils/PerformanceProfiler.h @@ -3,15 +3,15 @@ #include #include #include -#include +#include "../architecture/Intrinsics.h" // @todo consider to log/ignore outliers uint64_t measure_cycles(int count, size_t (*func)(const char *), const char *str) { - uint64_t start = __rdtsc(); - for (int = 0; i < count; ++i) { + uint64_t start = intrin_timestamp_counter(); + for (int i = 0; i < count; ++i) { func(str); } - uint64_t end = __rdtsc(); + uint64_t end = intrin_timestamp_counter(); return end - start; } diff --git a/utils/StringUtils.h b/utils/StringUtils.h index 587b8d3..3c8295e 100644 --- a/utils/StringUtils.h +++ b/utils/StringUtils.h @@ -546,8 +546,7 @@ void str_copy_until(const char* __restrict src, char* __restrict dest, const cha } } - *dest++ = *src; - ++src; + *dest++ = *src++; } *dest = '\0'; @@ -605,7 +604,7 @@ void str_copy_long(char* __restrict dest, const char* __restrict src) } inline -void str_copy_move_until(char** __restrict src, char* __restrict dest, char delim) +void str_copy_move_until(const char** __restrict src, char* __restrict dest, char delim) { while (**src != delim && **src != '\0') { *dest++ = **src; @@ -616,7 +615,7 @@ void str_copy_move_until(char** __restrict src, char* __restrict dest, char deli } inline -void str_copy_move_until(char** __restrict src, char* __restrict dest, const char* __restrict delim) +void str_copy_move_until(const char** __restrict src, char* __restrict dest, const char* __restrict delim) { size_t len = strlen(delim); @@ -1019,13 +1018,14 @@ int32 str_to(const char* str, char delim) } inline -void str_move_to(char** str, char delim) +void str_move_to(const char** str, char delim) { while (**str != delim && **str != '\0') { ++(*str); } } +// Negative pos counts backwards inline void str_move_to_pos(const char** str, int32 pos) { @@ -1037,7 +1037,7 @@ void str_move_to_pos(const char** str, int32 pos) } inline -void str_move_past(char** str, char delim) +void str_move_past(const char** str, char delim) { while (**str != delim && **str != '\0') { ++(*str); @@ -1049,7 +1049,7 @@ void str_move_past(char** str, char delim) } inline -void str_move_past_alpha_num(char** str) +void str_move_past_alpha_num(const char** str) { while ((**str >= 48 && **str <= 57) || (**str >= 65 && **str <= 90) @@ -1061,13 +1061,13 @@ void str_move_past_alpha_num(char** str) } inline -bool str_is_comment(char* str) +bool str_is_comment(const char* str) { return (*str == '/' && str[1] == '/') || (*str == '/' && str[1] == '*'); } inline -void str_skip(char** str, char delim) +void str_skip(const char** str, char delim) { while (**str && **str == delim) { ++(*str); @@ -1075,7 +1075,7 @@ void str_skip(char** str, char delim) } inline -void str_skip_whitespace(char** str) +void str_skip_whitespace(const char** str) { while (**str && (**str == ' ' || **str == '\t')) { ++(*str); @@ -1083,7 +1083,7 @@ void str_skip_whitespace(char** str) } inline -void str_skip_empty(char** str) +void str_skip_empty(const char** str) { while (**str == ' ' || **str == '\t' || **str == '\n' || **str == '\r') { ++(*str); @@ -1091,7 +1091,7 @@ void str_skip_empty(char** str) } inline -void str_skip_non_empty(char** str) +void str_skip_non_empty(const char** str) { while (**str != ' ' && **str != '\t' && **str != '\n' && **str != '\0') { ++(*str); @@ -1099,7 +1099,7 @@ void str_skip_non_empty(char** str) } inline -void str_skip_list(char** __restrict str, const char* __restrict delim, int32 len) +void str_skip_list(const char** __restrict str, const char* __restrict delim, int32 len) { bool run = true; while (run && **str != '\0') { @@ -1117,7 +1117,7 @@ void str_skip_list(char** __restrict str, const char* __restrict delim, int32 le } inline -void str_skip_until_list(char** __restrict str, const char* __restrict delim) +void str_skip_until_list(const char** __restrict str, const char* __restrict delim) { while (**str != '\0') { const char* delim_temp = delim; diff --git a/utils/TestUtils.h b/utils/TestUtils.h index 2cfd9a2..ff05e23 100644 --- a/utils/TestUtils.h +++ b/utils/TestUtils.h @@ -10,6 +10,7 @@ #define TOS_UTILS_TEST_UTILS_H #include +#include "../architecture/Intrinsics.h" #define ASSERT_EQUALS(a, b, t1, t2) \ ({ \ @@ -118,12 +119,12 @@ #define ASSERT_PERFORMANCE_START(time_start) \ ({ \ - time_start = __rdtsc(); \ + time_start = intrin_timestamp_counter(); \ }) -#define ASSERT_PERFORMANCE_END(time_start, max_duration) \ -({ \ - ASSERT_TRUE(__rdtsc() - (time_start) <= (max_duration)); \ +#define ASSERT_PERFORMANCE_END(time_start, max_duration) \ +({ \ + ASSERT_TRUE(intrin_timestamp_counter() - (time_start) <= (max_duration)); \ }) #endif