mirror of
https://github.com/Karaka-Management/cOMS.git
synced 2026-01-10 02:48:40 +00:00
update
This commit is contained in:
parent
44c2e9fb05
commit
dc9f37b726
45
account/Permission.h
Normal file
45
account/Permission.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* @copyright Jingga
|
||||
* @license OMS License 2.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
#ifndef COMS_ACCOUNT_PERMISSION_H
|
||||
#define COMS_ACCOUNT_PERMISSION_H
|
||||
|
||||
#include "../stdlib/Types.h"
|
||||
|
||||
struct Permission {
|
||||
uint32 id;
|
||||
uint32 uint;
|
||||
uint32 app;
|
||||
uint16 module;
|
||||
|
||||
// Providing module
|
||||
uint16 from;
|
||||
|
||||
// Used by the module to internally handle permssions for different areas
|
||||
// e.g. In the news module one category could be news to specify the permissions for news, or news category, ...
|
||||
uint16 category;
|
||||
|
||||
// Specific element
|
||||
uint32 element;
|
||||
|
||||
// Component of an element (e.g. only allowed to change content but not title of news)
|
||||
uint32 component;
|
||||
|
||||
/**
|
||||
* 0x00000001 = read permission
|
||||
* 0x00000010 = update permission
|
||||
* 0x00000100 = create permission
|
||||
* 0x00001000 = delete permission
|
||||
* 0x00010000 = can change permission
|
||||
*/
|
||||
byte permission_flag;
|
||||
|
||||
// @question Is this defaultCPermissions used?
|
||||
};
|
||||
|
||||
#endif
|
||||
23
account/PermissionType.h
Normal file
23
account/PermissionType.h
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* @copyright Jingga
|
||||
* @license OMS License 2.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
#ifndef COMS_ACCOUNT_PERMISSION_TYPE_H
|
||||
#define COMS_ACCOUNT_PERMISSION_TYPE_H
|
||||
|
||||
#include "../stdlib/Types.h"
|
||||
|
||||
enum PermissionType {
|
||||
PERMISSION_TYPE_NONE = 0,
|
||||
PERMISSION_TYPE_READ = 1 << 0,
|
||||
PERMISSION_TYPE_UPDATE = 1 << 1,
|
||||
PERMISSION_TYPE_CREATE = 1 << 2,
|
||||
PERMISSION_TYPE_DELETE = 1 << 3,
|
||||
PERMISSION_TYPE_PERMISSION = 1 << 4,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -91,7 +91,7 @@ struct CpuInfo {
|
|||
char brand[49];
|
||||
byte model;
|
||||
byte family;
|
||||
byte thread_count;
|
||||
int16 core_count;
|
||||
int32 mhz;
|
||||
uint32 page_size;
|
||||
CpuCacheInfo cache[4];
|
||||
|
|
|
|||
|
|
@ -17,12 +17,12 @@
|
|||
|
||||
// @question When do we want to use neon and when do we want to use sve?
|
||||
// Only allowed for data >= 64 bits
|
||||
bool is_empty(const uint8_t* region, uint64_t size, int32_t steps = 8) {
|
||||
if (*((uint64_t *) region) != 0) {
|
||||
bool is_empty(const uint8* region, uint64 size, int32 steps = 8) {
|
||||
if (*((uint64 *) region) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint8_t* end = region + size;
|
||||
const uint8* end = region + size;
|
||||
steps = intrin_validate_steps(region, steps);
|
||||
|
||||
switch (steps) {
|
||||
|
|
@ -85,7 +85,7 @@ bool is_empty(const uint8_t* region, uint64_t size, int32_t steps = 8) {
|
|||
}
|
||||
case 1: {
|
||||
while (region + 4 <= end) {
|
||||
if (*((const uint32_t *) region) != 0) {
|
||||
if (*((const uint32 *) region) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,15 +16,15 @@
|
|||
#include <arm_sve.h>
|
||||
|
||||
// Only allowed for data >= 64 bits
|
||||
bool is_empty(const uint8_t* region, uint64_t size, int32_t steps = 8) {
|
||||
if (*((uint64_t *) region) != 0) {
|
||||
bool is_empty(const uint8* region, uint64 size, int32 steps = 8) {
|
||||
if (*((uint64 *) region) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint8_t* end = region + size;
|
||||
const uint8* end = region + size;
|
||||
steps = intrin_validate_steps(region, steps);
|
||||
|
||||
uint64_t sve_vector_bytes = svcntb();
|
||||
uint64 sve_vector_bytes = svcntb();
|
||||
|
||||
switch (steps) {
|
||||
case 16: {
|
||||
|
|
@ -86,7 +86,7 @@ bool is_empty(const uint8_t* region, uint64_t size, int32_t steps = 8) {
|
|||
}
|
||||
case 1: {
|
||||
while (region + 4 <= end) {
|
||||
if (*((const uint32_t *) region) != 0) {
|
||||
if (*((const uint32 *) region) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ uint64 cpu_info_features() {
|
|||
}
|
||||
|
||||
void cpu_info_cache(byte level, CpuCacheInfo* cache) {
|
||||
uint32 eax, ebx, ecx, edx;
|
||||
uint32 eax, ebx, ecx; //, edx;
|
||||
int32 type;
|
||||
|
||||
cache->level = level;
|
||||
|
|
@ -113,7 +113,7 @@ void cpu_info_cache(byte level, CpuCacheInfo* cache) {
|
|||
eax = regs[0];
|
||||
ebx = regs[1];
|
||||
ecx = regs[2];
|
||||
edx = regs[3];
|
||||
// edx = regs[3];
|
||||
|
||||
type = (eax & 0x1F);
|
||||
|
||||
|
|
|
|||
|
|
@ -14,30 +14,29 @@
|
|||
|
||||
#include "../../../stdlib/Types.h"
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_SSE42
|
||||
#ifdef __SSE4_2__
|
||||
#include "SIMD_F32_SSE.h"
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_AVX2
|
||||
#ifdef __AVX2__
|
||||
#include "SIMD_F32_AVX2.h"
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_AVX512
|
||||
#ifdef __AVX512F__
|
||||
#include "SIMD_F32_AVX512.h"
|
||||
#endif
|
||||
|
||||
// @todo from down here we can optimize some of the code by NOT using the wrappers
|
||||
// the code is self contained and we could use te intrinsic functions directly
|
||||
|
||||
inline
|
||||
void simd_mult(const f32* a, const f32* b, f32* result, int32 size, int32 steps)
|
||||
void simd_mult(const f32* a, const f32* b, f32* result, int32 size, int32 steps = 16)
|
||||
{
|
||||
int32 i = 0;
|
||||
steps = intrin_validate_steps((const byte*) a, steps);
|
||||
steps = intrin_validate_steps((const byte*) b, steps);
|
||||
steps = intrin_validate_steps((const byte*) result, steps);
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_AVX512
|
||||
#ifdef __AVX512F__
|
||||
if (steps >= 16) {
|
||||
steps = 16;
|
||||
__m512 a_16;
|
||||
|
|
@ -59,7 +58,7 @@ void simd_mult(const f32* a, const f32* b, f32* result, int32 size, int32 steps)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_AVX2
|
||||
#ifdef __AVX2__
|
||||
if (steps >= 8) {
|
||||
steps = 8;
|
||||
__m256 a_8;
|
||||
|
|
@ -81,7 +80,7 @@ void simd_mult(const f32* a, const f32* b, f32* result, int32 size, int32 steps)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_SSE42
|
||||
#ifdef __SSE4_2__
|
||||
if (steps >= 4) {
|
||||
steps = 4;
|
||||
__m128 a_4;
|
||||
|
|
@ -111,13 +110,13 @@ void simd_mult(const f32* a, const f32* b, f32* result, int32 size, int32 steps)
|
|||
}
|
||||
|
||||
inline
|
||||
void simd_mult(const f32* a, f32 b, f32* result, int32 size, int32 steps)
|
||||
void simd_mult(const f32* a, f32 b, f32* result, int32 size, int32 steps = 16)
|
||||
{
|
||||
int32 i = 0;
|
||||
steps = intrin_validate_steps((const byte*) a, steps);
|
||||
steps = intrin_validate_steps((const byte*) result, steps);
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_AVX512
|
||||
#ifdef __AVX512F__
|
||||
if (steps >= 16) {
|
||||
steps = 16;
|
||||
__m512 a_16;
|
||||
|
|
@ -135,7 +134,7 @@ void simd_mult(const f32* a, f32 b, f32* result, int32 size, int32 steps)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_AVX2
|
||||
#ifdef __AVX2__
|
||||
if (steps >= 8) {
|
||||
steps = 8;
|
||||
__m256 a_8;
|
||||
|
|
@ -153,7 +152,7 @@ void simd_mult(const f32* a, f32 b, f32* result, int32 size, int32 steps)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_SSE42
|
||||
#ifdef __SSE4_2__
|
||||
if (steps >= 4) {
|
||||
steps = 4;
|
||||
__m128 a_4;
|
||||
|
|
@ -180,13 +179,13 @@ void simd_mult(const f32* a, f32 b, f32* result, int32 size, int32 steps)
|
|||
}
|
||||
|
||||
inline
|
||||
void simd_div(const f32* a, f32 b, f32* result, int32 size, int32 steps)
|
||||
void simd_div(const f32* a, f32 b, f32* result, int32 size, int32 steps = 16)
|
||||
{
|
||||
int32 i = 0;
|
||||
steps = intrin_validate_steps((const byte*) a, steps);
|
||||
steps = intrin_validate_steps((const byte*) result, steps);
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_AVX512
|
||||
#ifdef __AVX512F__
|
||||
if (steps >= 16) {
|
||||
steps = 16;
|
||||
__m512 a_16;
|
||||
|
|
@ -204,7 +203,7 @@ void simd_div(const f32* a, f32 b, f32* result, int32 size, int32 steps)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_AVX2
|
||||
#ifdef __AVX2__
|
||||
if (steps >= 8) {
|
||||
steps = 8;
|
||||
__m256 a_8;
|
||||
|
|
@ -222,7 +221,7 @@ void simd_div(const f32* a, f32 b, f32* result, int32 size, int32 steps)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_SSE42
|
||||
#ifdef __SSE4_2__
|
||||
if (steps >= 4) {
|
||||
steps = 4;
|
||||
__m128 a_4;
|
||||
|
|
|
|||
|
|
@ -14,15 +14,15 @@
|
|||
|
||||
#include "../../../stdlib/Types.h"
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_SSE42
|
||||
#ifdef __SSE4_2__
|
||||
#include "SIMD_F64_SSE.h"
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_AVX2
|
||||
#ifdef __AVX2__
|
||||
#include "SIMD_F64_AVX2.h"
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_AVX512
|
||||
#ifdef __AVX512F__
|
||||
#include "SIMD_F64_AVX512.h"
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -6,23 +6,23 @@
|
|||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
#ifndef COMS_TOS_STDLIB_SIMD_I16_H
|
||||
#define COMS_TOS_STDLIB_SIMD_I16_H
|
||||
#ifndef COMS_STDLIB_SIMD_I16_H
|
||||
#define COMS_STDLIB_SIMD_I16_H
|
||||
|
||||
#include <immintrin.h>
|
||||
#include <xmmintrin.h>
|
||||
|
||||
#include "../../../stdlib/Types.h"
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_SSE42
|
||||
#ifdef __SSE4_2__
|
||||
#include "SIMD_I16_SSE.h"
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_AVX2
|
||||
#ifdef __AVX2__
|
||||
#include "SIMD_I16_AVX2.h"
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_AVX512
|
||||
#ifdef __AVX512F__
|
||||
#include "SIMD_I16_AVX512.h"
|
||||
#endif
|
||||
|
||||
|
|
@ -30,13 +30,13 @@
|
|||
// the code is self contained and we could use te intrinsic functions directly
|
||||
|
||||
inline
|
||||
void simd_mult(const int16* a, f32 b, int16* result, int32 size, int32 steps)
|
||||
void simd_mult(const int16* a, f32 b, int16* result, int32 size, int32 steps = 16)
|
||||
{
|
||||
int32 i = 0;
|
||||
steps = intrin_validate_steps((const byte*) a, steps);
|
||||
steps = intrin_validate_steps((const byte*) result, steps);
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_AVX512
|
||||
#ifdef __AVX512F__
|
||||
if (steps >= 16) {
|
||||
steps = 16;
|
||||
__m512i a_16;
|
||||
|
|
@ -65,7 +65,7 @@ void simd_mult(const int16* a, f32 b, int16* result, int32 size, int32 steps)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_AVX2
|
||||
#ifdef __AVX2__
|
||||
if (steps >= 8) {
|
||||
steps = 8;
|
||||
__m256i a_8;
|
||||
|
|
@ -94,7 +94,7 @@ void simd_mult(const int16* a, f32 b, int16* result, int32 size, int32 steps)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_SSE42
|
||||
#ifdef __SSE4_2__
|
||||
if (steps >= 4) {
|
||||
steps = 4;
|
||||
__m128i a_4;
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@
|
|||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
#ifndef COMS_TOS_STDLIB_SIMD_I16_AVX2_H
|
||||
#define COMS_TOS_STDLIB_SIMD_I16_AVX2_H
|
||||
#ifndef COMS_STDLIB_SIMD_I16_AVX2_H
|
||||
#define COMS_STDLIB_SIMD_I16_AVX2_H
|
||||
|
||||
#include <immintrin.h>
|
||||
#include <xmmintrin.h>
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@
|
|||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
#ifndef COMS_TOS_STDLIB_SIMD_I16_AVX512_H
|
||||
#define COMS_TOS_STDLIB_SIMD_I16_AVX512_H
|
||||
#ifndef COMS_STDLIB_SIMD_I16_AVX512_H
|
||||
#define COMS_STDLIB_SIMD_I16_AVX512_H
|
||||
|
||||
#include <immintrin.h>
|
||||
#include <xmmintrin.h>
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@
|
|||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
#ifndef COMS_TOS_STDLIB_SIMD_I16_SSE_H
|
||||
#define COMS_TOS_STDLIB_SIMD_I16_SSE_H
|
||||
#ifndef COMS_STDLIB_SIMD_I16_SSE_H
|
||||
#define COMS_STDLIB_SIMD_I16_SSE_H
|
||||
|
||||
#include <immintrin.h>
|
||||
#include <xmmintrin.h>
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@
|
|||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
#ifndef COMS_TOS_STDLIB_SIMD_I32_H
|
||||
#define COMS_TOS_STDLIB_SIMD_I32_H
|
||||
#ifndef COMS_STDLIB_SIMD_I32_H
|
||||
#define COMS_STDLIB_SIMD_I32_H
|
||||
|
||||
#include <immintrin.h>
|
||||
#include <xmmintrin.h>
|
||||
|
|
@ -16,27 +16,27 @@
|
|||
#include "../../../stdlib/Types.h"
|
||||
#include "../../../utils/BitUtils.h"
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_SSE42
|
||||
#ifdef __SSE4_2__
|
||||
#include "SIMD_I32_SSE.h"
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_AVX2
|
||||
#ifdef __AVX2__
|
||||
#include "SIMD_I32_AVX2.h"
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_AVX512
|
||||
#ifdef __AVX512F__
|
||||
#include "SIMD_I32_AVX512.h"
|
||||
#endif
|
||||
|
||||
inline
|
||||
void simd_mult(const int32* a, const int32* b, int32* result, int32 size, int32 steps)
|
||||
void simd_mult(const int32* a, const int32* b, int32* result, int32 size, int32 steps = 16)
|
||||
{
|
||||
int32 i = 0;
|
||||
steps = intrin_validate_steps((const byte*) a, steps);
|
||||
steps = intrin_validate_steps((const byte*) b, steps);
|
||||
steps = intrin_validate_steps((const byte*) result, steps);
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_AVX512
|
||||
#ifdef __AVX512F__
|
||||
if (steps >= 16) {
|
||||
steps = 16;
|
||||
__m512i a_16;
|
||||
|
|
@ -58,7 +58,7 @@ void simd_mult(const int32* a, const int32* b, int32* result, int32 size, int32
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_AVX2
|
||||
#ifdef __AVX2__
|
||||
if (steps >= 8) {
|
||||
steps = 8;
|
||||
__m256i a_8;
|
||||
|
|
@ -80,7 +80,7 @@ void simd_mult(const int32* a, const int32* b, int32* result, int32 size, int32
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_SSE42
|
||||
#ifdef __SSE4_2__
|
||||
if (steps >= 4) {
|
||||
steps = 4;
|
||||
__m128i a_4;
|
||||
|
|
@ -110,14 +110,14 @@ void simd_mult(const int32* a, const int32* b, int32* result, int32 size, int32
|
|||
}
|
||||
|
||||
inline
|
||||
void simd_mult(const int32* a, const f32* b, f32* result, int32 size, int32 steps)
|
||||
void simd_mult(const int32* a, const f32* b, f32* result, int32 size, int32 steps = 16)
|
||||
{
|
||||
int32 i = 0;
|
||||
steps = intrin_validate_steps((const byte*) a, steps);
|
||||
steps = intrin_validate_steps((const byte*) b, steps);
|
||||
steps = intrin_validate_steps((const byte*) result, steps);
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_AVX512
|
||||
#ifdef __AVX512F__
|
||||
if (steps >= 16) {
|
||||
steps = 16;
|
||||
__m512i a_16;
|
||||
|
|
@ -141,7 +141,7 @@ void simd_mult(const int32* a, const f32* b, f32* result, int32 size, int32 step
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_AVX2
|
||||
#ifdef __AVX2__
|
||||
if (steps >= 8) {
|
||||
steps = 8;
|
||||
__m256i a_8;
|
||||
|
|
@ -165,7 +165,7 @@ void simd_mult(const int32* a, const f32* b, f32* result, int32 size, int32 step
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_SSE42
|
||||
#ifdef __SSE4_2__
|
||||
if (steps >= 4) {
|
||||
steps = 4;
|
||||
__m128i a_4;
|
||||
|
|
@ -197,14 +197,14 @@ void simd_mult(const int32* a, const f32* b, f32* result, int32 size, int32 step
|
|||
}
|
||||
|
||||
inline
|
||||
void simd_mult(const int32* a, const f32* b, int32* result, int32 size, int32 steps)
|
||||
void simd_mult(const int32* a, const f32* b, int32* result, int32 size, int32 steps = 16)
|
||||
{
|
||||
int32 i = 0;
|
||||
steps = intrin_validate_steps((const byte*) a, steps);
|
||||
steps = intrin_validate_steps((const byte*) b, steps);
|
||||
steps = intrin_validate_steps((const byte*) result, steps);
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_AVX512
|
||||
#ifdef __AVX512F__
|
||||
if (steps >= 16) {
|
||||
steps = 16;
|
||||
__m512i a_16;
|
||||
|
|
@ -230,7 +230,7 @@ void simd_mult(const int32* a, const f32* b, int32* result, int32 size, int32 st
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_AVX2
|
||||
#ifdef __AVX2__
|
||||
if (steps >= 8) {
|
||||
steps = 8;
|
||||
__m256i a_8;
|
||||
|
|
@ -256,7 +256,7 @@ void simd_mult(const int32* a, const f32* b, int32* result, int32 size, int32 st
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_SSE42
|
||||
#ifdef __SSE4_2__
|
||||
if (steps >= 4) {
|
||||
steps = 4;
|
||||
__m128i a_4;
|
||||
|
|
@ -290,13 +290,13 @@ void simd_mult(const int32* a, const f32* b, int32* result, int32 size, int32 st
|
|||
}
|
||||
|
||||
inline
|
||||
void simd_mult(const int32* a, f32 b, int32* result, int32 size, int32 steps)
|
||||
void simd_mult(const int32* a, f32 b, int32* result, int32 size, int32 steps = 16)
|
||||
{
|
||||
int32 i = 0;
|
||||
steps = intrin_validate_steps((const byte*) a, steps);
|
||||
steps = intrin_validate_steps((const byte*) result, steps);
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_AVX512
|
||||
#ifdef __AVX512F__
|
||||
if (steps >= 16) {
|
||||
steps = 16;
|
||||
__m512i a_16;
|
||||
|
|
@ -320,7 +320,7 @@ void simd_mult(const int32* a, f32 b, int32* result, int32 size, int32 steps)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_AVX2
|
||||
#ifdef __AVX2__
|
||||
if (steps >= 8) {
|
||||
steps = 8;
|
||||
__m256i a_8;
|
||||
|
|
@ -344,7 +344,7 @@ void simd_mult(const int32* a, f32 b, int32* result, int32 size, int32 steps)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_SSE42
|
||||
#ifdef __SSE4_2__
|
||||
if (steps >= 4) {
|
||||
steps = 4;
|
||||
__m128i a_4;
|
||||
|
|
@ -375,13 +375,13 @@ void simd_mult(const int32* a, f32 b, int32* result, int32 size, int32 steps)
|
|||
}
|
||||
|
||||
inline
|
||||
void simd_div(const int32* a, f32 b, f32* result, int32 size, int32 steps)
|
||||
void simd_div(const int32* a, f32 b, f32* result, int32 size, int32 steps = 16)
|
||||
{
|
||||
int32 i = 0;
|
||||
steps = intrin_validate_steps((const byte*) a, steps);
|
||||
steps = intrin_validate_steps((const byte*) result, steps);
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_AVX512
|
||||
#ifdef __AVX512F__
|
||||
if (steps >= 16) {
|
||||
steps = 16;
|
||||
__m512i a_16;
|
||||
|
|
@ -403,7 +403,7 @@ void simd_div(const int32* a, f32 b, f32* result, int32 size, int32 steps)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_AVX2
|
||||
#ifdef __AVX2__
|
||||
if (steps >= 8) {
|
||||
steps = 8;
|
||||
__m256i a_8;
|
||||
|
|
@ -425,7 +425,7 @@ void simd_div(const int32* a, f32 b, f32* result, int32 size, int32 steps)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_SSE42
|
||||
#ifdef __SSE4_2__
|
||||
if (steps >= 4) {
|
||||
steps = 4;
|
||||
__m128i a_4;
|
||||
|
|
@ -454,14 +454,14 @@ void simd_div(const int32* a, f32 b, f32* result, int32 size, int32 steps)
|
|||
}
|
||||
|
||||
inline
|
||||
void simd_add(const int32* a, const int32* b, int32* result, int32 size, int32 steps)
|
||||
void simd_add(const int32* a, const int32* b, int32* result, int32 size, int32 steps = 16)
|
||||
{
|
||||
int32 i = 0;
|
||||
steps = intrin_validate_steps((const byte*) a, steps);
|
||||
steps = intrin_validate_steps((const byte*) b, steps);
|
||||
steps = intrin_validate_steps((const byte*) result, steps);
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_AVX512
|
||||
#ifdef __AVX512F__
|
||||
if (steps >= 16) {
|
||||
steps = 16;
|
||||
__m512i a_16;
|
||||
|
|
@ -483,7 +483,7 @@ void simd_add(const int32* a, const int32* b, int32* result, int32 size, int32 s
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_AVX2
|
||||
#ifdef __AVX2__
|
||||
if (steps >= 8) {
|
||||
steps = 8;
|
||||
__m256i a_8;
|
||||
|
|
@ -505,7 +505,7 @@ void simd_add(const int32* a, const int32* b, int32* result, int32 size, int32 s
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_SSE42
|
||||
#ifdef __SSE4_2__
|
||||
if (steps >= 4) {
|
||||
steps = 4;
|
||||
__m128i a_4;
|
||||
|
|
@ -535,14 +535,14 @@ void simd_add(const int32* a, const int32* b, int32* result, int32 size, int32 s
|
|||
}
|
||||
|
||||
inline
|
||||
void simd_add(const int32* a, const f32* b, f32* result, int32 size, int32 steps)
|
||||
void simd_add(const int32* a, const f32* b, f32* result, int32 size, int32 steps = 16)
|
||||
{
|
||||
int32 i = 0;
|
||||
steps = intrin_validate_steps((const byte*) a, steps);
|
||||
steps = intrin_validate_steps((const byte*) b, steps);
|
||||
steps = intrin_validate_steps((const byte*) result, steps);
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_AVX512
|
||||
#ifdef __AVX512F__
|
||||
if (steps >= 16) {
|
||||
steps = 16;
|
||||
__m512i a_16;
|
||||
|
|
@ -566,7 +566,7 @@ void simd_add(const int32* a, const f32* b, f32* result, int32 size, int32 steps
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_AVX2
|
||||
#ifdef __AVX2__
|
||||
if (steps >= 8) {
|
||||
steps = 8;
|
||||
__m256i a_8;
|
||||
|
|
@ -590,7 +590,7 @@ void simd_add(const int32* a, const f32* b, f32* result, int32 size, int32 steps
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_SSE42
|
||||
#ifdef __SSE4_2__
|
||||
if (steps >= 4) {
|
||||
steps = 4;
|
||||
__m128i a_4;
|
||||
|
|
@ -622,14 +622,14 @@ void simd_add(const int32* a, const f32* b, f32* result, int32 size, int32 steps
|
|||
}
|
||||
|
||||
inline
|
||||
void simd_add(const int32* a, const f32* b, int32* result, int32 size, int32 steps)
|
||||
void simd_add(const int32* a, const f32* b, int32* result, int32 size, int32 steps = 16)
|
||||
{
|
||||
int32 i = 0;
|
||||
steps = intrin_validate_steps((const byte*) a, steps);
|
||||
steps = intrin_validate_steps((const byte*) b, steps);
|
||||
steps = intrin_validate_steps((const byte*) result, steps);
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_AVX512
|
||||
#ifdef __AVX512F__
|
||||
if (steps >= 16) {
|
||||
steps = 16;
|
||||
__m512i a_16;
|
||||
|
|
@ -655,7 +655,7 @@ void simd_add(const int32* a, const f32* b, int32* result, int32 size, int32 ste
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_AVX2
|
||||
#ifdef __AVX2__
|
||||
if (steps >= 8) {
|
||||
steps = 8;
|
||||
__m256i a_8;
|
||||
|
|
@ -681,7 +681,7 @@ void simd_add(const int32* a, const f32* b, int32* result, int32 size, int32 ste
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_SSE42
|
||||
#ifdef __SSE4_2__
|
||||
if (steps >= 4) {
|
||||
steps = 4;
|
||||
__m128i a_4;
|
||||
|
|
@ -715,13 +715,13 @@ void simd_add(const int32* a, const f32* b, int32* result, int32 size, int32 ste
|
|||
}
|
||||
|
||||
void
|
||||
endian_swap(const int32* val, int32* result, int32 size, int32 steps)
|
||||
endian_swap(const int32* val, int32* result, int32 size, int32 steps = 16)
|
||||
{
|
||||
int32 i = 0;
|
||||
steps = intrin_validate_steps((const byte*) val, steps);
|
||||
steps = intrin_validate_steps((const byte*) result, steps);
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_AVX2
|
||||
#ifdef __AVX2__
|
||||
if (steps >= 8) {
|
||||
steps = 8;
|
||||
const __m256i mask_256 = _mm256_setr_epi8(
|
||||
|
|
@ -742,7 +742,7 @@ endian_swap(const int32* val, int32* result, int32 size, int32 steps)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_SSE42
|
||||
#ifdef __SSE4_2__
|
||||
if (steps >= 4) {
|
||||
steps = 4;
|
||||
const __m128i mask_128 = _mm_setr_epi8(
|
||||
|
|
@ -771,13 +771,13 @@ endian_swap(const int32* val, int32* result, int32 size, int32 steps)
|
|||
}
|
||||
|
||||
void
|
||||
endian_swap(const uint32* val, uint32* result, int32 size, int32 steps)
|
||||
endian_swap(const uint32* val, uint32* result, int32 size, int32 steps = 16)
|
||||
{
|
||||
int32 i = 0;
|
||||
steps = intrin_validate_steps((const byte*) val, steps);
|
||||
steps = intrin_validate_steps((const byte*) result, steps);
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_AVX2
|
||||
#ifdef __AVX2__
|
||||
if (steps >= 8) {
|
||||
steps = 8;
|
||||
const __m256i mask_256 = _mm256_setr_epi8(
|
||||
|
|
@ -798,7 +798,7 @@ endian_swap(const uint32* val, uint32* result, int32 size, int32 steps)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_SSE42
|
||||
#ifdef __SSE4_2__
|
||||
if (steps >= 4) {
|
||||
steps = 4;
|
||||
const __m128i mask_128 = _mm_setr_epi8(
|
||||
|
|
@ -826,13 +826,13 @@ endian_swap(const uint32* val, uint32* result, int32 size, int32 steps)
|
|||
}
|
||||
}
|
||||
|
||||
void endian_swap(const int16* val, int16* result, int32 size, int32 steps)
|
||||
void endian_swap(const int16* val, int16* result, int32 size, int32 steps = 16)
|
||||
{
|
||||
int32 i = 0;
|
||||
steps = intrin_validate_steps((const byte*) val, steps);
|
||||
steps = intrin_validate_steps((const byte*) result, steps);
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_AVX2
|
||||
#ifdef __AVX2__
|
||||
if (steps >= 8) {
|
||||
steps = 8;
|
||||
const __m256i mask_256 = _mm256_setr_epi8(
|
||||
|
|
@ -851,7 +851,7 @@ void endian_swap(const int16* val, int16* result, int32 size, int32 steps)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_SSE42
|
||||
#ifdef __SSE4_2__
|
||||
if (steps >= 4) {
|
||||
steps = 4;
|
||||
const __m128i mask_128 = _mm_setr_epi8(
|
||||
|
|
@ -873,13 +873,13 @@ void endian_swap(const int16* val, int16* result, int32 size, int32 steps)
|
|||
}
|
||||
}
|
||||
|
||||
void endian_swap(const uint16* val, uint16* result, int32 size, int32 steps)
|
||||
void endian_swap(const uint16* val, uint16* result, int32 size, int32 steps = 16)
|
||||
{
|
||||
int32 i = 0;
|
||||
steps = intrin_validate_steps((const byte*) val, steps);
|
||||
steps = intrin_validate_steps((const byte*) result, steps);
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_AVX2
|
||||
#ifdef __AVX2__
|
||||
if (steps >= 8) {
|
||||
steps = 8;
|
||||
const __m256i mask_256 = _mm256_setr_epi8(
|
||||
|
|
@ -898,7 +898,7 @@ void endian_swap(const uint16* val, uint16* result, int32 size, int32 steps)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_SSE42
|
||||
#ifdef __SSE4_2__
|
||||
if (steps >= 4) {
|
||||
steps = 4;
|
||||
const __m128i mask_128 = _mm_setr_epi8(
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@
|
|||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
#ifndef COMS_TOS_STDLIB_SIMD_I32_H
|
||||
#define COMS_TOS_STDLIB_SIMD_I32_H
|
||||
#ifndef COMS_STDLIB_SIMD_I32_H
|
||||
#define COMS_STDLIB_SIMD_I32_H
|
||||
|
||||
#include <immintrin.h>
|
||||
#include <xmmintrin.h>
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@
|
|||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
#ifndef COMS_TOS_STDLIB_SIMD_I32_H
|
||||
#define COMS_TOS_STDLIB_SIMD_I32_H
|
||||
#ifndef COMS_STDLIB_SIMD_I32_H
|
||||
#define COMS_STDLIB_SIMD_I32_H
|
||||
|
||||
#include <immintrin.h>
|
||||
#include <xmmintrin.h>
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@
|
|||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
#ifndef COMS_TOS_STDLIB_SIMD_I32_H
|
||||
#define COMS_TOS_STDLIB_SIMD_I32_H
|
||||
#ifndef COMS_STDLIB_SIMD_I32_H
|
||||
#define COMS_STDLIB_SIMD_I32_H
|
||||
|
||||
#include <immintrin.h>
|
||||
#include <xmmintrin.h>
|
||||
|
|
|
|||
|
|
@ -6,23 +6,23 @@
|
|||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
#ifndef COMS_TOS_STDLIB_SIMD_I64_H
|
||||
#define COMS_TOS_STDLIB_SIMD_I64_H
|
||||
#ifndef COMS_STDLIB_SIMD_I64_H
|
||||
#define COMS_STDLIB_SIMD_I64_H
|
||||
|
||||
#include <immintrin.h>
|
||||
#include <xmmintrin.h>
|
||||
|
||||
#include "../../../stdlib/Types.h"
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_SSE42
|
||||
#ifdef __SSE4_2__
|
||||
#include "SIMD_I64_SSE.h"
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_AVX2
|
||||
#ifdef __AVX2__
|
||||
#include "SIMD_I64_AVX2.h"
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_AVX512
|
||||
#ifdef __AVX512F__
|
||||
#include "SIMD_I64_AVX512.h"
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@
|
|||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
#ifndef COMS_TOS_STDLIB_SIMD_I64_AVX2_H
|
||||
#define COMS_TOS_STDLIB_SIMD_I64_AVX2_H
|
||||
#ifndef COMS_STDLIB_SIMD_I64_AVX2_H
|
||||
#define COMS_STDLIB_SIMD_I64_AVX2_H
|
||||
|
||||
#include <immintrin.h>
|
||||
#include <xmmintrin.h>
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@
|
|||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
#ifndef COMS_TOS_STDLIB_SIMD_I64_AVX512_H
|
||||
#define COMS_TOS_STDLIB_SIMD_I64_AVX512_H
|
||||
#ifndef COMS_STDLIB_SIMD_I64_AVX512_H
|
||||
#define COMS_STDLIB_SIMD_I64_AVX512_H
|
||||
|
||||
#include <immintrin.h>
|
||||
#include <xmmintrin.h>
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@
|
|||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
#ifndef COMS_TOS_STDLIB_SIMD_I64_SSE_H
|
||||
#define COMS_TOS_STDLIB_SIMD_I64_SSE_H
|
||||
#ifndef COMS_STDLIB_SIMD_I64_SSE_H
|
||||
#define COMS_STDLIB_SIMD_I64_SSE_H
|
||||
|
||||
#include <immintrin.h>
|
||||
#include <xmmintrin.h>
|
||||
|
|
|
|||
|
|
@ -6,23 +6,23 @@
|
|||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
#ifndef COMS_TOS_STDLIB_SIMD_I8_H
|
||||
#define COMS_TOS_STDLIB_SIMD_I8_H
|
||||
#ifndef COMS_STDLIB_SIMD_I8_H
|
||||
#define COMS_STDLIB_SIMD_I8_H
|
||||
|
||||
#include <immintrin.h>
|
||||
#include <xmmintrin.h>
|
||||
|
||||
#include "../../../stdlib/Types.h"
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_SSE42
|
||||
#ifdef __SSE4_2__
|
||||
#include "SIMD_I8_SSE.h"
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_AVX2
|
||||
#ifdef __AVX2__
|
||||
#include "SIMD_I8_AVX2.h"
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_AVX512
|
||||
#ifdef __AVX512F__
|
||||
#include "SIMD_I8_AVX512.h"
|
||||
#endif
|
||||
|
||||
|
|
@ -31,7 +31,7 @@ int simd_equal(const byte* a, const byte* b, uint32 size, uint32 steps = 8) {
|
|||
steps = intrin_validate_steps((const byte*) a, steps);
|
||||
steps = intrin_validate_steps((const byte*) b, steps);
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_AVX512
|
||||
#ifdef __AVX512F__
|
||||
if (steps >= 16) {
|
||||
steps = 16;
|
||||
if (size >= 128) {
|
||||
|
|
@ -62,7 +62,7 @@ int simd_equal(const byte* a, const byte* b, uint32 size, uint32 steps = 8) {
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_AVX2
|
||||
#ifdef __AVX2__
|
||||
if (steps >= 8) {
|
||||
steps = 8;
|
||||
if (size >= 64) {
|
||||
|
|
@ -91,7 +91,7 @@ int simd_equal(const byte* a, const byte* b, uint32 size, uint32 steps = 8) {
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_SSE42
|
||||
#ifdef __SSE4_2__
|
||||
if (steps >= 4) {
|
||||
steps = 4;
|
||||
if (size >= 16) {
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@
|
|||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
#ifndef COMS_TOS_STDLIB_SIMD_I8_H
|
||||
#define COMS_TOS_STDLIB_SIMD_I8_H
|
||||
#ifndef COMS_STDLIB_SIMD_I8_H
|
||||
#define COMS_STDLIB_SIMD_I8_H
|
||||
|
||||
#include <immintrin.h>
|
||||
#include <xmmintrin.h>
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@
|
|||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
#ifndef COMS_TOS_STDLIB_SIMD_I8_H
|
||||
#define COMS_TOS_STDLIB_SIMD_I8_H
|
||||
#ifndef COMS_STDLIB_SIMD_I8_H
|
||||
#define COMS_STDLIB_SIMD_I8_H
|
||||
|
||||
#include <immintrin.h>
|
||||
#include <xmmintrin.h>
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@
|
|||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
#ifndef COMS_TOS_STDLIB_SIMD_I8_H
|
||||
#define COMS_TOS_STDLIB_SIMD_I8_H
|
||||
#ifndef COMS_STDLIB_SIMD_I8_H
|
||||
#define COMS_STDLIB_SIMD_I8_H
|
||||
|
||||
#include <immintrin.h>
|
||||
#include <xmmintrin.h>
|
||||
|
|
|
|||
|
|
@ -9,15 +9,15 @@
|
|||
#ifndef COMS_STDLIB_SIMD_SVML_H
|
||||
#define COMS_STDLIB_SIMD_SVML_H
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_SSE42
|
||||
#ifdef __SSE4_2__
|
||||
#include "SIMD_SVML_SSE.h"
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_AVX2
|
||||
#ifdef __AVX2__
|
||||
#include "SIMD_SVML_AVX2.h"
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_CPU_FEATURE_AVX512
|
||||
#ifdef __AVX512F__
|
||||
#include "SIMD_SVML_AVX512.h"
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ bool is_empty(const byte* region, uint64 size, int32 steps = 8)
|
|||
steps = intrin_validate_steps(region, steps);
|
||||
|
||||
switch (steps) {
|
||||
#ifdef MACRO_CPU_FEATURE_AVX512
|
||||
#ifdef __AVX512F__
|
||||
case 16: {
|
||||
while (region + 64 <= end) {
|
||||
__m512i chunk = _mm512_load_si512((const __m512i *) region);
|
||||
|
|
@ -42,7 +42,7 @@ bool is_empty(const byte* region, uint64 size, int32 steps = 8)
|
|||
#else
|
||||
case 16: [[fallthrough]];
|
||||
#endif
|
||||
#ifdef MACRO_CPU_FEATURE_AVX2
|
||||
#ifdef __AVX2__
|
||||
case 8: {
|
||||
while (region + 32 <= end) {
|
||||
__m256i chunk = _mm256_load_si256((const __m256i *) region);
|
||||
|
|
@ -57,7 +57,7 @@ bool is_empty(const byte* region, uint64 size, int32 steps = 8)
|
|||
#else
|
||||
case 8: [[fallthrough]];
|
||||
#endif
|
||||
#ifdef MACRO_CPU_FEATURE_SSE42
|
||||
#ifdef __SSE4_2__
|
||||
case 4: {
|
||||
while (region + 16 <= end) {
|
||||
__m128i chunk = _mm_load_si128((const __m128i *) region);
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ struct AssetComponent {
|
|||
uint64 asset_count;
|
||||
|
||||
// @question Do we want to add a mutex to assets. This way we don't have to lock the entire ams.
|
||||
coms_pthread_mutex_t mutex;
|
||||
mutex mutex;
|
||||
};
|
||||
|
||||
struct AssetManagementSystem {
|
||||
|
|
@ -55,7 +55,7 @@ void ams_component_create(AssetComponent* ac, BufferMemory* buf, int32 chunk_siz
|
|||
LOG_1("Create AMS Component for %n assets and %n B", {{LOG_DATA_INT32, &count}, {LOG_DATA_UINT32, &chunk_size}});
|
||||
|
||||
chunk_init(&ac->asset_memory, buf, count, chunk_size, 64);
|
||||
coms_pthread_mutex_init(&ac->mutex, NULL);
|
||||
mutex_init(&ac->mutex, NULL);
|
||||
}
|
||||
|
||||
inline
|
||||
|
|
@ -71,13 +71,13 @@ void ams_component_create(AssetComponent* ac, byte* buf, int32 chunk_size, int32
|
|||
ac->asset_memory.memory = buf;
|
||||
ac->asset_memory.free = (uint64 *) (ac->asset_memory.memory + ac->asset_memory.chunk_size * count);
|
||||
|
||||
coms_pthread_mutex_init(&ac->mutex, NULL);
|
||||
mutex_init(&ac->mutex, NULL);
|
||||
}
|
||||
|
||||
inline
|
||||
void ams_component_free(AssetComponent* ac)
|
||||
{
|
||||
coms_pthread_mutex_destroy(&ac->mutex);
|
||||
mutex_destroy(&ac->mutex);
|
||||
}
|
||||
|
||||
inline
|
||||
|
|
@ -400,15 +400,15 @@ Asset* thrd_ams_reserve_asset(AssetManagementSystem* ams, byte type, const char*
|
|||
AssetComponent* ac = &ams->asset_components[type];
|
||||
uint16 elements = ams_calculate_chunks(ac, size, overhead);
|
||||
|
||||
coms_pthread_mutex_lock(&ams->asset_components[type].mutex);
|
||||
mutex_lock(&ams->asset_components[type].mutex);
|
||||
int32 free_data = chunk_reserve(&ac->asset_memory, elements);
|
||||
if (free_data < 0) {
|
||||
coms_pthread_mutex_unlock(&ams->asset_components[type].mutex);
|
||||
mutex_unlock(&ams->asset_components[type].mutex);
|
||||
ASSERT_SIMPLE(free_data >= 0);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
coms_pthread_mutex_unlock(&ams->asset_components[type].mutex);
|
||||
mutex_unlock(&ams->asset_components[type].mutex);
|
||||
|
||||
byte* asset_data = chunk_get_element(&ac->asset_memory, free_data, true);
|
||||
|
||||
|
|
@ -514,15 +514,15 @@ Asset* thrd_ams_insert_asset(AssetManagementSystem* ams, Asset* asset_temp, cons
|
|||
{
|
||||
AssetComponent* ac = &ams->asset_components[asset_temp->component_id];
|
||||
|
||||
coms_pthread_mutex_lock(&ams->asset_components[asset_temp->component_id].mutex);
|
||||
mutex_lock(&ams->asset_components[asset_temp->component_id].mutex);
|
||||
int32 free_data = chunk_reserve(&ac->asset_memory, asset_temp->size);
|
||||
if (free_data < 0) {
|
||||
coms_pthread_mutex_unlock(&ams->asset_components[asset_temp->component_id].mutex);
|
||||
mutex_unlock(&ams->asset_components[asset_temp->component_id].mutex);
|
||||
ASSERT_SIMPLE(free_data >= 0);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
coms_pthread_mutex_unlock(&ams->asset_components[asset_temp->component_id].mutex);
|
||||
mutex_unlock(&ams->asset_components[asset_temp->component_id].mutex);
|
||||
|
||||
byte* asset_data = chunk_get_element(&ac->asset_memory, free_data);
|
||||
memcpy(asset_data, asset_temp->self, sizeof(Asset));
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ inline
|
|||
void cmd_buffer_create(AppCmdBuffer* cb, BufferMemory* buf, int32 commands_count)
|
||||
{
|
||||
chunk_init(&cb->commands, buf, commands_count, sizeof(Command), 64);
|
||||
coms_pthread_mutex_init(&cb->mutex, NULL);
|
||||
mutex_init(&cb->mutex, NULL);
|
||||
|
||||
LOG_1("Created AppCmdBuffer: %n B", {{LOG_DATA_UINT64, &cb->commands.size}});
|
||||
}
|
||||
|
|
@ -181,10 +181,10 @@ Asset* cmd_font_load_async(AppCmdBuffer* __restrict cb, Command* __restrict cmd)
|
|||
inline
|
||||
void thrd_cmd_insert(AppCmdBuffer* __restrict cb, Command* __restrict cmd_temp)
|
||||
{
|
||||
coms_pthread_mutex_lock(&cb->mutex);
|
||||
mutex_lock(&cb->mutex);
|
||||
int32 index = chunk_reserve(&cb->commands, 1);
|
||||
if (index < 0) {
|
||||
coms_pthread_mutex_unlock(&cb->mutex);
|
||||
mutex_unlock(&cb->mutex);
|
||||
ASSERT_SIMPLE(false);
|
||||
|
||||
return;
|
||||
|
|
@ -196,7 +196,7 @@ void thrd_cmd_insert(AppCmdBuffer* __restrict cb, Command* __restrict cmd_temp)
|
|||
|
||||
Command* cmd = (Command *) chunk_get_element(&cb->commands, index);
|
||||
memcpy(cmd, cmd_temp, sizeof(Command));
|
||||
coms_pthread_mutex_unlock(&cb->mutex);
|
||||
mutex_unlock(&cb->mutex);
|
||||
}
|
||||
|
||||
inline
|
||||
|
|
@ -697,9 +697,9 @@ void cmd_iterate(AppCmdBuffer* cb)
|
|||
// This shouldn't happen since the command buffer shouldn't fill up in just 1-3 frames
|
||||
void thrd_cmd_iterate(AppCmdBuffer* cb)
|
||||
{
|
||||
coms_pthread_mutex_lock(&cb->mutex);
|
||||
mutex_lock(&cb->mutex);
|
||||
cmd_iterate(cb);
|
||||
coms_pthread_mutex_unlock(&cb->mutex);
|
||||
mutex_unlock(&cb->mutex);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -29,7 +29,7 @@ struct AppCmdBuffer {
|
|||
ChunkMemory commands;
|
||||
int32 last_element;
|
||||
|
||||
coms_pthread_mutex_t mutex;
|
||||
mutex mutex;
|
||||
|
||||
// Application data for cmd access
|
||||
// The list below depends on what kind of systems our command buffer needs access to
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ FORCE_INLINE void atomic_add_relaxed(volatile int32* value, int32 increment) noe
|
|||
FORCE_INLINE void atomic_sub_relaxed(volatile int32* value, int32 decrement) noexcept { __atomic_sub_fetch(value, decrement, __ATOMIC_RELAXED); }
|
||||
FORCE_INLINE void atomic_add_relaxed(volatile int64* value, int64 increment) noexcept { __atomic_add_fetch(value, increment, __ATOMIC_RELAXED); }
|
||||
FORCE_INLINE void atomic_sub_relaxed(volatile int64* value, int64 decrement) noexcept { __atomic_sub_fetch(value, decrement, __ATOMIC_RELAXED); }
|
||||
FORCE_INLINE f32 atomic_compare_exchange_weak_relaxed(volatile f32* value, f32* expected, f32 desired) noexcept {
|
||||
FORCE_INLINE f32 atomic_compare_exchange_strong_relaxed(volatile f32* value, f32* expected, f32 desired) noexcept {
|
||||
volatile _atomic_32* value_as_union = (volatile _atomic_32*)value;
|
||||
_atomic_32* expected_as_union = (_atomic_32*)expected;
|
||||
_atomic_32 desired_as_union;
|
||||
|
|
@ -58,7 +58,7 @@ FORCE_INLINE f32 atomic_compare_exchange_weak_relaxed(volatile f32* value, f32*
|
|||
|
||||
return expected_as_union->f;
|
||||
}
|
||||
FORCE_INLINE f64 atomic_compare_exchange_weak_relaxed(volatile f64* value, f64* expected, f64 desired) noexcept {
|
||||
FORCE_INLINE f64 atomic_compare_exchange_strong_relaxed(volatile f64* value, f64* expected, f64 desired) noexcept {
|
||||
volatile _atomic_64* value_as_union = (volatile _atomic_64*)value;
|
||||
_atomic_64* expected_as_union = (_atomic_64*)expected;
|
||||
_atomic_64 desired_as_union;
|
||||
|
|
@ -71,8 +71,8 @@ FORCE_INLINE f64 atomic_compare_exchange_weak_relaxed(volatile f64* value, f64*
|
|||
|
||||
return expected_as_union->f;
|
||||
}
|
||||
FORCE_INLINE int32 atomic_compare_exchange_weak_relaxed(volatile int32* value, int32* expected, int32 desired) noexcept { __atomic_compare_exchange_n(value, expected, desired, 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED); return *expected; }
|
||||
FORCE_INLINE int64 atomic_compare_exchange_weak_relaxed(volatile int64* value, int64* expected, int64 desired) noexcept { __atomic_compare_exchange_n(value, expected, desired, 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED); return *expected; }
|
||||
FORCE_INLINE int32 atomic_compare_exchange_strong_relaxed(volatile int32* value, int32* expected, int32 desired) noexcept { __atomic_compare_exchange_n(value, expected, desired, 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED); return *expected; }
|
||||
FORCE_INLINE int64 atomic_compare_exchange_strong_relaxed(volatile int64* value, int64* expected, int64 desired) noexcept { __atomic_compare_exchange_n(value, expected, desired, 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED); return *expected; }
|
||||
FORCE_INLINE int8 atomic_fetch_add_relaxed(volatile int8* value, int8 operand) noexcept { return __atomic_add_fetch(value, operand, __ATOMIC_RELAXED); }
|
||||
FORCE_INLINE int8 atomic_fetch_sub_relaxed(volatile int8* value, int8 operand) noexcept { return __atomic_sub_fetch(value, operand, __ATOMIC_RELAXED); }
|
||||
FORCE_INLINE int16 atomic_fetch_add_relaxed(volatile int16* value, int16 operand) noexcept { return __atomic_add_fetch(value, operand, __ATOMIC_RELAXED); }
|
||||
|
|
@ -109,8 +109,8 @@ FORCE_INLINE void atomic_add_relaxed(volatile uint32* value, uint32 increment) n
|
|||
FORCE_INLINE void atomic_sub_relaxed(volatile uint32* value, uint32 decrement) noexcept { __atomic_sub_fetch(value, decrement, __ATOMIC_RELAXED); }
|
||||
FORCE_INLINE void atomic_add_relaxed(volatile uint64* value, uint64 increment) noexcept { __atomic_add_fetch(value, increment, __ATOMIC_RELAXED); }
|
||||
FORCE_INLINE void atomic_sub_relaxed(volatile uint64* value, uint64 decrement) noexcept { __atomic_sub_fetch(value, decrement, __ATOMIC_RELAXED); }
|
||||
FORCE_INLINE uint32 atomic_compare_exchange_weak_relaxed(volatile uint32* value, uint32* expected, uint32 desired) noexcept { __atomic_compare_exchange_n(value, expected, desired, 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED); return *expected; }
|
||||
FORCE_INLINE uint64 atomic_compare_exchange_weak_relaxed(volatile uint64* value, uint64* expected, uint64 desired) noexcept { __atomic_compare_exchange_n(value, expected, desired, 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED); return *expected; }
|
||||
FORCE_INLINE uint32 atomic_compare_exchange_strong_relaxed(volatile uint32* value, uint32* expected, uint32 desired) noexcept { __atomic_compare_exchange_n(value, expected, desired, 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED); return *expected; }
|
||||
FORCE_INLINE uint64 atomic_compare_exchange_strong_relaxed(volatile uint64* value, uint64* expected, uint64 desired) noexcept { __atomic_compare_exchange_n(value, expected, desired, 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED); return *expected; }
|
||||
FORCE_INLINE uint8 atomic_fetch_add_relaxed(volatile uint8* value, uint8 operand) noexcept { return __atomic_add_fetch(value, operand, __ATOMIC_RELAXED); }
|
||||
FORCE_INLINE uint8 atomic_fetch_sub_relaxed(volatile uint8* value, uint8 operand) noexcept { return __atomic_sub_fetch(value, operand, __ATOMIC_RELAXED); }
|
||||
FORCE_INLINE uint16 atomic_fetch_add_relaxed(volatile uint16* value, uint16 operand) noexcept { return __atomic_add_fetch(value, operand, __ATOMIC_RELAXED); }
|
||||
|
|
@ -161,7 +161,7 @@ FORCE_INLINE void atomic_add_acquire(volatile int32* value, int32 increment) noe
|
|||
FORCE_INLINE void atomic_sub_acquire(volatile int32* value, int32 decrement) noexcept { __atomic_sub_fetch(value, decrement, __ATOMIC_ACQUIRE); }
|
||||
FORCE_INLINE void atomic_add_acquire(volatile int64* value, int64 increment) noexcept { __atomic_add_fetch(value, increment, __ATOMIC_ACQUIRE); }
|
||||
FORCE_INLINE void atomic_sub_acquire(volatile int64* value, int64 decrement) noexcept { __atomic_sub_fetch(value, decrement, __ATOMIC_ACQUIRE); }
|
||||
FORCE_INLINE f32 atomic_compare_exchange_weak_acquire(volatile f32* value, f32* expected, f32 desired) noexcept {
|
||||
FORCE_INLINE f32 atomic_compare_exchange_strong_acquire(volatile f32* value, f32* expected, f32 desired) noexcept {
|
||||
volatile _atomic_32* value_as_union = (volatile _atomic_32*)value;
|
||||
_atomic_32* expected_as_union = (_atomic_32*)expected;
|
||||
_atomic_32 desired_as_union;
|
||||
|
|
@ -169,12 +169,12 @@ FORCE_INLINE f32 atomic_compare_exchange_weak_acquire(volatile f32* value, f32*
|
|||
|
||||
__atomic_compare_exchange_n(
|
||||
&value_as_union->l, &expected_as_union->l, desired_as_union.l, 0,
|
||||
__ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE
|
||||
__ATOMIC_ACQUIRE, __ATOMIC_RELAXED
|
||||
);
|
||||
|
||||
return expected_as_union->f;
|
||||
}
|
||||
FORCE_INLINE f64 atomic_compare_exchange_weak_acquire(volatile f64* value, f64* expected, f64 desired) noexcept {
|
||||
FORCE_INLINE f64 atomic_compare_exchange_strong_acquire(volatile f64* value, f64* expected, f64 desired) noexcept {
|
||||
volatile _atomic_64* value_as_union = (volatile _atomic_64*)value;
|
||||
_atomic_64* expected_as_union = (_atomic_64*)expected;
|
||||
_atomic_64 desired_as_union;
|
||||
|
|
@ -182,13 +182,13 @@ FORCE_INLINE f64 atomic_compare_exchange_weak_acquire(volatile f64* value, f64*
|
|||
|
||||
__atomic_compare_exchange_n(
|
||||
&value_as_union->l, &expected_as_union->l, desired_as_union.l, 0,
|
||||
__ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE
|
||||
__ATOMIC_ACQUIRE, __ATOMIC_RELAXED
|
||||
);
|
||||
|
||||
return expected_as_union->f;
|
||||
}
|
||||
FORCE_INLINE int32 atomic_compare_exchange_weak_acquire(volatile int32* value, int32* expected, int32 desired) noexcept { __atomic_compare_exchange_n(value, expected, desired, 0, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE); return *expected; }
|
||||
FORCE_INLINE int64 atomic_compare_exchange_weak_acquire(volatile int64* value, int64* expected, int64 desired) noexcept { __atomic_compare_exchange_n(value, expected, desired, 0, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE); return *expected; }
|
||||
FORCE_INLINE int32 atomic_compare_exchange_strong_acquire(volatile int32* value, int32* expected, int32 desired) noexcept { __atomic_compare_exchange_n(value, expected, desired, 0, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE); return *expected; }
|
||||
FORCE_INLINE int64 atomic_compare_exchange_strong_acquire(volatile int64* value, int64* expected, int64 desired) noexcept { __atomic_compare_exchange_n(value, expected, desired, 0, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE); return *expected; }
|
||||
FORCE_INLINE int8 atomic_fetch_add_acquire(volatile int8* value, int8 operand) noexcept { return __atomic_add_fetch(value, operand, __ATOMIC_ACQUIRE); }
|
||||
FORCE_INLINE int8 atomic_fetch_sub_acquire(volatile int8* value, int8 operand) noexcept { return __atomic_sub_fetch(value, operand, __ATOMIC_ACQUIRE); }
|
||||
FORCE_INLINE int16 atomic_fetch_add_acquire(volatile int16* value, int16 operand) noexcept { return __atomic_add_fetch(value, operand, __ATOMIC_ACQUIRE); }
|
||||
|
|
@ -225,8 +225,8 @@ FORCE_INLINE void atomic_add_acquire(volatile uint32* value, uint32 increment) n
|
|||
FORCE_INLINE void atomic_sub_acquire(volatile uint32* value, uint32 decrement) noexcept { __atomic_sub_fetch(value, decrement, __ATOMIC_ACQUIRE); }
|
||||
FORCE_INLINE void atomic_add_acquire(volatile uint64* value, uint64 increment) noexcept { __atomic_add_fetch(value, increment, __ATOMIC_ACQUIRE); }
|
||||
FORCE_INLINE void atomic_sub_acquire(volatile uint64* value, uint64 decrement) noexcept { __atomic_sub_fetch(value, decrement, __ATOMIC_ACQUIRE); }
|
||||
FORCE_INLINE uint32 atomic_compare_exchange_weak_acquire(volatile uint32* value, uint32* expected, uint32 desired) noexcept { __atomic_compare_exchange_n(value, expected, desired, 0, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE); return *expected; }
|
||||
FORCE_INLINE uint64 atomic_compare_exchange_weak_acquire(volatile uint64* value, uint64* expected, uint64 desired) noexcept { __atomic_compare_exchange_n(value, expected, desired, 0, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE); return *expected; }
|
||||
FORCE_INLINE uint32 atomic_compare_exchange_strong_acquire(volatile uint32* value, uint32* expected, uint32 desired) noexcept { __atomic_compare_exchange_n(value, expected, desired, 0, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE); return *expected; }
|
||||
FORCE_INLINE uint64 atomic_compare_exchange_strong_acquire(volatile uint64* value, uint64* expected, uint64 desired) noexcept { __atomic_compare_exchange_n(value, expected, desired, 0, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE); return *expected; }
|
||||
FORCE_INLINE uint8 atomic_fetch_add_acquire(volatile uint8* value, uint8 operand) noexcept { return __atomic_add_fetch(value, operand, __ATOMIC_ACQUIRE); }
|
||||
FORCE_INLINE uint8 atomic_fetch_sub_acquire(volatile uint8* value, uint8 operand) noexcept { return __atomic_sub_fetch(value, operand, __ATOMIC_ACQUIRE); }
|
||||
FORCE_INLINE uint16 atomic_fetch_add_acquire(volatile uint16* value, uint16 operand) noexcept { return __atomic_add_fetch(value, operand, __ATOMIC_ACQUIRE); }
|
||||
|
|
@ -282,7 +282,7 @@ FORCE_INLINE void atomic_add_release(volatile int32* value, int32 increment) noe
|
|||
FORCE_INLINE void atomic_sub_release(volatile int32* value, int32 decrement) noexcept { __atomic_sub_fetch(value, decrement, __ATOMIC_RELEASE); }
|
||||
FORCE_INLINE void atomic_add_release(volatile int64* value, int64 increment) noexcept { __atomic_add_fetch(value, increment, __ATOMIC_RELEASE); }
|
||||
FORCE_INLINE void atomic_sub_release(volatile int64* value, int64 decrement) noexcept { __atomic_sub_fetch(value, decrement, __ATOMIC_RELEASE); }
|
||||
FORCE_INLINE f32 atomic_compare_exchange_weak_release(volatile f32* value, f32* expected, f32 desired) noexcept {
|
||||
FORCE_INLINE f32 atomic_compare_exchange_strong_release(volatile f32* value, f32* expected, f32 desired) noexcept {
|
||||
volatile _atomic_32* value_as_union = (volatile _atomic_32*)value;
|
||||
_atomic_32* expected_as_union = (_atomic_32*)expected;
|
||||
_atomic_32 desired_as_union;
|
||||
|
|
@ -290,12 +290,12 @@ FORCE_INLINE f32 atomic_compare_exchange_weak_release(volatile f32* value, f32*
|
|||
|
||||
__atomic_compare_exchange_n(
|
||||
&value_as_union->l, &expected_as_union->l, desired_as_union.l, 0,
|
||||
__ATOMIC_RELEASE, __ATOMIC_RELEASE
|
||||
__ATOMIC_RELEASE, __ATOMIC_RELAXED
|
||||
);
|
||||
|
||||
return expected_as_union->f;
|
||||
}
|
||||
FORCE_INLINE f64 atomic_compare_exchange_weak_release(volatile f64* value, f64* expected, f64 desired) noexcept {
|
||||
FORCE_INLINE f64 atomic_compare_exchange_strong_release(volatile f64* value, f64* expected, f64 desired) noexcept {
|
||||
volatile _atomic_64* value_as_union = (volatile _atomic_64*)value;
|
||||
_atomic_64* expected_as_union = (_atomic_64*)expected;
|
||||
_atomic_64 desired_as_union;
|
||||
|
|
@ -303,13 +303,13 @@ FORCE_INLINE f64 atomic_compare_exchange_weak_release(volatile f64* value, f64*
|
|||
|
||||
__atomic_compare_exchange_n(
|
||||
&value_as_union->l, &expected_as_union->l, desired_as_union.l, 0,
|
||||
__ATOMIC_RELEASE, __ATOMIC_RELEASE
|
||||
__ATOMIC_RELEASE, __ATOMIC_RELAXED
|
||||
);
|
||||
|
||||
return expected_as_union->f;
|
||||
}
|
||||
FORCE_INLINE int32 atomic_compare_exchange_weak_release(volatile int32* value, int32* expected, int32 desired) noexcept { __atomic_compare_exchange_n(value, expected, desired, 0, __ATOMIC_RELEASE, __ATOMIC_RELEASE); return *expected; }
|
||||
FORCE_INLINE int64 atomic_compare_exchange_weak_release(volatile int64* value, int64* expected, int64 desired) noexcept { __atomic_compare_exchange_n(value, expected, desired, 0, __ATOMIC_RELEASE, __ATOMIC_RELEASE); return *expected; }
|
||||
FORCE_INLINE int32 atomic_compare_exchange_strong_release(volatile int32* value, int32* expected, int32 desired) noexcept { __atomic_compare_exchange_n(value, expected, desired, 0, __ATOMIC_RELEASE, __ATOMIC_RELEASE); return *expected; }
|
||||
FORCE_INLINE int64 atomic_compare_exchange_strong_release(volatile int64* value, int64* expected, int64 desired) noexcept { __atomic_compare_exchange_n(value, expected, desired, 0, __ATOMIC_RELEASE, __ATOMIC_RELEASE); return *expected; }
|
||||
FORCE_INLINE int8 atomic_fetch_add_release(volatile int8* value, int8 operand) noexcept { return __atomic_add_fetch(value, operand, __ATOMIC_RELEASE); }
|
||||
FORCE_INLINE int8 atomic_fetch_sub_release(volatile int8* value, int8 operand) noexcept { return __atomic_sub_fetch(value, operand, __ATOMIC_RELEASE); }
|
||||
FORCE_INLINE int16 atomic_fetch_add_release(volatile int16* value, int16 operand) noexcept { return __atomic_add_fetch(value, operand, __ATOMIC_RELEASE); }
|
||||
|
|
@ -346,8 +346,8 @@ FORCE_INLINE void atomic_add_release(volatile uint32* value, uint32 increment) n
|
|||
FORCE_INLINE void atomic_sub_release(volatile uint32* value, uint32 decrement) noexcept { __atomic_sub_fetch(value, decrement, __ATOMIC_RELEASE); }
|
||||
FORCE_INLINE void atomic_add_release(volatile uint64* value, uint64 increment) noexcept { __atomic_add_fetch(value, increment, __ATOMIC_RELEASE); }
|
||||
FORCE_INLINE void atomic_sub_release(volatile uint64* value, uint64 decrement) noexcept { __atomic_sub_fetch(value, decrement, __ATOMIC_RELEASE); }
|
||||
FORCE_INLINE uint32 atomic_compare_exchange_weak_release(volatile uint32* value, uint32* expected, uint32 desired) noexcept { __atomic_compare_exchange_n(value, expected, desired, 0, __ATOMIC_RELEASE, __ATOMIC_RELEASE); return *expected; }
|
||||
FORCE_INLINE uint64 atomic_compare_exchange_weak_release(volatile uint64* value, uint64* expected, uint64 desired) noexcept { __atomic_compare_exchange_n(value, expected, desired, 0, __ATOMIC_RELEASE, __ATOMIC_RELEASE); return *expected; }
|
||||
FORCE_INLINE uint32 atomic_compare_exchange_strong_release(volatile uint32* value, uint32* expected, uint32 desired) noexcept { __atomic_compare_exchange_n(value, expected, desired, 0, __ATOMIC_RELEASE, __ATOMIC_RELAXED); return *expected; }
|
||||
FORCE_INLINE uint64 atomic_compare_exchange_strong_release(volatile uint64* value, uint64* expected, uint64 desired) noexcept { __atomic_compare_exchange_n(value, expected, desired, 0, __ATOMIC_RELEASE, __ATOMIC_RELAXED); return *expected; }
|
||||
FORCE_INLINE uint8 atomic_fetch_add_release(volatile uint8* value, uint8 operand) noexcept { return __atomic_add_fetch(value, operand, __ATOMIC_RELEASE); }
|
||||
FORCE_INLINE uint8 atomic_fetch_sub_release(volatile uint8* value, uint8 operand) noexcept { return __atomic_sub_fetch(value, operand, __ATOMIC_RELEASE); }
|
||||
FORCE_INLINE uint16 atomic_fetch_add_release(volatile uint16* value, uint16 operand) noexcept { return __atomic_add_fetch(value, operand, __ATOMIC_RELEASE); }
|
||||
|
|
@ -403,7 +403,7 @@ FORCE_INLINE void atomic_add_acquire_release(volatile int32* value, int32 increm
|
|||
FORCE_INLINE void atomic_sub_acquire_release(volatile int32* value, int32 decrement) noexcept { __atomic_sub_fetch(value, decrement, __ATOMIC_SEQ_CST); }
|
||||
FORCE_INLINE void atomic_add_acquire_release(volatile int64* value, int64 increment) noexcept { __atomic_add_fetch(value, increment, __ATOMIC_SEQ_CST); }
|
||||
FORCE_INLINE void atomic_sub_acquire_release(volatile int64* value, int64 decrement) noexcept { __atomic_sub_fetch(value, decrement, __ATOMIC_SEQ_CST); }
|
||||
FORCE_INLINE f32 atomic_compare_exchange_weak_acquire_release(volatile f32* value, f32* expected, f32 desired) noexcept {
|
||||
FORCE_INLINE f32 atomic_compare_exchange_strong_acquire_release(volatile f32* value, f32* expected, f32 desired) noexcept {
|
||||
volatile _atomic_32* value_as_union = (volatile _atomic_32*)value;
|
||||
_atomic_32* expected_as_union = (_atomic_32*)expected;
|
||||
_atomic_32 desired_as_union;
|
||||
|
|
@ -416,7 +416,7 @@ FORCE_INLINE f32 atomic_compare_exchange_weak_acquire_release(volatile f32* valu
|
|||
|
||||
return expected_as_union->f;
|
||||
}
|
||||
FORCE_INLINE f64 atomic_compare_exchange_weak_acquire_release(volatile f64* value, f64* expected, f64 desired) noexcept {
|
||||
FORCE_INLINE f64 atomic_compare_exchange_strong_acquire_release(volatile f64* value, f64* expected, f64 desired) noexcept {
|
||||
volatile _atomic_64* value_as_union = (volatile _atomic_64*)value;
|
||||
_atomic_64* expected_as_union = (_atomic_64*)expected;
|
||||
_atomic_64 desired_as_union;
|
||||
|
|
@ -429,8 +429,8 @@ FORCE_INLINE f64 atomic_compare_exchange_weak_acquire_release(volatile f64* valu
|
|||
|
||||
return expected_as_union->f;
|
||||
}
|
||||
FORCE_INLINE int32 atomic_compare_exchange_weak_acquire_release(volatile int32* value, int32* expected, int32 desired) noexcept { __atomic_compare_exchange_n(value, expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); return *expected; }
|
||||
FORCE_INLINE int64 atomic_compare_exchange_weak_acquire_release(volatile int64* value, int64* expected, int64 desired) noexcept { __atomic_compare_exchange_n(value, expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); return *expected; }
|
||||
FORCE_INLINE int32 atomic_compare_exchange_strong_acquire_release(volatile int32* value, int32* expected, int32 desired) noexcept { __atomic_compare_exchange_n(value, expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); return *expected; }
|
||||
FORCE_INLINE int64 atomic_compare_exchange_strong_acquire_release(volatile int64* value, int64* expected, int64 desired) noexcept { __atomic_compare_exchange_n(value, expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); return *expected; }
|
||||
FORCE_INLINE int8 atomic_fetch_add_acquire_release(volatile int8* value, int8 operand) noexcept { return __atomic_add_fetch(value, operand, __ATOMIC_SEQ_CST); }
|
||||
FORCE_INLINE int8 atomic_fetch_sub_acquire_release(volatile int8* value, int8 operand) noexcept { return __atomic_sub_fetch(value, operand, __ATOMIC_SEQ_CST); }
|
||||
FORCE_INLINE int16 atomic_fetch_add_acquire_release(volatile int16* value, int16 operand) noexcept { return __atomic_add_fetch(value, operand, __ATOMIC_SEQ_CST); }
|
||||
|
|
@ -467,8 +467,8 @@ FORCE_INLINE void atomic_add_acquire_release(volatile uint32* value, uint32 incr
|
|||
FORCE_INLINE void atomic_sub_acquire_release(volatile uint32* value, uint32 decrement) noexcept { __atomic_sub_fetch(value, decrement, __ATOMIC_SEQ_CST); }
|
||||
FORCE_INLINE void atomic_add_acquire_release(volatile uint64* value, uint64 increment) noexcept { __atomic_add_fetch(value, increment, __ATOMIC_SEQ_CST); }
|
||||
FORCE_INLINE void atomic_sub_acquire_release(volatile uint64* value, uint64 decrement) noexcept { __atomic_sub_fetch(value, decrement, __ATOMIC_SEQ_CST); }
|
||||
FORCE_INLINE uint32 atomic_compare_exchange_weak_acquire_release(volatile uint32* value, uint32* expected, uint32 desired) noexcept { __atomic_compare_exchange_n(value, expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); return *expected; }
|
||||
FORCE_INLINE uint64 atomic_compare_exchange_weak_acquire_release(volatile uint64* value, uint64* expected, uint64 desired) noexcept { __atomic_compare_exchange_n(value, expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); return *expected; }
|
||||
FORCE_INLINE uint32 atomic_compare_exchange_strong_acquire_release(volatile uint32* value, uint32* expected, uint32 desired) noexcept { __atomic_compare_exchange_n(value, expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED); return *expected; }
|
||||
FORCE_INLINE uint64 atomic_compare_exchange_strong_acquire_release(volatile uint64* value, uint64* expected, uint64 desired) noexcept { __atomic_compare_exchange_n(value, expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED); return *expected; }
|
||||
FORCE_INLINE uint8 atomic_fetch_add_acquire_release(volatile uint8* value, uint8 operand) noexcept { return __atomic_add_fetch(value, operand, __ATOMIC_SEQ_CST); }
|
||||
FORCE_INLINE uint8 atomic_fetch_sub_acquire_release(volatile uint8* value, uint8 operand) noexcept { return __atomic_sub_fetch(value, operand, __ATOMIC_SEQ_CST); }
|
||||
FORCE_INLINE uint16 atomic_fetch_add_acquire_release(volatile uint16* value, uint16 operand) noexcept { return __atomic_add_fetch(value, operand, __ATOMIC_SEQ_CST); }
|
||||
|
|
|
|||
|
|
@ -10,26 +10,31 @@
|
|||
#define COMS_DATABASE_H
|
||||
|
||||
#include "../stdlib/Types.h"
|
||||
#include "../../EngineDependencies/sqlite/src/sqlite3.h"
|
||||
|
||||
#include "DatabaseType.h"
|
||||
#include "DatabaseConnection.h"
|
||||
|
||||
inline
|
||||
int db_open_sqlite(DatabaseConnection* con)
|
||||
{
|
||||
int rc;
|
||||
rc = sqlite3_open(con->host, &con->db_sqlite);
|
||||
#if DB_MYSQL || DB_MARIA
|
||||
#else
|
||||
int32 db_open_maria(void*) { return 0; };
|
||||
void db_close_maria(void*) {};
|
||||
#endif
|
||||
|
||||
if (rc) {
|
||||
return rc;
|
||||
}
|
||||
#if DB_PSQL
|
||||
#else
|
||||
int32 db_open_psql(void*) { return 0; };
|
||||
void db_close_psql(void*) {};
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
#if DB_SQLITE
|
||||
#include "sqlite/SqliteDatabase.h"
|
||||
#else
|
||||
int32 db_open_sqlite(void*) { return 0; };
|
||||
void db_close_sqlite(void*) {};
|
||||
#endif
|
||||
|
||||
inline
|
||||
int db_open(DatabaseConnection* con)
|
||||
int32 db_open(DatabaseConnection* con)
|
||||
{
|
||||
switch (con->type) {
|
||||
case DB_TYPE_SQLITE: {
|
||||
|
|
@ -49,12 +54,6 @@ int db_open(DatabaseConnection* con)
|
|||
return 0;
|
||||
}
|
||||
|
||||
inline
|
||||
void db_close_sqlite(DatabaseConnection* con)
|
||||
{
|
||||
sqlite3_close(con->db_sqlite);
|
||||
}
|
||||
|
||||
inline
|
||||
void db_close(DatabaseConnection* con)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -10,15 +10,10 @@
|
|||
#define COMS_DATABASE_CONNECTION_H
|
||||
|
||||
#include "../stdlib/Types.h"
|
||||
#include "../../EngineDependencies/sqlite/src/sqlite3.h"
|
||||
|
||||
#include "DatabaseType.h"
|
||||
|
||||
struct DatabaseConnection {
|
||||
union {
|
||||
sqlite3* db_sqlite;
|
||||
sqlite3* db_pgsql;
|
||||
};
|
||||
void* con;
|
||||
|
||||
DatabaseType type;
|
||||
uint16 port;
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
#ifndef COMS_DATABASE_TYPE_H
|
||||
#define COMS_DATABASE_TYPE_H
|
||||
|
||||
enum DatabaseType {
|
||||
enum DatabaseType : byte {
|
||||
DB_TYPE_SQLITE,
|
||||
DB_TYPE_MARIA,
|
||||
DB_TYPE_PSQL,
|
||||
|
|
|
|||
34
database/sqlite/SqliteDatabase.h
Normal file
34
database/sqlite/SqliteDatabase.h
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* @copyright Jingga
|
||||
* @license OMS License 2.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
#ifndef COMS_DATABASE_SQLITE_H
|
||||
#define COMS_DATABASE_SQLITE_H
|
||||
|
||||
#include "../../stdlib/Types.h"
|
||||
#include "../../EngineDependencies/sqlite/src/sqlite3.h"
|
||||
|
||||
inline
|
||||
int32 db_open_sqlite(DatabaseConnection* con)
|
||||
{
|
||||
int32 rc;
|
||||
rc = sqlite3_open(con->host, &con->db_sqlite);
|
||||
|
||||
if (rc) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline
|
||||
void db_close_sqlite(DatabaseConnection* con)
|
||||
{
|
||||
sqlite3_close(con->db_sqlite);
|
||||
}
|
||||
|
||||
#endif
|
||||
110
encoding/Base64.h
Normal file
110
encoding/Base64.h
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* @copyright Jingga
|
||||
* @license OMS License 2.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
#ifndef COMS_ENCODING_BASE64_H
|
||||
#define COMS_ENCODING_BASE64_H
|
||||
|
||||
#include "../stdlib/Types.h"
|
||||
#include "../utils/StringUtils.h"
|
||||
#include "Base64Definitions.h"
|
||||
|
||||
void base64_encode(const byte* data, char* encoded_data, size_t data_length = 0) {
|
||||
size_t output_length = 4 * ((data_length + 2) / 3);
|
||||
|
||||
if (!data_length) {
|
||||
// WARNING: This should only happen if the data is a char string
|
||||
// Binary data is not allowed since it often has '\0' characters
|
||||
data_length = str_length((const char *) data);
|
||||
}
|
||||
|
||||
size_t i = 0;
|
||||
size_t j = 0;
|
||||
while (i + 3 <= data_length) {
|
||||
uint32 triple = ((uint32) data[i] << 16) | ((uint32) data[i + 1] << 8) | data[i + 2];
|
||||
|
||||
encoded_data[j++] = BASE64_CHARS[(triple >> 3 * 6) & 0x3F];
|
||||
encoded_data[j++] = BASE64_CHARS[(triple >> 2 * 6) & 0x3F];
|
||||
encoded_data[j++] = BASE64_CHARS[(triple >> 1 * 6) & 0x3F];
|
||||
encoded_data[j++] = BASE64_CHARS[(triple >> 0 * 6) & 0x3F];
|
||||
|
||||
i += 3;
|
||||
}
|
||||
|
||||
if (i < data_length) {
|
||||
uint32 triple = ((uint32) data[i] << 16);
|
||||
if (i + 1 < data_length) {
|
||||
triple |= ((uint32) data[i + 1] << 8);
|
||||
}
|
||||
|
||||
encoded_data[j++] = BASE64_CHARS[(triple >> 18) & 0x3F];
|
||||
encoded_data[j++] = BASE64_CHARS[(triple >> 12) & 0x3F];
|
||||
encoded_data[j] = (i + 1 < data_length) ? BASE64_CHARS[(triple >> 6) & 0x3F] : '=';
|
||||
encoded_data[j + 1] = '=';
|
||||
}
|
||||
|
||||
encoded_data[output_length] = '\0';
|
||||
}
|
||||
|
||||
size_t base64_decode(const char* encoded_data, byte* data, size_t encoded_length = 0) {
|
||||
if (!encoded_length) {
|
||||
encoded_length = str_length(encoded_data);
|
||||
}
|
||||
|
||||
size_t output_length = encoded_length / 4 * 3;
|
||||
int32 padding = 0;
|
||||
|
||||
if (data[encoded_length - 1] == '=') {
|
||||
--output_length;
|
||||
++padding;
|
||||
|
||||
if (data[encoded_length - 2] == '=') {
|
||||
--output_length;
|
||||
++padding;
|
||||
}
|
||||
}
|
||||
|
||||
size_t complete_blocks = (encoded_length - padding) / 4;
|
||||
size_t i, j;
|
||||
|
||||
for (i = 0, j = 0; i < complete_blocks * 4; i += 4, j += 3) {
|
||||
uint32 sextet_a = BASE64_LOOKUP[(byte) encoded_data[i]];
|
||||
uint32 sextet_b = BASE64_LOOKUP[(byte) encoded_data[i + 1]];
|
||||
uint32 sextet_c = BASE64_LOOKUP[(byte) encoded_data[i + 2]];
|
||||
uint32 sextet_d = BASE64_LOOKUP[(byte) encoded_data[i + 3]];
|
||||
|
||||
uint32 triple = (sextet_a << 18) | (sextet_b << 12) | (sextet_c << 6) | sextet_d;
|
||||
|
||||
data[j] = (triple >> 16) & 0xFF;
|
||||
data[j + 1] = (triple >> 8) & 0xFF;
|
||||
data[j + 2] = triple & 0xFF;
|
||||
}
|
||||
|
||||
if (padding > 0) {
|
||||
uint32 sextet_a = BASE64_LOOKUP[(byte) encoded_data[i]];
|
||||
uint32 sextet_b = BASE64_LOOKUP[(byte) encoded_data[i + 1]];
|
||||
uint32 sextet_c = (padding > 1) ? 0 : BASE64_LOOKUP[(byte) encoded_data[i + 2]];
|
||||
uint32 sextet_d = 0;
|
||||
|
||||
uint32 triple = (sextet_a << 18) | (sextet_b << 12) | (sextet_c << 6) | sextet_d;
|
||||
|
||||
data[j + 1] = (triple >> 16) & 0xFF;
|
||||
if (padding == 1) {
|
||||
data[j + 2] = (triple >> 8) & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
return output_length;
|
||||
}
|
||||
|
||||
#if __aarch64__
|
||||
#include "Base64SimdArm.h"
|
||||
#else
|
||||
#include "Base64SimdX86.h"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
46
encoding/Base64Definitions.h
Normal file
46
encoding/Base64Definitions.h
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* @copyright Jingga
|
||||
* @license OMS License 2.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
#ifndef COMS_ENCODING_BASE64_DEFINITIONS_H
|
||||
#define COMS_ENCODING_BASE64_DEFINITIONS_H
|
||||
|
||||
#include "../stdlib/Types.h"
|
||||
|
||||
static const char BASE64_CHARS[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
static const int8 BASE64_LOOKUP[256] = {
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63,
|
||||
52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1,
|
||||
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,
|
||||
15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,
|
||||
-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,
|
||||
41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
|
||||
};
|
||||
|
||||
inline
|
||||
size_t base64_encoded_length(size_t data_length) {
|
||||
return 4 * ((data_length + 2) / 3);
|
||||
}
|
||||
|
||||
inline
|
||||
size_t base64_encoded_length(size_t encoded_length) {
|
||||
return encoded_length / 4 * 3;
|
||||
}
|
||||
|
||||
#endif
|
||||
271
encoding/Base64SimdArm.h
Normal file
271
encoding/Base64SimdArm.h
Normal file
|
|
@ -0,0 +1,271 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* @copyright Jingga
|
||||
* @license OMS License 2.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
#ifndef COMS_ENCODING_BASE64_SIMD_ARM_H
|
||||
#define COMS_ENCODING_BASE64_SIMD_ARM_H
|
||||
|
||||
#include "../stdlib/Types.h"
|
||||
#include "../stdlib/Simd.h"
|
||||
#include "../utils/StringUtils.h"
|
||||
#include "Base64Definitions.h"
|
||||
|
||||
#ifdef __ARM_FEATURE_SVE
|
||||
#include <arm_sve.h>
|
||||
#endif
|
||||
|
||||
#ifdef __ARM_NEON
|
||||
#include <arm_neon.h>
|
||||
#endif
|
||||
|
||||
void base64_encode_simd(const byte* data, char* encoded_data, size_t data_length = 0, int32 steps = 16) {
|
||||
if (!data_length) {
|
||||
// WARNING: This should only happen if the data is a char string
|
||||
// Binary data is not allowed since it often has '\0' characters
|
||||
data_length = str_length((const char *) data);
|
||||
}
|
||||
|
||||
steps = intrin_validate_steps(data, steps);
|
||||
steps = intrin_validate_steps((const byte*) encoded_data, steps);
|
||||
|
||||
size_t i = 0;
|
||||
|
||||
#ifdef __ARM_FEATURE_SVE
|
||||
if (steps >= 8) {
|
||||
const size_t sve_vec_bytes = steps;
|
||||
const size_t triple_per_vec = sve_vec_bytes / 3;
|
||||
|
||||
for (; i + (triple_per_vec * 3 - 1) < data_length; i += triple_per_vec * 3) {
|
||||
svuint8_t in = svld1_u8(svptrue_b8(), data + i);
|
||||
|
||||
svuint32_t triple0 = svreinterpret_u32(svld1_u8(svptrue_b8(), data + i));
|
||||
svuint32_t triple1 = svreinterpret_u32(svld1_u8(svptrue_b8(), data + i + 4));
|
||||
svuint32_t triple2 = svreinterpret_u32(svld1_u8(svptrue_b8(), data + i + 8));
|
||||
|
||||
svuint32_t combined = svorr_u32_x(svptrue_b32(),
|
||||
svlsl_n_u32_x(svptrue_b32(), triple0, 16),
|
||||
svorr_u32_x(svptrue_b32(),
|
||||
svlsl_n_u32_x(svptrue_b32(), triple1, 8),
|
||||
triple2));
|
||||
|
||||
svuint32_t idx0 = svand_u32_x(svptrue_b32(), svlsr_n_u32_x(svptrue_b32(), combined, 18), 0x3F);
|
||||
svuint32_t idx1 = svand_u32_x(svptrue_b32(), svlsr_n_u32_x(svptrue_b32(), combined, 12), 0x3F);
|
||||
svuint32_t idx2 = svand_u32_x(svptrue_b32(), svlsr_n_u32_x(svptrue_b32(), combined, 6), 0x3F);
|
||||
svuint32_t idx3 = svand_u32_x(svptrue_b32(), combined, 0x3F);
|
||||
|
||||
svuint8_t chars0 = svld1_u8(svptrue_b8(), (const byte*)BASE64_CHARS);
|
||||
svuint8_t enc0 = svtbl_u8(chars0, svreinterpret_u8_u32(idx0));
|
||||
svuint8_t enc1 = svtbl_u8(chars0, svreinterpret_u8_u32(idx1));
|
||||
svuint8_t enc2 = svtbl_u8(chars0, svreinterpret_u8_u32(idx2));
|
||||
svuint8_t enc3 = svtbl_u8(chars0, svreinterpret_u8_u32(idx3));
|
||||
|
||||
svuint8_t encoded = svzip1_u8(svzip1_u8(enc0, enc1), svzip1_u8(enc2, enc3));
|
||||
|
||||
svst1_u8(svptrue_b8(), (uint8_t*)(encoded_data + (i/3*4)), encoded);
|
||||
}
|
||||
|
||||
steps = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __ARM_NEON
|
||||
if (steps >= 4) {
|
||||
steps = 4;
|
||||
|
||||
const uint8x16_t base64_table = vld1q_u8((const byte*)BASE64_CHARS);
|
||||
const uint8x16_t mask_3F = vdupq_n_u8(0x3F);
|
||||
|
||||
for (; i + 11 < data_length; i += 12) {
|
||||
uint8x16_t in = vld1q_u8(data + i);
|
||||
|
||||
uint32x4_t triple0 = vreinterpretq_u32_u8(vshrq_n_u8(in, 2));
|
||||
uint32x4_t triple1 = vreinterpretq_u32_u8(vshrq_n_u8(vextq_u8(in, in, 1), 4));
|
||||
uint32x4_t triple2 = vreinterpretq_u32_u8(vshrq_n_u8(vextq_u8(in, in, 2), 6));
|
||||
|
||||
uint32x4_t combined = vorrq_u32(
|
||||
vshlq_n_u32(triple0, 16),
|
||||
vorrq_u32(
|
||||
vshlq_n_u32(triple1, 8),
|
||||
triple2));
|
||||
|
||||
uint32x4_t idx0 = vandq_u32(vshrq_n_u32(combined, 18), 0x3F);
|
||||
uint32x4_t idx1 = vandq_u32(vshrq_n_u32(combined, 12), 0x3F);
|
||||
uint32x4_t idx2 = vandq_u32(vshrq_n_u32(combined, 6), 0x3F);
|
||||
uint32x4_t idx3 = vandq_u32(combined, 0x3F);
|
||||
|
||||
uint8x16_t enc0 = vqtbl1q_u8(base64_table, vreinterpretq_u8_u32(idx0));
|
||||
uint8x16_t enc1 = vqtbl1q_u8(base64_table, vreinterpretq_u8_u32(idx1));
|
||||
uint8x16_t enc2 = vqtbl1q_u8(base64_table, vreinterpretq_u8_u32(idx2));
|
||||
uint8x16_t enc3 = vqtbl1q_u8(base64_table, vreinterpretq_u8_u32(idx3));
|
||||
|
||||
uint8x16x2_t zip01 = vzipq_u8(enc0, enc1);
|
||||
uint8x16x2_t zip23 = vzipq_u8(enc2, enc3);
|
||||
uint8x16_t encoded = vcombine_u8(vget_low_u8(zip01.val[0]), vget_low_u8(zip23.val[0]));
|
||||
|
||||
vst1q_u8((uint8_t*)(encoded_data + (i/3*4)), encoded);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
for (; i + 3 <= data_length; i += 3) {
|
||||
uint32 triple = ((uint32)data[i] << 16) | ((uint32)data[i + 1] << 8) | data[i + 2];
|
||||
|
||||
encoded_data[i/3*4 + 0] = BASE64_CHARS[(triple >> 18) & 0x3F];
|
||||
encoded_data[i/3*4 + 1] = BASE64_CHARS[(triple >> 12) & 0x3F];
|
||||
encoded_data[i/3*4 + 2] = BASE64_CHARS[(triple >> 6) & 0x3F];
|
||||
encoded_data[i/3*4 + 3] = BASE64_CHARS[triple & 0x3F];
|
||||
}
|
||||
|
||||
if (i < data_length) {
|
||||
uint32 triple = ((uint32)data[i] << 16);
|
||||
if (i + 1 < data_length) {
|
||||
triple |= ((uint32)data[i + 1] << 8);
|
||||
}
|
||||
|
||||
size_t j = i/3*4;
|
||||
encoded_data[j++] = BASE64_CHARS[(triple >> 18) & 0x3F];
|
||||
encoded_data[j++] = BASE64_CHARS[(triple >> 12) & 0x3F];
|
||||
encoded_data[j++] = (i + 1 < data_length) ? BASE64_CHARS[(triple >> 6) & 0x3F] : '=';
|
||||
encoded_data[j] = '=';
|
||||
}
|
||||
|
||||
encoded_data[base64_encoded_length(data_length)] = '\0';
|
||||
}
|
||||
|
||||
size_t base64_decode_simd(const char* encoded_data, byte* data, size_t encoded_length = 0, int32 steps = 16) {
|
||||
if (!encoded_length) {
|
||||
encoded_length = str_length(encoded_data);
|
||||
}
|
||||
|
||||
size_t padding = 0;
|
||||
if (encoded_data[encoded_length - 1] == '=') {
|
||||
++padding;
|
||||
if (encoded_data[encoded_length - 2] == '=') {
|
||||
++padding;
|
||||
}
|
||||
}
|
||||
|
||||
size_t output_length = (encoded_length / 4) * 3 - padding;
|
||||
size_t complete_blocks = (encoded_length - padding) / 4;
|
||||
|
||||
steps = intrin_validate_steps((const byte*) encoded_data, steps);
|
||||
steps = intrin_validate_steps(data, steps);
|
||||
|
||||
size_t i = 0;
|
||||
size_t j = 0;
|
||||
|
||||
#ifdef __ARM_FEATURE_SVE
|
||||
if (steps >= 8) {
|
||||
const size_t sve_vec_bytes = steps;
|
||||
const size_t quad_per_vec = sve_vec_bytes / 4;
|
||||
|
||||
for (; i + (quad_per_vec * 4 - 1) < complete_blocks * 4; i += quad_per_vec * 4, j += quad_per_vec * 3) {
|
||||
|
||||
svuint8_t in = svld1_u8(svptrue_b8(), (const byte*)(encoded_data + i));
|
||||
|
||||
byte chars[sve_vec_bytes];
|
||||
svst1_u8(svptrue_b8(), chars, in);
|
||||
|
||||
uint32 sextets[quad_per_vec];
|
||||
for (size_t k = 0; k < quad_per_vec; ++k) {
|
||||
sextets[k] =
|
||||
(BASE64_LOOKUP[chars[k*4 + 0]] << 18) |
|
||||
(BASE64_LOOKUP[chars[k*4 + 1]] << 12) |
|
||||
(BASE64_LOOKUP[chars[k*4 + 2]] << 6) |
|
||||
(BASE64_LOOKUP[chars[k*4 + 3]]);
|
||||
}
|
||||
|
||||
byte output_bytes[quad_per_vec * 3];
|
||||
for (size_t k = 0; k < quad_per_vec; ++k) {
|
||||
output_bytes[k*3 + 0] = (sextets[k] >> 16) & 0xFF;
|
||||
output_bytes[k*3 + 1] = (sextets[k] >> 8) & 0xFF;
|
||||
output_bytes[k*3 + 2] = sextets[k] & 0xFF;
|
||||
}
|
||||
|
||||
|
||||
svst1_u8(svptrue_b8(), data + j, svld1_u8(svptrue_b8(), output_bytes));
|
||||
}
|
||||
|
||||
steps = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __ARM_NEON
|
||||
if (steps >= 4) {
|
||||
steps = 4;
|
||||
|
||||
const uint8x16_t mask_3F = vdupq_n_u8(0x3F);
|
||||
const uint8x16_t shuffle_mask = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2
|
||||
};
|
||||
|
||||
for (; i + 15 < complete_blocks * 4; i += 16, j += 12) {
|
||||
|
||||
uint8x16_t in = vld1q_u8((const byte*)(encoded_data + i));
|
||||
|
||||
byte chars[16];
|
||||
vst1q_u8(chars, in);
|
||||
|
||||
uint32 sextets[4];
|
||||
for (int k = 0; k < 4; ++k) {
|
||||
sextets[k] =
|
||||
(BASE64_LOOKUP[chars[k*4 + 0]] << 18) |
|
||||
(BASE64_LOOKUP[chars[k*4 + 1]] << 12) |
|
||||
(BASE64_LOOKUP[chars[k*4 + 2]] << 6) |
|
||||
(BASE64_LOOKUP[chars[k*4 + 3]]);
|
||||
}
|
||||
|
||||
uint8x16_t bytes0 = vreinterpretq_u8_u32(vshrq_n_u32(vld1q_u32(sextets), 16));
|
||||
uint8x16_t bytes1 = vreinterpretq_u8_u32(vshrq_n_u32(vld1q_u32(sextets), 8));
|
||||
uint8x16_t bytes2 = vreinterpretq_u8_u32(vld1q_u32(sextets));
|
||||
|
||||
bytes0 = vandq_u8(bytes0, vdupq_n_u8(0xFF));
|
||||
bytes1 = vandq_u8(bytes1, vdupq_n_u8(0xFF));
|
||||
bytes2 = vandq_u8(bytes2, vdupq_n_u8(0xFF));
|
||||
|
||||
|
||||
uint8x16_t packed = vqtbl1q_u8(vcombine_u8(
|
||||
vget_low_u8(bytes0), vget_low_u8(bytes1)), shuffle_mask);
|
||||
|
||||
vst1q_u8(data + j, packed);
|
||||
|
||||
vst1_u8(data + j + 8, vget_low_u8(bytes2));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
for (; i < complete_blocks * 4; i += 4, j += 3) {
|
||||
uint32 sextet_a = BASE64_LOOKUP[(byte) encoded_data[i]];
|
||||
uint32 sextet_b = BASE64_LOOKUP[(byte) encoded_data[i + 1]];
|
||||
uint32 sextet_c = BASE64_LOOKUP[(byte) encoded_data[i + 2]];
|
||||
uint32 sextet_d = BASE64_LOOKUP[(byte) encoded_data[i + 3]];
|
||||
|
||||
uint32 triple = (sextet_a << 18) | (sextet_b << 12) | (sextet_c << 6) | sextet_d;
|
||||
|
||||
data[j] = (triple >> 16) & 0xFF;
|
||||
data[j + 1] = (triple >> 8) & 0xFF;
|
||||
data[j + 2] = triple & 0xFF;
|
||||
}
|
||||
|
||||
if (padding > 0) {
|
||||
uint32 sextet_a = BASE64_LOOKUP[(byte) encoded_data[i]];
|
||||
uint32 sextet_b = BASE64_LOOKUP[(byte) encoded_data[i + 1]];
|
||||
uint32 sextet_c = (padding > 1) ? 0 : BASE64_LOOKUP[(byte) encoded_data[i + 2]];
|
||||
uint32 sextet_d = 0;
|
||||
|
||||
uint32 triple = (sextet_a << 18) | (sextet_b << 12) | (sextet_c << 6) | sextet_d;
|
||||
|
||||
data[j] = (triple >> 16) & 0xFF;
|
||||
if (padding == 1) {
|
||||
data[j + 1] = (triple >> 8) & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
return output_length;
|
||||
}
|
||||
|
||||
#endif
|
||||
405
encoding/Base64SimdX86.h
Normal file
405
encoding/Base64SimdX86.h
Normal file
|
|
@ -0,0 +1,405 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* @copyright Jingga
|
||||
* @license OMS License 2.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
#ifndef COMS_ENCODING_BASE64_SIMD_X86_H
|
||||
#define COMS_ENCODING_BASE64_SIMD_X86_H
|
||||
|
||||
#include <immintrin.h>
|
||||
#include "../stdlib/Types.h"
|
||||
#include "../stdlib/Simd.h"
|
||||
#include "../utils/StringUtils.h"
|
||||
#include "Base64Definitions.h"
|
||||
|
||||
void base64_encode_simd(const byte* data, char* encoded_data, size_t data_length = 0, int32 steps = 16) {
|
||||
if (!data_length) {
|
||||
// WARNING: This should only happen if the data is a char string
|
||||
// Binary data is not allowed since it often has '\0' characters
|
||||
data_length = str_length((const char *) data);
|
||||
}
|
||||
|
||||
steps = intrin_validate_steps(data, steps);
|
||||
steps = intrin_validate_steps((const byte*) encoded_data, steps);
|
||||
|
||||
size_t i = 0;
|
||||
|
||||
#ifdef __AVX512F__
|
||||
if (steps >= 16) {
|
||||
const __m512i mask0 = _mm512_set1_epi32(0x00FC0000);
|
||||
const __m512i mask1 = _mm512_set1_epi32(0x0003F000);
|
||||
const __m512i mask2 = _mm512_set1_epi32(0x00000FC0);
|
||||
const __m512i mask3 = _mm512_set1_epi32(0x0000003F);
|
||||
|
||||
const __m512i shift0 = _mm512_set1_epi32(18);
|
||||
const __m512i shift1 = _mm512_set1_epi32(12);
|
||||
const __m512i shift2 = _mm512_set1_epi32(6);
|
||||
const __m512i shift3 = _mm512_set1_epi32(0);
|
||||
|
||||
const __m512i shuffle_mask = _mm512_set_epi8(
|
||||
5,4,6,5,7,6,8,7,9,8,10,9,11,10,12,11,
|
||||
1,0,2,1,3,2,4,3,5,4,6,5,7,6,8,7,
|
||||
5,4,6,5,7,6,8,7,9,8,10,9,11,10,12,11,
|
||||
1,0,2,1,3,2,4,3,5,4,6,5,7,6,8,7
|
||||
);
|
||||
|
||||
const __m512i permute_mask = _mm512_set_epi32(15,13,11,9,7,5,3,1,14,12,10,8,6,4,2,0);
|
||||
|
||||
for (; i + 47 < data_length; i += 48) {
|
||||
__m512i in = _mm512_loadu_si512((const __m512i*)(data + i));
|
||||
|
||||
__m512i shuffled = _mm512_shuffle_epi8(in, shuffle_mask);
|
||||
|
||||
__m512i permuted = _mm512_permutexvar_epi32(permute_mask, shuffled);
|
||||
|
||||
__m512i indices0 = _mm512_srlv_epi32(permuted, shift0);
|
||||
__m512i indices1 = _mm512_srlv_epi32(permuted, shift1);
|
||||
__m512i indices2 = _mm512_srlv_epi32(permuted, shift2);
|
||||
__m512i indices3 = _mm512_srlv_epi32(permuted, shift3);
|
||||
|
||||
indices0 = _mm512_and_si512(indices0, mask0);
|
||||
indices1 = _mm512_and_si512(indices1, mask1);
|
||||
indices2 = _mm512_and_si512(indices2, mask2);
|
||||
indices3 = _mm512_and_si512(indices3, mask3);
|
||||
|
||||
__m512i indices = _mm512_or_si512(
|
||||
_mm512_or_si512(indices0, indices1),
|
||||
_mm512_or_si512(indices2, indices3)
|
||||
);
|
||||
|
||||
alignas(64) uint32 idx[16];
|
||||
_mm512_store_si512((__m512i*)idx, indices);
|
||||
|
||||
for (int32 k = 0; k < 16; ++k) {
|
||||
encoded_data[i/3*4 + k*4 + 0] = BASE64_CHARS[(idx[k] >> 18) & 0x3F];
|
||||
encoded_data[i/3*4 + k*4 + 1] = BASE64_CHARS[(idx[k] >> 12) & 0x3F];
|
||||
encoded_data[i/3*4 + k*4 + 2] = BASE64_CHARS[(idx[k] >> 6) & 0x3F];
|
||||
encoded_data[i/3*4 + k*4 + 3] = BASE64_CHARS[(idx[k] >> 0) & 0x3F];
|
||||
}
|
||||
}
|
||||
|
||||
steps = 1;
|
||||
} else
|
||||
#endif
|
||||
|
||||
#ifdef __AVX2__
|
||||
if (steps >= 8) {
|
||||
const __m256i mask0 = _mm256_set1_epi32(0x00FC0000);
|
||||
const __m256i mask1 = _mm256_set1_epi32(0x0003F000);
|
||||
const __m256i mask2 = _mm256_set1_epi32(0x00000FC0);
|
||||
const __m256i mask3 = _mm256_set1_epi32(0x0000003F);
|
||||
|
||||
const __m256i shift0 = _mm256_set1_epi32(18);
|
||||
const __m256i shift1 = _mm256_set1_epi32(12);
|
||||
const __m256i shift2 = _mm256_set1_epi32(6);
|
||||
const __m256i shift3 = _mm256_set1_epi32(0);
|
||||
|
||||
const __m256i shuffle_mask = _mm256_set_epi8(
|
||||
5,4,6,5,7,6,8,7,9,8,10,9,11,10,12,11,
|
||||
1,0,2,1,3,2,4,3,5,4,6,5,7,6,8,7
|
||||
);
|
||||
|
||||
const __m256i permute_mask = _mm256_set_epi32(7,5,3,1,6,4,2,0);
|
||||
|
||||
for (; i + 23 < data_length; i += 24) {
|
||||
__m256i in = _mm256_loadu_si256((const __m256i*)(data + i));
|
||||
|
||||
__m256i shuffled = _mm256_shuffle_epi8(in, shuffle_mask);
|
||||
|
||||
__m256i permuted = _mm256_permutevar8x32_epi32(shuffled, permute_mask);
|
||||
|
||||
__m256i indices0 = _mm256_srlv_epi32(permuted, shift0);
|
||||
__m256i indices1 = _mm256_srlv_epi32(permuted, shift1);
|
||||
__m256i indices2 = _mm256_srlv_epi32(permuted, shift2);
|
||||
__m256i indices3 = _mm256_srlv_epi32(permuted, shift3);
|
||||
|
||||
indices0 = _mm256_and_si256(indices0, mask0);
|
||||
indices1 = _mm256_and_si256(indices1, mask1);
|
||||
indices2 = _mm256_and_si256(indices2, mask2);
|
||||
indices3 = _mm256_and_si256(indices3, mask3);
|
||||
|
||||
__m256i indices = _mm256_or_si256(
|
||||
_mm256_or_si256(indices0, indices1),
|
||||
_mm256_or_si256(indices2, indices3)
|
||||
);
|
||||
|
||||
alignas(32) uint32 idx[8];
|
||||
_mm256_store_si256((__m256i*)idx, indices);
|
||||
|
||||
for (int32 k = 0; k < 8; ++k) {
|
||||
encoded_data[i/3*4 + k*4 + 0] = BASE64_CHARS[(idx[k] >> 18) & 0x3F];
|
||||
encoded_data[i/3*4 + k*4 + 1] = BASE64_CHARS[(idx[k] >> 12) & 0x3F];
|
||||
encoded_data[i/3*4 + k*4 + 2] = BASE64_CHARS[(idx[k] >> 6) & 0x3F];
|
||||
encoded_data[i/3*4 + k*4 + 3] = BASE64_CHARS[(idx[k] >> 0) & 0x3F];
|
||||
}
|
||||
}
|
||||
|
||||
steps = 1;
|
||||
} else
|
||||
#endif
|
||||
|
||||
#ifdef __SSE4_2__
|
||||
if (steps >= 4) {
|
||||
const __m128i mask0 = _mm_set1_epi32(0x00FC0000);
|
||||
const __m128i mask1 = _mm_set1_epi32(0x0003F000);
|
||||
const __m128i mask2 = _mm_set1_epi32(0x00000FC0);
|
||||
const __m128i mask3 = _mm_set1_epi32(0x0000003F);
|
||||
|
||||
const __m128i shift0 = _mm_set1_epi32(18);
|
||||
const __m128i shift1 = _mm_set1_epi32(12);
|
||||
const __m128i shift2 = _mm_set1_epi32(6);
|
||||
const __m128i shift3 = _mm_set1_epi32(0);
|
||||
|
||||
const __m128i shuffle_mask = _mm_set_epi8(
|
||||
5,4,6,5,7,6,8,7,9,8,10,9,11,10,12,11
|
||||
);
|
||||
|
||||
for (; i + 11 < data_length; i += 12) {
|
||||
__m128i in = _mm_loadu_si128((const __m128i*)(data + i));
|
||||
|
||||
__m128i shuffled = _mm_shuffle_epi8(in, shuffle_mask);
|
||||
|
||||
__m128i indices0 = _mm_srlv_epi32(shuffled, shift0);
|
||||
__m128i indices1 = _mm_srlv_epi32(shuffled, shift1);
|
||||
__m128i indices2 = _mm_srlv_epi32(shuffled, shift2);
|
||||
__m128i indices3 = _mm_srlv_epi32(shuffled, shift3);
|
||||
|
||||
indices0 = _mm_and_si128(indices0, mask0);
|
||||
indices1 = _mm_and_si128(indices1, mask1);
|
||||
indices2 = _mm_and_si128(indices2, mask2);
|
||||
indices3 = _mm_and_si128(indices3, mask3);
|
||||
|
||||
__m128i indices = _mm_or_si128(_mm_or_si128(indices0, indices1), _mm_or_si128(indices2, indices3));
|
||||
|
||||
alignas(16) uint32 idx[4];
|
||||
_mm_store_si128((__m128i*)idx, indices);
|
||||
|
||||
for (int32 k = 0; k < 4; ++k) {
|
||||
encoded_data[i/3*4 + k*4 + 0] = BASE64_CHARS[(idx[k] >> 18) & 0x3F];
|
||||
encoded_data[i/3*4 + k*4 + 1] = BASE64_CHARS[(idx[k] >> 12) & 0x3F];
|
||||
encoded_data[i/3*4 + k*4 + 2] = BASE64_CHARS[(idx[k] >> 6) & 0x3F];
|
||||
encoded_data[i/3*4 + k*4 + 3] = BASE64_CHARS[(idx[k] >> 0) & 0x3F];
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
for (; i + 3 <= data_length; i += 3) {
|
||||
uint32 triple = ((uint32)data[i] << 16) | ((uint32)data[i + 1] << 8) | data[i + 2];
|
||||
|
||||
encoded_data[i/3*4 + 0] = BASE64_CHARS[(triple >> 18) & 0x3F];
|
||||
encoded_data[i/3*4 + 1] = BASE64_CHARS[(triple >> 12) & 0x3F];
|
||||
encoded_data[i/3*4 + 2] = BASE64_CHARS[(triple >> 6) & 0x3F];
|
||||
encoded_data[i/3*4 + 3] = BASE64_CHARS[triple & 0x3F];
|
||||
}
|
||||
|
||||
if (i < data_length) {
|
||||
uint32 triple = ((uint32)data[i] << 16);
|
||||
if (i + 1 < data_length) {
|
||||
triple |= ((uint32)data[i + 1] << 8);
|
||||
}
|
||||
|
||||
size_t j = i/3*4;
|
||||
encoded_data[j++] = BASE64_CHARS[(triple >> 18) & 0x3F];
|
||||
encoded_data[j++] = BASE64_CHARS[(triple >> 12) & 0x3F];
|
||||
encoded_data[j++] = (i + 1 < data_length) ? BASE64_CHARS[(triple >> 6) & 0x3F] : '=';
|
||||
encoded_data[j] = '=';
|
||||
}
|
||||
|
||||
encoded_data[base64_encoded_length(data_length)] = '\0';
|
||||
}
|
||||
|
||||
size_t base64_decode_simd(const char* encoded_data, byte* data, size_t encoded_length, int32 steps = 16) {
|
||||
if (!encoded_length) {
|
||||
encoded_length = str_length(encoded_data);
|
||||
}
|
||||
|
||||
size_t padding = 0;
|
||||
if (encoded_data[encoded_length - 1] == '=') {
|
||||
++padding;
|
||||
|
||||
if (encoded_data[encoded_length - 2] == '=') {
|
||||
++padding;
|
||||
}
|
||||
}
|
||||
|
||||
size_t output_length = (encoded_length / 4) * 3 - padding;
|
||||
size_t complete_blocks = (encoded_length - padding) / 4;
|
||||
|
||||
steps = intrin_validate_steps((const byte*)encoded_data, steps);
|
||||
steps = intrin_validate_steps(data, steps);
|
||||
|
||||
size_t i = 0;
|
||||
size_t j = 0;
|
||||
|
||||
#ifdef __AVX512F__
|
||||
if (steps >= 16) {
|
||||
steps = 16;
|
||||
|
||||
const __m512i mask6bits = _mm512_set1_epi32(0x3F);
|
||||
const __m512i shuffle_mask = _mm512_set_epi8(
|
||||
-1,-1,-1,-1,-1,-1,11,10,9,8,7,6,5,4,3,2,
|
||||
-1,-1,-1,-1,-1,-1,11,10,9,8,7,6,5,4,3,2,
|
||||
-1,-1,-1,-1,-1,-1,11,10,9,8,7,6,5,4,3,2,
|
||||
-1,-1,-1,-1,-1,-1,11,10,9,8,7,6,5,4,3,2
|
||||
);
|
||||
|
||||
const __m512i permute_mask = _mm512_set_epi32(0,0,0,0,0,0,0,0,14,12,10,8,6,4,2,0);
|
||||
|
||||
for (; i + 63 < complete_blocks * 4; i += 64, j += 48) {
|
||||
__m512i in = _mm512_loadu_si512((const __m512i*)(encoded_data + i));
|
||||
|
||||
alignas(64) byte chars[64];
|
||||
_mm512_store_si512((__m512i*)chars, in);
|
||||
|
||||
alignas(64) uint32 sextets[16];
|
||||
for (int32 k = 0; k < 16; ++k) {
|
||||
sextets[k] =
|
||||
(BASE64_LOOKUP[(byte)chars[k*4 + 0]] << 18) |
|
||||
(BASE64_LOOKUP[(byte)chars[k*4 + 1]] << 12) |
|
||||
(BASE64_LOOKUP[(byte)chars[k*4 + 2]] << 6) |
|
||||
(BASE64_LOOKUP[(byte)chars[k*4 + 3]]);
|
||||
}
|
||||
|
||||
__m512i sextet_vec = _mm512_load_si512((const __m512i*)sextets);
|
||||
|
||||
__m512i bytes0 = _mm512_srli_epi32(sextet_vec, 16);
|
||||
__m512i bytes1 = _mm512_srli_epi32(sextet_vec, 8);
|
||||
__m512i bytes2 = sextet_vec;
|
||||
|
||||
bytes0 = _mm512_and_si512(bytes0, _mm512_set1_epi32(0xFF));
|
||||
bytes1 = _mm512_and_si512(bytes1, _mm512_set1_epi32(0xFF));
|
||||
bytes2 = _mm512_and_si512(bytes2, _mm512_set1_epi32(0xFF));
|
||||
|
||||
__m512i packed = _mm512_shuffle_epi8(_mm512_packus_epi32(bytes0, bytes1), shuffle_mask);
|
||||
packed = _mm512_permutexvar_epi32(permute_mask, packed);
|
||||
|
||||
_mm512_storeu_si512((__m512i*)(data + j), packed);
|
||||
}
|
||||
|
||||
steps = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __AVX2__
|
||||
if (steps >= 8) {
|
||||
steps = 8;
|
||||
|
||||
const __m256i mask6bits = _mm256_set1_epi32(0x3F);
|
||||
const __m256i shuffle_mask = _mm256_set_epi8(
|
||||
-1,-1,-1,-1,-1,-1,11,10,9,8,7,6,5,4,3,2,
|
||||
-1,-1,-1,-1,-1,-1,11,10,9,8,7,6,5,4,3,2
|
||||
);
|
||||
|
||||
const __m256i permute_mask = _mm256_set_epi32(0,0,0,0,6,4,2,0);
|
||||
|
||||
for (; i + 31 < complete_blocks * 4; i += 32, j += 24) {
|
||||
__m256i in = _mm256_loadu_si256((const __m256i*)(encoded_data + i));
|
||||
|
||||
alignas(32) byte chars[32];
|
||||
_mm256_store_si256((__m256i*)chars, in);
|
||||
|
||||
alignas(32) uint32 sextets[8];
|
||||
for (int32 k = 0; k < 8; ++k) {
|
||||
sextets[k] =
|
||||
(BASE64_LOOKUP[(byte)chars[k*4 + 0]] << 18) |
|
||||
(BASE64_LOOKUP[(byte)chars[k*4 + 1]] << 12) |
|
||||
(BASE64_LOOKUP[(byte)chars[k*4 + 2]] << 6) |
|
||||
(BASE64_LOOKUP[(byte)chars[k*4 + 3]]);
|
||||
}
|
||||
|
||||
__m256i sextet_vec = _mm256_load_si256((const __m256i*)sextets);
|
||||
|
||||
__m256i bytes0 = _mm256_srli_epi32(sextet_vec, 16);
|
||||
__m256i bytes1 = _mm256_srli_epi32(sextet_vec, 8);
|
||||
__m256i bytes2 = sextet_vec;
|
||||
|
||||
bytes0 = _mm256_and_si256(bytes0, _mm256_set1_epi32(0xFF));
|
||||
bytes1 = _mm256_and_si256(bytes1, _mm256_set1_epi32(0xFF));
|
||||
bytes2 = _mm256_and_si256(bytes2, _mm256_set1_epi32(0xFF));
|
||||
|
||||
__m256i packed = _mm256_shuffle_epi8(_mm256_packus_epi32(bytes0, bytes1), shuffle_mask);
|
||||
packed = _mm256_permutevar8x32_epi32(packed, permute_mask);
|
||||
|
||||
_mm256_storeu_si256((__m256i*)(data + j), packed);
|
||||
}
|
||||
|
||||
steps = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __SSE4_2__
|
||||
if (steps >= 4) {
|
||||
steps = 4;
|
||||
|
||||
const __m128i mask6bits = _mm_set1_epi32(0x3F);
|
||||
const __m128i shuffle_mask = _mm_set_epi8(
|
||||
-1,-1,-1,-1,-1,-1,11,10,9,8,7,6,5,4,3,2
|
||||
);
|
||||
|
||||
for (; i + 15 < complete_blocks * 4; i += 16, j += 12) {
|
||||
__m128i in = _mm_loadu_si128((const __m128i*)(encoded_data + i));
|
||||
|
||||
alignas(16) byte chars[16];
|
||||
_mm_store_si128((__m128i*)chars, in);
|
||||
|
||||
alignas(16) uint32 sextets[4];
|
||||
for (int32 k = 0; k < 4; ++k) {
|
||||
sextets[k] =
|
||||
(BASE64_LOOKUP[(byte)chars[k*4 + 0]] << 18) |
|
||||
(BASE64_LOOKUP[(byte)chars[k*4 + 1]] << 12) |
|
||||
(BASE64_LOOKUP[(byte)chars[k*4 + 2]] << 6) |
|
||||
(BASE64_LOOKUP[(byte)chars[k*4 + 3]]);
|
||||
}
|
||||
|
||||
__m128i sextet_vec = _mm_load_si128((const __m128i*)sextets);
|
||||
|
||||
__m128i bytes0 = _mm_srli_epi32(sextet_vec, 16);
|
||||
__m128i bytes1 = _mm_srli_epi32(sextet_vec, 8);
|
||||
__m128i bytes2 = sextet_vec;
|
||||
|
||||
bytes0 = _mm_and_si128(bytes0, _mm_set1_epi32(0xFF));
|
||||
bytes1 = _mm_and_si128(bytes1, _mm_set1_epi32(0xFF));
|
||||
bytes2 = _mm_and_si128(bytes2, _mm_set1_epi32(0xFF));
|
||||
|
||||
__m128i packed = _mm_shuffle_epi8(_mm_packus_epi32(bytes0, bytes1), shuffle_mask);
|
||||
|
||||
_mm_storeu_si128((__m128i*)(data + j), packed);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
for (; i < complete_blocks * 4; i += 4, j += 3) {
|
||||
uint32 sextet_a = BASE64_LOOKUP[(byte) encoded_data[i]];
|
||||
uint32 sextet_b = BASE64_LOOKUP[(byte) encoded_data[i + 1]];
|
||||
uint32 sextet_c = BASE64_LOOKUP[(byte) encoded_data[i + 2]];
|
||||
uint32 sextet_d = BASE64_LOOKUP[(byte) encoded_data[i + 3]];
|
||||
|
||||
uint32 triple = (sextet_a << 18) | (sextet_b << 12) | (sextet_c << 6) | sextet_d;
|
||||
|
||||
data[j] = (triple >> 16) & 0xFF;
|
||||
data[j + 1] = (triple >> 8) & 0xFF;
|
||||
data[j + 2] = triple & 0xFF;
|
||||
}
|
||||
|
||||
if (padding > 0) {
|
||||
uint32 sextet_a = BASE64_LOOKUP[(byte) encoded_data[i]];
|
||||
uint32 sextet_b = BASE64_LOOKUP[(byte) encoded_data[i + 1]];
|
||||
uint32 sextet_c = (padding > 1) ? 0 : BASE64_LOOKUP[(byte) encoded_data[i + 2]];
|
||||
uint32 sextet_d = 0;
|
||||
|
||||
uint32 triple = (sextet_a << 18) | (sextet_b << 12) | (sextet_c << 6) | sextet_d;
|
||||
|
||||
data[j] = (triple >> 16) & 0xFF;
|
||||
if (padding == 1) {
|
||||
data[j + 1] = (triple >> 8) & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
return output_length;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -34,8 +34,8 @@ struct EntityComponentSystem {
|
|||
uint64 component_count;
|
||||
|
||||
// @question Do we want to add a mutex to assets. This way we don't have to lock the entire ams.
|
||||
coms_pthread_mutex_t* entity_mutex;
|
||||
coms_pthread_mutex_t* component_mutex;
|
||||
mutex* entity_mutex;
|
||||
mutex* component_mutex;
|
||||
};
|
||||
|
||||
inline
|
||||
|
|
@ -54,7 +54,7 @@ void ecs_entity_type_create(ChunkMemory* ec, BufferMemory* buf, int32 chunk_size
|
|||
ASSERT_SIMPLE(chunk_size);
|
||||
|
||||
chunk_init(ec, buf, count, chunk_size, 64);
|
||||
//coms_pthread_mutex_init(&ec->mutex, NULL);
|
||||
//mutex_init(&ec->mutex, NULL);
|
||||
}
|
||||
|
||||
inline
|
||||
|
|
@ -63,7 +63,7 @@ void ecs_component_type_create(ChunkMemory* ec, BufferMemory* buf, int32 chunk_s
|
|||
ASSERT_SIMPLE(chunk_size);
|
||||
|
||||
chunk_init(ec, buf, count, chunk_size, 64);
|
||||
//coms_pthread_mutex_init(&ec->mutex, NULL);
|
||||
//mutex_init(&ec->mutex, NULL);
|
||||
}
|
||||
|
||||
Entity* ecs_get_entity(EntityComponentSystem* ecs, int32 entity_id)
|
||||
|
|
|
|||
|
|
@ -14,10 +14,10 @@
|
|||
#include <d3d12.h>
|
||||
#include <dxgi1_6.h>
|
||||
#include <d3dcommon.h>
|
||||
#include "../../../GameEngine/log/Log.h"
|
||||
#include "../../../GameEngine/memory/RingMemory.h"
|
||||
#include "../../../GameEngine/object/Texture.h"
|
||||
#include "../../../GameEngine/image/Image.cpp"
|
||||
#include "../../../cOMS/log/Log.h"
|
||||
#include "../../../cOMS/memory/RingMemory.h"
|
||||
#include "../../../cOMS/object/Texture.h"
|
||||
#include "../../../cOMS/image/Image.cpp"
|
||||
#include "../../compiler/CompilerUtils.h"
|
||||
// #include "../../../EngineDependencies/directx/d3d12.h"
|
||||
// #include "../../../EngineDependencies/directx/d3dx12.h"
|
||||
|
|
|
|||
|
|
@ -482,14 +482,14 @@ void gpuapi_swapchain_create(
|
|||
} else {
|
||||
swapchain_extent->width = OMS_CLAMP(
|
||||
window->width,
|
||||
swap_chain_support.capabilities.maxImageExtent.width,
|
||||
swap_chain_support.capabilities.minImageExtent.width
|
||||
swap_chain_support.capabilities.minImageExtent.width,
|
||||
swap_chain_support.capabilities.maxImageExtent.width
|
||||
);
|
||||
|
||||
swapchain_extent->height = OMS_CLAMP(
|
||||
window->height,
|
||||
swap_chain_support.capabilities.maxImageExtent.height,
|
||||
swap_chain_support.capabilities.minImageExtent.height
|
||||
swap_chain_support.capabilities.minImageExtent.height,
|
||||
swap_chain_support.capabilities.maxImageExtent.height
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
171
hash/Sha1.h
Normal file
171
hash/Sha1.h
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* @copyright Jingga
|
||||
* @license OMS License 2.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
#ifndef COMS_HASH_SHA1_H
|
||||
#define COMS_HASH_SHA1_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../stdlib/Types.h"
|
||||
#include "../stdlib/Simd.h"
|
||||
#include "Sha1Definitions.h"
|
||||
|
||||
#ifdef __SSE4_2__
|
||||
#include "Sha1SimdX86.h"
|
||||
#elif defined(__ARM_FEATURE_SVE) || defined(__ARM_NEON)
|
||||
#include "Sha1SimdArm.h"
|
||||
#else
|
||||
static
|
||||
void sha1_transform(SHA1_CTX *ctx, const byte data[64], [[mayb_unused]] int32 steps) {
|
||||
uint32 a, b, c, d, e, temp;
|
||||
uint32 w[80];
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
w[i] = ((uint32)data[i * 4 + 0] << 24) |
|
||||
((uint32)data[i * 4 + 1] << 16) |
|
||||
((uint32)data[i * 4 + 2] << 8) |
|
||||
((uint32)data[i * 4 + 3]);
|
||||
}
|
||||
|
||||
for (int i = 16; i < 80; i++) {
|
||||
temp = w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16];
|
||||
w[i] = (temp << 1) | (temp >> 31);
|
||||
}
|
||||
|
||||
a = ctx->state[0];
|
||||
b = ctx->state[1];
|
||||
c = ctx->state[2];
|
||||
d = ctx->state[3];
|
||||
e = ctx->state[4];
|
||||
|
||||
// Main compression loop - unrolled for better performance
|
||||
// Round 1 (0-19)
|
||||
for (int i = 0; i < 20; i++) {
|
||||
temp = SHA1_ROTL32(a, 5) + SHA1_Ch(b, c, d) + e + K1 + w[i];
|
||||
e = d;
|
||||
d = c;
|
||||
c = SHA1_ROTL32(b, 30);
|
||||
b = a;
|
||||
a = temp;
|
||||
}
|
||||
|
||||
// Round 2 (20-39)
|
||||
for (int i = 20; i < 40; i++) {
|
||||
temp = SHA1_ROTL32(a, 5) + SHA1_Parity(b, c, d) + e + K2 + w[i];
|
||||
e = d;
|
||||
d = c;
|
||||
c = SHA1_ROTL32(b, 30);
|
||||
b = a;
|
||||
a = temp;
|
||||
}
|
||||
|
||||
// Round 3 (40-59)
|
||||
for (int i = 40; i < 60; i++) {
|
||||
temp = SHA1_ROTL32(a, 5) + SHA1_Maj(b, c, d) + e + K3 + w[i];
|
||||
e = d;
|
||||
d = c;
|
||||
c = SHA1_ROTL32(b, 30);
|
||||
b = a;
|
||||
a = temp;
|
||||
}
|
||||
|
||||
// Round 4 (60-79)
|
||||
for (int i = 60; i < 80; i++) {
|
||||
temp = SHA1_ROTL32(a, 5) + SHA1_Parity(b, c, d) + e + K4 + w[i];
|
||||
e = d;
|
||||
d = c;
|
||||
c = SHA1_ROTL32(b, 30);
|
||||
b = a;
|
||||
a = temp;
|
||||
}
|
||||
|
||||
ctx->state[0] += a;
|
||||
ctx->state[1] += b;
|
||||
ctx->state[2] += c;
|
||||
ctx->state[3] += d;
|
||||
ctx->state[4] += e;
|
||||
}
|
||||
#endif
|
||||
|
||||
void sha1_init(SHA1_CTX* ctx) {
|
||||
ctx->state[0] = 0x67452301;
|
||||
ctx->state[1] = 0xEFCDAB89;
|
||||
ctx->state[2] = 0x98BADCFE;
|
||||
ctx->state[3] = 0x10325476;
|
||||
ctx->state[4] = 0xC3D2E1F0;
|
||||
ctx->count = 0;
|
||||
}
|
||||
|
||||
static
|
||||
void sha1_update(SHA1_CTX* ctx, const byte* data, size_t len, int32 steps) {
|
||||
size_t i, index, part_len;
|
||||
|
||||
index = (size_t)((ctx->count >> 3) & 0x3F);
|
||||
ctx->count += len << 3;
|
||||
part_len = 64 - index;
|
||||
|
||||
if (len >= part_len) {
|
||||
memcpy(&ctx->buffer[index], data, part_len);
|
||||
sha1_transform(ctx, ctx->buffer, steps);
|
||||
|
||||
for (i = part_len; i + 63 < len; i += 64) {
|
||||
sha1_transform(ctx, &data[i], steps);
|
||||
}
|
||||
|
||||
index = 0;
|
||||
} else {
|
||||
i = 0;
|
||||
}
|
||||
|
||||
memcpy(&ctx->buffer[index], &data[i], len - i);
|
||||
}
|
||||
|
||||
static
|
||||
void sha1_final(SHA1_CTX* ctx, byte digest[20], int32 steps) {
|
||||
byte bits[8];
|
||||
uint32 index, pad_len;
|
||||
|
||||
for (int32 i = 0; i < 8; i++) {
|
||||
bits[i] = (byte) ((ctx->count >> ((7 - i) * 8)) & 0xFF);
|
||||
}
|
||||
|
||||
index = (uint32)((ctx->count >> 3) & 0x3F);
|
||||
pad_len = (index < 56) ? (56 - index) : (120 - index);
|
||||
sha1_update(ctx, (const byte*) "\x80", 1, steps);
|
||||
while (pad_len-- > 1) {
|
||||
sha1_update(ctx, (const byte*) "\0", 1, steps);
|
||||
}
|
||||
|
||||
sha1_update(ctx, bits, 8, steps);
|
||||
|
||||
for (int32 i = 0; i < 5; i++) {
|
||||
digest[i*4+0] = (byte) ((ctx->state[i] >> 24) & 0xFF);
|
||||
digest[i*4+1] = (byte) ((ctx->state[i] >> 16) & 0xFF);
|
||||
digest[i*4+2] = (byte) ((ctx->state[i] >> 8) & 0xFF);
|
||||
digest[i*4+3] = (byte) ( ctx->state[i] & 0xFF);
|
||||
}
|
||||
|
||||
// WARNING: We are not doing this since no sensitive data should use sha1 anyways
|
||||
// Normally this would be done to reduce side channel attacks
|
||||
// memset(ctx, 0, sizeof(*ctx));
|
||||
}
|
||||
|
||||
inline
|
||||
void sha1_hash(const byte* data, size_t len, byte digest[20], int32 steps = 16) {
|
||||
SHA1_CTX ctx;
|
||||
sha1_init(&ctx);
|
||||
|
||||
steps = intrin_validate_steps(data, steps);
|
||||
|
||||
sha1_update(&ctx, data, len, steps);
|
||||
sha1_final(&ctx, digest, steps);
|
||||
}
|
||||
|
||||
#endif
|
||||
31
hash/Sha1Definitions.h
Normal file
31
hash/Sha1Definitions.h
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* @copyright Jingga
|
||||
* @license OMS License 2.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
#ifndef COMS_HASH_SHA1_DEFINITIONS_H
|
||||
#define COMS_HASH_SHA1_DEFINITIONS_H
|
||||
|
||||
#include "../stdlib/Types.h"
|
||||
|
||||
#define SHA1_ROTL32(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
|
||||
|
||||
#define SHA1_Ch(x, y, z) (((x) & (y)) ^ (~(x) & (z)))
|
||||
#define SHA1_Parity(x, y, z) ((x) ^ (y) ^ (z))
|
||||
#define SHA1_Maj(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
|
||||
|
||||
#define K1 0x5A827999
|
||||
#define K2 0x6ED9EBA1
|
||||
#define K3 0x8F1BBCDC
|
||||
#define K4 0xCA62C1D6
|
||||
|
||||
struct SHA1_CTX {
|
||||
alignas(64) byte buffer[64];
|
||||
uint64 count;
|
||||
uint32 state[5];
|
||||
};
|
||||
|
||||
#endif
|
||||
156
hash/Sha1SimdArm.h
Normal file
156
hash/Sha1SimdArm.h
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* @copyright Jingga
|
||||
* @license OMS License 2.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
#ifndef COMS_HASH_SHA1_SIMD_ARM_H
|
||||
#define COMS_HASH_SHA1_SIMD_ARM_H
|
||||
|
||||
#include <immintrin.h>
|
||||
#include "../stdlib/Types.h"
|
||||
#include "Sha1Definitions.h"
|
||||
|
||||
#ifdef __ARM_FEATURE_SVE
|
||||
#include <arm_sve.h>
|
||||
|
||||
static
|
||||
void sha1_transform(SHA1_CTX* ctx, const byte data[64], int32 steps) {
|
||||
uint32 a, b, c, d, e, temp;
|
||||
alignas(64) uint32 w[80];
|
||||
|
||||
// @question Does it make sense to also do SIMD here?
|
||||
for (int32 i = 0; i < 16; ++i) {
|
||||
w[i] = ((uint32) data[i * 4 + 0] << 24)
|
||||
| ((uint32) data[i * 4 + 1] << 16)
|
||||
| ((uint32) data[i * 4 + 2] << 8)
|
||||
| ((uint32) data[i * 4 + 3]);
|
||||
}
|
||||
|
||||
svuint32_t sv_k3 = svdup_n_u32(3);
|
||||
svuint32_t sv_k8 = svdup_n_u32(8);
|
||||
svuint32_t sv_k14 = svdup_n_u32(14);
|
||||
svuint32_t sv_k16 = svdup_n_u32(16);
|
||||
|
||||
for (int32 i = 16; i < 80; i += steps) {
|
||||
svbool_t pg = svwhilelt_b32(i, 80);
|
||||
|
||||
// Calculate indices
|
||||
svuint32_t idx_3 = svsub_n_u32_z(pg, svindex_u32(i, 1), 3);
|
||||
svuint32_t idx_8 = svsub_n_u32_z(pg, svindex_u32(i, 1), 8);
|
||||
svuint32_t idx_14 = svsub_n_u32_z(pg, svindex_u32(i, 1), 14);
|
||||
svuint32_t idx_16 = svsub_n_u32_z(pg, svindex_u32(i, 1), 16);
|
||||
|
||||
// Gather values
|
||||
svuint32_t v_3 = svld1_gather_index_u32(pg, w, idx_3);
|
||||
svuint32_t v_8 = svld1_gather_index_u32(pg, w, idx_8);
|
||||
svuint32_t v_14 = svld1_gather_index_u32(pg, w, idx_14);
|
||||
svuint32_t v_16 = svld1_gather_index_u32(pg, w, idx_16);
|
||||
|
||||
// Compute w[i] = (w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16]) <<< 1
|
||||
svuint32_t v = sveor_u32_z(pg, v_3, v_8);
|
||||
v = sveor_u32_z(pg, v, v_14);
|
||||
v = sveor_u32_z(pg, v, v_16);
|
||||
v = svorr_u32_z(pg, svlsl_n_u32_z(pg, v, 1), svlsr_n_u32_z(pg, v, 31));
|
||||
|
||||
svst1_u32(pg, &w[i], v);
|
||||
}
|
||||
|
||||
a = ctx->state[0];
|
||||
b = ctx->state[1];
|
||||
c = ctx->state[2];
|
||||
d = ctx->state[3];
|
||||
e = ctx->state[4];
|
||||
|
||||
for (int32 i = 0; i < 80; ++i) {
|
||||
if (i < 20) {
|
||||
temp = SHA1_ROTL32(a, 5) + SHA1_Ch(b, c, d) + e + K1 + w[i];
|
||||
} else if (i < 40) {
|
||||
temp = SHA1_ROTL32(a, 5) + SHA1_Parity(b, c, d) + e + K2 + w[i];
|
||||
} else if (i < 60) {
|
||||
temp = SHA1_ROTL32(a, 5) + SHA1_Maj(b, c, d) + e + K3 + w[i];
|
||||
} else {
|
||||
temp = SHA1_ROTL32(a, 5) + SHA1_Parity(b, c, d) + e + K4 + w[i];
|
||||
}
|
||||
|
||||
e = d;
|
||||
d = c;
|
||||
c = SHA1_ROTL32(b, 30);
|
||||
b = a;
|
||||
a = temp;
|
||||
}
|
||||
|
||||
ctx->state[0] += a;
|
||||
ctx->state[1] += b;
|
||||
ctx->state[2] += c;
|
||||
ctx->state[3] += d;
|
||||
ctx->state[4] += e;
|
||||
}
|
||||
#elif defined (__ARM_NEON)
|
||||
#include <arm_neon.h>
|
||||
|
||||
static
|
||||
void sha1_transform(SHA1_CTX* ctx, const byte data[64], int32 steps) {
|
||||
uint32 a, b, c, d, e, temp;
|
||||
alignas(64) uint32 w[80];
|
||||
|
||||
// @question Does it make sense to also do SIMD here?
|
||||
for (int32 i = 0; i < 16; ++i) {
|
||||
w[i] = ((uint32) data[i * 4 + 0] << 24)
|
||||
| ((uint32) data[i * 4 + 1] << 16)
|
||||
| ((uint32) data[i * 4 + 2] << 8)
|
||||
| ((uint32) data[i * 4 + 3]);
|
||||
}
|
||||
|
||||
for (int32 i = 16; i < 80; i += 4) {
|
||||
uint32x4_t v = veorq_u32(
|
||||
vld1q_u32(&w[i-3]),
|
||||
vld1q_u32(&w[i-8])
|
||||
);
|
||||
v = veorq_u32(v, vld1q_u32(&w[i-14]));
|
||||
v = veorq_u32(v, vld1q_u32(&w[i-16]));
|
||||
|
||||
// Rotate left by 1
|
||||
uint32x4_t v_rot = vorrq_u32(
|
||||
vshlq_n_u32(v, 1),
|
||||
vshrq_n_u32(v, 31)
|
||||
);
|
||||
|
||||
vst1q_u32(&w[i], v_rot);
|
||||
}
|
||||
|
||||
a = ctx->state[0];
|
||||
b = ctx->state[1];
|
||||
c = ctx->state[2];
|
||||
d = ctx->state[3];
|
||||
e = ctx->state[4];
|
||||
|
||||
for (int32 i = 0; i < 80; ++i) {
|
||||
if (i < 20) {
|
||||
temp = SHA1_ROTL32(a, 5) + SHA1_Ch(b, c, d) + e + K1 + w[i];
|
||||
} else if (i < 40) {
|
||||
temp = SHA1_ROTL32(a, 5) + SHA1_Parity(b, c, d) + e + K2 + w[i];
|
||||
} else if (i < 60) {
|
||||
temp = SHA1_ROTL32(a, 5) + SHA1_Maj(b, c, d) + e + K3 + w[i];
|
||||
} else {
|
||||
temp = SHA1_ROTL32(a, 5) + SHA1_Parity(b, c, d) + e + K4 + w[i];
|
||||
}
|
||||
|
||||
e = d;
|
||||
d = c;
|
||||
c = SHA1_ROTL32(b, 30);
|
||||
b = a;
|
||||
a = temp;
|
||||
}
|
||||
|
||||
ctx->state[0] += a;
|
||||
ctx->state[1] += b;
|
||||
ctx->state[2] += c;
|
||||
ctx->state[3] += d;
|
||||
ctx->state[4] += e;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
125
hash/Sha1SimdX86.h
Normal file
125
hash/Sha1SimdX86.h
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* @copyright Jingga
|
||||
* @license OMS License 2.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
#ifndef COMS_HASH_SHA1_SIMD_X86_H
|
||||
#define COMS_HASH_SHA1_SIMD_X86_H
|
||||
|
||||
#include <immintrin.h>
|
||||
#include "../stdlib/Types.h"
|
||||
#include "Sha1Definitions.h"
|
||||
|
||||
static
|
||||
void sha1_transform(SHA1_CTX* ctx, const byte data[64], int32 steps) {
|
||||
uint32 a, b, c, d, e, temp;
|
||||
alignas(64) uint32 w[80];
|
||||
|
||||
// @question Does it make sense to also do SIMD here?
|
||||
for (int32 i = 0; i < 16; ++i) {
|
||||
w[i] = ((uint32) data[i * 4 + 0] << 24)
|
||||
| ((uint32) data[i * 4 + 1] << 16)
|
||||
| ((uint32) data[i * 4 + 2] << 8)
|
||||
| ((uint32) data[i * 4 + 3]);
|
||||
}
|
||||
|
||||
#ifdef __AVX512F__
|
||||
if (steps >= 16) {
|
||||
for (int i = 16; i < 80; i += 16) {
|
||||
__m512i v3 = _mm512_loadu_si512((__m512i*)&w[i-3]);
|
||||
__m512i v8 = _mm512_load_si512((__m512i*)&w[i-8]);
|
||||
__m512i v14 = _mm512_loadu_si512((__m512i*)&w[i-14]);
|
||||
__m512i v16 = _mm512_load_si512((__m512i*)&w[i-16]);
|
||||
|
||||
__m512i v = _mm512_xor_si512(v3, v8);
|
||||
v = _mm512_xor_si512(v, v14);
|
||||
v = _mm512_xor_si512(v, v16);
|
||||
|
||||
__m512i v_rot = _mm512_or_si512(
|
||||
_mm512_slli_epi32(v, 1),
|
||||
_mm512_srli_epi32(v, 31)
|
||||
);
|
||||
|
||||
_mm512_store_si512((__m512i*)&w[i], v_rot);
|
||||
}
|
||||
|
||||
steps = 1
|
||||
} else
|
||||
#endif
|
||||
|
||||
#ifdef __AVX2__
|
||||
if (steps >= 8) {
|
||||
for (int i = 16; i < 80; i += 8) {
|
||||
__m256i v3 = _mm256_loadu_si256((__m256i*)&w[i-3]);
|
||||
__m256i v8 = _mm256_load_si256((__m256i*)&w[i-8]);
|
||||
__m256i v14 = _mm256_loadu_si256((__m256i*)&w[i-14]);
|
||||
__m256i v16 = _mm256_load_si256((__m256i*)&w[i-16]);
|
||||
|
||||
__m256i v = _mm256_xor_si256(v3, v8);
|
||||
v = _mm256_xor_si256(v, v14);
|
||||
v = _mm256_xor_si256(v, v16);
|
||||
|
||||
__m256i v_rot = _mm256_or_si256(
|
||||
_mm256_slli_epi32(v, 1),
|
||||
_mm256_srli_epi32(v, 31)
|
||||
);
|
||||
|
||||
_mm256_store_si256((__m256i*)&w[i], v_rot);
|
||||
}
|
||||
|
||||
steps = 1;
|
||||
} else
|
||||
#endif
|
||||
|
||||
#ifdef __SSE4_2__
|
||||
if (steps >= 4) {
|
||||
for (int32 i = 16; i < 80; i += 4) {
|
||||
__m128i v = _mm_xor_si128(
|
||||
_mm_loadu_si128((__m128i*) &w[i-3]),
|
||||
_mm_load_si128((__m128i*) &w[i-8])
|
||||
);
|
||||
v = _mm_xor_si128(v, _mm_loadu_si128((__m128i*) &w[i-14]));
|
||||
v = _mm_xor_si128(v, _mm_load_si128((__m128i*) &w[i-16]));
|
||||
|
||||
v = _mm_or_si128(_mm_slli_epi32(v, 1), _mm_srli_epi32(v, 31));
|
||||
|
||||
_mm_store_si128((__m128i*) &w[i], v);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
a = ctx->state[0];
|
||||
b = ctx->state[1];
|
||||
c = ctx->state[2];
|
||||
d = ctx->state[3];
|
||||
e = ctx->state[4];
|
||||
|
||||
for (int32 i = 0; i < 80; ++i) {
|
||||
if (i < 20) {
|
||||
temp = SHA1_ROTL32(a, 5) + SHA1_Ch(b, c, d) + e + K1 + w[i];
|
||||
} else if (i < 40) {
|
||||
temp = SHA1_ROTL32(a, 5) + SHA1_Parity(b, c, d) + e + K2 + w[i];
|
||||
} else if (i < 60) {
|
||||
temp = SHA1_ROTL32(a, 5) + SHA1_Maj(b, c, d) + e + K3 + w[i];
|
||||
} else {
|
||||
temp = SHA1_ROTL32(a, 5) + SHA1_Parity(b, c, d) + e + K4 + w[i];
|
||||
}
|
||||
|
||||
e = d;
|
||||
d = c;
|
||||
c = SHA1_ROTL32(b, 30);
|
||||
b = a;
|
||||
a = temp;
|
||||
}
|
||||
|
||||
ctx->state[0] += a;
|
||||
ctx->state[1] += b;
|
||||
ctx->state[2] += c;
|
||||
ctx->state[3] += d;
|
||||
ctx->state[4] += e;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -27,6 +27,7 @@ struct HtmlTemplateCache {
|
|||
byte* cache;
|
||||
|
||||
// Total cache size
|
||||
// It has to contain the templates and the AST of the template
|
||||
uint32 cache_size;
|
||||
|
||||
// Current position
|
||||
|
|
@ -55,20 +56,32 @@ void html_template_find(const char* path, va_list args) {
|
|||
++(*path_count);
|
||||
}
|
||||
|
||||
void html_template_cache_init(HtmlTemplateCache* cache, const char* basedir, BufferMemory* buf, RingMemory* ring) {
|
||||
void html_template_cache_alloc(HtmlTemplateCache* cache, const char* basedir, RingMemory* ring, int32 alignment = 64) {
|
||||
// @todo limit the maximum cache size in the dynamic resize
|
||||
|
||||
uint32 max_path_count = 1000;
|
||||
uint32 path_count = 0;
|
||||
char* paths = (char *) ring_get_memory(ring, max_path_count * 256 * sizeof(char), 8, true);
|
||||
uint32 total_file_size = 0;
|
||||
|
||||
iterate_directory(basedir, ".tpl.html", html_template_find, &paths, &path_count, &max_path_count, &total_file_size, ring);
|
||||
cache->cache_size = (uint64) (total_file_size * 1.2);
|
||||
cache->cache = (byte *) buffer_get_memory(buf, cache->cache_size, 64, true);
|
||||
cache->cache_size = OMS_MAX((uint64) (total_file_size * 1.2f), (uint64) (total_file_size + 1 * KILOBYTE));
|
||||
|
||||
uint32 buffer_size = ROUND_TO_NEAREST(cache->cache_size + perfect_hashmap_size(path_count, sizeof(PerfectHashEntryInt32)), 4096);
|
||||
byte* buf = (byte *) platform_alloc_aligned(buffer_size, alignment);
|
||||
perfect_hashmap_create(&cache->hm, path_count, sizeof(PerfectHashEntryInt32), buf);
|
||||
|
||||
cache->cache = (byte *) ROUND_TO_NEAREST((uintptr_t) (buf + perfect_hashmap_size(path_count, sizeof(PerfectHashEntryInt32))), alignment);
|
||||
perfect_hashmap_prepare(&cache->hm, (const char*) paths, path_count, 256, 10000, ring);
|
||||
|
||||
LOG_1("Created HtmlTemplateCache with %n B for %n templates with %n B in uncompressed file size", {{LOG_DATA_INT64, &cache->cache_size}, {LOG_DATA_INT32, &path_count}, {LOG_DATA_INT32, &total_file_size}});
|
||||
LOG_1(
|
||||
"Created HtmlTemplateCache with %n B for %n templates with %n B in uncompressed file size",
|
||||
{
|
||||
{LOG_DATA_INT64, &cache->cache_size},
|
||||
{LOG_DATA_INT32, &path_count},
|
||||
{LOG_DATA_INT32, &total_file_size}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
bool html_template_in_control_structure(const char* str, const char** controls, int32 control_length) {
|
||||
|
|
@ -81,8 +94,8 @@ bool html_template_in_control_structure(const char* str, const char** controls,
|
|||
return false;
|
||||
}
|
||||
|
||||
void html_template_cache_load(HtmlTemplateCache* cache, const char* key, const char* str) {
|
||||
char* minified = (char *) ROUND_TO_NEAREST((uintptr_t) cache->cache + (uintptr_t) cache->cache_pos, 64);
|
||||
void html_template_cache_load(HtmlTemplateCache* cache, const char* key, const char* str, int32 alignment = 64) {
|
||||
char* minified = (char *) ROUND_TO_NEAREST((uintptr_t) cache->cache + (uintptr_t) cache->cache_pos, alignment);
|
||||
char* minified_start = minified;
|
||||
|
||||
static const char* CONTROL_STRUCTURE_START[] = {
|
||||
|
|
@ -99,14 +112,23 @@ void html_template_cache_load(HtmlTemplateCache* cache, const char* key, const c
|
|||
// All-in-all let's consider this a pre-pass that we might want to move to the lexer in the future but I don't think so
|
||||
int32 in_control_structure = 0;
|
||||
while (*str) {
|
||||
// @performance What about optional tags such as </li>, </br>, </td>, </tr>, </option>, ...
|
||||
// @performance Remove comments /* */ and //
|
||||
if (!in_control_structure && str_is_eol(*str)) {
|
||||
str_skip_eol(&str);
|
||||
//continue; // @question Why does this fail?
|
||||
} else if (!in_control_structure && str_is_empty(*str)) {
|
||||
// @performance This keeps <tag> </tag> whitespaces, which we don't want and could optimize away
|
||||
str_skip_empty(&str);
|
||||
// @performance This keeps <tag> </tag> whitespaces, which we don't want and could optimize away
|
||||
// We would have to check the previous char and the next char to be != > and != <
|
||||
// the problem however is that we would have to specially handle the first char and last char in str
|
||||
--str;
|
||||
}
|
||||
|
||||
if (!(*str)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!in_control_structure
|
||||
&& html_template_in_control_structure(str, CONTROL_STRUCTURE_START, ARRAY_COUNT(CONTROL_STRUCTURE_START))
|
||||
) {
|
||||
|
|
@ -144,7 +166,8 @@ void html_template_cache_load(HtmlTemplateCache* cache, const char* key, const c
|
|||
|
||||
cache->cache_pos += ((uintptr_t) memory - (uintptr_t) memory_start);
|
||||
|
||||
ASSERT_SIMPLE(((uintptr_t) ast) % 64 == 0);
|
||||
ASSERT_SIMPLE(ast);
|
||||
ASSERT_SIMPLE(((uintptr_t) ast) % alignment == 0);
|
||||
perfect_hashmap_insert(&cache->hm, key, (int32) ((uintptr_t) ast - (uintptr_t) cache->cache));
|
||||
}
|
||||
|
||||
|
|
|
|||
97
http/HttpDispatcher.h
Normal file
97
http/HttpDispatcher.h
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* @copyright Jingga
|
||||
* @license OMS License 2.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
#ifndef COMS_HTML_DISPATCHER_H
|
||||
#define COMS_HTML_DISPATCHER_H
|
||||
|
||||
#include "../stdlib/Types.h"
|
||||
#include "../memory/BufferMemory.h"
|
||||
#include "HttpRequest.h"
|
||||
#include "HttpResponse.h"
|
||||
#include "../module/WebModule.h"
|
||||
|
||||
typedef void* (*ControllerFunction)(WebModule* module, HttpRequest* request, HttpResponse* response, void* data);
|
||||
|
||||
struct DispatchData {
|
||||
WebModule* module;
|
||||
HttpRequest* request;
|
||||
HttpResponse* response;
|
||||
void* data;
|
||||
};
|
||||
|
||||
struct Dispatcher {
|
||||
void* app;
|
||||
|
||||
// This is an array of arrays to make looking up functions faster
|
||||
// The first index defines the module id, the second level defines the function
|
||||
// functions[module_id][function_id]
|
||||
// The 0 index is used for custom functions
|
||||
// The other indeces are filled by the WebModuleManager
|
||||
ControllerFunction** functions;
|
||||
int16 category_count;
|
||||
int16 base_func_count;
|
||||
};
|
||||
|
||||
void dispatcher_alloc(Dispatcher* dispatcher, void* app, int32 category_count, int32 func_count, BufferMemory* buf, int32 alignment = 64) {
|
||||
dispatcher->app = app;
|
||||
dispatcher->base_func_count = func_count;
|
||||
dispatcher->functions = (ControllerFunction **) buffer_get_memory(buf, sizeof(ControllerFunction *) * category_count, alignment, true);
|
||||
dispatcher->functions[0] = (ControllerFunction *) buffer_get_memory(buf, sizeof(ControllerFunction) * func_count, alignment, true);
|
||||
}
|
||||
|
||||
void dispatcher_set_func(Dispatcher* dispatcher, uint32 id, ControllerFunction func) {
|
||||
/**
|
||||
* The 16 high bits of function_id define the module id
|
||||
* and the lower 16 bits define the relative function id in that module.
|
||||
*/
|
||||
uint16 category_id = id >> 16;
|
||||
if (category_id >= dispatcher->category_count) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint16 function_id = id & 0x0000FFFF;
|
||||
if (category_id == 0 && function_id >= dispatcher->base_func_count) {
|
||||
return;
|
||||
}
|
||||
|
||||
dispatcher->functions[category_id][function_id] = func;
|
||||
}
|
||||
|
||||
void dispatcher_set_category(Dispatcher* dispatcher, uint16 category, ControllerFunction* functions) {
|
||||
if (category >= dispatcher->category_count) {
|
||||
return;
|
||||
}
|
||||
|
||||
dispatcher->functions[category] = functions;
|
||||
}
|
||||
|
||||
ControllerFunction dispatcher_get_function(Dispatcher* dispatcher, uint32 id) {
|
||||
uint16 category_id = id >> 16;
|
||||
if (category_id >= dispatcher->category_count) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint16 function_id = id & 0x0000FFFF;
|
||||
if (category_id == 0 && function_id >= dispatcher->base_func_count) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return dispatcher->functions[category_id][function_id];
|
||||
}
|
||||
|
||||
void* dispatcher_dispatch(Dispatcher* dispatcher, uint32 id, DispatchData* dispatch_data) {
|
||||
ControllerFunction func = dispatcher_get_function(dispatcher, id);
|
||||
|
||||
if (func) {
|
||||
return func(dispatch_data->module, dispatch_data->request, dispatch_data->response, dispatch_data->data);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
22
http/HttpHeader.h
Normal file
22
http/HttpHeader.h
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* @copyright Jingga
|
||||
* @license OMS License 2.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
#ifndef COMS_JINGGA_HTTP_HEADER_H
|
||||
#define COMS_JINGGA_HTTP_HEADER_H
|
||||
|
||||
#include "../stdlib/Types.h"
|
||||
#include "HttpHeaderKey.h"
|
||||
|
||||
struct HttpHeader {
|
||||
HttpHeaderKey key;
|
||||
byte value_length;
|
||||
|
||||
uint16 value_offset;
|
||||
};
|
||||
|
||||
#endif
|
||||
153
http/HttpHeaderKey.h
Normal file
153
http/HttpHeaderKey.h
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* @copyright Jingga
|
||||
* @license OMS License 2.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
#ifndef COMS_JINGGA_HTTP_HEADER_KEY_H
|
||||
#define COMS_JINGGA_HTTP_HEADER_KEY_H
|
||||
|
||||
#include "../stdlib/Types.h"
|
||||
|
||||
enum HttpHeaderKey : byte {
|
||||
// Standard HTTP/1.1 & HTTP/2 Headers (RFC 9110, 9113, etc.)
|
||||
HTTP_HEADER_KEY_HOST,
|
||||
HTTP_HEADER_KEY_USER_AGENT,
|
||||
HTTP_HEADER_KEY_ACCEPT,
|
||||
HTTP_HEADER_KEY_ACCEPT_CHARSET,
|
||||
HTTP_HEADER_KEY_ACCEPT_ENCODING,
|
||||
HTTP_HEADER_KEY_ACCEPT_LANGUAGE,
|
||||
HTTP_HEADER_KEY_ACCEPT_DATETIME,
|
||||
HTTP_HEADER_KEY_ACCEPT_PATCH,
|
||||
HTTP_HEADER_KEY_ACCEPT_RANGES,
|
||||
HTTP_HEADER_KEY_AGE,
|
||||
HTTP_HEADER_KEY_ALLOW,
|
||||
HTTP_HEADER_KEY_AUTHORIZATION,
|
||||
HTTP_HEADER_KEY_CACHE_CONTROL,
|
||||
HTTP_HEADER_KEY_CONNECTION,
|
||||
HTTP_HEADER_KEY_CONTENT_DISPOSITION,
|
||||
HTTP_HEADER_KEY_CONTENT_ENCODING,
|
||||
HTTP_HEADER_KEY_CONTENT_LANGUAGE,
|
||||
HTTP_HEADER_KEY_CONTENT_LENGTH,
|
||||
HTTP_HEADER_KEY_CONTENT_LOCATION,
|
||||
HTTP_HEADER_KEY_CONTENT_MD5,
|
||||
HTTP_HEADER_KEY_CONTENT_RANGE,
|
||||
HTTP_HEADER_KEY_CONTENT_TYPE,
|
||||
HTTP_HEADER_KEY_COOKIE,
|
||||
HTTP_HEADER_KEY_DATE,
|
||||
HTTP_HEADER_KEY_ETAG,
|
||||
HTTP_HEADER_KEY_EXPECT,
|
||||
HTTP_HEADER_KEY_EXPIRES,
|
||||
HTTP_HEADER_KEY_FROM,
|
||||
HTTP_HEADER_KEY_IF_MATCH,
|
||||
HTTP_HEADER_KEY_IF_MODIFIED_SINCE,
|
||||
HTTP_HEADER_KEY_IF_NONE_MATCH,
|
||||
HTTP_HEADER_KEY_IF_RANGE,
|
||||
HTTP_HEADER_KEY_IF_UNMODIFIED_SINCE,
|
||||
HTTP_HEADER_KEY_LAST_MODIFIED,
|
||||
HTTP_HEADER_KEY_LINK,
|
||||
HTTP_HEADER_KEY_LOCATION,
|
||||
HTTP_HEADER_KEY_MAX_FORWARDS,
|
||||
HTTP_HEADER_KEY_ORIGIN,
|
||||
HTTP_HEADER_KEY_PRAGMA,
|
||||
HTTP_HEADER_KEY_PROXY_AUTHENTICATE,
|
||||
HTTP_HEADER_KEY_PROXY_AUTHORIZATION,
|
||||
HTTP_HEADER_KEY_RANGE,
|
||||
HTTP_HEADER_KEY_REFERER,
|
||||
HTTP_HEADER_KEY_RETRY_AFTER,
|
||||
HTTP_HEADER_KEY_SERVER,
|
||||
HTTP_HEADER_KEY_SET_COOKIE,
|
||||
HTTP_HEADER_KEY_STRICT_TRANSPORT_SECURITY,
|
||||
HTTP_HEADER_KEY_TE,
|
||||
HTTP_HEADER_KEY_TRAILER,
|
||||
HTTP_HEADER_KEY_TRANSFER_ENCODING,
|
||||
HTTP_HEADER_KEY_UPGRADE,
|
||||
HTTP_HEADER_KEY_VARY,
|
||||
HTTP_HEADER_KEY_VIA,
|
||||
HTTP_HEADER_KEY_WARNING,
|
||||
HTTP_HEADER_KEY_WWW_AUTHENTICATE,
|
||||
|
||||
// Common Non-Standard (X-*) and Extension Headers
|
||||
HTTP_HEADER_KEY_X_FORWARDED_FOR,
|
||||
HTTP_HEADER_KEY_X_FORWARDED_HOST,
|
||||
HTTP_HEADER_KEY_X_FORWARDED_PROTO,
|
||||
HTTP_HEADER_KEY_X_REQUESTED_WITH,
|
||||
HTTP_HEADER_KEY_X_CSRF_TOKEN,
|
||||
HTTP_HEADER_KEY_X_XSS_PROTECTION,
|
||||
HTTP_HEADER_KEY_X_CONTENT_TYPE_OPTIONS,
|
||||
HTTP_HEADER_KEY_X_FRAME_OPTIONS,
|
||||
HTTP_HEADER_KEY_X_POWERED_BY,
|
||||
HTTP_HEADER_KEY_X_UPLOAD_ID,
|
||||
HTTP_HEADER_KEY_X_RATE_LIMIT_LIMIT,
|
||||
HTTP_HEADER_KEY_X_RATE_LIMIT_REMAINING,
|
||||
HTTP_HEADER_KEY_X_RATE_LIMIT_RESET,
|
||||
HTTP_HEADER_KEY_X_UA_COMPATIBLE,
|
||||
HTTP_HEADER_KEY_X_DNS_PREFETCH_CONTROL,
|
||||
HTTP_HEADER_KEY_X_DOWNLOAD_OPTIONS,
|
||||
HTTP_HEADER_KEY_X_PERMITTED_CROSS_DOMAIN_POLICIES,
|
||||
|
||||
// CORS Headers
|
||||
HTTP_HEADER_KEY_ACCESS_CONTROL_ALLOW_ORIGIN,
|
||||
HTTP_HEADER_KEY_ACCESS_CONTROL_ALLOW_CREDENTIALS,
|
||||
HTTP_HEADER_KEY_ACCESS_CONTROL_ALLOW_HEADERS,
|
||||
HTTP_HEADER_KEY_ACCESS_CONTROL_ALLOW_METHODS,
|
||||
HTTP_HEADER_KEY_ACCESS_CONTROL_EXPOSE_HEADERS,
|
||||
HTTP_HEADER_KEY_ACCESS_CONTROL_MAX_AGE,
|
||||
HTTP_HEADER_KEY_ACCESS_CONTROL_REQUEST_HEADERS,
|
||||
HTTP_HEADER_KEY_ACCESS_CONTROL_REQUEST_METHOD,
|
||||
|
||||
// Security Headers
|
||||
HTTP_HEADER_KEY_CONTENT_SECURITY_POLICY,
|
||||
HTTP_HEADER_KEY_PERMISSIONS_POLICY,
|
||||
HTTP_HEADER_KEY_REFERRER_POLICY,
|
||||
HTTP_HEADER_KEY_EXPECT_CT,
|
||||
HTTP_HEADER_KEY_FEATURE_POLICY,
|
||||
HTTP_HEADER_KEY_CROSS_ORIGIN_EMBEDDER_POLICY,
|
||||
HTTP_HEADER_KEY_CROSS_ORIGIN_OPENER_POLICY,
|
||||
HTTP_HEADER_KEY_CROSS_ORIGIN_RESOURCE_POLICY,
|
||||
|
||||
// WebSocket Headers
|
||||
HTTP_HEADER_KEY_SEC_WEBSOCKET_KEY,
|
||||
HTTP_HEADER_KEY_SEC_WEBSOCKET_ACCEPT,
|
||||
HTTP_HEADER_KEY_SEC_WEBSOCKET_VERSION,
|
||||
HTTP_HEADER_KEY_SEC_WEBSOCKET_PROTOCOL,
|
||||
HTTP_HEADER_KEY_SEC_WEBSOCKET_EXTENSIONS,
|
||||
|
||||
// HTTP/3 and QUIC Headers
|
||||
HTTP_HEADER_KEY_ALT_SVC,
|
||||
HTTP_HEADER_KEY_EARLY_DATA,
|
||||
|
||||
// Cloud & CDN Headers
|
||||
HTTP_HEADER_KEY_CF_CONNECTING_IP,
|
||||
HTTP_HEADER_KEY_CF_IPCOUNTRY,
|
||||
HTTP_HEADER_KEY_CF_RAY,
|
||||
HTTP_HEADER_KEY_TRUE_CLIENT_IP,
|
||||
HTTP_HEADER_KEY_X_AMZ_CF_ID,
|
||||
HTTP_HEADER_KEY_X_AMZN_TRACE_ID,
|
||||
|
||||
// Custom/Experimental Headers
|
||||
HTTP_HEADER_KEY_DNT, // Do Not Track
|
||||
HTTP_HEADER_KEY_SAVE_DATA,
|
||||
HTTP_HEADER_KEY_DOWNLINK,
|
||||
HTTP_HEADER_KEY_ECT, // Effective Connection Type
|
||||
HTTP_HEADER_KEY_RTT,
|
||||
HTTP_HEADER_KEY_PURPOSE,
|
||||
HTTP_HEADER_KEY_SEC_FETCH_SITE,
|
||||
HTTP_HEADER_KEY_SEC_FETCH_MODE,
|
||||
HTTP_HEADER_KEY_SEC_FETCH_USER,
|
||||
HTTP_HEADER_KEY_SEC_FETCH_DEST,
|
||||
HTTP_HEADER_KEY_SERVICE_WORKER_NAVIGATION_PRELOAD,
|
||||
HTTP_HEADER_KEY_LAST_EVENT_ID,
|
||||
HTTP_HEADER_KEY_REPORT_TO,
|
||||
HTTP_HEADER_KEY_PRIORITY,
|
||||
HTTP_HEADER_KEY_SIGNATURE,
|
||||
HTTP_HEADER_KEY_SIGNATURE_KEY,
|
||||
HTTP_HEADER_KEY_FORWARDED,
|
||||
HTTP_HEADER_KEY_ORIGINAL_METHOD,
|
||||
HTTP_HEADER_KEY_ORIGINAL_URL,
|
||||
HTTP_HEADER_KEY_ORIGINAL_HOST,
|
||||
};
|
||||
|
||||
#endif
|
||||
25
http/HttpMethod.h
Normal file
25
http/HttpMethod.h
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* @copyright Jingga
|
||||
* @license OMS License 2.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
#ifndef COMS_JINGGA_HTTP_METHOD_H
|
||||
#define COMS_JINGGA_HTTP_METHOD_H
|
||||
|
||||
#include "../stdlib/Types.h"
|
||||
|
||||
enum HttpMethod : byte {
|
||||
HTTP_METHOD_UNKNOWN = 0,
|
||||
HTTP_METHOD_GET = 1 << 0,
|
||||
HTTP_METHOD_POST = 1 << 1,
|
||||
HTTP_METHOD_PUT = 1 << 2,
|
||||
HTTP_METHOD_DELETE = 1 << 3,
|
||||
HTTP_METHOD_ANY = (1 << 4) - 1,
|
||||
};
|
||||
|
||||
typedef HttpMethod HttpVerb;
|
||||
|
||||
#endif
|
||||
21
http/HttpProtocol.h
Normal file
21
http/HttpProtocol.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* @copyright Jingga
|
||||
* @license OMS License 2.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
#ifndef COMS_JINGGA_HTTP_PROTOCOL_H
|
||||
#define COMS_JINGGA_HTTP_PROTOCOL_H
|
||||
|
||||
#include "../stdlib/Types.h"
|
||||
|
||||
enum HttpProtocol : byte {
|
||||
HTTP_PROTOCOL_UNKNOWN,
|
||||
HTTP_PROTOCOL_1_1,
|
||||
HTTP_PROTOCOL_2,
|
||||
HTTP_PROTOCOL_3,
|
||||
};
|
||||
|
||||
#endif
|
||||
260
http/HttpRequest.h
Normal file
260
http/HttpRequest.h
Normal file
|
|
@ -0,0 +1,260 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* @copyright Jingga
|
||||
* @license OMS License 2.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
#ifndef COMS_JINGGA_HTTP_REQUEST_H
|
||||
#define COMS_JINGGA_HTTP_REQUEST_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../stdlib/Types.h"
|
||||
#include "../utils/StringUtils.h"
|
||||
#include "../log/Log.h"
|
||||
|
||||
#include "HttpMethod.h"
|
||||
#include "HttpProtocol.h"
|
||||
#include "HttpHeaderKey.h"
|
||||
#include "HttpUri.h"
|
||||
#include "HttpHeader.h"
|
||||
|
||||
/**
|
||||
* Data layout
|
||||
* HttpRequest
|
||||
* ...
|
||||
* Request body (excl. file data if available)
|
||||
* HttpHeader[]
|
||||
*
|
||||
*/
|
||||
|
||||
// The order of the members and their types is carefully chosen to make them fit into 1 cache line
|
||||
// The request content must come directly after the request
|
||||
struct HttpRequest {
|
||||
HttpUri uri;
|
||||
HttpMethod method;
|
||||
HttpProtocol protocol;
|
||||
|
||||
uint16 header_count;
|
||||
uint16 body_offset;
|
||||
uint32 body_length;
|
||||
uint32 request_length;
|
||||
uint32 headers_offset;
|
||||
};
|
||||
|
||||
inline
|
||||
bool http_request_header_is_complete(const char* request, size_t length) {
|
||||
return str_contains(request, "\r\n\r\n", length);
|
||||
}
|
||||
|
||||
// Binary search for the key
|
||||
inline
|
||||
const HttpHeader* http_request_header_get(const HttpRequest* request, HttpHeaderKey key) {
|
||||
const HttpHeader* base = (HttpHeader *) ((uintptr_t) request + sizeof(HttpRequest) + request->request_length);
|
||||
int32 header_count = OMS_MIN(request->header_count, (uint16) key);
|
||||
|
||||
while (header_count > 1) {
|
||||
int32 half = header_count / 2;
|
||||
header_count -= half;
|
||||
|
||||
base += (base[half - 1].key < key) * half;
|
||||
}
|
||||
|
||||
return base->key == key ? base : NULL;
|
||||
}
|
||||
|
||||
inline
|
||||
const char* http_request_header_value_get(const HttpRequest* request, const HttpHeader* header) {
|
||||
const char* request_data = (const char *) ((uintptr_t) request + sizeof(HttpRequest));
|
||||
|
||||
return request_data + header->value_offset;
|
||||
}
|
||||
|
||||
bool http_request_has_file_upload(const HttpRequest* request) {
|
||||
const HttpHeader* header = http_request_header_get(request, HTTP_HEADER_KEY_CONTENT_TYPE);
|
||||
if (!header) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* header_value = http_request_header_value_get(request, header);
|
||||
if ((str_compare_caseless(header_value, "application/", OMS_MIN(header->value_length, sizeof("application/") - 1)) == 0
|
||||
&& str_compare_caseless(header_value, "application/json", OMS_MIN(header->value_length, sizeof("application/json") - 1)) != 0)
|
||||
|| str_compare_caseless(header_value, "image/", OMS_MIN(header->value_length, sizeof("image/") - 1)) == 0
|
||||
|| str_compare_caseless(header_value, "audio/", OMS_MIN(header->value_length, sizeof("audio/") - 1)) == 0
|
||||
|| str_compare_caseless(header_value, "video/", OMS_MIN(header->value_length, sizeof("video/") - 1)) == 0
|
||||
|| str_compare_caseless(header_value, "text/csv", OMS_MIN(header->value_length, sizeof("text/csv") - 1)) == 0
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (str_compare_caseless(header_value, "multipart/form-data", OMS_MIN(header->value_length, sizeof("multipart/form-data") - 1)) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// @todo not every form-data is a file upload but it is at least possible
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void http_request_header_parse(HttpRequest* http_request, const char* request) {
|
||||
const char* request_start = request;
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
// Parsing HTTP request line
|
||||
//////////////////////////////////////////////////
|
||||
|
||||
str_skip_empty(&request);
|
||||
|
||||
// Parse request type
|
||||
if (str_compare(request, "GET") == 0) {
|
||||
http_request->method = HTTP_METHOD_GET;
|
||||
} else if (str_compare(request, "POST") == 0) {
|
||||
http_request->method = HTTP_METHOD_POST;
|
||||
} else if (str_compare(request, "PUT") == 0) {
|
||||
http_request->method = HTTP_METHOD_PUT;
|
||||
} else if (str_compare(request, "DELETE") == 0) {
|
||||
http_request->method = HTTP_METHOD_DELETE;
|
||||
} else {
|
||||
// Additional request types are possible BUT we don't support them in our internal framework
|
||||
// If this would be a public framework we would've to support additional request types
|
||||
http_request->method = HTTP_METHOD_UNKNOWN;
|
||||
}
|
||||
|
||||
// Parse reuqest path
|
||||
str_move_past(&request, ' ');
|
||||
http_request->uri.path_offset = request - request_start;
|
||||
|
||||
str_skip_until_list(&request, ":?# ");
|
||||
http_request->uri.path_length = (request - request_start) - http_request->uri.path_offset;
|
||||
|
||||
// Parse port
|
||||
if (*request == ':') {
|
||||
http_request->uri.port = (uint16) str_to_int(request, &request);
|
||||
}
|
||||
|
||||
// Parse query parameters
|
||||
if (*request == '?') {
|
||||
http_request->uri.parameter_offset = request - request_start;
|
||||
str_skip_until_list(&request, "# ");
|
||||
http_request->uri.path_length = (request - request_start) - http_request->uri.parameter_offset;
|
||||
}
|
||||
|
||||
// Parse fragment
|
||||
if (*request == '#') {
|
||||
http_request->uri.fragment_offset = request - request_start;
|
||||
str_move_to(&request, ' ');
|
||||
http_request->uri.fragment_length = (request - request_start) - http_request->uri.fragment_offset;
|
||||
}
|
||||
|
||||
// Parse protocol
|
||||
str_move_past(&request, ' ');
|
||||
if (str_compare(request, "HTTP/", sizeof("HTTP/") - 1) != 0) {
|
||||
LOG_1("Invalid HTTP header, no protocol defined");
|
||||
ASSERT_SIMPLE(false);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
request += sizeof("HTTP/") - 1;
|
||||
if (*request == '1') {
|
||||
http_request->protocol = HTTP_PROTOCOL_1_1;
|
||||
} else if (*request == '2') {
|
||||
http_request->protocol = HTTP_PROTOCOL_2;
|
||||
} else if (*request == '3') {
|
||||
http_request->protocol = HTTP_PROTOCOL_3;
|
||||
} else {
|
||||
http_request->protocol = HTTP_PROTOCOL_UNKNOWN;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
// Parsing HTTP headers
|
||||
//////////////////////////////////////////////////
|
||||
// The HTTP headers end with \r\n\r\n (= one empty line/element)
|
||||
while (request[0] != '\r' && request[1] != '\n' && request[2] != '\r' && request[3] != '\n') {
|
||||
str_move_past(&request, '\n');
|
||||
|
||||
// @todo parse headers
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
// Parsing HTTP body
|
||||
//////////////////////////////////////////////////
|
||||
request += 4;
|
||||
http_request->body_offset = request - request_start;
|
||||
http_request->body_length = http_request->request_length - http_request->body_offset;
|
||||
}
|
||||
|
||||
void parse_multipart_data(const char *body, const char *boundary) {
|
||||
char *buffer = strdup(body);
|
||||
if (!buffer) {
|
||||
perror("Failed to allocate memory for buffer");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
char *part = strtok(buffer, boundary);
|
||||
while (part) {
|
||||
// Skip leading and trailing newlines
|
||||
while (*part == '\r' || *part == '\n') part++;
|
||||
|
||||
// Parse part headers and content
|
||||
char *headers_end = strstr(part, "\r\n\r\n");
|
||||
if (headers_end) {
|
||||
*headers_end = '\0'; // Terminate headers
|
||||
char *content = headers_end + 4; // Skip "\r\n\r\n"
|
||||
|
||||
printf("Part Headers:\n%s\n", part);
|
||||
printf("Part Content:\n%s\n", content);
|
||||
}
|
||||
|
||||
part = strtok(NULL, boundary);
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
/*
|
||||
int main() {
|
||||
const char *http_request =
|
||||
"POST /submit HTTP/1.1\n"
|
||||
"Host: www.example.com\n"
|
||||
"Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW\n"
|
||||
"Content-Length: 348\n"
|
||||
"\n"
|
||||
"------WebKitFormBoundary7MA4YWxkTrZu0gW\n"
|
||||
"Content-Disposition: form-data; name=\"username\"\n"
|
||||
"\n"
|
||||
"john_doe\n"
|
||||
"------WebKitFormBoundary7MA4YWxkTrZu0gW\n"
|
||||
"Content-Disposition: form-data; name=\"file\"; filename=\"example.txt\"\n"
|
||||
"Content-Type: text/plain\n"
|
||||
"\n"
|
||||
"This is a sample file.\n"
|
||||
"------WebKitFormBoundary7MA4YWxkTrZu0gW--\n";
|
||||
|
||||
HttpRequest request;
|
||||
http_request_parse(http_request, &request);
|
||||
print_http_request(&request);
|
||||
|
||||
// Parse multipart data if Content-Type is multipart/form-data
|
||||
for (int i = 0; i < request.header_count; i++) {
|
||||
if (strstr(request.headers[i], "Content-Type: multipart/form-data")) {
|
||||
const char *boundary_start = strstr(request.headers[i], "boundary=");
|
||||
if (boundary_start) {
|
||||
char boundary[128];
|
||||
sscanf(boundary_start, "boundary=%127s", boundary);
|
||||
printf("\nParsing multipart data with boundary: %s\n", boundary);
|
||||
parse_multipart_data(request.body, boundary);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
|
||||
#endif
|
||||
27
http/HttpResponse.h
Normal file
27
http/HttpResponse.h
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* @copyright Jingga
|
||||
* @license OMS License 2.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
#ifndef COMS_JINGGA_HTTP_RESPONSE_H
|
||||
#define COMS_JINGGA_HTTP_RESPONSE_H
|
||||
|
||||
#include "../stdlib/Types.h"
|
||||
|
||||
#include "HttpMethod.h"
|
||||
#include "HttpProtocol.h"
|
||||
#include "HttpStatusCode.h"
|
||||
|
||||
struct HttpResponse {
|
||||
HttpMethod method;
|
||||
HttpProtocol protocol;
|
||||
HttpStatusCode status_code;
|
||||
};
|
||||
|
||||
// @performance Create a cached header line for 200 responses
|
||||
// @performance Create a cached header for most common response (incl. CSP, referrer, x-*, ...)
|
||||
|
||||
#endif
|
||||
51
http/HttpRoute.h
Normal file
51
http/HttpRoute.h
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* @copyright Jingga
|
||||
* @license OMS License 2.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
#ifndef COMS_JINGGA_HTTP_ROUTE_H
|
||||
#define COMS_JINGGA_HTTP_ROUTE_H
|
||||
|
||||
#include "../stdlib/Types.h"
|
||||
#include "HttpMethod.h"
|
||||
#include "../account/PermissionType.h"
|
||||
|
||||
#define MAX_HTTP_ROUTE_LENGTH 127
|
||||
|
||||
enum HttpRouteFlags {
|
||||
HTTP_ROUTE_FLAG_ACTUVE = 1 << 0,
|
||||
HTTP_ROUTE_FLAG_CSRF_REQUIRED = 1 << 1,
|
||||
};
|
||||
|
||||
struct HttpRoutePermission {
|
||||
uint16 unit;
|
||||
uint16 app;
|
||||
uint16 module;
|
||||
PermissionType type;
|
||||
uint16 category;
|
||||
};
|
||||
|
||||
// A route can have different end points depending on the method
|
||||
struct HttpRouteDetails {
|
||||
uint32 func_id;
|
||||
|
||||
// bit field for HttpMethod
|
||||
byte method;
|
||||
|
||||
// bit field for HttpRouteFlags
|
||||
byte flags;
|
||||
|
||||
HttpRoutePermission permission;
|
||||
};
|
||||
|
||||
struct HttpRoute {
|
||||
char route[MAX_HTTP_ROUTE_LENGTH];
|
||||
|
||||
byte details_count;
|
||||
HttpRouteDetails* details;
|
||||
};
|
||||
|
||||
#endif
|
||||
208
http/HttpRouter.h
Normal file
208
http/HttpRouter.h
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* @copyright Jingga
|
||||
* @license OMS License 2.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
#ifndef COMS_JINGGA_HTTP_ROUTER_H
|
||||
#define COMS_JINGGA_HTTP_ROUTER_H
|
||||
|
||||
#include "../stdlib/Types.h"
|
||||
#include "../memory/BufferMemory.h"
|
||||
#include "../utils/RegexSimplified.h"
|
||||
#include "HttpRoute.h"
|
||||
#include "HttpMethod.h"
|
||||
|
||||
#define HTTP_ROUTE_SEGMENT_LENGTH 32
|
||||
|
||||
struct HttpRouteNode {
|
||||
char segment[HTTP_ROUTE_SEGMENT_LENGTH];
|
||||
|
||||
// Route information
|
||||
// This is empty relatively often since only the last node(s) in a path usually have an endpoint defined
|
||||
// However, replacing this with another uint16 route_id for example only saves us 4 bytes,
|
||||
// BUT costs us another indirection once we arrive at a matched route/endpoint
|
||||
// The current implemenation allows us to directly jump into the detail definitions and iterate them
|
||||
uint32 detail_offset;
|
||||
byte detail_count;
|
||||
|
||||
// Do this node require regex matching?
|
||||
bool is_regex;
|
||||
|
||||
// How many child nodes does this node have
|
||||
uint16 children_count;
|
||||
|
||||
// Defines the offset into the nodes array where the children can be found
|
||||
uint32 children_offset;
|
||||
};
|
||||
|
||||
struct HttpRouter {
|
||||
HttpRouteNode* nodes;
|
||||
HttpRouteDetails* route_details;
|
||||
|
||||
uint16 node_count;
|
||||
uint16 node_capacity;
|
||||
|
||||
uint32 route_detail_count;
|
||||
uint32 route_detail_capacity;
|
||||
};
|
||||
|
||||
void http_router_init(HttpRouter* router, uint32 route_count, BufferMemory* buf, int32 alignment = 64) {
|
||||
// We expect 3 path components per route
|
||||
// If more are required, we will increase the memory later
|
||||
router->nodes = (HttpRouteNode *) buffer_get_memory(buf, route_count * 3 * sizeof(HttpRouteNode), alignment, true);
|
||||
router->node_capacity = route_count * 3;
|
||||
router->node_count = 0;
|
||||
|
||||
// We expect at least one route detail per route
|
||||
// On average it is probably more like 1.x but if we need more we will increase as required later
|
||||
router->route_details = (HttpRouteDetails *) buffer_get_memory(buf, route_count * sizeof(HttpRouteDetails), alignment, true);
|
||||
router->route_detail_capacity = route_count;
|
||||
router->route_detail_count = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Optimizes the memory layout of the router by making all nodes with the same level consecutive in memory
|
||||
* This improves the caching since an element doesn't match we need to compare our current search with the other elements of the same level
|
||||
* If these elements are consecutive, there is a bigger chance that they are already loaded into L1 or L2 cache
|
||||
*/
|
||||
void http_router_optimize() {
|
||||
|
||||
}
|
||||
|
||||
// Add a new route
|
||||
void http_router_add(
|
||||
HttpRouter* router,
|
||||
const HttpRoute* route
|
||||
) {
|
||||
|
||||
}
|
||||
|
||||
void http_router_find_iter(
|
||||
const HttpRouter* router,
|
||||
const char* uri_segments,
|
||||
int32 uri_segment_index,
|
||||
int32 uri_segment_count,
|
||||
HttpRouteDetails** matches,
|
||||
int32* match_count,
|
||||
HttpRouteNode* node = NULL
|
||||
) {
|
||||
for (uint32 i = 0; i < node->children_count; ++i) {
|
||||
HttpRouteNode* test_node = &router->nodes[node->children_offset + i];
|
||||
if ((!test_node->is_regex && str_compare(test_node->segment, uri_segments) == 0)
|
||||
|| (test_node->is_regex && regex_simplified_validate(test_node->segment, uri_segments))
|
||||
) {
|
||||
if (uri_segment_index < uri_segment_count && test_node->children_count) {
|
||||
// We have more in our uri path AND more child nodes
|
||||
// -> We need to continue pattern matching
|
||||
http_router_find_iter(
|
||||
router,
|
||||
uri_segments + str_length(uri_segments) + 1,
|
||||
uri_segment_index + 1,
|
||||
uri_segment_count,
|
||||
matches,
|
||||
match_count,
|
||||
test_node
|
||||
);
|
||||
} else if (uri_segment_index == uri_segment_count && !test_node->children_count) {
|
||||
// We reached the end of the uri path and the end of the node chain
|
||||
// -> We found a possible match
|
||||
matches[(*match_count)++] = &router->route_details[test_node->detail_offset + i];
|
||||
} else if (uri_segment_index >= uri_segment_count && test_node->children_count) {
|
||||
// We reached the end of the uri path BUT still have child nodes
|
||||
// -> This can only be a match if any of the child chains from here on are optional/wildcard matches
|
||||
http_router_find_iter(
|
||||
router,
|
||||
"",
|
||||
uri_segment_index + 1,
|
||||
uri_segment_count,
|
||||
matches,
|
||||
match_count,
|
||||
test_node
|
||||
);
|
||||
} else if (uri_segment_index < uri_segment_count && !test_node->children_count) {
|
||||
// We have more in our uri path BUT no more child nodes
|
||||
// -> This can only be a match if the test_node is a regex node that also matches all other path segments
|
||||
if (test_node->is_regex) {
|
||||
bool is_valid = true;
|
||||
for (int32 j = uri_segment_index + 1; j < uri_segment_count; ++j) {
|
||||
if (!regex_simplified_validate(test_node->segment, uri_segments)) {
|
||||
is_valid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_valid) {
|
||||
matches[(*match_count)++] = &router->route_details[test_node->detail_offset + i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void http_router_route(
|
||||
const HttpRouter* router,
|
||||
const char* uri,
|
||||
bool has_csrf,
|
||||
HttpMethod method,
|
||||
HttpRouteDetails** matches,
|
||||
int32* match_count
|
||||
) {
|
||||
char uri_segments[MAX_HTTP_ROUTE_LENGTH];
|
||||
char* segments_temp = uri_segments;
|
||||
|
||||
int32 uri_segment_count = 0;
|
||||
int32 i = 0;
|
||||
|
||||
while (*uri != '\0' && i < MAX_HTTP_ROUTE_LENGTH) {
|
||||
if (*uri == '/') {
|
||||
*segments_temp++ = '\0';
|
||||
++uri;
|
||||
++uri_segment_count;
|
||||
} else {
|
||||
*segments_temp++ = *uri++;
|
||||
}
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
*segments_temp = '\0';
|
||||
|
||||
// Find potential matches based on the route
|
||||
int32 temp_match_count = 0;
|
||||
http_router_find_iter(
|
||||
router,
|
||||
uri_segments,
|
||||
0,
|
||||
uri_segment_count,
|
||||
matches,
|
||||
&temp_match_count,
|
||||
router->nodes
|
||||
);
|
||||
|
||||
// Remove matches that don't fit the additional criteria
|
||||
// The reason why we don't do this in the route iteration is that we don't want to pass this information in every step
|
||||
// We need to remember that often only the last 1/2 path entries have actually a route attached
|
||||
*match_count = 0;
|
||||
for (i = 0; i < temp_match_count; ++i) {
|
||||
if ((matches[i]->method & method) // matches method/verb
|
||||
&& (matches[i]->flags & HTTP_ROUTE_FLAG_ACTUVE) // route is active
|
||||
&& (!(matches[i]->flags & HTTP_ROUTE_FLAG_CSRF_REQUIRED) // doesn't require csrf
|
||||
|| ((matches[i]->flags & HTTP_ROUTE_FLAG_CSRF_REQUIRED) && has_csrf) // requires csrf & person has csrf
|
||||
)
|
||||
) {
|
||||
// We only have to re-assign if the temp result has different elements than the final result
|
||||
// aka if a route has additional conditions like method, activity, ...
|
||||
if (*match_count != i) {
|
||||
matches[*match_count] = matches[i];
|
||||
}
|
||||
|
||||
++(*match_count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
275
http/HttpSessionManager.h
Normal file
275
http/HttpSessionManager.h
Normal file
|
|
@ -0,0 +1,275 @@
|
|||
#include "../stdlib/Types.h"
|
||||
#include "../memory/BufferMemory.h"
|
||||
#include "../system/Allocator.h"
|
||||
#include "../stdlib/HashMap.h"
|
||||
#include "../utils/StringUtils.h"
|
||||
#include "../utils/RandomUtils.h"
|
||||
|
||||
#define MAX_SESSION_ID_LENGTH 32
|
||||
|
||||
struct Session {
|
||||
uint64 last_used;
|
||||
|
||||
// Hash map that contains the offsets into the data memory
|
||||
// The hash map starts at the
|
||||
HashMap hm;
|
||||
|
||||
// offset into the data memory
|
||||
uint32 offset;
|
||||
uint32 data_size;
|
||||
};
|
||||
|
||||
struct SessionManager {
|
||||
// Hash map used to find sessions by ID
|
||||
// The hash map contains the offsets into the sessions array
|
||||
// @todo make random_string() for the session_id
|
||||
HashMap hm;
|
||||
|
||||
Session *sessions;
|
||||
|
||||
// Data shared accross sessions
|
||||
byte* session_data;
|
||||
|
||||
size_t count;
|
||||
size_t capacity;
|
||||
const char *storage_path;
|
||||
uint64 last_cleanup;
|
||||
};
|
||||
|
||||
SessionManager* session_manager_alloc(
|
||||
SessionManager* manager,
|
||||
const char* storage_path,
|
||||
size_t initial_capacity,
|
||||
int32 alignment = 64
|
||||
) {
|
||||
size_t internal_buffer_size = ROUND_TO_NEAREST(sizeof(Session) * initial_capacity, 4096);
|
||||
byte* internal_buffer = (byte *) platform_alloc_aligned(internal_buffer_size, alignment);
|
||||
|
||||
// distribute internal_buffer to:
|
||||
// session_key_data
|
||||
// session_data
|
||||
// hm per session
|
||||
|
||||
manager->sessions = (Session *) internal_buffer;
|
||||
|
||||
manager->count = 0;
|
||||
manager->capacity = initial_capacity;
|
||||
manager->storage_path = strdup(storage_path);
|
||||
manager->last_cleanup = time(NULL);
|
||||
|
||||
ensure_storage_directory_exists(storage_path);
|
||||
|
||||
return manager;
|
||||
}
|
||||
|
||||
Session* session_manager_create(SessionManager *manager) {
|
||||
if (manager->count >= manager->capacity) {
|
||||
// Try to cleanup first
|
||||
session_manager_cleanup(manager);
|
||||
|
||||
// If still full, move oldest session to disk
|
||||
if (manager->count >= manager->capacity) {
|
||||
// Find oldest session
|
||||
time_t oldest_time = time(NULL);
|
||||
size_t oldest_index = 0;
|
||||
|
||||
for (size_t i = 0; i < manager->count; i++) {
|
||||
if (manager->sessions[i].last_used < oldest_time) {
|
||||
oldest_time = manager->sessions[i].last_used;
|
||||
oldest_index = i;
|
||||
}
|
||||
}
|
||||
|
||||
// Save to disk
|
||||
save_session_to_disk(manager, &manager->sessions[oldest_index]);
|
||||
|
||||
// Remove from memory
|
||||
if (oldest_index != manager->count - 1) {
|
||||
memmove(&manager->sessions[oldest_index],
|
||||
&manager->sessions[oldest_index + 1],
|
||||
(manager->count - oldest_index - 1) * sizeof(Session));
|
||||
}
|
||||
manager->count--;
|
||||
}
|
||||
}
|
||||
|
||||
// Create new session
|
||||
Session *session = &manager->sessions[manager->count++];
|
||||
session_id_generate(session->id);
|
||||
session->last_used = time(NULL);
|
||||
session->data_size = 0;
|
||||
session->data[0] = '\0';
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
Session* session_manager_get(SessionManager *manager, const char *session_id) {
|
||||
// First check memory
|
||||
for (size_t i = 0; i < manager->count; i++) {
|
||||
if (strcmp(manager->sessions[i].id, session_id) == 0) {
|
||||
manager->sessions[i].last_used = time(NULL);
|
||||
return &manager->sessions[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Not in memory, try disk
|
||||
Session temp_session;
|
||||
if (load_session_from_disk(manager, &temp_session, session_id)) {
|
||||
// Make space if needed
|
||||
if (manager->count >= manager->capacity) {
|
||||
session_manager_cleanup(manager);
|
||||
|
||||
if (manager->count >= manager->capacity) {
|
||||
// Still full, need to move one to disk
|
||||
time_t oldest_time = time(NULL);
|
||||
size_t oldest_index = 0;
|
||||
|
||||
for (size_t i = 0; i < manager->count; i++) {
|
||||
if (manager->sessions[i].last_used < oldest_time) {
|
||||
oldest_time = manager->sessions[i].last_used;
|
||||
oldest_index = i;
|
||||
}
|
||||
}
|
||||
|
||||
save_session_to_disk(manager, &manager->sessions[oldest_index]);
|
||||
|
||||
if (oldest_index != manager->count - 1) {
|
||||
memmove(&manager->sessions[oldest_index],
|
||||
&manager->sessions[oldest_index + 1],
|
||||
(manager->count - oldest_index - 1) * sizeof(Session));
|
||||
}
|
||||
manager->count--;
|
||||
}
|
||||
}
|
||||
|
||||
// Add to memory
|
||||
Session *session = &manager->sessions[manager->count++];
|
||||
memcpy(session, &temp_session, sizeof(Session));
|
||||
session->last_used = time(NULL); // Update last used time
|
||||
|
||||
// Remove from disk (it's now in memory)
|
||||
delete_session_from_disk(manager, session_id);
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
return NULL; // Not found
|
||||
}
|
||||
|
||||
void session_manager_delete(SessionManager *manager, const char *session_id) {
|
||||
// Delete from memory
|
||||
for (size_t i = 0; i < manager->count; i++) {
|
||||
if (strcmp(manager->sessions[i].id, session_id) == 0) {
|
||||
if (i != manager->count - 1) {
|
||||
memmove(&manager->sessions[i],
|
||||
&manager->sessions[i + 1],
|
||||
(manager->count - i - 1) * sizeof(Session));
|
||||
}
|
||||
manager->count--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Delete from disk
|
||||
delete_session_from_disk(manager, session_id);
|
||||
}
|
||||
|
||||
void session_manager_cleanup(SessionManager *manager) {
|
||||
time_t now = time(NULL);
|
||||
|
||||
// Clean memory
|
||||
size_t i = 0;
|
||||
while (i < manager->count) {
|
||||
if (now - manager->sessions[i].last_used > SESSION_EXPIRY_SECONDS) {
|
||||
// Move to disk before deleting (if we want to keep expired sessions on disk)
|
||||
// Or just delete completely:
|
||||
|
||||
if (i != manager->count - 1) {
|
||||
memmove(&manager->sessions[i],
|
||||
&manager->sessions[i + 1],
|
||||
(manager->count - i - 1) * sizeof(Session));
|
||||
}
|
||||
manager->count--;
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
// Clean disk storage (do this less frequently)
|
||||
if (now - manager->last_cleanup > (SESSION_EXPIRY_SECONDS / 2)) {
|
||||
DIR *dir = opendir(manager->storage_path);
|
||||
if (dir) {
|
||||
struct dirent *entry;
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
if (strlen(entry->d_name) == SESSION_ID_LENGTH) {
|
||||
char path[PATH_MAX];
|
||||
snprintf(path, sizeof(path), "%s/%s", manager->storage_path, entry->d_name);
|
||||
|
||||
struct stat st;
|
||||
if (stat(path, &st) == 0) {
|
||||
if (now - st.st_mtime > SESSION_EXPIRY_SECONDS) {
|
||||
unlink(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
}
|
||||
manager->last_cleanup = now;
|
||||
}
|
||||
}
|
||||
|
||||
void session_id_generate(char* id) {
|
||||
uint64 x = time_index();
|
||||
int32 id_length = (rand_fast(&x) % 6) + HASH_MAP_MAX_KEY_LENGTH - 5;
|
||||
|
||||
random_string(
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@!",
|
||||
sizeof("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@!") - 1,
|
||||
id,
|
||||
id_length - 1
|
||||
);
|
||||
}
|
||||
|
||||
static void save_session_to_disk(SessionManager *manager, const Session *session) {
|
||||
char path[PATH_MAX];
|
||||
snprintf(path, sizeof(path), "%s/%s", manager->storage_path, session->id);
|
||||
|
||||
FILE *file = fopen(path, "wb");
|
||||
if (!file) return;
|
||||
|
||||
fwrite(session, sizeof(Session), 1, file);
|
||||
fclose(file);
|
||||
|
||||
// Update file modification time to match last_used
|
||||
struct utimbuf times;
|
||||
times.actime = session->last_used;
|
||||
times.modtime = session->last_used;
|
||||
utime(path, ×);
|
||||
}
|
||||
|
||||
static bool load_session_from_disk(SessionManager *manager, Session *session, const char *session_id) {
|
||||
char path[PATH_MAX];
|
||||
snprintf(path, sizeof(path), "%s/%s", manager->storage_path, session_id);
|
||||
|
||||
FILE *file = fopen(path, "rb");
|
||||
if (!file) return false;
|
||||
|
||||
bool success = fread(session, sizeof(Session), 1, file) == 1;
|
||||
fclose(file);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static void delete_session_from_disk(SessionManager *manager, const char *session_id) {
|
||||
char path[PATH_MAX];
|
||||
snprintf(path, sizeof(path), "%s/%s", manager->storage_path, session_id);
|
||||
unlink(path);
|
||||
}
|
||||
|
||||
static void ensure_storage_directory_exists(const char *path) {
|
||||
struct stat st = {0};
|
||||
if (stat(path, &st) == -1) {
|
||||
mkdir(path, 0700);
|
||||
}
|
||||
}
|
||||
194
http/HttpStatusCode.h
Normal file
194
http/HttpStatusCode.h
Normal file
|
|
@ -0,0 +1,194 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* @copyright Jingga
|
||||
* @license OMS License 2.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
#ifndef COMS_JINGGA_HTTP_STATUS_CODE_H
|
||||
#define COMS_JINGGA_HTTP_STATUS_CODE_H
|
||||
|
||||
#include "../stdlib/Types.h"
|
||||
|
||||
enum HttpStatusCode : uint16 {
|
||||
HTTP_STATUS_CODE_100 = 100,
|
||||
HTTP_STATUS_CODE_101 = 101,
|
||||
HTTP_STATUS_CODE_102 = 102,
|
||||
HTTP_STATUS_CODE_200 = 200,
|
||||
HTTP_STATUS_CODE_201 = 201,
|
||||
HTTP_STATUS_CODE_202 = 202,
|
||||
HTTP_STATUS_CODE_203 = 203,
|
||||
HTTP_STATUS_CODE_204 = 204,
|
||||
HTTP_STATUS_CODE_205 = 205,
|
||||
HTTP_STATUS_CODE_206 = 206,
|
||||
HTTP_STATUS_CODE_207 = 207,
|
||||
HTTP_STATUS_CODE_300 = 300,
|
||||
HTTP_STATUS_CODE_301 = 301,
|
||||
HTTP_STATUS_CODE_302 = 302,
|
||||
HTTP_STATUS_CODE_303 = 303,
|
||||
HTTP_STATUS_CODE_304 = 304,
|
||||
HTTP_STATUS_CODE_305 = 305,
|
||||
HTTP_STATUS_CODE_306 = 306,
|
||||
HTTP_STATUS_CODE_307 = 307,
|
||||
HTTP_STATUS_CODE_308 = 308,
|
||||
HTTP_STATUS_CODE_400 = 400,
|
||||
HTTP_STATUS_CODE_401 = 401,
|
||||
HTTP_STATUS_CODE_402 = 402,
|
||||
HTTP_STATUS_CODE_403 = 403,
|
||||
HTTP_STATUS_CODE_404 = 404,
|
||||
HTTP_STATUS_CODE_405 = 405,
|
||||
HTTP_STATUS_CODE_406 = 406,
|
||||
HTTP_STATUS_CODE_407 = 407,
|
||||
HTTP_STATUS_CODE_408 = 408,
|
||||
HTTP_STATUS_CODE_409 = 409,
|
||||
HTTP_STATUS_CODE_410 = 410,
|
||||
HTTP_STATUS_CODE_411 = 411,
|
||||
HTTP_STATUS_CODE_412 = 412,
|
||||
HTTP_STATUS_CODE_413 = 413,
|
||||
HTTP_STATUS_CODE_414 = 414,
|
||||
HTTP_STATUS_CODE_415 = 415,
|
||||
HTTP_STATUS_CODE_416 = 416,
|
||||
HTTP_STATUS_CODE_417 = 417,
|
||||
HTTP_STATUS_CODE_421 = 421,
|
||||
HTTP_STATUS_CODE_422 = 422,
|
||||
HTTP_STATUS_CODE_423 = 423,
|
||||
HTTP_STATUS_CODE_424 = 424,
|
||||
HTTP_STATUS_CODE_425 = 425,
|
||||
HTTP_STATUS_CODE_426 = 426,
|
||||
HTTP_STATUS_CODE_428 = 428,
|
||||
HTTP_STATUS_CODE_429 = 429,
|
||||
HTTP_STATUS_CODE_431 = 431,
|
||||
HTTP_STATUS_CODE_451 = 451,
|
||||
HTTP_STATUS_CODE_500 = 500,
|
||||
HTTP_STATUS_CODE_501 = 501,
|
||||
HTTP_STATUS_CODE_502 = 502,
|
||||
HTTP_STATUS_CODE_503 = 503,
|
||||
HTTP_STATUS_CODE_504 = 504,
|
||||
HTTP_STATUS_CODE_505 = 505,
|
||||
HTTP_STATUS_CODE_506 = 506,
|
||||
HTTP_STATUS_CODE_507 = 507,
|
||||
HTTP_STATUS_CODE_508 = 508,
|
||||
HTTP_STATUS_CODE_509 = 509,
|
||||
HTTP_STATUS_CODE_510 = 510,
|
||||
HTTP_STATUS_CODE_511 = 511,
|
||||
};
|
||||
|
||||
const char* http_status_text(HttpStatusCode code) {
|
||||
switch (code) {
|
||||
case HTTP_STATUS_CODE_100:
|
||||
return "Continue";
|
||||
case HTTP_STATUS_CODE_101:
|
||||
return "Switching Protocols";
|
||||
case HTTP_STATUS_CODE_102:
|
||||
return "Processing";
|
||||
case HTTP_STATUS_CODE_200:
|
||||
return "OK";
|
||||
case HTTP_STATUS_CODE_201:
|
||||
return "Created";
|
||||
case HTTP_STATUS_CODE_202:
|
||||
return "Accepted";
|
||||
case HTTP_STATUS_CODE_203:
|
||||
return "Non-Authoritative Information";
|
||||
case HTTP_STATUS_CODE_204:
|
||||
return "No Content";
|
||||
case HTTP_STATUS_CODE_205:
|
||||
return "Reset Content";
|
||||
case HTTP_STATUS_CODE_206:
|
||||
return "Partial Content";
|
||||
case HTTP_STATUS_CODE_207:
|
||||
return "Multi-Status";
|
||||
case HTTP_STATUS_CODE_300:
|
||||
return "Multiple Choices";
|
||||
case HTTP_STATUS_CODE_301:
|
||||
return "Moved Permanently";
|
||||
case HTTP_STATUS_CODE_302:
|
||||
return "Found";
|
||||
case HTTP_STATUS_CODE_303:
|
||||
return "See Other";
|
||||
case HTTP_STATUS_CODE_304:
|
||||
return "Not Modified";
|
||||
case HTTP_STATUS_CODE_305:
|
||||
return "Use Proxy";
|
||||
case HTTP_STATUS_CODE_306:
|
||||
return "Switch Proxy";
|
||||
case HTTP_STATUS_CODE_307:
|
||||
return "Temporary Redirect";
|
||||
case HTTP_STATUS_CODE_400:
|
||||
return "Bad Request";
|
||||
case HTTP_STATUS_CODE_401:
|
||||
return "Unauthorized";
|
||||
case HTTP_STATUS_CODE_402:
|
||||
return "Payment Required";
|
||||
case HTTP_STATUS_CODE_403:
|
||||
return "Forbidden";
|
||||
case HTTP_STATUS_CODE_404:
|
||||
return "Not Found";
|
||||
case HTTP_STATUS_CODE_405:
|
||||
return "Method Not Allowed";
|
||||
case HTTP_STATUS_CODE_406:
|
||||
return "Not Acceptable";
|
||||
case HTTP_STATUS_CODE_407:
|
||||
return "Proxy Authentication Required";
|
||||
case HTTP_STATUS_CODE_408:
|
||||
return "Request Timeout";
|
||||
case HTTP_STATUS_CODE_409:
|
||||
return "Conflict";
|
||||
case HTTP_STATUS_CODE_410:
|
||||
return "Gone";
|
||||
case HTTP_STATUS_CODE_411:
|
||||
return "Length Required";
|
||||
case HTTP_STATUS_CODE_412:
|
||||
return "Precondition Failed";
|
||||
case HTTP_STATUS_CODE_413:
|
||||
return "Request Entity Too Large";
|
||||
case HTTP_STATUS_CODE_414:
|
||||
return "Request-URI Too Long";
|
||||
case HTTP_STATUS_CODE_415:
|
||||
return "Unsupported Media Type";
|
||||
case HTTP_STATUS_CODE_416:
|
||||
return "Requested Range Not Satisfiable";
|
||||
case HTTP_STATUS_CODE_417:
|
||||
return "Expectation Failed";
|
||||
case HTTP_STATUS_CODE_421:
|
||||
return "Misdirected Request";
|
||||
case HTTP_STATUS_CODE_422:
|
||||
return "Unprocessable Entity";
|
||||
case HTTP_STATUS_CODE_423:
|
||||
return "Locked";
|
||||
case HTTP_STATUS_CODE_424:
|
||||
return "Failed Dependency";
|
||||
case HTTP_STATUS_CODE_425:
|
||||
return "Unordered Collection";
|
||||
case HTTP_STATUS_CODE_426:
|
||||
return "Upgrade Required";
|
||||
case HTTP_STATUS_CODE_431:
|
||||
return "Request Header Fields Too Large";
|
||||
case HTTP_STATUS_CODE_500:
|
||||
return "Internal Server Error";
|
||||
case HTTP_STATUS_CODE_501:
|
||||
return "Not Implemented";
|
||||
case HTTP_STATUS_CODE_502:
|
||||
return "Bad Gateway";
|
||||
case HTTP_STATUS_CODE_503:
|
||||
return "Service Unavailable";
|
||||
case HTTP_STATUS_CODE_504:
|
||||
return "Gateway Timeout";
|
||||
case HTTP_STATUS_CODE_505:
|
||||
return "HTTP Version Not Supported";
|
||||
case HTTP_STATUS_CODE_506:
|
||||
return "Variant Also Negotiates";
|
||||
case HTTP_STATUS_CODE_507:
|
||||
return "Insufficient Storage";
|
||||
case HTTP_STATUS_CODE_509:
|
||||
return "Bandwidth Limit Exceeded";
|
||||
case HTTP_STATUS_CODE_510:
|
||||
return "Not Extended";
|
||||
case HTTP_STATUS_CODE_511:
|
||||
return "Network Authentication Required";
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
31
http/HttpUri.h
Normal file
31
http/HttpUri.h
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* @copyright Jingga
|
||||
* @license OMS License 2.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
#ifndef COMS_JINGGA_HTTP_URI_H
|
||||
#define COMS_JINGGA_HTTP_URI_H
|
||||
|
||||
#include "../stdlib/Types.h"
|
||||
|
||||
// WARNING: Be careful when changing order, members and types
|
||||
// The current configuration is carefully chosen (see below)
|
||||
struct HttpUri {
|
||||
byte path_offset;
|
||||
byte path_length;
|
||||
|
||||
uint16 parameter_offset;
|
||||
uint16 parementers_length;
|
||||
|
||||
// A parameter consists of 2 values: n-th value = length; n+1-th value = offset
|
||||
uint16 parementer_array_offset;
|
||||
byte parameter_array_count;
|
||||
byte fragment_length;
|
||||
uint16 fragment_offset;
|
||||
|
||||
uint16 port;
|
||||
};
|
||||
#endif
|
||||
|
|
@ -159,7 +159,7 @@ void log(const char* str, const char* file, const char* function, int32 line)
|
|||
return;
|
||||
}
|
||||
|
||||
size_t len = str_length(str);
|
||||
int32 len = str_length(str);
|
||||
while (len > 0) {
|
||||
LogMessage* msg = (LogMessage *) log_get_memory();
|
||||
|
||||
|
|
@ -171,7 +171,7 @@ void log(const char* str, const char* file, const char* function, int32 line)
|
|||
msg->time = system_time();
|
||||
msg->newline = '\n';
|
||||
|
||||
int32 message_length = (int32) OMS_MIN(MAX_LOG_LENGTH - sizeof(LogMessage) - 1, len);
|
||||
int32 message_length = (int32) OMS_MIN((int32) (MAX_LOG_LENGTH - sizeof(LogMessage) - 1), len);
|
||||
|
||||
memcpy(msg->message, str, message_length);
|
||||
msg->message[message_length] = '\0';
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
PROFILE_BUFFER_ALLOC,
|
||||
PROFILE_CHUNK_ALLOC,
|
||||
PROFILE_RING_ALLOC,
|
||||
PROFILE_THREAD_POOL_ALLOC,
|
||||
PROFILE_CMD_ITERATE,
|
||||
PROFILE_CMD_FONT_LOAD_SYNC,
|
||||
PROFILE_CMD_SHADER_LOAD_SYNC,
|
||||
|
|
@ -154,7 +155,7 @@ struct PerformanceProfiler {
|
|||
if (this->auto_log) {
|
||||
if (this->info_msg && this->info_msg[0]) {
|
||||
LOG_2(
|
||||
"-PERF %s (%s): %l cycles",
|
||||
"-PERF %s (%s): %n cycles",
|
||||
{
|
||||
{LOG_DATA_CHAR_STR, (void *) perf->name},
|
||||
{LOG_DATA_CHAR_STR, (void *) this->info_msg},
|
||||
|
|
@ -163,7 +164,7 @@ struct PerformanceProfiler {
|
|||
);
|
||||
} else {
|
||||
LOG_2(
|
||||
"-PERF %s: %l cycles",
|
||||
"-PERF %s: %n cycles",
|
||||
{
|
||||
{LOG_DATA_CHAR_STR, (void *) perf->name},
|
||||
{LOG_DATA_INT64, (void *) &perf->total_cycle},
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@
|
|||
struct ChunkMemory {
|
||||
byte* memory;
|
||||
|
||||
// @question Why are we making the count 64 bit? is this really realistically possible?
|
||||
uint64 size;
|
||||
int32 last_pos;
|
||||
uint32 count;
|
||||
|
|
@ -35,7 +34,7 @@ struct ChunkMemory {
|
|||
|
||||
// length = count
|
||||
// free describes which locations are used and which are free
|
||||
uint64* free;
|
||||
alignas(8) uint64* free;
|
||||
};
|
||||
|
||||
// INFO: A chunk count of 2^n is recommended for maximum performance
|
||||
|
|
@ -49,18 +48,22 @@ void chunk_alloc(ChunkMemory* buf, uint32 count, uint32 chunk_size, int32 alignm
|
|||
|
||||
chunk_size = ROUND_TO_NEAREST(chunk_size, alignment);
|
||||
|
||||
uint64 size = count * chunk_size
|
||||
+ sizeof(uint64) * CEIL_DIV(count, alignment) // free
|
||||
+ alignment * 2; // overhead for alignment
|
||||
|
||||
buf->memory = alignment < 2
|
||||
? (byte *) platform_alloc(count * chunk_size + sizeof(uint64) * CEIL_DIV(count, 64))
|
||||
: (byte *) platform_alloc_aligned(count * chunk_size + sizeof(uint64) * CEIL_DIV(count, 64), alignment);
|
||||
? (byte *) platform_alloc(size)
|
||||
: (byte *) platform_alloc_aligned(size, alignment);
|
||||
|
||||
buf->count = count;
|
||||
buf->size = count * chunk_size + sizeof(uint64) * CEIL_DIV(count, 64);
|
||||
buf->size = size;
|
||||
buf->chunk_size = chunk_size;
|
||||
buf->last_pos = -1;
|
||||
buf->alignment = alignment;
|
||||
|
||||
// @question Could it be beneficial to have this before the element data?
|
||||
buf->free = (uint64 *) (buf->memory + count * chunk_size);
|
||||
buf->free = (uint64 *) ROUND_TO_NEAREST((uintptr_t) (buf->memory + count * chunk_size), alignment);
|
||||
|
||||
memset(buf->memory, 0, buf->size);
|
||||
|
||||
|
|
@ -75,10 +78,14 @@ void chunk_init(ChunkMemory* buf, BufferMemory* data, uint32 count, uint32 chunk
|
|||
|
||||
chunk_size = ROUND_TO_NEAREST(chunk_size, alignment);
|
||||
|
||||
buf->memory = buffer_get_memory(data, count * chunk_size + sizeof(uint64) * CEIL_DIV(count, 64));
|
||||
uint64 size = count * chunk_size
|
||||
+ sizeof(uint64) * CEIL_DIV(count, alignment) // free
|
||||
+ alignment * 2; // overhead for alignment
|
||||
|
||||
buf->memory = buffer_get_memory(data, size);
|
||||
|
||||
buf->count = count;
|
||||
buf->size = count * chunk_size + sizeof(uint64) * CEIL_DIV(count, 64);
|
||||
buf->size = size;
|
||||
buf->chunk_size = chunk_size;
|
||||
buf->last_pos = -1;
|
||||
buf->alignment = alignment;
|
||||
|
|
@ -86,7 +93,7 @@ void chunk_init(ChunkMemory* buf, BufferMemory* data, uint32 count, uint32 chunk
|
|||
// @question Could it be beneficial to have this before the element data?
|
||||
// On the other hand the way we do it right now we never have to move past the free array since it is at the end
|
||||
// On another hand we could by accident overwrite the values in free if we are not careful
|
||||
buf->free = (uint64 *) (buf->memory + count * chunk_size);
|
||||
buf->free = (uint64 *) ROUND_TO_NEAREST((uintptr_t) (buf->memory + count * chunk_size), 64);
|
||||
|
||||
DEBUG_MEMORY_SUBREGION((uintptr_t) buf->memory, buf->size);
|
||||
}
|
||||
|
|
@ -99,11 +106,15 @@ void chunk_init(ChunkMemory* buf, byte* data, uint32 count, uint32 chunk_size, i
|
|||
|
||||
chunk_size = ROUND_TO_NEAREST(chunk_size, alignment);
|
||||
|
||||
uint64 size = count * chunk_size
|
||||
+ sizeof(uint64) * CEIL_DIV(count, alignment) // free
|
||||
+ alignment * 2; // overhead for alignment
|
||||
|
||||
// @bug what if an alignment is defined?
|
||||
buf->memory = data;
|
||||
|
||||
buf->count = count;
|
||||
buf->size = count * chunk_size + sizeof(uint64) * CEIL_DIV(count, 64);
|
||||
buf->size = size;
|
||||
buf->chunk_size = chunk_size;
|
||||
buf->last_pos = -1;
|
||||
buf->alignment = alignment;
|
||||
|
|
@ -111,7 +122,7 @@ void chunk_init(ChunkMemory* buf, byte* data, uint32 count, uint32 chunk_size, i
|
|||
// @question Could it be beneficial to have this before the element data?
|
||||
// On the other hand the way we do it right now we never have to move past the free array since it is at the end
|
||||
// On another hand we could by accident overwrite the values in free if we are not careful
|
||||
buf->free = (uint64 *) (buf->memory + count * chunk_size);
|
||||
buf->free = (uint64 *) ROUND_TO_NEAREST((uintptr_t) (buf->memory + count * chunk_size), alignment);
|
||||
|
||||
DEBUG_MEMORY_SUBREGION((uintptr_t) buf->memory, buf->size);
|
||||
}
|
||||
|
|
@ -131,13 +142,13 @@ void chunk_free(ChunkMemory* buf)
|
|||
buf->memory = NULL;
|
||||
}
|
||||
|
||||
inline
|
||||
FORCE_INLINE
|
||||
uint32 chunk_id_from_memory(const ChunkMemory* buf, const byte* pos) noexcept {
|
||||
return (uint32) ((uintptr_t) pos - (uintptr_t) buf->memory) / buf->chunk_size;
|
||||
}
|
||||
|
||||
inline
|
||||
byte* chunk_get_element(ChunkMemory* buf, uint64 element, bool zeroed = false) noexcept
|
||||
byte* chunk_get_element(ChunkMemory* buf, uint32 element, bool zeroed = false) noexcept
|
||||
{
|
||||
if (element >= buf->count) {
|
||||
return NULL;
|
||||
|
|
@ -155,6 +166,39 @@ byte* chunk_get_element(ChunkMemory* buf, uint64 element, bool zeroed = false) n
|
|||
return offset;
|
||||
}
|
||||
|
||||
int32 chunk_get_unset(uint64* state, uint32 state_count, int32 start_index = 0) {
|
||||
if ((uint32) start_index >= state_count) {
|
||||
start_index = 0;
|
||||
}
|
||||
|
||||
uint32 free_index = start_index / 64;
|
||||
uint32 bit_index = start_index & 63;
|
||||
|
||||
// Check standard simple solution
|
||||
if (!IS_BIT_SET_64_R2L(state[free_index], bit_index)) {
|
||||
state[free_index] |= (1ULL << bit_index);
|
||||
|
||||
return free_index * 64 + bit_index;
|
||||
}
|
||||
|
||||
for (uint32 i = 0; i < state_count; ++i) {
|
||||
if (state[free_index] != 0xFFFFFFFFFFFFFFFF) {
|
||||
bit_index = compiler_find_first_bit_r2l(~state[free_index]);
|
||||
state[free_index] |= (1ULL << bit_index);
|
||||
|
||||
return free_index * 64 + bit_index;
|
||||
}
|
||||
|
||||
++free_index;
|
||||
if (free_index * 64 >= state_count) {
|
||||
free_index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
inline
|
||||
int32 chunk_reserve(ChunkMemory* buf, uint32 elements = 1) noexcept
|
||||
{
|
||||
if ((uint32) (buf->last_pos + 1) >= buf->count) {
|
||||
|
|
@ -265,15 +309,13 @@ int32 chunk_reserve(ChunkMemory* buf, uint32 elements = 1) noexcept
|
|||
inline
|
||||
void chunk_free_element(ChunkMemory* buf, uint64 free_index, int32 bit_index) noexcept
|
||||
{
|
||||
DEBUG_MEMORY_DELETE((uintptr_t) (buf->memory + (free_index * 64 + bit_index) * buf->chunk_size), buf->chunk_size);
|
||||
buf->free[free_index] &= ~(1ULL << bit_index);
|
||||
DEBUG_MEMORY_DELETE((uintptr_t) (buf->memory + (free_index * 64 + bit_index) * buf->chunk_size), buf->chunk_size);
|
||||
}
|
||||
|
||||
inline
|
||||
void chunk_free_elements(ChunkMemory* buf, uint64 element, uint32 element_count = 1) noexcept
|
||||
{
|
||||
DEBUG_MEMORY_DELETE((uintptr_t) (buf->memory + element * buf->chunk_size), buf->chunk_size);
|
||||
|
||||
uint64 free_index = element / 64;
|
||||
uint32 bit_index = element & 63;
|
||||
|
||||
|
|
@ -295,6 +337,8 @@ void chunk_free_elements(ChunkMemory* buf, uint64 element, uint32 element_count
|
|||
++free_index;
|
||||
bit_index = 0;
|
||||
}
|
||||
|
||||
DEBUG_MEMORY_DELETE((uintptr_t) (buf->memory + element * buf->chunk_size), buf->chunk_size);
|
||||
}
|
||||
|
||||
inline
|
||||
|
|
|
|||
164
memory/DataPool.h
Normal file
164
memory/DataPool.h
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* @copyright Jingga
|
||||
* @license OMS License 2.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
#ifndef COMS_MEMORY_DATA_POOL_H
|
||||
#define COMS_MEMORY_DATA_POOL_H
|
||||
|
||||
#include "../stdlib/Types.h"
|
||||
#include "ChunkMemory.h"
|
||||
|
||||
// WARNING: Structure needs to be the same as RingMemory
|
||||
struct DataPool {
|
||||
byte* memory;
|
||||
|
||||
uint64 size;
|
||||
uint32 last_pos;
|
||||
uint32 count;
|
||||
uint32 chunk_size;
|
||||
int32 alignment;
|
||||
|
||||
// length = count
|
||||
// free describes which locations are used and which are free
|
||||
alignas(8) uint64* free;
|
||||
|
||||
// Chunk implementation ends here
|
||||
// This is a bit field that specifies which elements in the data pool are currently in use
|
||||
alignas(8) uint64* used;
|
||||
};
|
||||
|
||||
// INFO: A chunk count of 2^n is recommended for maximum performance
|
||||
inline
|
||||
void pool_alloc(DataPool* buf, uint32 count, uint32 chunk_size, int32 alignment = 64)
|
||||
{
|
||||
ASSERT_SIMPLE(chunk_size);
|
||||
ASSERT_SIMPLE(count);
|
||||
PROFILE(PROFILE_CHUNK_ALLOC, NULL, false, true);
|
||||
LOG_1("Allocating DataPool");
|
||||
|
||||
chunk_size = ROUND_TO_NEAREST(chunk_size, alignment);
|
||||
|
||||
uint64 size = count * chunk_size
|
||||
+ sizeof(uint64) * CEIL_DIV(count, alignment) // free
|
||||
+ sizeof(uint64) * CEIL_DIV(count, alignment) // used
|
||||
+ alignment * 3; // overhead for alignment
|
||||
|
||||
buf->memory = alignment < 2
|
||||
? (byte *) platform_alloc(size)
|
||||
: (byte *) platform_alloc_aligned(size, alignment);
|
||||
|
||||
buf->count = count;
|
||||
buf->size = size;
|
||||
buf->chunk_size = chunk_size;
|
||||
buf->last_pos = -1;
|
||||
buf->alignment = alignment;
|
||||
|
||||
// @question Could it be beneficial to have this before the element data?
|
||||
buf->free = (uint64 *) ROUND_TO_NEAREST((uintptr_t) (buf->memory + count * chunk_size), alignment);
|
||||
buf->used = (uint64 *) ROUND_TO_NEAREST((uintptr_t) (buf->free + count), 6alignment4);
|
||||
|
||||
memset(buf->memory, 0, buf->size);
|
||||
|
||||
LOG_1("Allocated DataPool: %n B", {{LOG_DATA_UINT64, &buf->size}});
|
||||
}
|
||||
|
||||
inline
|
||||
void pool_init(DataPool* buf, BufferMemory* data, uint32 count, uint32 chunk_size, int32 alignment = 64)
|
||||
{
|
||||
ASSERT_SIMPLE(chunk_size);
|
||||
ASSERT_SIMPLE(count);
|
||||
|
||||
chunk_size = ROUND_TO_NEAREST(chunk_size, alignment);
|
||||
|
||||
uint64 size = count * chunk_size
|
||||
+ sizeof(uint64) * CEIL_DIV(count, alignment) // free
|
||||
+ sizeof(uint64) * CEIL_DIV(count, alignment) // used
|
||||
+ alignment * 3; // overhead for alignment
|
||||
|
||||
buf->memory = buffer_get_memory(data, size);
|
||||
|
||||
buf->count = count;
|
||||
buf->size = size;
|
||||
buf->chunk_size = chunk_size;
|
||||
buf->last_pos = -1;
|
||||
buf->alignment = alignment;
|
||||
|
||||
// @question Could it be beneficial to have this before the element data?
|
||||
// On the other hand the way we do it right now we never have to move past the free array since it is at the end
|
||||
// On another hand we could by accident overwrite the values in free if we are not careful
|
||||
buf->free = (uint64 *) ROUND_TO_NEAREST((uintptr_t) (buf->memory + count * chunk_size), alignment);
|
||||
buf->used = (uint64 *) ROUND_TO_NEAREST((uintptr_t) (buf->free + count), alignment);
|
||||
|
||||
DEBUG_MEMORY_SUBREGION((uintptr_t) buf->memory, buf->size);
|
||||
}
|
||||
|
||||
inline
|
||||
void pool_init(DataPool* buf, byte* data, uint32 count, uint32 chunk_size, int32 alignment = 64)
|
||||
{
|
||||
ASSERT_SIMPLE(chunk_size);
|
||||
ASSERT_SIMPLE(count);
|
||||
|
||||
chunk_size = ROUND_TO_NEAREST(chunk_size, alignment);
|
||||
|
||||
uint64 size = count * chunk_size
|
||||
+ sizeof(uint64) * CEIL_DIV(count, alignment) // free
|
||||
+ sizeof(uint64) * CEIL_DIV(count, alignment) // used
|
||||
+ alignment * 3; // overhead for alignment
|
||||
|
||||
// @bug what if an alignment is defined?
|
||||
buf->memory = data;
|
||||
|
||||
buf->count = count;
|
||||
buf->size = size;
|
||||
buf->chunk_size = chunk_size;
|
||||
buf->last_pos = -1;
|
||||
buf->alignment = alignment;
|
||||
|
||||
// @question Could it be beneficial to have this before the element data?
|
||||
// On the other hand the way we do it right now we never have to move past the free array since it is at the end
|
||||
// On another hand we could by accident overwrite the values in free if we are not careful
|
||||
buf->free = (uint64 *) ROUND_TO_NEAREST((uintptr_t) (buf->memory + count * chunk_size), alignment);
|
||||
buf->used = (uint64 *) ROUND_TO_NEAREST((uintptr_t) (buf->free + count), alignment);
|
||||
|
||||
DEBUG_MEMORY_SUBREGION((uintptr_t) buf->memory, buf->size);
|
||||
}
|
||||
|
||||
FORCE_INLINE
|
||||
void pool_free(DataPool* buf) noexcept
|
||||
{
|
||||
chunk_free((ChunkMemory *) buf);
|
||||
}
|
||||
|
||||
FORCE_INLINE
|
||||
int32 pool_reserve(DataPool* buf, uint32 elements = 1) noexcept
|
||||
{
|
||||
return chunk_reserve((ChunkMemory *) buf, elements);
|
||||
}
|
||||
|
||||
FORCE_INLINE
|
||||
byte* pool_get_element(DataPool* buf, uint64 element, bool zeroed = false) noexcept
|
||||
{
|
||||
return chunk_get_element((ChunkMemory *) buf, element, zeroed);
|
||||
}
|
||||
|
||||
// Find a unused/unlocked element in the data pool
|
||||
FORCE_INLINE
|
||||
int32 pool_get_unused(DataPool* buf, int32 start_index = 0) noexcept
|
||||
{
|
||||
return chunk_get_unset(buf->used, buf->count, start_index);
|
||||
}
|
||||
|
||||
// Release an element to be used by someone else
|
||||
inline
|
||||
void pool_release(DataPool* buf, int32 element) noexcept
|
||||
{
|
||||
uint32 free_index = element / 64;
|
||||
uint32 bit_index = element & 63;
|
||||
buf->used[free_index] |= (1ULL << bit_index);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -9,9 +9,9 @@
|
|||
#ifndef COMS_MEMORY_THREADED_CHUNK_MEMORY_H
|
||||
#define COMS_MEMORY_THREADED_CHUNK_MEMORY_H
|
||||
|
||||
#include <string.h>
|
||||
#include "../stdlib/Types.h"
|
||||
#include "../thread/Thread.h"
|
||||
#include "ChunkMemory.h"
|
||||
|
||||
struct ThreadedChunkMemory {
|
||||
byte* memory;
|
||||
|
|
@ -24,14 +24,276 @@ struct ThreadedChunkMemory {
|
|||
|
||||
// length = count
|
||||
// free describes which locations are used and which are free
|
||||
uint64* free;
|
||||
alignas(8) atomic_64 uint64* free;
|
||||
|
||||
// Chunk implementation ends here
|
||||
// The completeness indicates if the data is completely written to
|
||||
uint64* completeness;
|
||||
alignas(8) atomic_64 uint64* completeness;
|
||||
|
||||
coms_pthread_mutex_t mutex;
|
||||
coms_pthread_cond_t cond;
|
||||
mutex lock;
|
||||
};
|
||||
|
||||
// INFO: A chunk count of 2^n is recommended for maximum performance
|
||||
inline
|
||||
void thrd_chunk_alloc(ThreadedChunkMemory* buf, uint32 count, uint32 chunk_size, int32 alignment = 64)
|
||||
{
|
||||
ASSERT_SIMPLE(chunk_size);
|
||||
ASSERT_SIMPLE(count);
|
||||
PROFILE(PROFILE_CHUNK_ALLOC, NULL, false, true);
|
||||
LOG_1("Allocating ChunkMemory");
|
||||
|
||||
chunk_size = ROUND_TO_NEAREST(chunk_size, alignment);
|
||||
|
||||
uint64 size = count * chunk_size
|
||||
+ sizeof(uint64) * CEIL_DIV(count, alignment) // free
|
||||
+ sizeof(uint64) * CEIL_DIV(count, alignment) // completeness
|
||||
+ alignment * 3; // overhead for alignment
|
||||
|
||||
buf->memory = alignment < 2
|
||||
? (byte *) platform_alloc(size)
|
||||
: (byte *) platform_alloc_aligned(size, alignment);
|
||||
|
||||
buf->count = count;
|
||||
buf->size = size;
|
||||
buf->chunk_size = chunk_size;
|
||||
buf->last_pos = -1;
|
||||
buf->alignment = alignment;
|
||||
|
||||
// @question Could it be beneficial to have this before the element data?
|
||||
buf->free = (uint64 *) ROUND_TO_NEAREST((uintptr_t) (buf->memory + count * chunk_size), alignment);
|
||||
buf->completeness = (uint64 *) ROUND_TO_NEAREST((uintptr_t) (buf->free + count), alignment);
|
||||
|
||||
memset(buf->memory, 0, buf->size);
|
||||
mutex_init(&buf->lock, NULL);
|
||||
|
||||
LOG_1("Allocated ChunkMemory: %n B", {{LOG_DATA_UINT64, &buf->size}});
|
||||
}
|
||||
|
||||
inline
|
||||
void thrd_chunk_init(ThreadedChunkMemory* buf, BufferMemory* data, uint32 count, uint32 chunk_size, int32 alignment = 64)
|
||||
{
|
||||
ASSERT_SIMPLE(chunk_size);
|
||||
ASSERT_SIMPLE(count);
|
||||
|
||||
chunk_size = ROUND_TO_NEAREST(chunk_size, alignment);
|
||||
|
||||
uint64 size = count * chunk_size
|
||||
+ sizeof(uint64) * CEIL_DIV(count, alignment) // free
|
||||
+ sizeof(uint64) * CEIL_DIV(count, alignment) // completeness
|
||||
+ alignment * 3; // overhead for alignment
|
||||
|
||||
buf->memory = buffer_get_memory(data, size);
|
||||
|
||||
buf->count = count;
|
||||
buf->size = size;
|
||||
buf->chunk_size = chunk_size;
|
||||
buf->last_pos = -1;
|
||||
buf->alignment = alignment;
|
||||
|
||||
// @question Could it be beneficial to have this before the element data?
|
||||
// On the other hand the way we do it right now we never have to move past the free array since it is at the end
|
||||
// On another hand we could by accident overwrite the values in free if we are not careful
|
||||
buf->free = (uint64 *) ROUND_TO_NEAREST((uintptr_t) (buf->memory + count * chunk_size), alignment);
|
||||
buf->completeness = (uint64 *) ROUND_TO_NEAREST((uintptr_t) (buf->free + count), alignment);
|
||||
|
||||
mutex_init(&buf->lock, NULL);
|
||||
|
||||
DEBUG_MEMORY_SUBREGION((uintptr_t) buf->memory, buf->size);
|
||||
}
|
||||
|
||||
inline
|
||||
void thrd_chunk_init(ThreadedChunkMemory* buf, byte* data, uint32 count, uint32 chunk_size, int32 alignment = 64)
|
||||
{
|
||||
ASSERT_SIMPLE(chunk_size);
|
||||
ASSERT_SIMPLE(count);
|
||||
|
||||
chunk_size = ROUND_TO_NEAREST(chunk_size, alignment);
|
||||
|
||||
uint64 size = count * chunk_size
|
||||
+ sizeof(uint64) * CEIL_DIV(count, alignment) // free
|
||||
+ sizeof(uint64) * CEIL_DIV(count, alignment) // completeness
|
||||
+ alignment * 3; // overhead for alignment
|
||||
|
||||
// @bug what if an alignment is defined?
|
||||
buf->memory = data;
|
||||
|
||||
buf->count = count;
|
||||
buf->size = size;
|
||||
buf->chunk_size = chunk_size;
|
||||
buf->last_pos = -1;
|
||||
buf->alignment = alignment;
|
||||
|
||||
// @question Could it be beneficial to have this before the element data?
|
||||
// On the other hand the way we do it right now we never have to move past the free array since it is at the end
|
||||
// On another hand we could by accident overwrite the values in free if we are not careful
|
||||
buf->free = (uint64 *) ROUND_TO_NEAREST((uintptr_t) (buf->memory + count * chunk_size), alignment);
|
||||
buf->completeness = (uint64 *) ROUND_TO_NEAREST((uintptr_t) (buf->free + count), alignment);
|
||||
|
||||
mutex_init(&buf->lock, NULL);
|
||||
|
||||
DEBUG_MEMORY_SUBREGION((uintptr_t) buf->memory, buf->size);
|
||||
}
|
||||
|
||||
FORCE_INLINE
|
||||
void thrd_chunk_free(ThreadedChunkMemory* buf) noexcept
|
||||
{
|
||||
chunk_free((ChunkMemory *) buf);
|
||||
mutex_destroy(&buf->lock);
|
||||
}
|
||||
|
||||
FORCE_INLINE
|
||||
uint32 thrd_chunk_id_from_memory(const ThreadedChunkMemory* buf, const byte* pos) noexcept
|
||||
{
|
||||
return chunk_id_from_memory((ChunkMemory *) buf, pos);
|
||||
}
|
||||
|
||||
FORCE_INLINE
|
||||
byte* thrd_chunk_get_element(ThreadedChunkMemory* buf, uint32 element, bool zeroed = false) noexcept
|
||||
{
|
||||
return chunk_get_element((ChunkMemory *) buf, element, zeroed);
|
||||
}
|
||||
|
||||
void thrd_chunk_set_unset(uint32 element, atomic_64 uint64* state) {
|
||||
uint32 free_index = element / 64;
|
||||
uint32 bit_index = element & 63;
|
||||
|
||||
alignas(8) atomic_64 uint64* target = &state[free_index];
|
||||
uint64 old_value, new_value;
|
||||
|
||||
do {
|
||||
old_value = atomic_get_relaxed(target);
|
||||
new_value = old_value | (1ULL << bit_index);
|
||||
|
||||
if (old_value == new_value) {
|
||||
return;
|
||||
}
|
||||
} while (!atomic_compare_exchange_strong_release(target, &old_value, new_value));
|
||||
}
|
||||
|
||||
int32 thrd_chunk_get_unset(ThreadedChunkMemory* buf, atomic_64 uint64* state, int32 start_index = 0) {
|
||||
if ((uint32) start_index >= buf->count) {
|
||||
start_index = 0;
|
||||
}
|
||||
|
||||
uint32 free_index = start_index / 64;
|
||||
uint32 bit_index = start_index & 63;
|
||||
|
||||
if (!IS_BIT_SET_64_R2L(state[free_index], bit_index)) {
|
||||
uint64 expected = atomic_get_relaxed(&state[free_index]);
|
||||
expected &= ~(1ULL << bit_index);
|
||||
uint64 desired = expected | (1ULL << bit_index);
|
||||
|
||||
if (atomic_compare_exchange_strong_release(&state[free_index], &expected, desired)) {
|
||||
return free_index * 64 + bit_index;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32 i = 0; i < buf->count; ++i) {
|
||||
if (state[free_index] != 0xFFFFFFFFFFFFFFFF) {
|
||||
// We will try 3 times, usually this would be a while but since compiler_find_... doesn't use atomics
|
||||
// we might get the same index over and over again
|
||||
for (uint32 j = 0; j < 3; ++j) {
|
||||
bit_index = compiler_find_first_bit_r2l(~state[free_index]);
|
||||
|
||||
uint64 expected = atomic_get_relaxed(&state[free_index]);
|
||||
expected &= ~(1ULL << bit_index);
|
||||
uint64 desired = expected | (1ULL << bit_index);
|
||||
|
||||
if (atomic_compare_exchange_strong_release(&state[free_index], &expected, desired)) {
|
||||
return free_index * 64 + bit_index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
++free_index;
|
||||
if (free_index * 64 >= buf->count) {
|
||||
free_index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
inline
|
||||
int32 thrd_chunk_reserve(ThreadedChunkMemory* buf, uint32 elements = 1) noexcept
|
||||
{
|
||||
mutex_lock(&buf->lock);
|
||||
int32 free_element = chunk_reserve((ChunkMemory *) buf, elements);
|
||||
mutex_unlock(&buf->lock);
|
||||
|
||||
return free_element;
|
||||
}
|
||||
|
||||
inline
|
||||
void thrd_chunk_free_element(ThreadedChunkMemory* buf, uint64 free_index, int32 bit_index) noexcept
|
||||
{
|
||||
alignas(8) atomic_64 uint64* target = &buf->free[free_index];
|
||||
uint64 old_value, new_value;
|
||||
|
||||
do {
|
||||
old_value = atomic_get_relaxed(target);
|
||||
new_value = old_value | (1ULL << bit_index);
|
||||
|
||||
if (old_value == new_value) {
|
||||
return;
|
||||
}
|
||||
} while (!atomic_compare_exchange_strong_release(target, &old_value, new_value));
|
||||
|
||||
DEBUG_MEMORY_DELETE((uintptr_t) (buf->memory + (free_index * 64 + bit_index) * buf->chunk_size), buf->chunk_size);
|
||||
}
|
||||
|
||||
inline
|
||||
void thrd_chunk_free_elements(ThreadedChunkMemory* buf, uint64 element, uint32 element_count = 1) noexcept
|
||||
{
|
||||
uint64 free_index = element / 64;
|
||||
uint32 bit_index = element & 63;
|
||||
|
||||
if (element == 1) {
|
||||
thrd_chunk_free_element(buf, free_index, bit_index);
|
||||
return;
|
||||
}
|
||||
|
||||
alignas(8) atomic_64 uint64* target;
|
||||
uint64 old_value, new_value;
|
||||
|
||||
while (element_count > 0) {
|
||||
// Calculate the number of bits we can clear in the current 64-bit block
|
||||
uint32 bits_in_current_block = OMS_MIN(64 - bit_index, element_count);
|
||||
|
||||
// Create a mask to clear the bits
|
||||
uint64 mask = ((1ULL << bits_in_current_block) - 1) << bit_index;
|
||||
|
||||
target = &buf->free[free_index];
|
||||
|
||||
do {
|
||||
old_value = atomic_get_relaxed(target);
|
||||
new_value = old_value & ~mask;
|
||||
|
||||
if (old_value == new_value) {
|
||||
break;
|
||||
}
|
||||
} while (!atomic_compare_exchange_strong_release(target, &old_value, new_value));
|
||||
|
||||
// Update the counters and indices
|
||||
element_count -= bits_in_current_block;
|
||||
++free_index;
|
||||
bit_index = 0;
|
||||
}
|
||||
|
||||
DEBUG_MEMORY_DELETE((uintptr_t) (buf->memory + element * buf->chunk_size), buf->chunk_size);
|
||||
}
|
||||
|
||||
inline
|
||||
int32 thrd_chunk_resize(ThreadedChunkMemory* buf, int32 element_id, uint32 elements_old, uint32 elements_new) noexcept
|
||||
{
|
||||
byte* data = thrd_chunk_get_element(buf, element_id);
|
||||
|
||||
int32 chunk_id = thrd_chunk_reserve(buf, elements_new);
|
||||
byte* data_new = thrd_chunk_get_element(buf, chunk_id);
|
||||
|
||||
memcpy(data_new, data, buf->chunk_size * elements_old);
|
||||
|
||||
return chunk_id;
|
||||
}
|
||||
|
||||
#endif
|
||||
93
memory/ThreadedDataPool.h
Normal file
93
memory/ThreadedDataPool.h
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* @copyright Jingga
|
||||
* @license OMS License 2.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
#ifndef COMS_MEMORY_THREADED_DATA_POOL_H
|
||||
#define COMS_MEMORY_THREADED_DATA_POOL_H
|
||||
|
||||
#include "../stdlib/Types.h"
|
||||
#include "DataPool.h"
|
||||
#include "ThreadedChunkMemory.h"
|
||||
|
||||
/**
|
||||
* WARNING: This implementation assumes the initial setup (insertion of elements) is synchronous
|
||||
* Only the retrieval of unused elements and the release are thread protected
|
||||
*/
|
||||
|
||||
// WARNING: Structure needs to be the same as RingMemory
|
||||
struct ThreadedDataPool {
|
||||
byte* memory;
|
||||
|
||||
uint64 size;
|
||||
uint32 last_pos;
|
||||
uint32 count;
|
||||
uint32 chunk_size;
|
||||
int32 alignment;
|
||||
|
||||
// length = count
|
||||
// free describes which locations are used and which are free
|
||||
alignas(8) atomic_64 uint64* free;
|
||||
|
||||
// Chunk implementation ends here
|
||||
// This is a bit field that specifies which elements in the data pool are currently in use
|
||||
alignas(8) atomic_64 uint64* used;
|
||||
|
||||
mutex mutex;
|
||||
};
|
||||
|
||||
// INFO: A chunk count of 2^n is recommended for maximum performance
|
||||
FORCE_INLINE
|
||||
void thrd_pool_alloc(ThreadedDataPool* buf, uint32 count, uint32 chunk_size, int32 alignment = 64)
|
||||
{
|
||||
pool_alloc((DataPool *) buf, count, chunk_size, alignment);
|
||||
}
|
||||
|
||||
FORCE_INLINE
|
||||
void thrd_pool_init(ThreadedDataPool* buf, BufferMemory* data, uint32 count, uint32 chunk_size, int32 alignment = 64)
|
||||
{
|
||||
pool_init((DataPool *) buf, data, count, chunk_size, alignment);
|
||||
}
|
||||
|
||||
FORCE_INLINE
|
||||
void thrd_pool_init(ThreadedDataPool* buf, byte* data, uint32 count, uint32 chunk_size, int32 alignment = 64)
|
||||
{
|
||||
pool_init((DataPool *) buf, data, count, chunk_size, alignment);
|
||||
}
|
||||
|
||||
FORCE_INLINE
|
||||
void thrd_pool_free(ThreadedDataPool* buf) noexcept
|
||||
{
|
||||
chunk_free((ChunkMemory *) buf);
|
||||
}
|
||||
|
||||
FORCE_INLINE
|
||||
int32 thrd_pool_reserve(ThreadedDataPool* buf, uint32 elements = 1) noexcept
|
||||
{
|
||||
return chunk_reserve((ChunkMemory *) buf, elements);
|
||||
}
|
||||
|
||||
FORCE_INLINE
|
||||
byte* thrd_pool_get_element(ThreadedDataPool* buf, uint64 element, bool zeroed = false) noexcept
|
||||
{
|
||||
return chunk_get_element((ChunkMemory *) buf, element, zeroed);
|
||||
}
|
||||
|
||||
// Find a unused/unlocked element in the data pool
|
||||
FORCE_INLINE
|
||||
int32 thrd_pool_get_unused(ThreadedDataPool* buf, int32 start_index = 0) noexcept
|
||||
{
|
||||
return thrd_chunk_get_unset((ThreadedChunkMemory *) buf, buf->used, start_index);
|
||||
}
|
||||
|
||||
// Release an element to be used by someone else
|
||||
FORCE_INLINE
|
||||
void thrd_pool_release(ThreadedDataPool* buf, int32 element) noexcept
|
||||
{
|
||||
thrd_chunk_set_unset(element, buf->used);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -10,6 +10,9 @@
|
|||
#define COMS_MEMORY_THREADED_QUEUE_H
|
||||
|
||||
// @todo This is a horrible implementation. Please implement a lock free solution
|
||||
/**
|
||||
* WARNING: This implementation is a single-producer, single-consumer (SPSC) implementation
|
||||
*/
|
||||
|
||||
#include "../stdlib/Types.h"
|
||||
#include "../utils/Utils.h"
|
||||
|
|
@ -37,11 +40,11 @@ struct ThreadedQueue {
|
|||
|
||||
// We support both conditional locking and semaphore locking
|
||||
// These values are not initialized and not used unless you use the queue
|
||||
coms_pthread_mutex_t mutex;
|
||||
coms_pthread_cond_t cond;
|
||||
mutex mutex;
|
||||
mutex_cond cond;
|
||||
|
||||
sem_t empty;
|
||||
sem_t full;
|
||||
sem empty;
|
||||
sem full;
|
||||
};
|
||||
|
||||
inline
|
||||
|
|
@ -53,11 +56,11 @@ void thrd_queue_alloc(ThreadedQueue* queue, uint32 element_count, uint32 element
|
|||
|
||||
queue->element_size = element_size;
|
||||
|
||||
coms_pthread_mutex_init(&queue->mutex, NULL);
|
||||
mutex_init(&queue->mutex, NULL);
|
||||
coms_pthread_cond_init(&queue->cond, NULL);
|
||||
|
||||
sem_init(&queue->empty, element_count);
|
||||
sem_init(&queue->full, 0);
|
||||
coms_sem_init(&queue->empty, element_count);
|
||||
coms_sem_init(&queue->full, 0);
|
||||
}
|
||||
|
||||
inline
|
||||
|
|
@ -69,11 +72,11 @@ void thrd_queue_init(ThreadedQueue* queue, BufferMemory* buf, uint32 element_cou
|
|||
|
||||
queue->element_size = element_size;
|
||||
|
||||
coms_pthread_mutex_init(&queue->mutex, NULL);
|
||||
mutex_init(&queue->mutex, NULL);
|
||||
coms_pthread_cond_init(&queue->cond, NULL);
|
||||
|
||||
sem_init(&queue->empty, element_count);
|
||||
sem_init(&queue->full, 0);
|
||||
coms_sem_init(&queue->empty, element_count);
|
||||
coms_sem_init(&queue->full, 0);
|
||||
}
|
||||
|
||||
inline
|
||||
|
|
@ -85,20 +88,20 @@ void thrd_queue_init(ThreadedQueue* queue, byte* buf, uint32 element_count, uint
|
|||
|
||||
queue->element_size = element_size;
|
||||
|
||||
coms_pthread_mutex_init(&queue->mutex, NULL);
|
||||
mutex_init(&queue->mutex, NULL);
|
||||
coms_pthread_cond_init(&queue->cond, NULL);
|
||||
|
||||
sem_init(&queue->empty, element_count);
|
||||
sem_init(&queue->full, 0);
|
||||
coms_sem_init(&queue->empty, element_count);
|
||||
coms_sem_init(&queue->full, 0);
|
||||
}
|
||||
|
||||
inline
|
||||
void thrd_queue_free(ThreadedQueue* queue)
|
||||
{
|
||||
ring_free((RingMemory *) queue);
|
||||
sem_destroy(&queue->empty);
|
||||
sem_destroy(&queue->full);
|
||||
coms_pthread_mutex_destroy(&queue->mutex);
|
||||
coms_sem_destroy(&queue->empty);
|
||||
coms_sem_destroy(&queue->full);
|
||||
mutex_destroy(&queue->mutex);
|
||||
coms_pthread_cond_destroy(&queue->cond);
|
||||
}
|
||||
|
||||
|
|
@ -107,7 +110,7 @@ inline
|
|||
void thrd_queue_enqueue_unique_wait(ThreadedQueue* queue, const byte* data) noexcept
|
||||
{
|
||||
ASSERT_SIMPLE((uint64_t) data % 4 == 0);
|
||||
coms_pthread_mutex_lock(&queue->mutex);
|
||||
mutex_lock(&queue->mutex);
|
||||
|
||||
byte* tail = queue->tail;
|
||||
while (tail != queue->tail) {
|
||||
|
|
@ -115,7 +118,7 @@ void thrd_queue_enqueue_unique_wait(ThreadedQueue* queue, const byte* data) noex
|
|||
|
||||
// @performance we could probably make this faster since we don't need to compare the entire range
|
||||
if (is_equal(tail, data, queue->element_size) == 0) {
|
||||
coms_pthread_mutex_unlock(&queue->mutex);
|
||||
mutex_unlock(&queue->mutex);
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
@ -131,14 +134,14 @@ void thrd_queue_enqueue_unique_wait(ThreadedQueue* queue, const byte* data) noex
|
|||
memcpy(mem, data, queue->element_size);
|
||||
|
||||
coms_pthread_cond_signal(&queue->cond);
|
||||
coms_pthread_mutex_unlock(&queue->mutex);
|
||||
mutex_unlock(&queue->mutex);
|
||||
}
|
||||
|
||||
inline
|
||||
void thrd_queue_enqueue_unique(ThreadedQueue* queue, const byte* data) noexcept
|
||||
{
|
||||
ASSERT_SIMPLE((uint64_t) data % 4 == 0);
|
||||
coms_pthread_mutex_lock(&queue->mutex);
|
||||
mutex_lock(&queue->mutex);
|
||||
|
||||
byte* tail = queue->tail;
|
||||
while (tail != queue->tail) {
|
||||
|
|
@ -146,7 +149,7 @@ void thrd_queue_enqueue_unique(ThreadedQueue* queue, const byte* data) noexcept
|
|||
|
||||
// @performance we could probably make this faster since we don't need to compare the entire range
|
||||
if (is_equal(tail, data, queue->element_size) == 0) {
|
||||
coms_pthread_mutex_unlock(&queue->mutex);
|
||||
mutex_unlock(&queue->mutex);
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
@ -155,7 +158,7 @@ void thrd_queue_enqueue_unique(ThreadedQueue* queue, const byte* data) noexcept
|
|||
}
|
||||
|
||||
if (!ring_commit_safe((RingMemory *) queue, queue->element_size, queue->alignment)) {
|
||||
coms_pthread_mutex_unlock(&queue->mutex);
|
||||
mutex_unlock(&queue->mutex);
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
@ -164,17 +167,17 @@ void thrd_queue_enqueue_unique(ThreadedQueue* queue, const byte* data) noexcept
|
|||
memcpy(mem, data, queue->element_size);
|
||||
|
||||
coms_pthread_cond_signal(&queue->cond);
|
||||
coms_pthread_mutex_unlock(&queue->mutex);
|
||||
mutex_unlock(&queue->mutex);
|
||||
}
|
||||
|
||||
// Conditional Lock
|
||||
inline
|
||||
void thrd_queue_enqueue(ThreadedQueue* queue, const byte* data) noexcept
|
||||
{
|
||||
coms_pthread_mutex_lock(&queue->mutex);
|
||||
mutex_lock(&queue->mutex);
|
||||
|
||||
if (!ring_commit_safe((RingMemory *) queue, queue->element_size, queue->alignment)) {
|
||||
coms_pthread_mutex_unlock(&queue->mutex);
|
||||
mutex_unlock(&queue->mutex);
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
@ -183,13 +186,13 @@ void thrd_queue_enqueue(ThreadedQueue* queue, const byte* data) noexcept
|
|||
memcpy(mem, data, queue->element_size);
|
||||
|
||||
coms_pthread_cond_signal(&queue->cond);
|
||||
coms_pthread_mutex_unlock(&queue->mutex);
|
||||
mutex_unlock(&queue->mutex);
|
||||
}
|
||||
|
||||
inline
|
||||
void thrd_queue_enqueue_wait(ThreadedQueue* queue, const byte* data) noexcept
|
||||
{
|
||||
coms_pthread_mutex_lock(&queue->mutex);
|
||||
mutex_lock(&queue->mutex);
|
||||
|
||||
while (!ring_commit_safe((RingMemory *) queue, queue->element_size, queue->alignment)) {
|
||||
coms_pthread_cond_wait(&queue->cond, &queue->mutex);
|
||||
|
|
@ -199,13 +202,13 @@ void thrd_queue_enqueue_wait(ThreadedQueue* queue, const byte* data) noexcept
|
|||
memcpy(mem, data, queue->element_size);
|
||||
|
||||
coms_pthread_cond_signal(&queue->cond);
|
||||
coms_pthread_mutex_unlock(&queue->mutex);
|
||||
mutex_unlock(&queue->mutex);
|
||||
}
|
||||
|
||||
inline
|
||||
byte* thrd_queue_enqueue_start_wait(ThreadedQueue* queue) noexcept
|
||||
{
|
||||
coms_pthread_mutex_lock(&queue->mutex);
|
||||
mutex_lock(&queue->mutex);
|
||||
|
||||
while (!ring_commit_safe((RingMemory *) queue, queue->element_size, queue->alignment)) {
|
||||
coms_pthread_cond_wait(&queue->cond, &queue->mutex);
|
||||
|
|
@ -218,7 +221,7 @@ inline
|
|||
void thrd_queue_enqueue_end_wait(ThreadedQueue* queue) noexcept
|
||||
{
|
||||
coms_pthread_cond_signal(&queue->cond);
|
||||
coms_pthread_mutex_unlock(&queue->mutex);
|
||||
mutex_unlock(&queue->mutex);
|
||||
}
|
||||
|
||||
inline
|
||||
|
|
@ -229,9 +232,9 @@ bool thrd_queue_dequeue(ThreadedQueue* queue, byte* data) noexcept
|
|||
}
|
||||
|
||||
// we do this twice because the first one is very fast but may return a false positive
|
||||
coms_pthread_mutex_lock(&queue->mutex);
|
||||
mutex_lock(&queue->mutex);
|
||||
if (queue->head == queue->tail) {
|
||||
coms_pthread_mutex_unlock(&queue->mutex);
|
||||
mutex_unlock(&queue->mutex);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
@ -244,25 +247,25 @@ bool thrd_queue_dequeue(ThreadedQueue* queue, byte* data) noexcept
|
|||
ring_move_pointer((RingMemory *) queue, &queue->tail, queue->element_size, queue->alignment);
|
||||
|
||||
coms_pthread_cond_signal(&queue->cond);
|
||||
coms_pthread_mutex_unlock(&queue->mutex);
|
||||
mutex_unlock(&queue->mutex);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline
|
||||
bool thrd_queue_empty(ThreadedQueue* queue) noexcept {
|
||||
coms_pthread_mutex_lock(&queue->mutex);
|
||||
mutex_lock(&queue->mutex);
|
||||
bool is_empty = queue->head == queue->tail;
|
||||
coms_pthread_mutex_unlock(&queue->mutex);
|
||||
mutex_unlock(&queue->mutex);
|
||||
|
||||
return is_empty;
|
||||
}
|
||||
|
||||
inline
|
||||
bool thrd_queue_full(ThreadedQueue* queue) noexcept {
|
||||
coms_pthread_mutex_lock(&queue->mutex);
|
||||
mutex_lock(&queue->mutex);
|
||||
bool is_full = !ring_commit_safe((RingMemory *) queue, queue->element_size, queue->alignment);
|
||||
coms_pthread_mutex_unlock(&queue->mutex);
|
||||
mutex_unlock(&queue->mutex);
|
||||
|
||||
return is_full;
|
||||
}
|
||||
|
|
@ -271,7 +274,7 @@ bool thrd_queue_full(ThreadedQueue* queue) noexcept {
|
|||
inline
|
||||
void thrd_queue_dequeue_wait(ThreadedQueue* queue, byte* data) noexcept
|
||||
{
|
||||
coms_pthread_mutex_lock(&queue->mutex);
|
||||
mutex_lock(&queue->mutex);
|
||||
|
||||
while (queue->head == queue->tail) {
|
||||
coms_pthread_cond_wait(&queue->cond, &queue->mutex);
|
||||
|
|
@ -281,13 +284,13 @@ void thrd_queue_dequeue_wait(ThreadedQueue* queue, byte* data) noexcept
|
|||
ring_move_pointer((RingMemory *) queue, &queue->tail, queue->element_size, queue->alignment);
|
||||
|
||||
coms_pthread_cond_signal(&queue->cond);
|
||||
coms_pthread_mutex_unlock(&queue->mutex);
|
||||
mutex_unlock(&queue->mutex);
|
||||
}
|
||||
|
||||
inline
|
||||
byte* thrd_queue_dequeue_start_wait(ThreadedQueue* queue) noexcept
|
||||
{
|
||||
coms_pthread_mutex_lock(&queue->mutex);
|
||||
mutex_lock(&queue->mutex);
|
||||
|
||||
while (queue->head == queue->tail) {
|
||||
coms_pthread_cond_wait(&queue->cond, &queue->mutex);
|
||||
|
|
@ -302,104 +305,104 @@ void thrd_queue_dequeue_end_wait(ThreadedQueue* queue) noexcept
|
|||
ring_move_pointer((RingMemory *) queue, &queue->tail, queue->element_size, queue->alignment);
|
||||
|
||||
coms_pthread_cond_signal(&queue->cond);
|
||||
coms_pthread_mutex_unlock(&queue->mutex);
|
||||
mutex_unlock(&queue->mutex);
|
||||
}
|
||||
|
||||
// Semaphore Lock
|
||||
inline
|
||||
void thrd_queue_enqueue_sem_wait(ThreadedQueue* queue, const byte* data) noexcept
|
||||
void thrd_queue_enqueue_coms_sem_wait(ThreadedQueue* queue, const byte* data) noexcept
|
||||
{
|
||||
sem_wait(&queue->empty);
|
||||
coms_pthread_mutex_lock(&queue->mutex);
|
||||
coms_sem_wait(&queue->empty);
|
||||
mutex_lock(&queue->mutex);
|
||||
|
||||
byte* mem = ring_get_memory((RingMemory *) queue, queue->element_size, queue->alignment);
|
||||
memcpy(mem, data, queue->element_size);
|
||||
|
||||
coms_pthread_mutex_unlock(&queue->mutex);
|
||||
sem_post(&queue->full);
|
||||
mutex_unlock(&queue->mutex);
|
||||
coms_sem_post(&queue->full);
|
||||
}
|
||||
|
||||
inline
|
||||
bool thrd_queue_enqueue_sem_timedwait(ThreadedQueue* queue, const byte* data, uint64 wait) noexcept
|
||||
bool thrd_queue_enqueue_semimedwait(ThreadedQueue* queue, const byte* data, uint64 wait) noexcept
|
||||
{
|
||||
if (sem_timedwait(&queue->empty, wait)) {
|
||||
if (semimedwait(&queue->empty, wait)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
coms_pthread_mutex_lock(&queue->mutex);
|
||||
mutex_lock(&queue->mutex);
|
||||
|
||||
byte* mem = ring_get_memory((RingMemory *) queue, queue->element_size, queue->alignment);
|
||||
memcpy(mem, data, queue->element_size);
|
||||
|
||||
coms_pthread_mutex_unlock(&queue->mutex);
|
||||
sem_post(&queue->full);
|
||||
mutex_unlock(&queue->mutex);
|
||||
coms_sem_post(&queue->full);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline
|
||||
byte* thrd_queue_enqueue_start_sem_wait(ThreadedQueue* queue) noexcept
|
||||
byte* thrd_queue_enqueue_start_coms_sem_wait(ThreadedQueue* queue) noexcept
|
||||
{
|
||||
sem_wait(&queue->empty);
|
||||
coms_pthread_mutex_lock(&queue->mutex);
|
||||
coms_sem_wait(&queue->empty);
|
||||
mutex_lock(&queue->mutex);
|
||||
|
||||
return ring_get_memory((RingMemory *) queue, queue->element_size, queue->alignment);
|
||||
}
|
||||
|
||||
inline
|
||||
void thrd_queue_enqueue_end_sem_wait(ThreadedQueue* queue) noexcept
|
||||
void thrd_queue_enqueue_end_coms_sem_wait(ThreadedQueue* queue) noexcept
|
||||
{
|
||||
coms_pthread_mutex_unlock(&queue->mutex);
|
||||
sem_post(&queue->full);
|
||||
mutex_unlock(&queue->mutex);
|
||||
coms_sem_post(&queue->full);
|
||||
}
|
||||
|
||||
inline
|
||||
byte* thrd_queue_dequeue_sem_wait(ThreadedQueue* queue, byte* data) noexcept
|
||||
byte* thrd_queue_dequeue_coms_sem_wait(ThreadedQueue* queue, byte* data) noexcept
|
||||
{
|
||||
sem_wait(&queue->full);
|
||||
coms_pthread_mutex_lock(&queue->mutex);
|
||||
coms_sem_wait(&queue->full);
|
||||
mutex_lock(&queue->mutex);
|
||||
|
||||
memcpy(data, queue->tail, queue->element_size);
|
||||
ring_move_pointer((RingMemory *) queue, &queue->tail, queue->element_size, queue->alignment);
|
||||
|
||||
coms_pthread_mutex_unlock(&queue->mutex);
|
||||
sem_post(&queue->empty);
|
||||
mutex_unlock(&queue->mutex);
|
||||
coms_sem_post(&queue->empty);
|
||||
}
|
||||
|
||||
inline
|
||||
bool thrd_queue_dequeue_sem_timedwait(ThreadedQueue* queue, byte* data, uint64 wait) noexcept
|
||||
bool thrd_queue_dequeue_semimedwait(ThreadedQueue* queue, byte* data, uint64 wait) noexcept
|
||||
{
|
||||
if (sem_timedwait(&queue->full, wait)) {
|
||||
if (semimedwait(&queue->full, wait)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
coms_pthread_mutex_lock(&queue->mutex);
|
||||
mutex_lock(&queue->mutex);
|
||||
|
||||
memcpy(data, queue->tail, queue->element_size);
|
||||
ring_move_pointer((RingMemory *) queue, &queue->tail, queue->element_size, queue->alignment);
|
||||
|
||||
coms_pthread_mutex_unlock(&queue->mutex);
|
||||
sem_post(&queue->empty);
|
||||
mutex_unlock(&queue->mutex);
|
||||
coms_sem_post(&queue->empty);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline
|
||||
byte* thrd_queue_dequeue_start_sem_wait(ThreadedQueue* queue) noexcept
|
||||
byte* thrd_queue_dequeue_start_coms_sem_wait(ThreadedQueue* queue) noexcept
|
||||
{
|
||||
sem_wait(&queue->full);
|
||||
coms_pthread_mutex_lock(&queue->mutex);
|
||||
coms_sem_wait(&queue->full);
|
||||
mutex_lock(&queue->mutex);
|
||||
|
||||
return queue->tail;
|
||||
}
|
||||
|
||||
inline
|
||||
void thrd_queue_dequeue_end_sem_wait(ThreadedQueue* queue) noexcept
|
||||
void thrd_queue_dequeue_end_coms_sem_wait(ThreadedQueue* queue) noexcept
|
||||
{
|
||||
ring_move_pointer((RingMemory *) queue, &queue->tail, queue->element_size, queue->alignment);
|
||||
|
||||
coms_pthread_mutex_unlock(&queue->mutex);
|
||||
sem_post(&queue->empty);
|
||||
mutex_unlock(&queue->mutex);
|
||||
coms_sem_post(&queue->empty);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -30,7 +30,7 @@ struct ThreadedRingMemory {
|
|||
int32 alignment;
|
||||
|
||||
// The ring memory ends here
|
||||
coms_pthread_mutex_t mutex;
|
||||
mutex lock;
|
||||
};
|
||||
|
||||
// @bug alignment should also include the end point, not just the start
|
||||
|
|
@ -39,36 +39,36 @@ inline
|
|||
void thrd_ring_alloc(ThreadedRingMemory* ring, uint64 size, int32 alignment = 64)
|
||||
{
|
||||
ring_alloc((RingMemory *) ring, size, alignment);
|
||||
coms_pthread_mutex_init(&ring->mutex, NULL);
|
||||
mutex_init(&ring->lock, NULL);
|
||||
}
|
||||
|
||||
inline
|
||||
void thrd_ring_init(ThreadedRingMemory* ring, BufferMemory* buf, uint64 size, int32 alignment = 64)
|
||||
{
|
||||
ring_init((RingMemory *) ring, buf, size, alignment);
|
||||
coms_pthread_mutex_init(&ring->mutex, NULL);
|
||||
mutex_init(&ring->lock, NULL);
|
||||
}
|
||||
|
||||
inline
|
||||
void thrd_ring_init(ThreadedRingMemory* ring, byte* buf, uint64 size, int32 alignment = 64)
|
||||
{
|
||||
ring_init((RingMemory *) ring, buf, size, alignment);
|
||||
coms_pthread_mutex_init(&ring->mutex, NULL);
|
||||
mutex_init(&ring->lock, NULL);
|
||||
}
|
||||
|
||||
inline
|
||||
void thrd_ring_free(ThreadedRingMemory* ring)
|
||||
{
|
||||
ring_free((RingMemory *) ring);
|
||||
coms_pthread_mutex_destroy(&ring->mutex);
|
||||
mutex_destroy(&ring->lock);
|
||||
}
|
||||
|
||||
inline
|
||||
byte* thrd_ring_calculate_position(ThreadedRingMemory* ring, uint64 size, byte aligned = 4) noexcept
|
||||
{
|
||||
coms_pthread_mutex_lock(&ring->mutex);
|
||||
mutex_lock(&ring->lock);
|
||||
byte* result = ring_calculate_position((RingMemory *) ring, size, aligned);
|
||||
coms_pthread_mutex_unlock(&ring->mutex);
|
||||
mutex_unlock(&ring->lock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
@ -76,24 +76,24 @@ byte* thrd_ring_calculate_position(ThreadedRingMemory* ring, uint64 size, byte a
|
|||
inline
|
||||
void thrd_ring_reset(ThreadedRingMemory* ring) noexcept
|
||||
{
|
||||
coms_pthread_mutex_lock(&ring->mutex);
|
||||
mutex_lock(&ring->lock);
|
||||
ring_reset((RingMemory *) ring);
|
||||
coms_pthread_mutex_unlock(&ring->mutex);
|
||||
mutex_unlock(&ring->lock);
|
||||
}
|
||||
|
||||
// Moves a pointer based on the size you want to consume (new position = after consuming size)
|
||||
void thrd_ring_move_pointer(ThreadedRingMemory* ring, byte** pos, uint64 size, byte aligned = 4) noexcept
|
||||
{
|
||||
coms_pthread_mutex_lock(&ring->mutex);
|
||||
mutex_lock(&ring->lock);
|
||||
ring_move_pointer((RingMemory *) ring, pos, size, aligned);
|
||||
coms_pthread_mutex_unlock(&ring->mutex);
|
||||
mutex_unlock(&ring->lock);
|
||||
}
|
||||
|
||||
byte* thrd_ring_get_memory(ThreadedRingMemory* ring, uint64 size, byte aligned = 4, bool zeroed = false) noexcept
|
||||
{
|
||||
coms_pthread_mutex_lock(&ring->mutex);
|
||||
mutex_lock(&ring->lock);
|
||||
byte* result = ring_get_memory((RingMemory *) ring, size, aligned, zeroed);
|
||||
coms_pthread_mutex_unlock(&ring->mutex);
|
||||
mutex_unlock(&ring->lock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
@ -101,9 +101,9 @@ byte* thrd_ring_get_memory(ThreadedRingMemory* ring, uint64 size, byte aligned =
|
|||
// Same as ring_get_memory but DOESN'T move the head
|
||||
byte* thrd_ring_get_memory_nomove(ThreadedRingMemory* ring, uint64 size, byte aligned = 4, bool zeroed = false) noexcept
|
||||
{
|
||||
coms_pthread_mutex_lock(&ring->mutex);
|
||||
mutex_lock(&ring->lock);
|
||||
byte* result = ring_get_memory_nomove((RingMemory *) ring, size, aligned, zeroed);
|
||||
coms_pthread_mutex_unlock(&ring->mutex);
|
||||
mutex_unlock(&ring->lock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
@ -113,9 +113,9 @@ byte* thrd_ring_get_memory_nomove(ThreadedRingMemory* ring, uint64 size, byte al
|
|||
inline
|
||||
byte* thrd_ring_get_element(ThreadedRingMemory* ring, uint64 element, uint64 size) noexcept
|
||||
{
|
||||
coms_pthread_mutex_lock(&ring->mutex);
|
||||
mutex_lock(&ring->lock);
|
||||
byte* result = ring_get_element((RingMemory *) ring, element, size);
|
||||
coms_pthread_mutex_unlock(&ring->mutex);
|
||||
mutex_unlock(&ring->lock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
@ -126,9 +126,9 @@ byte* thrd_ring_get_element(ThreadedRingMemory* ring, uint64 element, uint64 siz
|
|||
inline
|
||||
bool thrd_ring_commit_safe(ThreadedRingMemory* ring, uint64 size, byte aligned = 4) noexcept
|
||||
{
|
||||
coms_pthread_mutex_lock(&ring->mutex);
|
||||
mutex_lock(&ring->lock);
|
||||
bool result = ring_commit_safe((RingMemory *) ring, size, aligned);
|
||||
coms_pthread_mutex_unlock(&ring->mutex);
|
||||
mutex_unlock(&ring->lock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
@ -148,9 +148,9 @@ void thrd_ring_force_tail_update(const ThreadedRingMemory* ring) noexcept
|
|||
inline
|
||||
int64 thrd_ring_dump(ThreadedRingMemory* ring, byte* data) noexcept
|
||||
{
|
||||
coms_pthread_mutex_lock(&ring->mutex);
|
||||
mutex_lock(&ring->lock);
|
||||
int64 result = ring_dump((RingMemory *) ring, data);
|
||||
coms_pthread_mutex_unlock(&ring->mutex);
|
||||
mutex_unlock(&ring->lock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#define COMS_MODULE_H
|
||||
|
||||
#include "../stdlib/Types.h"
|
||||
#include "../../GameEngine/system/Library.h"
|
||||
#include "../../cOMS/system/Library.h"
|
||||
|
||||
enum ModuleType {
|
||||
MODULE_TYPE_HUD,
|
||||
|
|
|
|||
9
module/WebModule.h
Normal file
9
module/WebModule.h
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#ifndef COMS_MODULE_WEB_H
|
||||
#define COMS_MODULE_WEB_H
|
||||
|
||||
#include "../stdlib/Types.h"
|
||||
|
||||
struct WebModule {
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -275,7 +275,7 @@ void file_read(const char* __restrict path, FileBody* __restrict file, RingMemor
|
|||
}
|
||||
|
||||
ssize_t bytes_read = read(fp, file->content, file->size);
|
||||
if (bytes_read <= 0 || (size_t) bytes_read != file->size) {
|
||||
if (bytes_read <= 0) {
|
||||
close(fp);
|
||||
file->content = NULL;
|
||||
file->size = 0;
|
||||
|
|
@ -378,6 +378,25 @@ bool file_write(const char* __restrict path, const FileBody* __restrict file) {
|
|||
return true;
|
||||
}
|
||||
|
||||
FileHandle file_read_handle(const char* path) {
|
||||
FileHandle fd;
|
||||
char full_path[MAX_PATH];
|
||||
|
||||
if (*path == '.') {
|
||||
relative_to_absolute(path, full_path);
|
||||
fd = open(full_path, O_RDONLY);
|
||||
} else {
|
||||
fd = open(path, O_RDONLY);
|
||||
}
|
||||
|
||||
if (fd == -1) {
|
||||
perror("open");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
inline
|
||||
void file_close_handle(FileHandle fp)
|
||||
{
|
||||
|
|
|
|||
61
platform/linux/GuiUtils.h
Normal file
61
platform/linux/GuiUtils.h
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* @copyright Jingga
|
||||
* @license OMS License 2.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
#ifndef COMS_PLATFORM_LINUX_GUI_UTILS_H
|
||||
#define COMS_PLATFORM_LINUX_GUI_UTILS_H
|
||||
|
||||
#include "../../stdlib/Types.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xatom.h>
|
||||
|
||||
void clipboard_get(char* text, int32 max_length)
|
||||
{
|
||||
*text = '\0';
|
||||
|
||||
Display *display = XOpenDisplay(NULL);
|
||||
if (display == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
Atom clipboard = XInternAtom(display, "CLIPBOARD", false);
|
||||
Atom utf8_string = XInternAtom(display, "UTF8_STRING", false);
|
||||
Atom xa_string = XInternAtom(display, "STRING", false);
|
||||
Window window = XDefaultRootWindow(display);
|
||||
|
||||
XConvertSelection(display, clipboard, utf8_string, xa_string, window, CurrentTime);
|
||||
XEvent event;
|
||||
XNextEvent(display, &event);
|
||||
|
||||
if (event.type == SelectionNotify) {
|
||||
if (event.xselection.property) {
|
||||
Atom type;
|
||||
int32 format;
|
||||
unsigned long nitems, bytes_after;
|
||||
byte* data = NULL;
|
||||
|
||||
XGetWindowProperty(
|
||||
display, event.xselection.requestor,
|
||||
event.xselection.property, 0, (~0L), false,
|
||||
AnyPropertyType, &type, &format, &nitems,
|
||||
&bytes_after, &data
|
||||
);
|
||||
|
||||
if (data) {
|
||||
str_copy_short(text, clipboard_text, max_length);
|
||||
XFree(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
XCloseDisplay(display);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -18,7 +18,7 @@
|
|||
#include "../../stdlib/Types.h"
|
||||
#include "../../utils/StringUtils.h"
|
||||
#include "../../system/Library.h"
|
||||
#include "UtilsLinux.h"
|
||||
#include "../../system/FileUtils.cpp"
|
||||
|
||||
inline
|
||||
bool library_load(Library* lib)
|
||||
|
|
@ -48,8 +48,11 @@ bool library_load(Library* lib)
|
|||
// @question we might want RTLD_NOW?
|
||||
lib->handle = dlopen(dst, RTLD_LAZY);
|
||||
if (!lib->handle) {
|
||||
const char* error = dlerror();
|
||||
LOG_1(error);
|
||||
|
||||
lib->is_valid = false;
|
||||
return lib->is_valid;
|
||||
return false;
|
||||
}
|
||||
|
||||
lib->is_valid = true;
|
||||
|
|
@ -59,6 +62,7 @@ bool library_load(Library* lib)
|
|||
lib->functions[c] = function;
|
||||
} else {
|
||||
lib->is_valid = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,8 +20,6 @@
|
|||
|
||||
#include <locale.h>
|
||||
#include <sys/resource.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/extensions/Xrandr.h>
|
||||
|
||||
// -lX11 -lXrandr
|
||||
|
||||
|
|
@ -76,46 +74,54 @@ uint16 system_country_code()
|
|||
}
|
||||
|
||||
void mainboard_info_get(MainboardInfo* info) {
|
||||
FileBody file = {};
|
||||
FileBody file;
|
||||
|
||||
file.content = info->name;
|
||||
file.size = sizeof(info->name);
|
||||
file.content = (byte *) info->name;
|
||||
file.size = sizeof(info->name) - 1;
|
||||
file_read("/sys/class/dmi/id/board_name", &file);
|
||||
|
||||
file.content = info->serial_number;
|
||||
file.size = sizeof(info->serial_number);
|
||||
file_read("/sys/class/dmi/id/board_serial", &file);
|
||||
|
||||
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';
|
||||
file.content = (byte *) info->serial_number;
|
||||
file.size = sizeof(info->serial_number) - 1;
|
||||
file_read("/sys/class/dmi/id/board_serial", &file);
|
||||
info->name[sizeof(info->serial_number) - 1] = '\0';
|
||||
}
|
||||
|
||||
int32 network_info_get(NetworkInfo* info) {
|
||||
char path[256];
|
||||
char path[64];
|
||||
memset(path, 0, sizeof(path));
|
||||
|
||||
struct stat st;
|
||||
int32 i = 0;
|
||||
|
||||
FileBody file = {};
|
||||
memcpy(path, "/sys/class/net/eth", sizeof("/sys/class/net/eth"));
|
||||
|
||||
for (i = 0; i < 4; ++i) {
|
||||
sprintf_fast(path, "/sys/class/net/eth%d", i);
|
||||
int_to_str(i, path + sizeof("/sys/class/net/eth"));
|
||||
|
||||
if (stat(path, &st) == 0) {
|
||||
// Read MAC address
|
||||
sprintf_fast(path, "/sys/class/net/eth%d/address", i);
|
||||
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.content = info[i].slot;
|
||||
file.size = sizeof(info[i].slot);
|
||||
file_read(path, &file);
|
||||
if (stat(path, &st) != 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
char path2[64];
|
||||
memcpy(path2, path, sizeof("/sys/class/net/eth"));
|
||||
|
||||
// Read MAC address
|
||||
path2[sizeof("/sys/class/net/eth") + 1] = '\0';
|
||||
str_concat_append(path2, "/address");
|
||||
|
||||
file.content = info[i].mac;
|
||||
file.size = sizeof(info[i].mac) - 1;
|
||||
file_read(path2, &file);
|
||||
|
||||
// Read interface name
|
||||
path2[sizeof("/sys/class/net/eth") + 1] = '\0';
|
||||
str_concat_append(path2, "/ifindex");
|
||||
|
||||
file.content = (byte *) info[i].slot;
|
||||
file.size = sizeof(info[i].slot) - 1;
|
||||
file_read(path, &file);
|
||||
}
|
||||
|
||||
return i;
|
||||
|
|
@ -129,15 +135,15 @@ void cpu_info_get(CpuInfo* info) {
|
|||
char* internal_pos = NULL;
|
||||
|
||||
while (file_read_line(fp, line, sizeof(line), internal_buffer, &internal_buffer_size, &internal_pos)) {
|
||||
if (str_compare(line, "vendor_id", 9) == 0) {
|
||||
if (str_compare(line, "vendor_id", sizeof("vendor_id") - 1) == 0) {
|
||||
sscanf(line, "vendor_id : %s", info->vendor);
|
||||
} else if (str_compare(line, "model", 5) == 0) {
|
||||
sscanf(line, "model : %d", &info->model);
|
||||
} else if (str_compare(line, "cpu MHz", 7) == 0) {
|
||||
} else if (str_compare(line, "model", sizeof("model") - 1) == 0) {
|
||||
sscanf(line, "model : %hhd", &info->model);
|
||||
} else if (str_compare(line, "cpu MHz", sizeof("cpu MHz") - 1) == 0) {
|
||||
sscanf(line, "cpu MHz : %d", &info->mhz);
|
||||
} else if (str_compare(line, "cpu cores", 10) == 0) {
|
||||
sscanf(line, "cpu cores : %d", &info->thread_coun);
|
||||
} else if (str_compare(line, "model name", 10) == 0) {
|
||||
} else if (str_compare(line, "cpu cores", sizeof("cpu cores") - 1) == 0) {
|
||||
sscanf(line, "cpu cores : %hd", &info->core_count);
|
||||
} else if (str_compare(line, "model name", sizeof("model name") - 1) == 0) {
|
||||
sscanf(line, "model name : %63[^\n]", info->brand);
|
||||
}
|
||||
}
|
||||
|
|
@ -232,13 +238,13 @@ uint32 gpu_info_get(GpuInfo* info) {
|
|||
++count;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
pclose(fp);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
uint32 display_info_get(DisplayInfo* info) {
|
||||
FILE* fp = popen("xrandr --current", "r");
|
||||
FILE* fp = popen("xrandr --current 2>/dev/null", "r");
|
||||
if (fp == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -262,49 +268,9 @@ uint32 display_info_get(DisplayInfo* info) {
|
|||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
pclose(fp);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
bool is_dedicated_gpu_connected() {
|
||||
Display* display = XOpenDisplay(NULL);
|
||||
if (!display) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Window root = DefaultRootWindow(display);
|
||||
XRRScreenResources* screenResources = XRRGetScreenResources(display, root);
|
||||
if (!screenResources) {
|
||||
XCloseDisplay(display);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < screenResources->noutput; i++) {
|
||||
XRROutputInfo* outputInfo = XRRGetOutputInfo(display, screenResources, screenResources->outputs[i]);
|
||||
if (outputInfo && outputInfo->connection == RR_Connected) {
|
||||
XRRProviderInfo* providerInfo = XRRGetProviderInfo(display, screenResources, outputInfo->provider);
|
||||
if (providerInfo && providerInfo->name) {
|
||||
if (strstr(providerInfo->name, "NVIDIA")
|
||||
|| strstr(providerInfo->name, "AMD")
|
||||
|| strstr(providerInfo->name, "Intel")
|
||||
) {
|
||||
XRRFreeOutputInfo(outputInfo);
|
||||
XRRFreeProviderInfo(providerInfo);
|
||||
XRRFreeScreenResources(screenResources);
|
||||
XCloseDisplay(display);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
XRRFreeProviderInfo(providerInfo);
|
||||
}
|
||||
XRRFreeOutputInfo(outputInfo);
|
||||
}
|
||||
|
||||
XRRFreeScreenResources(screenResources);
|
||||
XCloseDisplay(display);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -20,6 +20,15 @@ uint64 system_time() {
|
|||
return (uint64_t) ts.tv_sec * 1000000ULL + (uint64_t) ts.tv_nsec / 1000ULL;
|
||||
}
|
||||
|
||||
// Used as initializer for 64bit random number generators instead of time()
|
||||
inline
|
||||
uint64 time_index() {
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
|
||||
return (uint64) ts.tv_sec * 1000000ULL + (uint64) (ts.tv_nsec / 1000);
|
||||
}
|
||||
|
||||
uint64 time_mu() {
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
|
|
|
|||
|
|
@ -1,61 +0,0 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* @copyright Jingga
|
||||
* @license OMS License 2.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
#ifndef COMS_UTILS_LINUX_H
|
||||
#define COMS_UTILS_LINUX_H
|
||||
|
||||
#include "../../stdlib/Types.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xatom.h>
|
||||
|
||||
void clipboard_get(char* text, int32 max_length)
|
||||
{
|
||||
*text = '\0';
|
||||
|
||||
Display *display = XOpenDisplay(NULL);
|
||||
if (display == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
Atom clipboard = XInternAtom(display, "CLIPBOARD", false);
|
||||
Atom utf8_string = XInternAtom(display, "UTF8_STRING", false);
|
||||
Atom xa_string = XInternAtom(display, "STRING", false);
|
||||
Window window = XDefaultRootWindow(display);
|
||||
|
||||
XConvertSelection(display, clipboard, utf8_string, xa_string, window, CurrentTime);
|
||||
XEvent event;
|
||||
XNextEvent(display, &event);
|
||||
|
||||
if (event.type == SelectionNotify) {
|
||||
if (event.xselection.property) {
|
||||
Atom type;
|
||||
int32 format;
|
||||
unsigned long nitems, bytes_after;
|
||||
byte* data = NULL;
|
||||
|
||||
XGetWindowProperty(
|
||||
display, event.xselection.requestor,
|
||||
event.xselection.property, 0, (~0L), false,
|
||||
AnyPropertyType, &type, &format, &nitems,
|
||||
&bytes_after, &data
|
||||
);
|
||||
|
||||
if (data) {
|
||||
str_copy_short(text, clipboard_text, max_length);
|
||||
XFree(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
XCloseDisplay(display);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -25,21 +25,27 @@
|
|||
#include "../../../network/SocketConnection.h"
|
||||
#include "../../../utils/EndianUtils.h"
|
||||
|
||||
void socket_non_blocking(SocketConnection* con)
|
||||
{
|
||||
int flags = fcntl(con->sd, F_GETFL, 0);
|
||||
fcntl(con->sd, F_SETFL, flags | O_NONBLOCK);
|
||||
}
|
||||
|
||||
// WARNING: requires `sudo setcap cap_net_raw=eip /path/to/your_program`
|
||||
void socket_server_raw_create(SocketConnection* con) {
|
||||
bool socket_server_raw_create(SocketConnection* con) {
|
||||
con->sd = socket(AF_INET6, SOCK_RAW, 255);
|
||||
|
||||
int32 flags;
|
||||
if ((flags = fcntl(con->sd, F_GETFL, 0)) < 0) {
|
||||
close(con->sd);
|
||||
con->sd = 0;
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fcntl(con->sd, F_SETFL, flags | O_NONBLOCK) < 0) {
|
||||
close(con->sd);
|
||||
con->sd = 0;
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(&con->addr, 0, sizeof(con->addr));
|
||||
|
|
@ -50,25 +56,27 @@ void socket_server_raw_create(SocketConnection* con) {
|
|||
if (bind(con->sd, (sockaddr *) &con->addr, sizeof(con->addr)) < 0) {
|
||||
close(con->sd);
|
||||
con->sd = 0;
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// WARNING: requires `sudo setcap cap_net_raw=eip /path/to/your_program`
|
||||
void socket_server_udp_raw_create(SocketConnection* con) {
|
||||
bool socket_server_udp_raw_create(SocketConnection* con) {
|
||||
con->sd = socket(AF_INET6, SOCK_RAW, IPPROTO_UDP);
|
||||
|
||||
int32 flags;
|
||||
if ((flags = fcntl(con->sd, F_GETFL, 0)) < 0) {
|
||||
close(con->sd);
|
||||
con->sd = 0;
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fcntl(con->sd, F_SETFL, flags | O_NONBLOCK) < 0) {
|
||||
close(con->sd);
|
||||
con->sd = 0;
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(&con->addr, 0, sizeof(con->addr));
|
||||
|
|
@ -79,24 +87,26 @@ void socket_server_udp_raw_create(SocketConnection* con) {
|
|||
if (bind(con->sd, (sockaddr *) &con->addr, sizeof(con->addr)) < 0) {
|
||||
close(con->sd);
|
||||
con->sd = 0;
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void socket_server_udp_create(SocketConnection* con) {
|
||||
bool socket_server_udp_create(SocketConnection* con) {
|
||||
con->sd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
|
||||
|
||||
int32 flags;
|
||||
if ((flags = fcntl(con->sd, F_GETFL, 0)) < 0) {
|
||||
close(con->sd);
|
||||
con->sd = 0;
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fcntl(con->sd, F_SETFL, flags | O_NONBLOCK) < 0) {
|
||||
close(con->sd);
|
||||
con->sd = 0;
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(&con->addr, 0, sizeof(con->addr));
|
||||
|
|
@ -107,33 +117,72 @@ void socket_server_udp_create(SocketConnection* con) {
|
|||
if (bind(con->sd, (sockaddr *) &con->addr, sizeof(con->addr)) < 0) {
|
||||
close(con->sd);
|
||||
con->sd = 0;
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool socket_server_http_create(SocketConnection* con)
|
||||
{
|
||||
// Create socket
|
||||
con->sd = socket(AF_INET6, SOCK_STREAM, 0);
|
||||
if (con->sd < 0) {
|
||||
con->sd = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Bind socket
|
||||
int32 opt = 1;
|
||||
setsockopt(con->sd, SOL_SOCKET, SO_REUSEADDR, (const char*) &opt, sizeof(opt));
|
||||
|
||||
memset(&con->addr, 0, sizeof(con->addr));
|
||||
con->addr.sin6_family = AF_INET6;
|
||||
con->addr.sin6_addr = in6addr_any;
|
||||
con->addr.sin6_port = htons(con->port);
|
||||
|
||||
if (bind(con->sd, (struct sockaddr *) &con->addr, sizeof(con->addr)) < 0) {
|
||||
close(con->sd);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Listen for incoming connections
|
||||
if (listen(con->sd, 5) < 0) {
|
||||
close(con->sd);
|
||||
con->sd = 0;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool socket_server_websocket_create(SocketConnection* con) {
|
||||
con->sd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
|
||||
|
||||
int32 flags;
|
||||
if ((flags = fcntl(con->sd, F_GETFL, 0)) < 0 ||
|
||||
fcntl(con->sd, F_SETFL, flags | O_NONBLOCK) < 0) {
|
||||
close(con->sd);
|
||||
con->sd = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
int opt = 1;
|
||||
setsockopt(con->sd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
|
||||
|
||||
memset(&con->addr, 0, sizeof(con->addr));
|
||||
con->addr.sin6_family = AF_INET6;
|
||||
con->addr.sin6_addr = in6addr_any;
|
||||
con->addr.sin6_port = htons(con->port);
|
||||
|
||||
if (bind(con->sd, (sockaddr*)&con->addr, sizeof(con->addr)) < 0) {
|
||||
close(con->sd);
|
||||
con->sd = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (listen(con->sd, SOMAXCONN) < 0) {
|
||||
close(con->sd);
|
||||
con->sd = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,5 +10,23 @@
|
|||
#define COMS_PLATFORM_LINUX_THREADING_SEMAPHORE_H
|
||||
|
||||
#include <semaphore.h>
|
||||
#include <time.h>
|
||||
#include "../../../stdlib/Types.h"
|
||||
#include "../../../compiler/CompilerUtils.h"
|
||||
|
||||
typedef sem_t sem;
|
||||
|
||||
#define coms_sem_init(semaphore, value) sem_init((semaphore), 0, (value))
|
||||
#define coms_sem_destroy(semaphore) sem_destroy((semaphore))
|
||||
#define coms_sem_wait(semaphore) sem_wait((semaphore))
|
||||
#define coms_sem_post(semaphore) sem_post((semaphore))
|
||||
|
||||
int32 semimedwait(sem* semaphore, int32 wait) {
|
||||
timespec ts;
|
||||
clock_gettime(CLOCK_REALTIME, &ts);
|
||||
ts.tv_sec += wait;
|
||||
|
||||
return sem_timedwait(semaphore, &ts);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -20,7 +20,7 @@ void spinlock_start(spinlock32* lock, int32 delay = 10) {
|
|||
}
|
||||
}
|
||||
|
||||
inline
|
||||
FORCE_INLINE
|
||||
void spinlock_end(spinlock32* lock) {
|
||||
__atomic_store_n(lock, 0, __ATOMIC_RELEASE);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,24 +18,29 @@
|
|||
#include <sys/syscall.h>
|
||||
|
||||
#include "../../../stdlib/Types.h"
|
||||
#include "../../../compiler/CompilerUtils.h"
|
||||
#include "../Allocator.h"
|
||||
#include "ThreadDefines.h"
|
||||
#include "Atomic.h"
|
||||
|
||||
inline int32 futex_wait(int32 *futex, int32 val) {
|
||||
FORCE_INLINE
|
||||
int32 futex_wait(volatile int32* futex, int32 val) {
|
||||
return syscall(SYS_futex, futex, FUTEX_WAIT, val, NULL, NULL, 0);
|
||||
}
|
||||
|
||||
inline int32 futex_wake(int32 *futex, int32 n) {
|
||||
FORCE_INLINE
|
||||
int32 futex_wake(volatile int32* futex, int32 n) {
|
||||
return syscall(SYS_futex, futex, FUTEX_WAKE, n, NULL, NULL, 0);
|
||||
}
|
||||
|
||||
inline int32 coms_pthread_create(coms_pthread_t* thread, void*, ThreadJobFunc start_routine, void* arg) {
|
||||
inline
|
||||
int32 coms_pthread_create(coms_pthread_t* thread, void*, ThreadJobFunc start_routine, void* arg) {
|
||||
if (thread == NULL || start_routine == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int32 flags = CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM;
|
||||
*thread = clone((int32 (*)(void*))start_routine, (void*)((char*)malloc(4096) + 4096), flags, arg);
|
||||
*thread = clone((int32 (*)(void*))start_routine, NULL, flags, arg);
|
||||
if (*thread == -1) {
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -43,186 +48,220 @@ inline int32 coms_pthread_create(coms_pthread_t* thread, void*, ThreadJobFunc st
|
|||
return 0;
|
||||
}
|
||||
|
||||
inline int32 coms_pthread_join(coms_pthread_t thread, void** retval) {
|
||||
if (syscall(SYS_waitid, P_PID, thread, retval, WEXITED, NULL) == -1) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
FORCE_INLINE
|
||||
int32 coms_pthread_join(coms_pthread_t thread, void** retval) {
|
||||
return syscall(SYS_waitid, P_PID, thread, retval, WEXITED, NULL) == -1
|
||||
? 1
|
||||
: 0;
|
||||
}
|
||||
|
||||
inline int32 coms_pthread_detach(coms_pthread_t) {
|
||||
FORCE_INLINE
|
||||
int32 coms_pthread_detach(coms_pthread_t) {
|
||||
// In Linux, threads are automatically detached when they exit.
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline int32 coms_pthread_mutex_init(coms_pthread_mutex_t* mutex, coms_pthread_mutexattr_t*) {
|
||||
if (mutex == NULL) {
|
||||
return 1;
|
||||
}
|
||||
mutex->futex = 0;
|
||||
return 0;
|
||||
FORCE_INLINE
|
||||
int32 mutex_init(mutex* mutex, mutexattr_t*) {
|
||||
return mutex == NULL ? 1 : 0;
|
||||
}
|
||||
|
||||
inline int32 coms_pthread_mutex_destroy(coms_pthread_mutex_t* mutex) {
|
||||
if (mutex == NULL) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
FORCE_INLINE
|
||||
int32 mutex_destroy(mutex* mutex) {
|
||||
return mutex == NULL ? 1 : 0;
|
||||
}
|
||||
|
||||
inline int32 coms_pthread_mutex_lock(coms_pthread_mutex_t* mutex) {
|
||||
inline
|
||||
int32 mutex_lock(mutex* mutex) {
|
||||
if (mutex == NULL) {
|
||||
return 1;
|
||||
}
|
||||
while (__atomic_exchange_n(&mutex->futex, 1, __ATOMIC_ACQUIRE) != 0) {
|
||||
|
||||
while (atomic_fetch_set_acquire(&mutex->futex, 1) != 0) {
|
||||
futex_wait(&mutex->futex, 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline int32 coms_pthread_mutex_unlock(coms_pthread_mutex_t* mutex) {
|
||||
inline
|
||||
int32 mutex_unlock(mutex* mutex) {
|
||||
if (mutex == NULL) {
|
||||
return 1;
|
||||
}
|
||||
__atomic_store_n(&mutex->futex, 0, __ATOMIC_RELEASE);
|
||||
|
||||
atomic_set_release(&mutex->futex, 0);
|
||||
futex_wake(&mutex->futex, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline int32 coms_pthread_cond_init(coms_pthread_cond_t* cond, coms_pthread_condattr_t*) {
|
||||
inline
|
||||
int32 coms_pthread_cond_init(mutex_cond* cond, coms_pthread_condattr_t*) {
|
||||
if (cond == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
cond->futex = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline int32 coms_pthread_cond_destroy(coms_pthread_cond_t* cond) {
|
||||
if (cond == NULL) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
FORCE_INLINE
|
||||
int32 coms_pthread_cond_destroy(mutex_cond* cond) {
|
||||
return cond == NULL ? 1 : 0;
|
||||
}
|
||||
|
||||
inline int32 coms_pthread_cond_timedwait(coms_pthread_cond_t* cond, coms_pthread_mutex_t* mutex, const struct timespec*) {
|
||||
inline
|
||||
int32 mutex_condimedwait(mutex_cond* cond, mutex* mutex, const struct timespec*) {
|
||||
if (cond == NULL || mutex == NULL) {
|
||||
return 1;
|
||||
}
|
||||
int32 oldval = __atomic_load_n(&cond->futex, __ATOMIC_ACQUIRE);
|
||||
coms_pthread_mutex_unlock(mutex);
|
||||
|
||||
int32 oldval = atomic_get_acquire(&cond->futex);
|
||||
mutex_unlock(mutex);
|
||||
futex_wait(&cond->futex, oldval);
|
||||
coms_pthread_mutex_lock(mutex);
|
||||
mutex_lock(mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline int32 coms_pthread_cond_wait(coms_pthread_cond_t* cond, coms_pthread_mutex_t* mutex) {
|
||||
return coms_pthread_cond_timedwait(cond, mutex, NULL);
|
||||
inline
|
||||
int32 coms_pthread_cond_wait(mutex_cond* cond, mutex* mutex) {
|
||||
return mutex_condimedwait(cond, mutex, NULL);
|
||||
}
|
||||
|
||||
inline int32 coms_pthread_cond_signal(coms_pthread_cond_t* cond) {
|
||||
inline
|
||||
int32 coms_pthread_cond_signal(mutex_cond* cond) {
|
||||
if (cond == NULL) {
|
||||
return 1;
|
||||
}
|
||||
__atomic_add_fetch(&cond->futex, 1, __ATOMIC_RELEASE);
|
||||
|
||||
atomic_increment_release(&cond->futex);
|
||||
futex_wake(&cond->futex, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline int32 coms_pthread_cond_broadcast(coms_pthread_cond_t* cond) {
|
||||
inline
|
||||
int32 coms_pthread_cond_broadcast(mutex_cond* cond) {
|
||||
if (cond == NULL) {
|
||||
return 1;
|
||||
}
|
||||
__atomic_add_fetch(&cond->futex, 1, __ATOMIC_RELEASE);
|
||||
|
||||
atomic_increment_release(&cond->futex);
|
||||
futex_wake(&cond->futex, INT32_MAX);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline int32 coms_pthread_rwlock_init(coms_pthread_rwlock_t* rwlock, const coms_pthread_rwlockattr_t*) {
|
||||
inline
|
||||
int32 coms_pthread_rwlock_init(coms_pthread_rwlock_t* rwlock, const coms_pthread_rwlockattr_t*) {
|
||||
if (rwlock == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
rwlock->futex = 0;
|
||||
rwlock->exclusive = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline int32 coms_pthread_rwlock_destroy(coms_pthread_rwlock_t* rwlock) {
|
||||
inline
|
||||
int32 coms_pthread_rwlock_destroy(coms_pthread_rwlock_t* rwlock) {
|
||||
if (rwlock == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline int32 coms_pthread_rwlock_rdlock(coms_pthread_rwlock_t* rwlock) {
|
||||
inline
|
||||
int32 coms_pthread_rwlock_rdlock(coms_pthread_rwlock_t* rwlock) {
|
||||
if (rwlock == NULL) {
|
||||
return 1;
|
||||
}
|
||||
while (1) {
|
||||
int32 val = __atomic_load_n(&rwlock->futex, __ATOMIC_ACQUIRE);
|
||||
|
||||
while (true) {
|
||||
int32 val = atomic_get_acquire(&rwlock->futex);
|
||||
if (val >= 0 && __atomic_compare_exchange_n(&rwlock->futex, &val, val + 1, false, __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE)) {
|
||||
break;
|
||||
}
|
||||
futex_wait(&rwlock->futex, val);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline int32 coms_pthread_rwlock_tryrdlock(coms_pthread_rwlock_t* rwlock) {
|
||||
inline
|
||||
int32 coms_pthread_rwlock_tryrdlock(coms_pthread_rwlock_t* rwlock) {
|
||||
if (rwlock == NULL) {
|
||||
return 1;
|
||||
}
|
||||
int32 val = __atomic_load_n(&rwlock->futex, __ATOMIC_ACQUIRE);
|
||||
|
||||
int32 val = atomic_get_acquire(&rwlock->futex);
|
||||
if (val >= 0 && __atomic_compare_exchange_n(&rwlock->futex, &val, val + 1, false, __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
inline int32 coms_pthread_rwlock_wrlock(coms_pthread_rwlock_t* rwlock) {
|
||||
inline
|
||||
int32 coms_pthread_rwlock_wrlock(coms_pthread_rwlock_t* rwlock) {
|
||||
if (rwlock == NULL) {
|
||||
return 1;
|
||||
}
|
||||
while (1) {
|
||||
int32 val = __atomic_load_n(&rwlock->futex, __ATOMIC_ACQUIRE);
|
||||
|
||||
while (true) {
|
||||
int32 val = atomic_get_acquire(&rwlock->futex);
|
||||
if (val == 0 && __atomic_compare_exchange_n(&rwlock->futex, &val, -1, false, __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE)) {
|
||||
rwlock->exclusive = true;
|
||||
break;
|
||||
}
|
||||
futex_wait(&rwlock->futex, val);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline int32 coms_pthread_rwlock_trywrlock(coms_pthread_rwlock_t* rwlock) {
|
||||
inline
|
||||
int32 coms_pthread_rwlock_trywrlock(coms_pthread_rwlock_t* rwlock) {
|
||||
if (rwlock == NULL) {
|
||||
return 1;
|
||||
}
|
||||
int32 val = __atomic_load_n(&rwlock->futex, __ATOMIC_ACQUIRE);
|
||||
|
||||
int32 val = atomic_get_acquire(&rwlock->futex);
|
||||
if (val == 0 && __atomic_compare_exchange_n(&rwlock->futex, &val, -1, false, __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE)) {
|
||||
rwlock->exclusive = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
inline int32 coms_pthread_rwlock_unlock(coms_pthread_rwlock_t* rwlock) {
|
||||
inline
|
||||
int32 coms_pthread_rwlock_unlock(coms_pthread_rwlock_t* rwlock) {
|
||||
if (rwlock == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (rwlock->exclusive) {
|
||||
rwlock->exclusive = false;
|
||||
__atomic_store_n(&rwlock->futex, 0, __ATOMIC_RELEASE);
|
||||
atomic_set_release(&rwlock->futex, 0);
|
||||
futex_wake(&rwlock->futex, 1);
|
||||
} else {
|
||||
int32 val = __atomic_sub_fetch(&rwlock->futex, 1, __ATOMIC_RELEASE);
|
||||
int32 val = atomic_decrement_release(&rwlock->futex);
|
||||
if (val == 0) {
|
||||
futex_wake(&rwlock->futex, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline uint32 pcthread_get_num_procs() {
|
||||
FORCE_INLINE
|
||||
uint32 pcthread_get_num_procs() {
|
||||
return sysconf(_SC_NPROCESSORS_ONLN);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,22 +17,22 @@
|
|||
#define THREAD_RETURN int32
|
||||
typedef THREAD_RETURN (*ThreadJobFunc)(void*);
|
||||
|
||||
typedef struct {
|
||||
int32 futex;
|
||||
} coms_pthread_mutex_t;
|
||||
struct mutex {
|
||||
alignas(4) atomic_32 int32 futex;
|
||||
};
|
||||
|
||||
typedef void coms_pthread_mutexattr_t;
|
||||
typedef void mutexattr_t;
|
||||
typedef void coms_pthread_condattr_t;
|
||||
typedef void coms_pthread_rwlockattr_t;
|
||||
|
||||
typedef struct {
|
||||
int32 futex;
|
||||
} coms_pthread_cond_t;
|
||||
struct mutex_cond {
|
||||
alignas(4) atomic_32 int32 futex;
|
||||
} ;
|
||||
|
||||
typedef struct {
|
||||
int32 futex;
|
||||
struct coms_pthread_rwlock_t {
|
||||
alignas(4) atomic_32 int32 futex;
|
||||
bool exclusive;
|
||||
} coms_pthread_rwlock_t;
|
||||
};
|
||||
|
||||
typedef int coms_pthread_t;
|
||||
|
||||
|
|
|
|||
170
platform/win32/GuiUtils.h
Normal file
170
platform/win32/GuiUtils.h
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* @copyright Jingga
|
||||
* @license OMS License 2.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
#ifndef COMS_PLATFORM_WIN32_GUI_UTILS_H
|
||||
#define COMS_PLATFORM_WIN32_GUI_UTILS_H
|
||||
|
||||
#include <windows.h>
|
||||
#include "Window.h"
|
||||
#include "../../stdlib/Types.h"
|
||||
#include "../../utils/TestUtils.h"
|
||||
|
||||
// @question Shouldn't this function and the next one accept a parameter of what to add/remove?
|
||||
inline
|
||||
void window_remove_style(Window* w)
|
||||
{
|
||||
LONG_PTR style = GetWindowLongPtrA(w->hwnd, GWL_STYLE);
|
||||
style &= ~WS_OVERLAPPEDWINDOW;
|
||||
SetWindowLongPtr(w->hwnd, GWL_STYLE, style);
|
||||
}
|
||||
|
||||
inline
|
||||
void window_add_style(Window* w)
|
||||
{
|
||||
LONG_PTR style = GetWindowLongPtrA(w->hwnd, GWL_STYLE);
|
||||
style |= WS_OVERLAPPEDWINDOW;
|
||||
SetWindowLongPtr(w->hwnd, GWL_STYLE, style);
|
||||
}
|
||||
|
||||
inline
|
||||
void monitor_resolution(const Window* __restrict w, v2_int32* __restrict resolution)
|
||||
{
|
||||
resolution->width = GetDeviceCaps(w->hdc, HORZRES);
|
||||
resolution->height = GetDeviceCaps(w->hdc, VERTRES);
|
||||
}
|
||||
|
||||
inline
|
||||
void monitor_resolution(Window* w)
|
||||
{
|
||||
w->width = (uint16) GetDeviceCaps(w->hdc, HORZRES);
|
||||
w->height = (uint16) GetDeviceCaps(w->hdc, VERTRES);
|
||||
}
|
||||
|
||||
inline
|
||||
void window_resolution(Window* w)
|
||||
{
|
||||
RECT rect;
|
||||
GetClientRect(w->hwnd, &rect);
|
||||
|
||||
w->width = (uint16) (rect.right - rect.left);
|
||||
w->height = (uint16) (rect.bottom - rect.top);
|
||||
}
|
||||
|
||||
inline
|
||||
void window_fullscreen(Window* w)
|
||||
{
|
||||
monitor_resolution(w);
|
||||
w->x = 0;
|
||||
w->y = 0;
|
||||
|
||||
window_remove_style(w);
|
||||
SetWindowPos(w->hwnd, HWND_TOP, 0, 0, w->width, w->height, SWP_NOACTIVATE | SWP_NOZORDER);
|
||||
}
|
||||
|
||||
inline
|
||||
void window_restore(Window* w)
|
||||
{
|
||||
window_restore_state(w);
|
||||
|
||||
SetWindowLongPtr(w->hwnd, GWL_STYLE, w->state_old.style);
|
||||
SetWindowPos(
|
||||
w->hwnd, HWND_TOP,
|
||||
w->state_old.x, w->state_old.y,
|
||||
w->state_old.width, w->state_old.height,
|
||||
SWP_NOACTIVATE | SWP_NOZORDER
|
||||
);
|
||||
}
|
||||
|
||||
void window_create(Window* __restrict window, void* proc)
|
||||
{
|
||||
ASSERT_SIMPLE(proc);
|
||||
|
||||
WNDPROC wndproc = (WNDPROC) proc;
|
||||
WNDCLASSEXA wc = {};
|
||||
|
||||
if (!window->hInstance) {
|
||||
window->hInstance = GetModuleHandle(0);
|
||||
}
|
||||
|
||||
wc.cbSize = sizeof(WNDCLASSEXA);
|
||||
wc.style = CS_OWNDC;
|
||||
wc.lpfnWndProc = wndproc;
|
||||
wc.hInstance = window->hInstance;
|
||||
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||||
wc.lpszClassName = (LPCSTR) window->name;
|
||||
|
||||
if (!RegisterClassExA(&wc)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (window->is_fullscreen) {
|
||||
window->width = (uint16) GetSystemMetrics(SM_CXSCREEN);
|
||||
window->height = (uint16) GetSystemMetrics(SM_CYSCREEN);
|
||||
|
||||
DEVMODE screen_settings;
|
||||
|
||||
memset(&screen_settings, 0, sizeof(screen_settings));
|
||||
screen_settings.dmSize = sizeof(screen_settings);
|
||||
screen_settings.dmPelsWidth = (unsigned long) window->width;
|
||||
screen_settings.dmPelsHeight = (unsigned long) window->height;
|
||||
screen_settings.dmBitsPerPel = 32;
|
||||
screen_settings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
|
||||
|
||||
ChangeDisplaySettings(&screen_settings, CDS_FULLSCREEN);
|
||||
|
||||
window->x = 0;
|
||||
window->y = 0;
|
||||
}
|
||||
|
||||
window->hwnd = CreateWindowExA((DWORD) NULL,
|
||||
wc.lpszClassName, NULL,
|
||||
WS_OVERLAPPEDWINDOW,
|
||||
window->x, window->y,
|
||||
window->width,
|
||||
window->height,
|
||||
NULL, NULL, window->hInstance, window
|
||||
);
|
||||
|
||||
ASSERT_SIMPLE(window->hwnd);
|
||||
}
|
||||
|
||||
void window_open(Window* window)
|
||||
{
|
||||
ShowWindow(window->hwnd, SW_SHOW);
|
||||
SetForegroundWindow(window->hwnd);
|
||||
SetFocus(window->hwnd);
|
||||
UpdateWindow(window->hwnd);
|
||||
|
||||
window->state_changes |= WINDOW_STATE_CHANGE_FOCUS;
|
||||
}
|
||||
|
||||
void window_close(Window* window)
|
||||
{
|
||||
CloseWindow(window->hwnd);
|
||||
DestroyWindow(window->hwnd);
|
||||
}
|
||||
|
||||
HBITMAP CreateBitmapFromRGBA(HDC hdc, const byte* rgba, int32 width, int32 height) {
|
||||
BITMAPINFO bmi = {};
|
||||
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||||
bmi.bmiHeader.biWidth = width;
|
||||
bmi.bmiHeader.biHeight = height;
|
||||
bmi.bmiHeader.biPlanes = 1;
|
||||
bmi.bmiHeader.biBitCount = 32;
|
||||
bmi.bmiHeader.biCompression = BI_RGB;
|
||||
|
||||
void* pbits;
|
||||
HBITMAP hbitmap = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, &pbits, NULL, 0);
|
||||
if (hbitmap) {
|
||||
memcpy(pbits, rgba, width * height * 4);
|
||||
}
|
||||
|
||||
return hbitmap;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -14,9 +14,9 @@
|
|||
#include <string.h>
|
||||
|
||||
#include "../../stdlib/Types.h"
|
||||
#include "FileUtils.cpp"
|
||||
#include "../../utils/StringUtils.h"
|
||||
#include "../../system/Library.h"
|
||||
#include "../../system/FileUtils.cpp"
|
||||
|
||||
inline
|
||||
bool library_load(Library* lib)
|
||||
|
|
|
|||
|
|
@ -300,7 +300,7 @@ void cpu_info_get(CpuInfo* info) {
|
|||
|
||||
SYSTEM_INFO sys_info;
|
||||
GetSystemInfo(&sys_info);
|
||||
info->thread_count = (byte) sys_info.dwNumberOfProcessors;
|
||||
info->core_count = (uint16) sys_info.dwNumberOfProcessors;
|
||||
info->page_size = (uint16) sys_info.dwPageSize;
|
||||
|
||||
int32 cpuInfo[4] = { 0 };
|
||||
|
|
|
|||
|
|
@ -44,6 +44,15 @@ uint64 system_time()
|
|||
return ((uint64) (largeInt.QuadPart / 10000000ULL)) - ((uint64) 11644473600ULL);
|
||||
}
|
||||
|
||||
// Used as initializer for 64bit random number generators instead of time()
|
||||
inline
|
||||
uint64 time_index() {
|
||||
LARGE_INTEGER counter;
|
||||
QueryPerformanceCounter(&counter);
|
||||
|
||||
return counter.QuadPart;
|
||||
}
|
||||
|
||||
// doesn't return clock time, only to return time since program start
|
||||
// -> can be used for profiling
|
||||
inline
|
||||
|
|
|
|||
|
|
@ -1,170 +0,0 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* @copyright Jingga
|
||||
* @license OMS License 2.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
#ifndef COMS_PLATFORM_WIN32_UTILS_WINDOWS_H
|
||||
#define COMS_PLATFORM_WIN32_UTILS_WINDOWS_H
|
||||
|
||||
#include <windows.h>
|
||||
#include "Window.h"
|
||||
#include "../../stdlib/Types.h"
|
||||
#include "../../utils/TestUtils.h"
|
||||
|
||||
// @question Shouldn't this function and the next one accept a parameter of what to add/remove?
|
||||
inline
|
||||
void window_remove_style(Window* w)
|
||||
{
|
||||
LONG_PTR style = GetWindowLongPtrA(w->hwnd, GWL_STYLE);
|
||||
style &= ~WS_OVERLAPPEDWINDOW;
|
||||
SetWindowLongPtr(w->hwnd, GWL_STYLE, style);
|
||||
}
|
||||
|
||||
inline
|
||||
void window_add_style(Window* w)
|
||||
{
|
||||
LONG_PTR style = GetWindowLongPtrA(w->hwnd, GWL_STYLE);
|
||||
style |= WS_OVERLAPPEDWINDOW;
|
||||
SetWindowLongPtr(w->hwnd, GWL_STYLE, style);
|
||||
}
|
||||
|
||||
inline
|
||||
void monitor_resolution(const Window* __restrict w, v2_int32* __restrict resolution)
|
||||
{
|
||||
resolution->width = GetDeviceCaps(w->hdc, HORZRES);
|
||||
resolution->height = GetDeviceCaps(w->hdc, VERTRES);
|
||||
}
|
||||
|
||||
inline
|
||||
void monitor_resolution(Window* w)
|
||||
{
|
||||
w->width = (uint16) GetDeviceCaps(w->hdc, HORZRES);
|
||||
w->height = (uint16) GetDeviceCaps(w->hdc, VERTRES);
|
||||
}
|
||||
|
||||
inline
|
||||
void window_resolution(Window* w)
|
||||
{
|
||||
RECT rect;
|
||||
GetClientRect(w->hwnd, &rect);
|
||||
|
||||
w->width = (uint16) (rect.right - rect.left);
|
||||
w->height = (uint16) (rect.bottom - rect.top);
|
||||
}
|
||||
|
||||
inline
|
||||
void window_fullscreen(Window* w)
|
||||
{
|
||||
monitor_resolution(w);
|
||||
w->x = 0;
|
||||
w->y = 0;
|
||||
|
||||
window_remove_style(w);
|
||||
SetWindowPos(w->hwnd, HWND_TOP, 0, 0, w->width, w->height, SWP_NOACTIVATE | SWP_NOZORDER);
|
||||
}
|
||||
|
||||
inline
|
||||
void window_restore(Window* w)
|
||||
{
|
||||
window_restore_state(w);
|
||||
|
||||
SetWindowLongPtr(w->hwnd, GWL_STYLE, w->state_old.style);
|
||||
SetWindowPos(
|
||||
w->hwnd, HWND_TOP,
|
||||
w->state_old.x, w->state_old.y,
|
||||
w->state_old.width, w->state_old.height,
|
||||
SWP_NOACTIVATE | SWP_NOZORDER
|
||||
);
|
||||
}
|
||||
|
||||
void window_create(Window* __restrict window, void* proc)
|
||||
{
|
||||
ASSERT_SIMPLE(proc);
|
||||
|
||||
WNDPROC wndproc = (WNDPROC) proc;
|
||||
WNDCLASSEXA wc = {};
|
||||
|
||||
if (!window->hInstance) {
|
||||
window->hInstance = GetModuleHandle(0);
|
||||
}
|
||||
|
||||
wc.cbSize = sizeof(WNDCLASSEXA);
|
||||
wc.style = CS_OWNDC;
|
||||
wc.lpfnWndProc = wndproc;
|
||||
wc.hInstance = window->hInstance;
|
||||
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||||
wc.lpszClassName = (LPCSTR) window->name;
|
||||
|
||||
if (!RegisterClassExA(&wc)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (window->is_fullscreen) {
|
||||
window->width = (uint16) GetSystemMetrics(SM_CXSCREEN);
|
||||
window->height = (uint16) GetSystemMetrics(SM_CYSCREEN);
|
||||
|
||||
DEVMODE screen_settings;
|
||||
|
||||
memset(&screen_settings, 0, sizeof(screen_settings));
|
||||
screen_settings.dmSize = sizeof(screen_settings);
|
||||
screen_settings.dmPelsWidth = (unsigned long) window->width;
|
||||
screen_settings.dmPelsHeight = (unsigned long) window->height;
|
||||
screen_settings.dmBitsPerPel = 32;
|
||||
screen_settings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
|
||||
|
||||
ChangeDisplaySettings(&screen_settings, CDS_FULLSCREEN);
|
||||
|
||||
window->x = 0;
|
||||
window->y = 0;
|
||||
}
|
||||
|
||||
window->hwnd = CreateWindowExA((DWORD) NULL,
|
||||
wc.lpszClassName, NULL,
|
||||
WS_OVERLAPPEDWINDOW,
|
||||
window->x, window->y,
|
||||
window->width,
|
||||
window->height,
|
||||
NULL, NULL, window->hInstance, window
|
||||
);
|
||||
|
||||
ASSERT_SIMPLE(window->hwnd);
|
||||
}
|
||||
|
||||
void window_open(Window* window)
|
||||
{
|
||||
ShowWindow(window->hwnd, SW_SHOW);
|
||||
SetForegroundWindow(window->hwnd);
|
||||
SetFocus(window->hwnd);
|
||||
UpdateWindow(window->hwnd);
|
||||
|
||||
window->state_changes |= WINDOW_STATE_CHANGE_FOCUS;
|
||||
}
|
||||
|
||||
void window_close(Window* window)
|
||||
{
|
||||
CloseWindow(window->hwnd);
|
||||
DestroyWindow(window->hwnd);
|
||||
}
|
||||
|
||||
HBITMAP CreateBitmapFromRGBA(HDC hdc, const byte* rgba, int32 width, int32 height) {
|
||||
BITMAPINFO bmi = {};
|
||||
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||||
bmi.bmiHeader.biWidth = width;
|
||||
bmi.bmiHeader.biHeight = height;
|
||||
bmi.bmiHeader.biPlanes = 1;
|
||||
bmi.bmiHeader.biBitCount = 32;
|
||||
bmi.bmiHeader.biCompression = BI_RGB;
|
||||
|
||||
void* pbits;
|
||||
HBITMAP hbitmap = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, &pbits, NULL, 0);
|
||||
if (hbitmap) {
|
||||
memcpy(pbits, rgba, width * height * 4);
|
||||
}
|
||||
|
||||
return hbitmap;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -59,10 +59,10 @@ FORCE_INLINE void atomic_add_relaxed(volatile int32* value, int32 increment) noe
|
|||
FORCE_INLINE void atomic_sub_relaxed(volatile int32* value, int32 decrement) noexcept { InterlockedAddNoFence((volatile long *) value, -decrement); }
|
||||
FORCE_INLINE void atomic_add_relaxed(volatile int64* value, int64 increment) noexcept { InterlockedAddNoFence64((volatile LONG64 *) value, (LONG64) increment); }
|
||||
FORCE_INLINE void atomic_sub_relaxed(volatile int64* value, int64 decrement) noexcept { InterlockedAddNoFence64((volatile LONG64 *) value, -((LONG64) decrement)); }
|
||||
FORCE_INLINE f32 atomic_compare_exchange_weak_relaxed(volatile f32* value, f32* expected, f32 desired) noexcept { _atomic_32 temp = {.l = InterlockedCompareExchangeNoFence((volatile long *) value, (long) desired, (long) *expected) }; return temp.f; }
|
||||
FORCE_INLINE f64 atomic_compare_exchange_weak_relaxed(volatile f64* value, f64* expected, f64 desired) noexcept { _atomic_64 temp = {.l = InterlockedCompareExchangeNoFence64((volatile LONG64 *) value, (LONG64) desired, (LONG64) *expected) }; return temp.f; }
|
||||
FORCE_INLINE int32 atomic_compare_exchange_weak_relaxed(volatile int32* value, int32* expected, int32 desired) noexcept { return (int32) InterlockedCompareExchangeNoFence((volatile long *) value, desired, *expected); }
|
||||
FORCE_INLINE int64 atomic_compare_exchange_weak_relaxed(volatile int64* value, int64* expected, int64 desired) noexcept { return (int64) InterlockedCompareExchangeNoFence64((volatile LONG64 *) value, (LONG64) desired, (LONG64) *expected); }
|
||||
FORCE_INLINE f32 atomic_compare_exchange_strong_relaxed(volatile f32* value, f32* expected, f32 desired) noexcept { _atomic_32 temp = {.l = InterlockedCompareExchangeNoFence((volatile long *) value, (long) desired, (long) *expected) }; return temp.f; }
|
||||
FORCE_INLINE f64 atomic_compare_exchange_strong_relaxed(volatile f64* value, f64* expected, f64 desired) noexcept { _atomic_64 temp = {.l = InterlockedCompareExchangeNoFence64((volatile LONG64 *) value, (LONG64) desired, (LONG64) *expected) }; return temp.f; }
|
||||
FORCE_INLINE int32 atomic_compare_exchange_strong_relaxed(volatile int32* value, int32* expected, int32 desired) noexcept { return (int32) InterlockedCompareExchangeNoFence((volatile long *) value, desired, *expected); }
|
||||
FORCE_INLINE int64 atomic_compare_exchange_strong_relaxed(volatile int64* value, int64* expected, int64 desired) noexcept { return (int64) InterlockedCompareExchangeNoFence64((volatile LONG64 *) value, (LONG64) desired, (LONG64) *expected); }
|
||||
FORCE_INLINE int8 atomic_fetch_add_relaxed(volatile int8* value, int8 operand) noexcept { return (int8) InterlockedExchangeAdd8((volatile char *) value, (char) operand); }
|
||||
FORCE_INLINE int8 atomic_fetch_sub_relaxed(volatile int8* value, int8 operand) noexcept { return (int8) InterlockedExchangeAdd8((volatile char *) value, -((char) operand)); }
|
||||
FORCE_INLINE int16 atomic_fetch_add_relaxed(volatile int16* value, int16 operand) noexcept { return (int16) InterlockedExchangeAdd16((volatile short *) value, (short) operand); }
|
||||
|
|
@ -99,8 +99,8 @@ FORCE_INLINE void atomic_add_relaxed(volatile uint32* value, uint32 increment) n
|
|||
FORCE_INLINE void atomic_sub_relaxed(volatile uint32* value, uint32 decrement) noexcept { InterlockedAddNoFence((volatile long *) value, -1 * ((int32) decrement)); }
|
||||
FORCE_INLINE void atomic_add_relaxed(volatile uint64* value, uint64 increment) noexcept { InterlockedAddNoFence64((volatile LONG64 *) value, (LONG64) increment); }
|
||||
FORCE_INLINE void atomic_sub_relaxed(volatile uint64* value, uint64 decrement) noexcept { InterlockedAddNoFence64((volatile LONG64 *) value, -((LONG64) decrement)); }
|
||||
FORCE_INLINE uint32 atomic_compare_exchange_weak_relaxed(volatile uint32* value, uint32* expected, uint32 desired) noexcept { return (uint32) InterlockedCompareExchangeNoFence((volatile long *) value, desired, *expected); }
|
||||
FORCE_INLINE uint64 atomic_compare_exchange_weak_relaxed(volatile uint64* value, uint64* expected, uint64 desired) noexcept { return (uint64) InterlockedCompareExchangeNoFence64((volatile LONG64 *) value, (LONG64) desired, (LONG64) *expected); }
|
||||
FORCE_INLINE uint32 atomic_compare_exchange_strong_relaxed(volatile uint32* value, uint32* expected, uint32 desired) noexcept { return (uint32) InterlockedCompareExchangeNoFence((volatile long *) value, desired, *expected); }
|
||||
FORCE_INLINE uint64 atomic_compare_exchange_strong_relaxed(volatile uint64* value, uint64* expected, uint64 desired) noexcept { return (uint64) InterlockedCompareExchangeNoFence64((volatile LONG64 *) value, (LONG64) desired, (LONG64) *expected); }
|
||||
FORCE_INLINE uint8 atomic_fetch_add_relaxed(volatile uint8* value, uint8 operand) noexcept { return (uint8) InterlockedExchangeAdd8((volatile char *) value, (char) operand); }
|
||||
FORCE_INLINE uint8 atomic_fetch_sub_relaxed(volatile uint8* value, uint8 operand) noexcept { return (uint8) InterlockedExchangeAdd8((volatile char *) value, -((char) operand)); }
|
||||
FORCE_INLINE uint16 atomic_fetch_add_relaxed(volatile uint16* value, uint16 operand) noexcept { return (uint16) InterlockedExchangeAdd16((volatile short *) value, (short) operand); }
|
||||
|
|
@ -153,10 +153,10 @@ FORCE_INLINE void atomic_add_acquire(volatile int32* value, int32 increment) noe
|
|||
FORCE_INLINE void atomic_sub_acquire(volatile int32* value, int32 decrement) noexcept { InterlockedAddAcquire((volatile long *) value, -decrement); }
|
||||
FORCE_INLINE void atomic_add_acquire(volatile int64* value, int64 increment) noexcept { InterlockedAddAcquire64((volatile LONG64 *) value, (LONG64) increment); }
|
||||
FORCE_INLINE void atomic_sub_acquire(volatile int64* value, int64 decrement) noexcept { InterlockedAddAcquire64((volatile LONG64 *) value, -((LONG64) decrement)); }
|
||||
FORCE_INLINE f32 atomic_compare_exchange_weak_acquire(volatile f32* value, f32* expected, f32 desired) noexcept { _atomic_32 temp = {.l = InterlockedCompareExchangeAcquire((volatile long *) value, (long) desired, (long) *expected) }; return temp.f; }
|
||||
FORCE_INLINE f64 atomic_compare_exchange_weak_acquire(volatile f64* value, f64* expected, f64 desired) noexcept { _atomic_64 temp = {.l = InterlockedCompareExchangeAcquire64((volatile LONG64 *) value, (LONG64) desired, (LONG64) *expected) }; return temp.f; }
|
||||
FORCE_INLINE int32 atomic_compare_exchange_weak_acquire(volatile int32* value, int32* expected, int32 desired) noexcept { return (int32) InterlockedCompareExchangeAcquire((volatile long *) value, desired, *expected); }
|
||||
FORCE_INLINE int64 atomic_compare_exchange_weak_acquire(volatile int64* value, int64* expected, int64 desired) noexcept { return (int64) InterlockedCompareExchangeAcquire64((volatile LONG64 *) value, (LONG64) desired, (LONG64) *expected); }
|
||||
FORCE_INLINE f32 atomic_compare_exchange_strong_acquire(volatile f32* value, f32* expected, f32 desired) noexcept { _atomic_32 temp = {.l = InterlockedCompareExchangeAcquire((volatile long *) value, (long) desired, (long) *expected) }; return temp.f; }
|
||||
FORCE_INLINE f64 atomic_compare_exchange_strong_acquire(volatile f64* value, f64* expected, f64 desired) noexcept { _atomic_64 temp = {.l = InterlockedCompareExchangeAcquire64((volatile LONG64 *) value, (LONG64) desired, (LONG64) *expected) }; return temp.f; }
|
||||
FORCE_INLINE int32 atomic_compare_exchange_strong_acquire(volatile int32* value, int32* expected, int32 desired) noexcept { return (int32) InterlockedCompareExchangeAcquire((volatile long *) value, desired, *expected); }
|
||||
FORCE_INLINE int64 atomic_compare_exchange_strong_acquire(volatile int64* value, int64* expected, int64 desired) noexcept { return (int64) InterlockedCompareExchangeAcquire64((volatile LONG64 *) value, (LONG64) desired, (LONG64) *expected); }
|
||||
FORCE_INLINE int8 atomic_fetch_add_acquire(volatile int8* value, int8 operand) noexcept { return (int8) InterlockedExchangeAdd8((volatile char *) value, (char) operand); }
|
||||
FORCE_INLINE int8 atomic_fetch_sub_acquire(volatile int8* value, int8 operand) noexcept { return (int8) InterlockedExchangeAdd8((volatile char *) value, -((char) operand)); }
|
||||
FORCE_INLINE int16 atomic_fetch_add_acquire(volatile int16* value, int16 operand) noexcept { return (int16) InterlockedExchangeAdd16((volatile short *) value, (short) operand); }
|
||||
|
|
@ -193,8 +193,8 @@ FORCE_INLINE void atomic_add_acquire(volatile uint32* value, uint32 increment) n
|
|||
FORCE_INLINE void atomic_sub_acquire(volatile uint32* value, uint32 decrement) noexcept { InterlockedAddAcquire((volatile long *) value, -1 * ((int32) decrement)); }
|
||||
FORCE_INLINE void atomic_add_acquire(volatile uint64* value, uint64 increment) noexcept { InterlockedAddAcquire64((volatile LONG64 *) value, (LONG64) increment); }
|
||||
FORCE_INLINE void atomic_sub_acquire(volatile uint64* value, uint64 decrement) noexcept { InterlockedAddAcquire64((volatile LONG64 *) value, -((LONG64) decrement)); }
|
||||
FORCE_INLINE uint32 atomic_compare_exchange_weak_acquire(volatile uint32* value, uint32* expected, uint32 desired) noexcept { return (uint32) InterlockedCompareExchangeAcquire((volatile long *) value, desired, *expected); }
|
||||
FORCE_INLINE uint64 atomic_compare_exchange_weak_acquire(volatile uint64* value, uint64* expected, uint64 desired) noexcept { return (uint64) InterlockedCompareExchangeAcquire64((volatile LONG64 *) value, (LONG64) desired, (LONG64) *expected); }
|
||||
FORCE_INLINE uint32 atomic_compare_exchange_strong_acquire(volatile uint32* value, uint32* expected, uint32 desired) noexcept { return (uint32) InterlockedCompareExchangeAcquire((volatile long *) value, desired, *expected); }
|
||||
FORCE_INLINE uint64 atomic_compare_exchange_strong_acquire(volatile uint64* value, uint64* expected, uint64 desired) noexcept { return (uint64) InterlockedCompareExchangeAcquire64((volatile LONG64 *) value, (LONG64) desired, (LONG64) *expected); }
|
||||
FORCE_INLINE uint8 atomic_fetch_add_acquire(volatile uint8* value, uint8 operand) noexcept { return (uint8) InterlockedExchangeAdd8((volatile char *) value, (char) operand); }
|
||||
FORCE_INLINE uint8 atomic_fetch_sub_acquire(volatile uint8* value, uint8 operand) noexcept { return (uint8) InterlockedExchangeAdd8((volatile char *) value, -((char) operand)); }
|
||||
FORCE_INLINE uint16 atomic_fetch_add_acquire(volatile uint16* value, uint16 operand) noexcept { return (uint16) InterlockedExchangeAdd16((volatile short *) value, (short) operand); }
|
||||
|
|
@ -254,10 +254,10 @@ FORCE_INLINE void atomic_add_release(volatile int32* value, int32 increment) noe
|
|||
FORCE_INLINE void atomic_sub_release(volatile int32* value, int32 decrement) noexcept { InterlockedAddRelease((volatile long *) value, -decrement); }
|
||||
FORCE_INLINE void atomic_add_release(volatile int64* value, int64 increment) noexcept { InterlockedAddRelease64((volatile LONG64 *) value, (LONG64) increment); }
|
||||
FORCE_INLINE void atomic_sub_release(volatile int64* value, int64 decrement) noexcept { InterlockedAddRelease64((volatile LONG64 *) value, -((LONG64) decrement)); }
|
||||
FORCE_INLINE f32 atomic_compare_exchange_weak_release(volatile f32* value, f32* expected, f32 desired) noexcept { _atomic_32 temp = {.l = InterlockedCompareExchangeRelease((volatile long *) value, (long) desired, (long) *expected) }; return temp.f; }
|
||||
FORCE_INLINE f64 atomic_compare_exchange_weak_release(volatile f64* value, f64* expected, f64 desired) noexcept { _atomic_64 temp = {.l = InterlockedCompareExchangeRelease64((volatile LONG64 *) value, (LONG64) desired, (LONG64) *expected) }; return temp.f; }
|
||||
FORCE_INLINE int32 atomic_compare_exchange_weak_release(volatile int32* value, int32* expected, int32 desired) noexcept { return (int32) InterlockedCompareExchangeRelease((volatile long *) value, desired, *expected); }
|
||||
FORCE_INLINE int64 atomic_compare_exchange_weak_release(volatile int64* value, int64* expected, int64 desired) noexcept { return (int64) InterlockedCompareExchangeRelease64((volatile LONG64 *) value, (LONG64) desired, (LONG64) *expected); }
|
||||
FORCE_INLINE f32 atomic_compare_exchange_strong_release(volatile f32* value, f32* expected, f32 desired) noexcept { _atomic_32 temp = {.l = InterlockedCompareExchangeRelease((volatile long *) value, (long) desired, (long) *expected) }; return temp.f; }
|
||||
FORCE_INLINE f64 atomic_compare_exchange_strong_release(volatile f64* value, f64* expected, f64 desired) noexcept { _atomic_64 temp = {.l = InterlockedCompareExchangeRelease64((volatile LONG64 *) value, (LONG64) desired, (LONG64) *expected) }; return temp.f; }
|
||||
FORCE_INLINE int32 atomic_compare_exchange_strong_release(volatile int32* value, int32* expected, int32 desired) noexcept { return (int32) InterlockedCompareExchangeRelease((volatile long *) value, desired, *expected); }
|
||||
FORCE_INLINE int64 atomic_compare_exchange_strong_release(volatile int64* value, int64* expected, int64 desired) noexcept { return (int64) InterlockedCompareExchangeRelease64((volatile LONG64 *) value, (LONG64) desired, (LONG64) *expected); }
|
||||
FORCE_INLINE int8 atomic_fetch_add_release(volatile int8* value, int8 operand) noexcept { return (int8) InterlockedExchangeAdd8((volatile char *) value, (char) operand); }
|
||||
FORCE_INLINE int8 atomic_fetch_sub_release(volatile int8* value, int8 operand) noexcept { return (int8) InterlockedExchangeAdd8((volatile char *) value, -((char) operand)); }
|
||||
FORCE_INLINE int16 atomic_fetch_add_release(volatile int16* value, int16 operand) noexcept { return (int16) InterlockedExchangeAdd16((volatile short *) value, (short) operand); }
|
||||
|
|
@ -294,8 +294,8 @@ FORCE_INLINE void atomic_add_release(volatile uint32* value, uint32 increment) n
|
|||
FORCE_INLINE void atomic_sub_release(volatile uint32* value, uint32 decrement) noexcept { InterlockedAddRelease((volatile long *) value, -1 * ((int32) decrement)); }
|
||||
FORCE_INLINE void atomic_add_release(volatile uint64* value, uint64 increment) noexcept { InterlockedAddRelease64((volatile LONG64 *) value, (LONG64) increment); }
|
||||
FORCE_INLINE void atomic_sub_release(volatile uint64* value, uint64 decrement) noexcept { InterlockedAddRelease64((volatile LONG64 *) value, -((LONG64) decrement)); }
|
||||
FORCE_INLINE uint32 atomic_compare_exchange_weak_release(volatile uint32* value, uint32* expected, uint32 desired) noexcept { return (uint32) InterlockedCompareExchangeRelease((volatile long *) value, desired, *expected); }
|
||||
FORCE_INLINE uint64 atomic_compare_exchange_weak_release(volatile uint64* value, uint64* expected, uint64 desired) noexcept { return (uint64) InterlockedCompareExchangeRelease64((volatile LONG64 *) value, (LONG64) desired, (LONG64) *expected); }
|
||||
FORCE_INLINE uint32 atomic_compare_exchange_strong_release(volatile uint32* value, uint32* expected, uint32 desired) noexcept { return (uint32) InterlockedCompareExchangeRelease((volatile long *) value, desired, *expected); }
|
||||
FORCE_INLINE uint64 atomic_compare_exchange_strong_release(volatile uint64* value, uint64* expected, uint64 desired) noexcept { return (uint64) InterlockedCompareExchangeRelease64((volatile LONG64 *) value, (LONG64) desired, (LONG64) *expected); }
|
||||
FORCE_INLINE uint8 atomic_fetch_add_release(volatile uint8* value, uint8 operand) noexcept { return (uint8) InterlockedExchangeAdd8((volatile char *) value, (char) operand); }
|
||||
FORCE_INLINE uint8 atomic_fetch_sub_release(volatile uint8* value, uint8 operand) noexcept { return (uint8) InterlockedExchangeAdd8((volatile char *) value, -((char) operand)); }
|
||||
FORCE_INLINE uint16 atomic_fetch_add_release(volatile uint16* value, uint16 operand) noexcept { return (uint16) InterlockedExchangeAdd16((volatile short *) value, (short) operand); }
|
||||
|
|
@ -355,10 +355,10 @@ FORCE_INLINE void atomic_add_acquire_release(volatile int32* value, int32 increm
|
|||
FORCE_INLINE void atomic_sub_acquire_release(volatile int32* value, int32 decrement) noexcept { InterlockedAdd((volatile long *) value, -decrement); }
|
||||
FORCE_INLINE void atomic_add_acquire_release(volatile int64* value, int64 increment) noexcept { InterlockedAdd64((volatile LONG64 *) value, (LONG64) increment); }
|
||||
FORCE_INLINE void atomic_sub_acquire_release(volatile int64* value, int64 decrement) noexcept { InterlockedAdd64((volatile LONG64 *) value, -((LONG64) decrement)); }
|
||||
FORCE_INLINE f32 atomic_compare_exchange_weak_acquire_release(volatile f32* value, f32* expected, f32 desired) noexcept { _atomic_32 temp = {.l = InterlockedCompareExchange((volatile long *) value, (long) desired, (long) *expected) }; return temp.f; }
|
||||
FORCE_INLINE f64 atomic_compare_exchange_weak_acquire_release(volatile f64* value, f64* expected, f64 desired) noexcept { _atomic_64 temp = {.l = InterlockedCompareExchange64((volatile LONG64 *) value, (LONG64) desired, (LONG64) *expected) }; return temp.f; }
|
||||
FORCE_INLINE int32 atomic_compare_exchange_weak_acquire_release(volatile int32* value, int32* expected, int32 desired) noexcept { return (int32) InterlockedCompareExchange((volatile long *) value, desired, *expected); }
|
||||
FORCE_INLINE int64 atomic_compare_exchange_weak_acquire_release(volatile int64* value, int64* expected, int64 desired) noexcept { return (int64) InterlockedCompareExchange64((volatile LONG64 *) value, (LONG64) desired, (LONG64) *expected); }
|
||||
FORCE_INLINE f32 atomic_compare_exchange_strong_acquire_release(volatile f32* value, f32* expected, f32 desired) noexcept { _atomic_32 temp = {.l = InterlockedCompareExchange((volatile long *) value, (long) desired, (long) *expected) }; return temp.f; }
|
||||
FORCE_INLINE f64 atomic_compare_exchange_strong_acquire_release(volatile f64* value, f64* expected, f64 desired) noexcept { _atomic_64 temp = {.l = InterlockedCompareExchange64((volatile LONG64 *) value, (LONG64) desired, (LONG64) *expected) }; return temp.f; }
|
||||
FORCE_INLINE int32 atomic_compare_exchange_strong_acquire_release(volatile int32* value, int32* expected, int32 desired) noexcept { return (int32) InterlockedCompareExchange((volatile long *) value, desired, *expected); }
|
||||
FORCE_INLINE int64 atomic_compare_exchange_strong_acquire_release(volatile int64* value, int64* expected, int64 desired) noexcept { return (int64) InterlockedCompareExchange64((volatile LONG64 *) value, (LONG64) desired, (LONG64) *expected); }
|
||||
FORCE_INLINE int8 atomic_fetch_add_acquire_release(volatile int8* value, int8 operand) noexcept { return (int8) InterlockedExchangeAdd8((volatile char *) value, (char) operand); }
|
||||
FORCE_INLINE int8 atomic_fetch_sub_acquire_release(volatile int8* value, int8 operand) noexcept { return (int8) InterlockedExchangeAdd8((volatile char *) value, -((char) operand)); }
|
||||
FORCE_INLINE int16 atomic_fetch_add_acquire_release(volatile int16* value, int16 operand) noexcept { return (int16) InterlockedExchangeAdd16((volatile short *) value, (short) operand); }
|
||||
|
|
@ -395,8 +395,8 @@ FORCE_INLINE void atomic_add_acquire_release(volatile uint32* value, uint32 incr
|
|||
FORCE_INLINE void atomic_sub_acquire_release(volatile uint32* value, uint32 decrement) noexcept { InterlockedAdd((volatile long *) value, -1 * ((int32) decrement)); }
|
||||
FORCE_INLINE void atomic_add_acquire_release(volatile uint64* value, uint64 increment) noexcept { InterlockedAdd64((volatile LONG64 *) value, (LONG64) increment); }
|
||||
FORCE_INLINE void atomic_sub_acquire_release(volatile uint64* value, uint64 decrement) noexcept { InterlockedAdd64((volatile LONG64 *) value, -((LONG64) decrement)); }
|
||||
FORCE_INLINE uint32 atomic_compare_exchange_weak_acquire_release(volatile uint32* value, uint32* expected, uint32 desired) noexcept { return (uint32) InterlockedCompareExchange((volatile long *) value, desired, *expected); }
|
||||
FORCE_INLINE uint64 atomic_compare_exchange_weak_acquire_release(volatile uint64* value, uint64* expected, uint64 desired) noexcept { return (uint64) InterlockedCompareExchange64((volatile LONG64 *) value, (LONG64) desired, (LONG64) *expected); }
|
||||
FORCE_INLINE uint32 atomic_compare_exchange_strong_acquire_release(volatile uint32* value, uint32* expected, uint32 desired) noexcept { return (uint32) InterlockedCompareExchange((volatile long *) value, desired, *expected); }
|
||||
FORCE_INLINE uint64 atomic_compare_exchange_strong_acquire_release(volatile uint64* value, uint64* expected, uint64 desired) noexcept { return (uint64) InterlockedCompareExchange64((volatile LONG64 *) value, (LONG64) desired, (LONG64) *expected); }
|
||||
FORCE_INLINE uint8 atomic_fetch_add_acquire_release(volatile uint8* value, uint8 operand) noexcept { return (uint8) InterlockedExchangeAdd8((volatile char *) value, (char) operand); }
|
||||
FORCE_INLINE uint8 atomic_fetch_sub_acquire_release(volatile uint8* value, uint8 operand) noexcept { return (uint8) InterlockedExchangeAdd8((volatile char *) value, -((char) operand)); }
|
||||
FORCE_INLINE uint16 atomic_fetch_add_acquire_release(volatile uint16* value, uint16 operand) noexcept { return (uint16) InterlockedExchangeAdd16((volatile short *) value, (short) operand); }
|
||||
|
|
|
|||
|
|
@ -11,40 +11,41 @@
|
|||
|
||||
#include <windows.h>
|
||||
#include "../../../stdlib/Types.h"
|
||||
#include "../../../compiler/CompilerUtils.h"
|
||||
|
||||
typedef HANDLE sem_t;
|
||||
typedef HANDLE sem;
|
||||
|
||||
inline
|
||||
void sem_init(sem_t* semaphore, int32 value)
|
||||
FORCE_INLINE
|
||||
void coms_sem_init(sem* semaphore, int32 value)
|
||||
{
|
||||
*semaphore = CreateSemaphore(NULL, value, MAX_UINT32, NULL);
|
||||
}
|
||||
|
||||
inline
|
||||
void sem_destroy(sem_t* semaphore)
|
||||
FORCE_INLINE
|
||||
void coms_sem_destroy(sem* semaphore)
|
||||
{
|
||||
CloseHandle(*semaphore);
|
||||
}
|
||||
|
||||
// decrement if != 0, if = 0 wait
|
||||
inline
|
||||
void sem_wait(sem_t* semaphore) {
|
||||
FORCE_INLINE
|
||||
void coms_sem_wait(sem* semaphore) {
|
||||
WaitForSingleObject(*semaphore, INFINITE);
|
||||
}
|
||||
|
||||
inline
|
||||
int32 sem_timedwait(sem_t* semaphore, uint64 ms) {
|
||||
FORCE_INLINE
|
||||
int32 semimedwait(sem* semaphore, uint64 ms) {
|
||||
return (int32) WaitForSingleObject(*semaphore, (DWORD) ms);
|
||||
}
|
||||
|
||||
inline
|
||||
int32 sem_trywait(sem_t* semaphore) {
|
||||
FORCE_INLINE
|
||||
int32 semrywait(sem* semaphore) {
|
||||
return (int32) WaitForSingleObject(*semaphore, 0);
|
||||
}
|
||||
|
||||
// increment
|
||||
inline
|
||||
void sem_post(sem_t* semaphore) {
|
||||
FORCE_INLINE
|
||||
void coms_sem_post(sem* semaphore) {
|
||||
ReleaseSemaphore(*semaphore, 1, NULL);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,20 +13,21 @@
|
|||
#include "../../../stdlib/Types.h"
|
||||
#include "../TimeUtils.h"
|
||||
#include "Spinlock.h"
|
||||
#include "../../../compiler/CompilerUtils.h"
|
||||
|
||||
inline
|
||||
FORCE_INLINE
|
||||
void spinlock_init(spinlock32* lock) {
|
||||
lock = 0;
|
||||
}
|
||||
|
||||
inline
|
||||
FORCE_INLINE
|
||||
void spinlock_start(spinlock32* lock, int32 delay = 10) {
|
||||
while (InterlockedExchange(lock, 1) != 0) {
|
||||
usleep(delay);
|
||||
}
|
||||
}
|
||||
|
||||
inline
|
||||
FORCE_INLINE
|
||||
void spinlock_end(spinlock32* lock) {
|
||||
InterlockedExchange(lock, 0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ int32 coms_pthread_detach(coms_pthread_t thread)
|
|||
}
|
||||
|
||||
inline
|
||||
int32 coms_pthread_mutex_init(coms_pthread_mutex_t* mutex, coms_pthread_mutexattr_t*)
|
||||
int32 mutex_init(mutex* mutex, mutexattr_t*)
|
||||
{
|
||||
if (mutex == NULL) {
|
||||
return 1;
|
||||
|
|
@ -59,7 +59,7 @@ int32 coms_pthread_mutex_init(coms_pthread_mutex_t* mutex, coms_pthread_mutexatt
|
|||
}
|
||||
|
||||
inline
|
||||
int32 coms_pthread_mutex_destroy(coms_pthread_mutex_t* mutex)
|
||||
int32 mutex_destroy(mutex* mutex)
|
||||
{
|
||||
if (mutex == NULL) {
|
||||
return 1;
|
||||
|
|
@ -71,7 +71,7 @@ int32 coms_pthread_mutex_destroy(coms_pthread_mutex_t* mutex)
|
|||
}
|
||||
|
||||
inline
|
||||
int32 coms_pthread_mutex_lock(coms_pthread_mutex_t* mutex)
|
||||
int32 mutex_lock(mutex* mutex)
|
||||
{
|
||||
if (mutex == NULL) {
|
||||
return 1;
|
||||
|
|
@ -83,7 +83,7 @@ int32 coms_pthread_mutex_lock(coms_pthread_mutex_t* mutex)
|
|||
}
|
||||
|
||||
inline
|
||||
int32 coms_pthread_mutex_unlock(coms_pthread_mutex_t* mutex)
|
||||
int32 mutex_unlock(mutex* mutex)
|
||||
{
|
||||
if (mutex == NULL) {
|
||||
return 1;
|
||||
|
|
@ -96,7 +96,7 @@ int32 coms_pthread_mutex_unlock(coms_pthread_mutex_t* mutex)
|
|||
|
||||
// WARNING: We don't support windows events since they are much slower than conditional variables/mutexes
|
||||
inline
|
||||
int32 coms_pthread_cond_init(coms_pthread_cond_t* cond, coms_pthread_condattr_t*)
|
||||
int32 coms_pthread_cond_init(mutex_cond* cond, coms_pthread_condattr_t*)
|
||||
{
|
||||
if (cond == NULL) {
|
||||
return 1;
|
||||
|
|
@ -108,7 +108,7 @@ int32 coms_pthread_cond_init(coms_pthread_cond_t* cond, coms_pthread_condattr_t*
|
|||
}
|
||||
|
||||
inline
|
||||
int32 coms_pthread_cond_destroy(coms_pthread_cond_t*)
|
||||
int32 coms_pthread_cond_destroy(mutex_cond*)
|
||||
{
|
||||
/* Windows does not have a destroy for conditionals */
|
||||
return 0;
|
||||
|
|
@ -116,7 +116,7 @@ int32 coms_pthread_cond_destroy(coms_pthread_cond_t*)
|
|||
|
||||
// @question Can't we turn timespec in a typedef of uint64? I would like to avoid the time.h class
|
||||
inline
|
||||
int32 coms_pthread_cond_timedwait(coms_pthread_cond_t* cond, coms_pthread_mutex_t* mutex, const timespec* abstime)
|
||||
int32 mutex_condimedwait(mutex_cond* cond, mutex* mutex, const timespec* abstime)
|
||||
{
|
||||
if (cond == NULL || mutex == NULL) {
|
||||
return 1;
|
||||
|
|
@ -130,17 +130,17 @@ int32 coms_pthread_cond_timedwait(coms_pthread_cond_t* cond, coms_pthread_mutex_
|
|||
}
|
||||
|
||||
inline
|
||||
int32 coms_pthread_cond_wait(coms_pthread_cond_t* cond, coms_pthread_mutex_t* mutex)
|
||||
int32 coms_pthread_cond_wait(mutex_cond* cond, mutex* mutex)
|
||||
{
|
||||
if (cond == NULL || mutex == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return coms_pthread_cond_timedwait(cond, mutex, NULL);
|
||||
return mutex_condimedwait(cond, mutex, NULL);
|
||||
}
|
||||
|
||||
inline
|
||||
int32 coms_pthread_cond_signal(coms_pthread_cond_t* cond)
|
||||
int32 coms_pthread_cond_signal(mutex_cond* cond)
|
||||
{
|
||||
if (cond == NULL) {
|
||||
return 1;
|
||||
|
|
@ -152,7 +152,7 @@ int32 coms_pthread_cond_signal(coms_pthread_cond_t* cond)
|
|||
}
|
||||
|
||||
inline
|
||||
int32 coms_pthread_cond_broadcast(coms_pthread_cond_t* cond)
|
||||
int32 coms_pthread_cond_broadcast(mutex_cond* cond)
|
||||
{
|
||||
if (cond == NULL) {
|
||||
return 1;
|
||||
|
|
|
|||
|
|
@ -14,12 +14,12 @@
|
|||
|
||||
#define THREAD_RETURN DWORD WINAPI
|
||||
typedef DWORD (WINAPI *ThreadJobFunc)(void*);
|
||||
typedef CRITICAL_SECTION coms_pthread_mutex_t;
|
||||
typedef void coms_pthread_mutexattr_t;
|
||||
typedef CRITICAL_SECTION mutex;
|
||||
typedef void mutexattr_t;
|
||||
typedef void coms_pthread_condattr_t;
|
||||
typedef void coms_pthread_rwlockattr_t;
|
||||
typedef HANDLE coms_pthread_t;
|
||||
typedef CONDITION_VARIABLE coms_pthread_cond_t;
|
||||
typedef CONDITION_VARIABLE mutex_cond;
|
||||
|
||||
// Thread local variable Already exists in c++11
|
||||
// #define thread_local __declspec(thread)
|
||||
|
|
|
|||
|
|
@ -20,4 +20,15 @@ int32 lower_bound(int32* t, size_t len, int32 x) {
|
|||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
const char** string_lower_bound(const char** base, size_t len, const char* target) {
|
||||
while (len > 1) {
|
||||
size_t half = len / 2;
|
||||
len -= half;
|
||||
base += (strcmp(base[half - 1], target) < 0) * half;
|
||||
}
|
||||
return base;
|
||||
}
|
||||
*/
|
||||
|
||||
#endif
|
||||
|
|
@ -7,6 +7,7 @@
|
|||
// @performance We could optimize eytzinger by using 1 based index
|
||||
// Consider this https://en.algorithmica.org/hpc/data-structures/binary-search/
|
||||
|
||||
static
|
||||
void eytzinger_rearrange(byte* arr, byte* temp, size_t start, size_t* index, size_t num, size_t size) noexcept {
|
||||
if (start >= num) {
|
||||
return;
|
||||
|
|
@ -23,6 +24,7 @@ void eytzinger_rearrange(byte* arr, byte* temp, size_t start, size_t* index, siz
|
|||
eytzinger_rearrange(arr, temp, 2 * start + 2, index, num, size);
|
||||
}
|
||||
|
||||
// @performance Instead of expecting a sorted array maybe we can improve it by immediately create the eytzinger array and thus avoid one "sort"
|
||||
// arr MUST be sorted by a sorting algorithm of your choice
|
||||
void eytzinger_create(byte* arr, size_t num, size_t size, RingMemory* ring) {
|
||||
byte* temp = ring_get_memory(ring, size * num);
|
||||
|
|
|
|||
|
|
@ -124,12 +124,12 @@ struct HashMap {
|
|||
|
||||
// @todo Change so the hashmap can grow or maybe even better create a static and dynamic version
|
||||
inline
|
||||
void hashmap_alloc(HashMap* hm, int32 count, int32 element_size)
|
||||
void hashmap_alloc(HashMap* hm, int32 count, int32 element_size, int32 alignment = 64)
|
||||
{
|
||||
LOG_1("Allocate HashMap for %n elements with %n B per element", {{LOG_DATA_INT32, &count}, {LOG_DATA_INT32, &element_size}});
|
||||
byte* data = (byte *) platform_alloc(
|
||||
count * (sizeof(uint16) + element_size)
|
||||
+ CEIL_DIV(count, 64) * sizeof(hm->buf.free)
|
||||
+ CEIL_DIV(count, alignment) * sizeof(hm->buf.free)
|
||||
);
|
||||
|
||||
hm->table = (uint16 *) data;
|
||||
|
|
@ -148,13 +148,13 @@ void hashmap_free(HashMap* hm)
|
|||
|
||||
// WARNING: element_size = element size + remaining HashEntry data size
|
||||
inline
|
||||
void hashmap_create(HashMap* hm, int32 count, int32 element_size, RingMemory* ring) noexcept
|
||||
void hashmap_create(HashMap* hm, int32 count, int32 element_size, RingMemory* ring, int32 alignment = 64) noexcept
|
||||
{
|
||||
LOG_1("Create HashMap for %n elements with %n B per element", {{LOG_DATA_INT32, &count}, {LOG_DATA_INT32, &element_size}});
|
||||
byte* data = ring_get_memory(
|
||||
ring,
|
||||
count * (sizeof(uint16) + element_size)
|
||||
+ CEIL_DIV(count, 64) * sizeof(hm->buf.free)
|
||||
+ CEIL_DIV(count, alignment) * sizeof(hm->buf.free)
|
||||
);
|
||||
|
||||
hm->table = (uint16 *) data;
|
||||
|
|
@ -163,13 +163,13 @@ void hashmap_create(HashMap* hm, int32 count, int32 element_size, RingMemory* ri
|
|||
|
||||
// WARNING: element_size = element size + remaining HashEntry data size
|
||||
inline
|
||||
void hashmap_create(HashMap* hm, int32 count, int32 element_size, BufferMemory* buf) noexcept
|
||||
void hashmap_create(HashMap* hm, int32 count, int32 element_size, BufferMemory* buf, int32 alignment = 64) noexcept
|
||||
{
|
||||
LOG_1("Create HashMap for %n elements with %n B per element", {{LOG_DATA_INT32, &count}, {LOG_DATA_INT32, &element_size}});
|
||||
byte* data = buffer_get_memory(
|
||||
buf,
|
||||
count * (sizeof(uint16) + element_size)
|
||||
+ CEIL_DIV(count, 64) * sizeof(hm->buf.free)
|
||||
+ CEIL_DIV(count, alignment) * sizeof(hm->buf.free)
|
||||
);
|
||||
|
||||
hm->table = (uint16 *) data;
|
||||
|
|
@ -406,8 +406,10 @@ HashEntry* hashmap_get_reserve(HashMap* hm, const char* key) noexcept
|
|||
uint64 index = hash_djb2(key) % hm->buf.count;
|
||||
HashEntry* entry = (HashEntry *) chunk_get_element(&hm->buf, hm->table[index] - 1, false);
|
||||
|
||||
str_move_to_pos(&key, -HASH_MAP_MAX_KEY_LENGTH);
|
||||
|
||||
while (entry != NULL) {
|
||||
if (str_compare(entry->key, key, HASH_MAP_MAX_KEY_LENGTH) == 0) {
|
||||
if (str_compare(entry->key, key) == 0) {
|
||||
DEBUG_MEMORY_READ((uintptr_t) entry, sizeof(HashEntry));
|
||||
return entry;
|
||||
}
|
||||
|
|
@ -438,7 +440,6 @@ HashEntry* hashmap_get_reserve(HashMap* hm, const char* key) noexcept
|
|||
return entry_new;
|
||||
}
|
||||
|
||||
// @performance Some places use this in order to iterate the hashmap that is horrible!!! Use the actual iterate function!
|
||||
inline
|
||||
HashEntry* hashmap_get_entry_by_element(HashMap* hm, uint32 element) noexcept
|
||||
{
|
||||
|
|
@ -449,8 +450,10 @@ HashEntry* hashmap_get_entry(HashMap* hm, const char* key) noexcept {
|
|||
uint64 index = hash_djb2(key) % hm->buf.count;
|
||||
HashEntry* entry = (HashEntry *) chunk_get_element(&hm->buf, hm->table[index] - 1, false);
|
||||
|
||||
str_move_to_pos(&key, -HASH_MAP_MAX_KEY_LENGTH);
|
||||
|
||||
while (entry != NULL) {
|
||||
if (str_compare(entry->key, key, HASH_MAP_MAX_KEY_LENGTH) == 0) {
|
||||
if (str_compare(entry->key, key) == 0) {
|
||||
DEBUG_MEMORY_READ((uintptr_t) entry, sizeof(HashEntry));
|
||||
return entry;
|
||||
}
|
||||
|
|
@ -467,8 +470,10 @@ uint32 hashmap_get_element(const HashMap* hm, const char* key) noexcept {
|
|||
|
||||
uint32 element_id = hm->table[index];
|
||||
|
||||
str_move_to_pos(&key, -HASH_MAP_MAX_KEY_LENGTH);
|
||||
|
||||
while (entry != NULL) {
|
||||
if (str_compare(entry->key, key, HASH_MAP_MAX_KEY_LENGTH) == 0) {
|
||||
if (str_compare(entry->key, key) == 0) {
|
||||
DEBUG_MEMORY_READ((uintptr_t) entry, sizeof(HashEntry));
|
||||
return element_id;
|
||||
}
|
||||
|
|
@ -492,8 +497,10 @@ HashEntry* hashmap_get_entry(HashMap* hm, const char* key, uint64 hash) noexcept
|
|||
hash %= hm->buf.count;
|
||||
HashEntry* entry = (HashEntry *) chunk_get_element(&hm->buf, hm->table[hash] - 1, false);
|
||||
|
||||
str_move_to_pos(&key, -HASH_MAP_MAX_KEY_LENGTH);
|
||||
|
||||
while (entry != NULL) {
|
||||
if (str_compare(entry->key, key, HASH_MAP_MAX_KEY_LENGTH) == 0) {
|
||||
if (str_compare(entry->key, key) == 0) {
|
||||
DEBUG_MEMORY_READ((uintptr_t) entry, sizeof(HashEntry));
|
||||
return entry;
|
||||
}
|
||||
|
|
@ -514,8 +521,10 @@ void hashmap_remove(HashMap* hm, const char* key) noexcept {
|
|||
|
||||
uint32 element_id = hm->table[index];
|
||||
|
||||
str_move_to_pos(&key, -HASH_MAP_MAX_KEY_LENGTH);
|
||||
|
||||
while (entry != NULL) {
|
||||
if (str_compare(entry->key, key, HASH_MAP_MAX_KEY_LENGTH) == 0) {
|
||||
if (str_compare(entry->key, key) == 0) {
|
||||
if (prev == NULL) {
|
||||
hm->table[index] = entry->next;
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -179,13 +179,13 @@ void perfect_hashmap_create(PerfectHashMap* hm, int32 count, int32 element_size,
|
|||
|
||||
// Calculates how large a hashmap will be
|
||||
inline
|
||||
int64 perfect_hashmap_count(int count, int32 element_size)
|
||||
int64 perfect_hashmap_size(int32 count, int32 element_size)
|
||||
{
|
||||
return count * element_size;
|
||||
}
|
||||
|
||||
inline
|
||||
int64 perfect_hashmap_count(const PerfectHashMap* hm)
|
||||
int64 perfect_hashmap_size(const PerfectHashMap* hm)
|
||||
{
|
||||
return hm->entry_size * hm->map_count;
|
||||
}
|
||||
|
|
@ -195,7 +195,12 @@ inline
|
|||
void perfect_hashmap_insert(PerfectHashMap* hm, const char* key, int32 value) {
|
||||
int32 index = hm->hash_function(key, hm->hash_seed) % hm->map_count;
|
||||
PerfectHashEntryInt32* entry = (PerfectHashEntryInt32 *) (hm->hash_entries + hm->entry_size * index);
|
||||
str_copy_short(entry->key, key);
|
||||
|
||||
// Ensure key length
|
||||
str_move_to_pos(&key, -PERFECT_HASH_MAP_MAX_KEY_LENGTH);
|
||||
str_copy_short(entry->key, key, PERFECT_HASH_MAP_MAX_KEY_LENGTH);
|
||||
entry->key[PERFECT_HASH_MAP_MAX_KEY_LENGTH - 1] = '\0';
|
||||
|
||||
entry->value = value;
|
||||
}
|
||||
|
||||
|
|
@ -203,7 +208,12 @@ inline
|
|||
void perfect_hashmap_insert(PerfectHashMap* hm, const char* key, int64 value) {
|
||||
int32 index = hm->hash_function(key, hm->hash_seed) % hm->map_count;
|
||||
PerfectHashEntryInt64* entry = (PerfectHashEntryInt64 *) (hm->hash_entries + hm->entry_size * index);
|
||||
str_copy_short(entry->key, key);
|
||||
|
||||
// Ensure key length
|
||||
str_move_to_pos(&key, -PERFECT_HASH_MAP_MAX_KEY_LENGTH);
|
||||
str_copy_short(entry->key, key, PERFECT_HASH_MAP_MAX_KEY_LENGTH);
|
||||
entry->key[PERFECT_HASH_MAP_MAX_KEY_LENGTH - 1] = '\0';
|
||||
|
||||
entry->value = value;
|
||||
}
|
||||
|
||||
|
|
@ -211,7 +221,12 @@ inline
|
|||
void perfect_hashmap_insert(PerfectHashMap* hm, const char* key, uintptr_t value) {
|
||||
int32 index = hm->hash_function(key, hm->hash_seed) % hm->map_count;
|
||||
PerfectHashEntryUIntPtr* entry = (PerfectHashEntryUIntPtr *) (hm->hash_entries + hm->entry_size * index);
|
||||
str_copy_short(entry->key, key);
|
||||
|
||||
// Ensure key length
|
||||
str_move_to_pos(&key, -PERFECT_HASH_MAP_MAX_KEY_LENGTH);
|
||||
str_copy_short(entry->key, key, PERFECT_HASH_MAP_MAX_KEY_LENGTH);
|
||||
entry->key[PERFECT_HASH_MAP_MAX_KEY_LENGTH - 1] = '\0';
|
||||
|
||||
entry->value = value;
|
||||
}
|
||||
|
||||
|
|
@ -219,7 +234,12 @@ inline
|
|||
void perfect_hashmap_insert(PerfectHashMap* hm, const char* key, void* value) {
|
||||
int32 index = hm->hash_function(key, hm->hash_seed) % hm->map_count;
|
||||
PerfectHashEntryVoidP* entry = (PerfectHashEntryVoidP *) (hm->hash_entries + hm->entry_size * index);
|
||||
str_copy_short(entry->key, key);
|
||||
|
||||
// Ensure key length
|
||||
str_move_to_pos(&key, -PERFECT_HASH_MAP_MAX_KEY_LENGTH);
|
||||
str_copy_short(entry->key, key, PERFECT_HASH_MAP_MAX_KEY_LENGTH);
|
||||
entry->key[PERFECT_HASH_MAP_MAX_KEY_LENGTH - 1] = '\0';
|
||||
|
||||
entry->value = value;
|
||||
}
|
||||
|
||||
|
|
@ -227,7 +247,12 @@ inline
|
|||
void perfect_hashmap_insert(PerfectHashMap* hm, const char* key, f32 value) {
|
||||
int32 index = hm->hash_function(key, hm->hash_seed) % hm->map_count;
|
||||
PerfectHashEntryFloat* entry = (PerfectHashEntryFloat *) (hm->hash_entries + hm->entry_size * index);
|
||||
str_copy_short(entry->key, key);
|
||||
|
||||
// Ensure key length
|
||||
str_move_to_pos(&key, -PERFECT_HASH_MAP_MAX_KEY_LENGTH);
|
||||
str_copy_short(entry->key, key, PERFECT_HASH_MAP_MAX_KEY_LENGTH);
|
||||
entry->key[PERFECT_HASH_MAP_MAX_KEY_LENGTH - 1] = '\0';
|
||||
|
||||
entry->value = value;
|
||||
}
|
||||
|
||||
|
|
@ -235,7 +260,12 @@ inline
|
|||
void perfect_hashmap_insert(PerfectHashMap* hm, const char* key, const char* value) {
|
||||
int32 index = hm->hash_function(key, hm->hash_seed) % hm->map_count;
|
||||
PerfectHashEntryStr* entry = (PerfectHashEntryStr *) (hm->hash_entries + hm->entry_size * index);
|
||||
str_copy_short(entry->key, key);
|
||||
|
||||
// Ensure key length
|
||||
str_move_to_pos(&key, -PERFECT_HASH_MAP_MAX_KEY_LENGTH);
|
||||
str_copy_short(entry->key, key, PERFECT_HASH_MAP_MAX_KEY_LENGTH);
|
||||
entry->key[PERFECT_HASH_MAP_MAX_KEY_LENGTH - 1] = '\0';
|
||||
|
||||
str_copy_short(entry->value, value, PERFECT_HASH_MAP_MAX_KEY_LENGTH);
|
||||
}
|
||||
|
||||
|
|
@ -243,7 +273,12 @@ inline
|
|||
void perfect_hashmap_insert(PerfectHashMap* hm, const char* key, byte* value) {
|
||||
int32 index = hm->hash_function(key, hm->hash_seed) % hm->map_count;
|
||||
PerfectHashEntryStr* entry = (PerfectHashEntryStr *) (hm->hash_entries + hm->entry_size * index);
|
||||
str_copy_short(entry->key, key);
|
||||
|
||||
// Ensure key length
|
||||
str_move_to_pos(&key, -PERFECT_HASH_MAP_MAX_KEY_LENGTH);
|
||||
str_copy_short(entry->key, key, PERFECT_HASH_MAP_MAX_KEY_LENGTH);
|
||||
entry->key[PERFECT_HASH_MAP_MAX_KEY_LENGTH - 1] = '\0';
|
||||
|
||||
memcpy(entry->value, value, hm->entry_size - sizeof(PerfectHashEntry));
|
||||
}
|
||||
|
||||
|
|
@ -252,6 +287,8 @@ PerfectHashEntry* perfect_hashmap_get_entry(const PerfectHashMap* hm, const char
|
|||
int32 index = hm->hash_function(key, hm->hash_seed) % hm->map_count;
|
||||
PerfectHashEntry* entry = (PerfectHashEntry *) (hm->hash_entries + hm->entry_size * index);
|
||||
|
||||
str_move_to_pos(&key, -HASH_MAP_MAX_KEY_LENGTH);
|
||||
|
||||
return str_compare(entry->key, key) == 0 ? entry : NULL;
|
||||
}
|
||||
|
||||
|
|
@ -260,6 +297,8 @@ void perfect_hashmap_delete_entry(PerfectHashMap* hm, const char* key) {
|
|||
int32 index = hm->hash_function(key, hm->hash_seed) % hm->map_count;
|
||||
PerfectHashEntry* entry = (PerfectHashEntry *) (hm->hash_entries + hm->entry_size * index);
|
||||
|
||||
str_move_to_pos(&key, -HASH_MAP_MAX_KEY_LENGTH);
|
||||
|
||||
if (str_compare(entry->key, key) != 0) {
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,11 +14,6 @@
|
|||
// Adjusts the step size based on the memory alignment
|
||||
inline
|
||||
int32 intrin_validate_steps(const byte* mem, int32 steps) {
|
||||
// During development we want to spot invalid alignment
|
||||
ASSERT_SIMPLE(steps < 16 || (steps >= 16 && ((uintptr_t) mem & 63) == 0));
|
||||
ASSERT_SIMPLE(steps < 8 || (steps >= 8 && ((uintptr_t) mem & 31) == 0));
|
||||
ASSERT_SIMPLE(steps < 4 || (steps >= 4 && ((uintptr_t) mem & 15) == 0));
|
||||
|
||||
if (steps >= 16 && ((uintptr_t) mem & 63) == 0) {
|
||||
return 16;
|
||||
} else if (steps >= 8 && ((uintptr_t) mem & 31) == 0) {
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ struct ThreadedHashMap {
|
|||
void** table;
|
||||
ChunkMemory buf;
|
||||
|
||||
coms_pthread_mutex_t mutex;
|
||||
mutex mutex;
|
||||
};
|
||||
|
||||
// WARNING: element_size = element size + remaining HashEntry data size
|
||||
|
|
@ -28,7 +28,7 @@ inline
|
|||
void thrd_hashmap_create(ThreadedHashMap* hm, int32 count, int32 element_size, RingMemory* ring)
|
||||
{
|
||||
hashmap_create((HashMap *) hm, count, element_size, ring);
|
||||
coms_pthread_mutex_init(&hm->mutex, NULL);
|
||||
mutex_init(&hm->mutex, NULL);
|
||||
}
|
||||
|
||||
// WARNING: element_size = element size + remaining HashEntry data size
|
||||
|
|
@ -36,7 +36,7 @@ inline
|
|||
void thrd_hashmap_create(ThreadedHashMap* hm, int32 count, int32 element_size, BufferMemory* buf)
|
||||
{
|
||||
hashmap_create((HashMap *) hm, count, element_size, buf);
|
||||
coms_pthread_mutex_init(&hm->mutex, NULL);
|
||||
mutex_init(&hm->mutex, NULL);
|
||||
}
|
||||
|
||||
// WARNING: element_size = element size + remaining HashEntry data size
|
||||
|
|
@ -44,85 +44,85 @@ inline
|
|||
void thrd_hashmap_create(ThreadedHashMap* hm, int32 count, int32 element_size, byte* buf)
|
||||
{
|
||||
hashmap_create((HashMap *) hm, count, element_size, buf);
|
||||
coms_pthread_mutex_init(&hm->mutex, NULL);
|
||||
mutex_init(&hm->mutex, NULL);
|
||||
}
|
||||
|
||||
inline
|
||||
void thrd_hashmap_free(ThreadedHashMap* hm)
|
||||
{
|
||||
coms_pthread_mutex_destroy(&hm->mutex);
|
||||
mutex_destroy(&hm->mutex);
|
||||
}
|
||||
|
||||
inline
|
||||
void thrd_hashmap_insert(ThreadedHashMap* hm, const char* key, int32 value) {
|
||||
coms_pthread_mutex_lock(&hm->mutex);
|
||||
mutex_lock(&hm->mutex);
|
||||
hashmap_insert((HashMap *) hm, key, value);
|
||||
coms_pthread_mutex_unlock(&hm->mutex);
|
||||
mutex_unlock(&hm->mutex);
|
||||
}
|
||||
|
||||
inline
|
||||
void thrd_hashmap_insert(ThreadedHashMap* hm, const char* key, int64 value) {
|
||||
coms_pthread_mutex_lock(&hm->mutex);
|
||||
mutex_lock(&hm->mutex);
|
||||
hashmap_insert((HashMap *) hm, key, value);
|
||||
coms_pthread_mutex_unlock(&hm->mutex);
|
||||
mutex_unlock(&hm->mutex);
|
||||
}
|
||||
|
||||
inline
|
||||
void thrd_hashmap_insert(ThreadedHashMap* hm, const char* key, uintptr_t value) {
|
||||
coms_pthread_mutex_lock(&hm->mutex);
|
||||
mutex_lock(&hm->mutex);
|
||||
hashmap_insert((HashMap *) hm, key, value);
|
||||
coms_pthread_mutex_unlock(&hm->mutex);
|
||||
mutex_unlock(&hm->mutex);
|
||||
}
|
||||
|
||||
inline
|
||||
void thrd_hashmap_insert(ThreadedHashMap* hm, const char* key, void* value) {
|
||||
coms_pthread_mutex_lock(&hm->mutex);
|
||||
mutex_lock(&hm->mutex);
|
||||
hashmap_insert((HashMap *) hm, key, value);
|
||||
coms_pthread_mutex_unlock(&hm->mutex);
|
||||
mutex_unlock(&hm->mutex);
|
||||
}
|
||||
|
||||
inline
|
||||
void thrd_hashmap_insert(ThreadedHashMap* hm, const char* key, f32 value) {
|
||||
coms_pthread_mutex_lock(&hm->mutex);
|
||||
mutex_lock(&hm->mutex);
|
||||
hashmap_insert((HashMap *) hm, key, value);
|
||||
coms_pthread_mutex_unlock(&hm->mutex);
|
||||
mutex_unlock(&hm->mutex);
|
||||
}
|
||||
|
||||
inline
|
||||
void thrd_hashmap_insert(ThreadedHashMap* hm, const char* key, const char* value) {
|
||||
coms_pthread_mutex_lock(&hm->mutex);
|
||||
mutex_lock(&hm->mutex);
|
||||
hashmap_insert((HashMap *) hm, key, value);
|
||||
coms_pthread_mutex_unlock(&hm->mutex);
|
||||
mutex_unlock(&hm->mutex);
|
||||
}
|
||||
|
||||
inline
|
||||
void thrd_hashmap_insert(ThreadedHashMap* hm, const char* key, byte* value) {
|
||||
coms_pthread_mutex_lock(&hm->mutex);
|
||||
mutex_lock(&hm->mutex);
|
||||
hashmap_insert((HashMap *) hm, key, value);
|
||||
coms_pthread_mutex_unlock(&hm->mutex);
|
||||
mutex_unlock(&hm->mutex);
|
||||
}
|
||||
|
||||
inline
|
||||
void thrd_hashmap_get_entry(ThreadedHashMap* hm, HashEntry* entry, const char* key) {
|
||||
coms_pthread_mutex_lock(&hm->mutex);
|
||||
mutex_lock(&hm->mutex);
|
||||
HashEntry* temp = hashmap_get_entry((HashMap *) hm, key);
|
||||
memcpy(entry, temp, hm->buf.chunk_size);
|
||||
coms_pthread_mutex_unlock(&hm->mutex);
|
||||
mutex_unlock(&hm->mutex);
|
||||
}
|
||||
|
||||
inline
|
||||
void thrd_hashmap_get_entry(ThreadedHashMap* hm, HashEntry* entry, const char* key, uint64 index) {
|
||||
coms_pthread_mutex_lock(&hm->mutex);
|
||||
mutex_lock(&hm->mutex);
|
||||
HashEntry* temp = hashmap_get_entry((HashMap *) hm, key, index);
|
||||
memcpy(entry, temp, hm->buf.chunk_size);
|
||||
coms_pthread_mutex_unlock(&hm->mutex);
|
||||
mutex_unlock(&hm->mutex);
|
||||
}
|
||||
|
||||
inline
|
||||
void thrd_hashmap_remove(ThreadedHashMap* hm, const char* key) {
|
||||
coms_pthread_mutex_lock(&hm->mutex);
|
||||
mutex_lock(&hm->mutex);
|
||||
hashmap_remove((HashMap *) hm, key);
|
||||
coms_pthread_mutex_unlock(&hm->mutex);
|
||||
mutex_unlock(&hm->mutex);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -43,7 +43,6 @@ typedef char sbyte;
|
|||
typedef uintptr_t umm;
|
||||
typedef intptr_t smm;
|
||||
|
||||
// @question consider to implement atomic_16 depending on intrinsic support
|
||||
#define atomic_8 volatile
|
||||
#define atomic_16 volatile
|
||||
#define atomic_32 volatile
|
||||
|
|
@ -57,8 +56,7 @@ typedef intptr_t smm;
|
|||
#define OMS_MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
#define OMS_MIN(a, b) ((a) > (b) ? (b) : (a))
|
||||
|
||||
// @todo Switch the order of high and low
|
||||
#define OMS_CLAMP(val, high, low) ((val) < (low) ? (low) : ((val) > (high) ? (high) : (val)))
|
||||
#define OMS_CLAMP(val, low, high) ((val) < (low) ? (low) : ((val) > (high) ? (high) : (val)))
|
||||
|
||||
#define OMS_ABS(a) ((a) > 0 ? (a) : -(a))
|
||||
#define OMS_ABS_INT8(a) ((uint8) ((a) & 0x7F))
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
#endif
|
||||
|
||||
void system_info_render(char* buf, const SystemInfo* info) {
|
||||
sprintf_s(
|
||||
snprintf(
|
||||
buf,
|
||||
4096,
|
||||
"OS:\n"
|
||||
|
|
@ -39,7 +39,7 @@ void system_info_render(char* buf, const SystemInfo* info) {
|
|||
"\n"
|
||||
"CPU:\n"
|
||||
"==============\n"
|
||||
"Hardware\n" "Vendor: %s\n" "Brand: %s\n" "Model: %d\n" "Family: %d\n" "Mhz: %d\n" "Thread Count: %d\n" "Page Size: %d\n"
|
||||
"Hardware\n" "Vendor: %s\n" "Brand: %s\n" "Model: %d\n" "Family: %d\n" "Mhz: %d\n" "Core Count: %d\n" "Page Size: %d\n"
|
||||
"\n"
|
||||
"Cache:\n"
|
||||
"L1: Size %d Line %d\n"
|
||||
|
|
@ -47,7 +47,7 @@ void system_info_render(char* buf, const SystemInfo* info) {
|
|||
"L3: Size %d Line %d\n"
|
||||
"L4: Size %d Line %d\n"
|
||||
"\n"
|
||||
"Features: %lld\n"
|
||||
"Features: %ld\n"
|
||||
"\n"
|
||||
"GPU:\n"
|
||||
"==============\n"
|
||||
|
|
@ -73,7 +73,7 @@ void system_info_render(char* buf, const SystemInfo* info) {
|
|||
info->network_count < 2 ? "" : info->network[1].slot, info->network_count < 2 ? 0 : info->network[1].mac[0], info->network_count < 2 ? 0 : info->network[1].mac[1], info->network_count < 2 ? 0 : info->network[1].mac[2], info->network_count < 2 ? 0 : info->network[1].mac[3], info->network_count < 2 ? 0 : info->network[1].mac[4], info->network_count < 2 ? 0 : info->network[1].mac[5], info->network_count < 2 ? 0 : info->network[1].mac[6], info->network_count < 2 ? 0 : info->network[1].mac[7],
|
||||
info->network_count < 3 ? "" : info->network[2].slot, info->network_count < 3 ? 0 : info->network[2].mac[0], info->network_count < 3 ? 0 : info->network[2].mac[1], info->network_count < 3 ? 0 : info->network[2].mac[2], info->network_count < 3 ? 0 : info->network[2].mac[3], info->network_count < 3 ? 0 : info->network[2].mac[4], info->network_count < 3 ? 0 : info->network[2].mac[5], info->network_count < 3 ? 0 : info->network[2].mac[6], info->network_count < 3 ? 0 : info->network[2].mac[7],
|
||||
info->network_count < 4 ? "" : info->network[3].slot, info->network_count < 4 ? 0 : info->network[3].mac[0], info->network_count < 4 ? 0 : info->network[3].mac[1], info->network_count < 4 ? 0 : info->network[3].mac[2], info->network_count < 4 ? 0 : info->network[3].mac[3], info->network_count < 4 ? 0 : info->network[3].mac[4], info->network_count < 4 ? 0 : info->network[3].mac[5], info->network_count < 4 ? 0 : info->network[3].mac[6], info->network_count < 4 ? 0 : info->network[3].mac[7],
|
||||
info->cpu.vendor, info->cpu.brand, info->cpu.model, info->cpu.family, info->cpu.mhz, info->cpu.thread_count, info->cpu.page_size,
|
||||
info->cpu.vendor, info->cpu.brand, info->cpu.model, info->cpu.family, info->cpu.mhz, info->cpu.core_count, info->cpu.page_size,
|
||||
info->cpu.cache[0].size, info->cpu.cache[0].line_size,
|
||||
info->cpu.cache[1].size, info->cpu.cache[1].line_size,
|
||||
info->cpu.cache[2].size, info->cpu.cache[2].line_size,
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ if "%Platform%" neq "x64" (
|
|||
cd "%DESTINATION_DIR%"
|
||||
del *.pdb > NUL 2> NUL
|
||||
del *.idb > NUL 2> NUL
|
||||
cd ..\..\GameEngine
|
||||
cd ..\..\cOMS
|
||||
|
||||
REM Use /showIncludes for include debugging
|
||||
|
||||
|
|
|
|||
2
tests/.vscode/settings.json
vendored
2
tests/.vscode/settings.json
vendored
|
|
@ -207,7 +207,7 @@
|
|||
"uiwindow.h": "c",
|
||||
"uiattributefont.h": "c",
|
||||
"renderutils.h": "c",
|
||||
"application.h": "c",
|
||||
"ApplicationData.h": "c",
|
||||
"shaderutils.h": "c",
|
||||
"uiattributeshadow.h": "c",
|
||||
"matrixfloat32.h": "c",
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user