Add lambda emulation
This commit is contained in:
@@ -69,6 +69,7 @@ set(BreezeHeaders
|
|||||||
|
|
||||||
breeze/util/array.h
|
breeze/util/array.h
|
||||||
breeze/util/heap.h
|
breeze/util/heap.h
|
||||||
|
breeze/util/lambda.h
|
||||||
breeze/util/object_pool.h
|
breeze/util/object_pool.h
|
||||||
breeze/util/spatial_grid.h
|
breeze/util/spatial_grid.h
|
||||||
breeze/util/string.h
|
breeze/util/string.h
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
#include "breeze/util/array.h"
|
#include "breeze/util/array.h"
|
||||||
#include "breeze/util/heap.h"
|
#include "breeze/util/heap.h"
|
||||||
|
#include "breeze/util/lambda.h"
|
||||||
#include "breeze/util/object_pool.h"
|
#include "breeze/util/object_pool.h"
|
||||||
#include "breeze/util/spatial_grid.h"
|
#include "breeze/util/spatial_grid.h"
|
||||||
#include "breeze/util/string.h"
|
#include "breeze/util/string.h"
|
||||||
|
|||||||
63
engine/breeze/util/lambda.h
Normal file
63
engine/breeze/util/lambda.h
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
#ifndef BREEZE_LAMBDA_H
|
||||||
|
#define BREEZE_LAMBDA_H
|
||||||
|
|
||||||
|
#include "../memory/memory.h"
|
||||||
|
|
||||||
|
typedef struct BzLambda BzLambda;
|
||||||
|
|
||||||
|
typedef void (*BzLambdaFn)(BzLambda *lambda, ...);
|
||||||
|
|
||||||
|
#define BZ_LAMBDA_STACK_SIZE 52
|
||||||
|
struct BzLambda {
|
||||||
|
BzLambdaFn fn;
|
||||||
|
|
||||||
|
i32 captureSize;
|
||||||
|
/* stack contents */
|
||||||
|
u8 stack[BZ_LAMBDA_STACK_SIZE];
|
||||||
|
};
|
||||||
|
static_assert(sizeof(BzLambda) == 64, "");
|
||||||
|
|
||||||
|
#define BZ_LAMBDA(lambdaName) \
|
||||||
|
(BzLambda) { \
|
||||||
|
.fn = (BzLambdaFn) lambdaName \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BZ_LAMBDA_BEGIN_CAPTURE(lambda) \
|
||||||
|
do { \
|
||||||
|
BzLambda *_lam = (lambda); \
|
||||||
|
_lam->captureSize = 0; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define BZ_LAMBDA_CAPTURE(lambda, var) \
|
||||||
|
do { \
|
||||||
|
BzLambda *_lam = (lambda); \
|
||||||
|
i32 _stackSize = _lam->captureSize; \
|
||||||
|
i32 _varSize = sizeof(var); \
|
||||||
|
assert(_stackSize + _varSize < (i32) sizeof(_lam->stack)); \
|
||||||
|
void *_location = &(var); \
|
||||||
|
bzMemCpy(&_lam->stack[_stackSize], _location, _varSize); \
|
||||||
|
_lam->captureSize += _varSize; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define BZ_LAMBDA_UNPACK_START() int32_t _stackOffset = 0
|
||||||
|
#define BZ_LAMBDA_UNPACK(type, name) \
|
||||||
|
type name = (_stackOffset += sizeof(type), \
|
||||||
|
assert(_stackOffset <= _lam->captureSize), \
|
||||||
|
*(type *) &_lam->stack[_stackOffset - sizeof(type)])
|
||||||
|
|
||||||
|
#define BZ_LAMBDA_CAST_RET(retType) (retType(*)(BzLambda *, ...))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note: C99 requires at least one argument for "..." in variadic macro,
|
||||||
|
* so we need to have 2 variants of CLAMBDA_CALL and CLAMBDA_DECL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define BZ_LAMBDA_CALL(lambda, retType, ...) ((BZ_LAMBDA_CAST_RET(retType)((lambda)->fn))(lambda, ##__VA_ARGS__))
|
||||||
|
#define BZ_LAMBDA_NOP_CALL(lambda, retType) ((BZ_LAMBDA_CAST_RET(retType)((lambda)->fn))(lambda))
|
||||||
|
|
||||||
|
#define BZ_LAMBDA_DECL(lambdaName, ...) lambdaName(BzLambda *_lam, ##__VA_ARGS__)
|
||||||
|
#define BZ_LAMBDA_NOP_DECL(lambdaName) lambdaName(BzLambda *_lam)
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BREEZE_LAMBDA_H
|
||||||
|
|
||||||
@@ -14,6 +14,9 @@ target_link_libraries(ecs_defer_test LINK_PRIVATE Breeze)
|
|||||||
add_executable(heap_test heap_test.c)
|
add_executable(heap_test heap_test.c)
|
||||||
target_link_libraries(heap_test LINK_PRIVATE Breeze)
|
target_link_libraries(heap_test LINK_PRIVATE Breeze)
|
||||||
|
|
||||||
|
add_executable(lambda_test lambda_test.c)
|
||||||
|
target_link_libraries(lambda_test LINK_PRIVATE Breeze)
|
||||||
|
|
||||||
add_executable(array_test array_test.c)
|
add_executable(array_test array_test.c)
|
||||||
target_link_libraries(array_test LINK_PRIVATE Breeze)
|
target_link_libraries(array_test LINK_PRIVATE Breeze)
|
||||||
|
|
||||||
|
|||||||
42
engine/tests/lambda_test.c
Normal file
42
engine/tests/lambda_test.c
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <breeze.h>
|
||||||
|
|
||||||
|
int BZ_LAMBDA_DECL(lambdaAdd, int a) {
|
||||||
|
BZ_LAMBDA_UNPACK_START();
|
||||||
|
BZ_LAMBDA_UNPACK(int, x); // still have access to x
|
||||||
|
|
||||||
|
return a + x;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BZ_LAMBDA_NOP_DECL(printArgs) {
|
||||||
|
BZ_LAMBDA_UNPACK_START();
|
||||||
|
BZ_LAMBDA_UNPACK(int, argc);
|
||||||
|
BZ_LAMBDA_UNPACK(char **, argv);
|
||||||
|
|
||||||
|
printf("Program arguments:\n");
|
||||||
|
for (int i = 0; i < argc; i++) {
|
||||||
|
printf("\t%s\n", argv[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BzLambda foo(int x) {
|
||||||
|
BzLambda lam = BZ_LAMBDA(lambdaAdd);
|
||||||
|
BZ_LAMBDA_BEGIN_CAPTURE(&lam);
|
||||||
|
BZ_LAMBDA_CAPTURE(&lam, x);
|
||||||
|
// x goes out of scope
|
||||||
|
return lam;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
|
||||||
|
BzLambda lambda1 = foo(8);
|
||||||
|
printf("%d\n", BZ_LAMBDA_CALL(&lambda1, int, 1));
|
||||||
|
|
||||||
|
BzLambda printLam = BZ_LAMBDA(printArgs);
|
||||||
|
BZ_LAMBDA_BEGIN_CAPTURE(&printLam);
|
||||||
|
BZ_LAMBDA_CAPTURE(&printLam, argc);
|
||||||
|
BZ_LAMBDA_CAPTURE(&printLam, argv);
|
||||||
|
BZ_LAMBDA_NOP_CALL(&printLam, void);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user