#ifndef CARYLL_SUPPORT_ELEMENT_IMPL_H #define CARYLL_SUPPORT_ELEMENT_IMPL_H #include "caryll/element.h" #include "otfcc-alloc.h" #ifndef __CARYLL_INLINE__ #ifdef _MSC_VER #define __CARYLL_INLINE__ __forceinline /* use __forceinline (VC++ specific) */ #else #define __CARYLL_INLINE__ inline /* use standard inline */ #endif #endif #define __NARG__(...) __NARG_I_(__VA_ARGS__, __RSEQ_N()) #define __NARG_I_(...) __ARG_N(__VA_ARGS__) #define __ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, \ _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, \ _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, \ _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, N, ...) \ N #define __RSEQ_N() \ 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, \ 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, \ 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 // general definition for any function name #define __CARYLL_VFUNC__2(name, n) name##n #define __CARYLL_VFUNC__1(name, n) __CARYLL_VFUNC__2(name, n) #define __CARYLLVFUNC(func, ...) __CARYLL_VFUNC__1(func, __NARG__(__VA_ARGS__))(__VA_ARGS__) #define caryll_trivialInit(T) \ static __CARYLL_INLINE__ void T##_init(MODIFY T *x) { \ memset(x, 0, sizeof(T)); \ } #define caryll_nonTrivialInit(T, __fn_init) \ static __CARYLL_INLINE__ void T##_init(MODIFY T *x) { \ (__fn_init)(x); \ } #define caryll_trivialEmpty(T) \ static __CARYLL_INLINE__ T T##_empty() { \ T x; \ T##_init(&x); \ return x; \ } #define caryll_trivialCreate(T) \ static __CARYLL_INLINE__ T *T##_create() { \ T *x = (T *)malloc(sizeof(T)); \ T##_init(x); \ return x; \ } #define caryll_trivialCopy(T) \ static __CARYLL_INLINE__ void T##_copy(MODIFY T *dst, const T *src) { \ memcpy(dst, src, sizeof(T)); \ } #define caryll_nonTrivialCopy(T, __fn_copy) \ static __CARYLL_INLINE__ void T##_copy(MODIFY T *dst, const T *src) { \ (__fn_copy)(dst, src); \ } #define caryll_trivialMove(T) \ static __CARYLL_INLINE__ void T##_move(MODIFY T *dst, T *src) { \ memcpy(dst, src, sizeof(T)); \ T##_init(src); \ } #define caryll_nonTrivialMove(T, __fn_move) \ static __CARYLL_INLINE__ void T##_move(MODIFY T *dst, T *src) { \ (__fn_move)(dst, src); \ T##_init(src); \ } #define caryll_trivialDispose(T) \ static __CARYLL_INLINE__ void T##_dispose(MODIFY T *x) { \ /* trivial */ \ } #define caryll_nonTrivialDispose(T, __fn_dispose) \ static __CARYLL_INLINE__ void T##_dispose(MODIFY T *x) { \ (__fn_dispose)(x); \ } #define caryll_trivialFree(T) \ static __CARYLL_INLINE__ void T##_free(MOVE T *x) { \ if (!x) return; \ T##_dispose(x); \ __caryll_free(x); \ } #define caryll_trivialDup(T) \ static __CARYLL_INLINE__ T T##_dup(const T src) { \ T dst; \ T##_copy(&dst, &src); \ return dst; \ } #define caryll_trivialReplace(T) \ static __CARYLL_INLINE__ void T##_replace(MODIFY T *dst, MOVE const T src) { \ T##_dispose(dst); \ memcpy(dst, &src, sizeof(T)); \ } \ static __CARYLL_INLINE__ void T##_copyReplace(MODIFY T *dst, const T src) { \ T##_dispose(dst); \ T##_copy(dst, &src); \ } #define caryll_standardTypeFn1(T) \ caryll_trivialInit(T) \ caryll_trivialCopy(T) \ caryll_trivialDispose(T) \ caryll_trivialMove(T) \ caryll_trivialReplace(T) #define caryll_standardTypeFn2(T, __fn_dispose) \ caryll_trivialInit(T) \ caryll_trivialCopy(T) \ caryll_nonTrivialDispose(T, __fn_dispose) \ caryll_trivialMove(T) \ caryll_trivialReplace(T) #define caryll_standardTypeFn3(T, __fn_init, __fn_dispose) \ caryll_nonTrivialInit(T, __fn_init) \ caryll_trivialCopy(T) \ caryll_nonTrivialDispose(T, __fn_dispose) \ caryll_trivialMove(T) \ caryll_trivialReplace(T) #define caryll_standardTypeFn4(T, __fn_init, __fn_copy, __fn_dispose) \ caryll_nonTrivialInit(T, __fn_init) \ caryll_nonTrivialCopy(T, __fn_copy) \ caryll_nonTrivialDispose(T, __fn_dispose) \ caryll_trivialMove(T) \ caryll_trivialReplace(T) #define caryll_standardTypeFn5(T, __fn_init, __fn_copy, __fn_dispose, __fn_move) \ caryll_nonTrivialInit(T, __fn_init) \ caryll_nonTrivialCopy(T, __fn_copy) \ caryll_nonTrivialDispose(T, __fn_dispose) \ caryll_nonTrivialMove(T, __fn_move) \ caryll_trivialReplace(T) #define caryll_standardTypeMethods(T) \ .init = T##_init, .copy = T##_copy, .dispose = T##_dispose, .move = T##_move, \ .replace = T##_replace, .copyReplace = T##_copyReplace #define caryll_standardRefTypeMethods(T) \ caryll_standardTypeMethods(T), .create = T##_create, .free = T##_free #define caryll_standardValTypeMethods(T) \ caryll_standardTypeMethods(T), .empty = T##_empty, .dup = T##_dup #define caryll_standardTypeFn(...) __CARYLLVFUNC(caryll_standardTypeFn, __VA_ARGS__) #ifdef __GNUC__ // GCC requires adding ## before __VA_ARGS__. // Make it happy. #define caryll_standardRefTypeFn(T, ...) \ caryll_standardTypeFn(T, ##__VA_ARGS__); \ caryll_trivialCreate(T); \ caryll_trivialFree(T); #define caryll_standardValTypeFn(T, ...) \ caryll_standardTypeFn(T, ##__VA_ARGS__); \ caryll_trivialEmpty(T); \ caryll_trivialDup(T); #define caryll_standardType(T, __name, ...) \ caryll_standardTypeFn(T, ##__VA_ARGS__); \ caryll_ElementInterfaceOf(T) __name = {caryll_standardTypeMethods(T)}; #define caryll_standardRefType(T, __name, ...) \ caryll_standardRefTypeFn(T, ##__VA_ARGS__); \ caryll_ElementInterfaceOf(T) __name = {caryll_standardRefTypeMethods(T)}; #define caryll_standardValType(T, __name, ...) \ caryll_standardValTypeFn(T, ##__VA_ARGS__); \ caryll_ElementInterfaceOf(T) __name = {caryll_standardValTypeMethods(T)}; #else #define caryll_standardRefTypeFn(T, ...) \ caryll_standardTypeFn(T, __VA_ARGS__) \ caryll_trivialCreate(T) \ caryll_trivialFree(T) #define caryll_standardValTypeFn(T, ...) \ caryll_standardTypeFn(T, __VA_ARGS__) \ caryll_trivialEmpty(T) \ caryll_trivialDup(T) #define caryll_standardType(T, __name, ...) \ caryll_standardTypeFn(T, __VA_ARGS__) \ caryll_ElementInterfaceOf(T) __name = {caryll_standardTypeMethods(T)} #define caryll_standardRefType(T, __name, ...) \ caryll_standardRefTypeFn(T, __VA_ARGS__) \ caryll_ElementInterfaceOf(T) __name = {caryll_standardRefTypeMethods(T)} #define caryll_standardValType(T, __name, ...) \ caryll_standardValTypeFn(T, __VA_ARGS__) \ caryll_ElementInterfaceOf(T) __name = {caryll_standardValTypeMethods(T)} #endif //// Traits // Show #define caryll_ShowFns(T, _fn_Show) \ static __CARYLL_INLINE__ void T##_show(const T a) { \ return (_fn_Show)(a); \ } #define caryll_ShowAssigns(T) .show = T##_show // Ord #define caryll_OrdFns(T, _fnCompare) \ static __CARYLL_INLINE__ int T##_compare(const T a, const T b) { \ return (_fnCompare)(a, b); \ } \ static __CARYLL_INLINE__ int T##_compareRef(const T *a, const T *b) { \ return (_fnCompare)(*a, *b); \ } #define caryll_OrdEqFns(T, _fnCompare) \ caryll_OrdFns(T, _fnCompare) \ static __CARYLL_INLINE__ bool T##_equal(const T a, const T b) { \ return !(_fnCompare)(a, b); \ } #define caryll_OrdEqAssigns(T) \ .compare = T##_compare, .compareRef = T##_compareRef, .equal = T##_equal // Monoid #define caryll_MonoidFns(T, _fn_neutral, _fn_inplacePlus) \ static __CARYLL_INLINE__ T T##_neutral() { \ return (_fn_neutral)(); \ } \ static __CARYLL_INLINE__ void T##_inplacePlus(MODIFY T *a, const T b) { \ (_fn_inplacePlus)(a, b); \ } \ static __CARYLL_INLINE__ T T##_plus(const T a, const T b) { \ T result = (_fn_neutral)(); \ (_fn_inplacePlus)(&result, a); \ (_fn_inplacePlus)(&result, b); \ return result; \ } #define caryll_MonoidAssigns(T) \ .neutral = T##_neutral, .inplacePlus = T##_inplacePlus, .plus = T##_plus // Group #define caryll_GroupFns(T, _fn_inplaceNegate) \ static __CARYLL_INLINE__ void T##_inplaceNegate(MODIFY T *a) { \ (_fn_inplaceNegate)(a); \ } \ static __CARYLL_INLINE__ T T##_negate(const T a) { \ T result; \ T##_copy(&result, &a); \ T##_inplaceNegate(&result); \ return result; \ } \ static __CARYLL_INLINE__ void T##_inplaceMinus(MODIFY T *a, const T b) { \ T tb = T##_negate(b); \ (T##_inplacePlus)(a, tb); \ T##_dispose(&tb); \ } \ static __CARYLL_INLINE__ T T##_minus(const T a, const T b) { \ T result = (T##_neutral)(); \ (T##_inplacePlus)(&result, a); \ (T##_inplaceMinus)(&result, b); \ return result; \ } #define caryll_GroupAssigns(T) \ .inplaceNegate = T##_inplaceNegate, .negate = T##_negate, .inplaceMinus = T##_inplaceMinus, \ .minus = T##_minus // Module #define caryll_ModuleFns(T, TS, _fn_inplaceScale) \ static __CARYLL_INLINE__ void T##_inplaceScale(MODIFY T *a, TS b) { \ (_fn_inplaceScale)(a, b); \ } \ static __CARYLL_INLINE__ T T##_scale(const T a, TS b) { \ T result; \ T##_copy(&result, &a); \ T##_inplaceScale(&result, b); \ return result; \ } \ static __CARYLL_INLINE__ void T##_inplacePlusScale(MODIFY T *a, TS b, const T c) { \ T x = T##_scale(c, b); \ T##_inplacePlus(a, x); \ T##_dispose(&x); \ } #define caryll_ModuleAssigns(T) \ .inplaceScale = T##_inplaceScale, .scale = T##_scale, .inplacePlusScale = T##_inplacePlusScale #endif