#include "sl.h"#include "operators.h"#include "cvalues.h"#include "types.h"#include "io.h"#include "equal.h" enum { MAX_INL_SIZE = 384, CVALUE_NWORDS = sizeof(sl_cv)/sizeof(sl_v), CV_OWNED = 1<<0,}; #define owned(cv) ((uintptr)(cv)->type & CV_OWNED) sl_type notype = {0};sl_type *unboxedtypes[T_UNBOXED_NUM];sl_v unboxedtypesyms[T_UNBOXED_NUM]; static void cvalue_init(sl_type *type, sl_v v, void *dest); voidadd_finalizer(sl_cv *cv){ if(slvm.nfinalizers == slvm.maxfinalizers){ slvm.maxfinalizers *= 2; slvm.finalizers = MEM_REALLOC(slvm.finalizers, slvm.maxfinalizers*sizeof(slvm.finalizers)); assert(slvm.finalizers != nil); } slvm.finalizers[slvm.nfinalizers++] = cv;} voidsweep_cv(sl_cv *cv){ sl_type *t = cv_class(cv); if(t->vtable != nil && t->vtable->finalize != nil) t->vtable->finalize(tagptr(cv, TAG_CVALUE)); if(!isinlined(cv) && owned(cv)){ MEM_FREE(cv_data(cv)); } cv->type = ¬ype;} // remove dead objects from finalization list in-placevoidsweep_finalizers(void){ sl_cv **lst = slvm.finalizers; usize n = 0, ndel = 0, l = slvm.nfinalizers; sl_cv *tmp;#define SWAP_sf(a, b) (tmp = a, a = b, b = tmp, 1) if(l == 0) return; do{ tmp = lst[n]; if(isforwarded((sl_v)tmp)){ // object is alive lst[n] = ptr(forwardloc((sl_v)tmp)); n++; }else{ sweep_cv(tmp); ndel++; } }while((n < l-ndel) && SWAP_sf(lst[n], lst[n+ndel])); slvm.nfinalizers -= ndel; slvm.malloc_pressure = 0;} // compute the size of the metadata object for a cvaluestatic usizecv_nwords(sl_cv *cv){ if(!isinlined(cv)) return CVALUE_NWORDS; usize n = cv_len(cv); if(cv_isstr(cv)) n++; return CVALUE_NWORDS + NWORDS(n);} voidcv_autorelease(sl_cv *cv){ cv->type = (sl_type*)(((uintptr)cv->type) | CV_OWNED); add_finalizer(cv);} voidcvalue_cutdown(sl_v cv, usize nb){ sl_cv *pcv = ptr(cv); bool isstr = cv_isstr(pcv); if(isinlined(pcv)) pcv->len = nb; else pcv->data = MEM_REALLOC(pcv->data, nb+(isstr ? 1 : 0)); if(isstr) ((char*)pcv->data)[nb] = 0;} sl_vcvalue_(sl_type *type, usize sz, bool nofinalize){ assert(type != nil); bool str = false; if(type->eltype == sl_utf8type){ if(sz == 0) return sl_emptystr; sz++; str = true; } sl_cv *pcv; if(sz <= MAX_INL_SIZE){ usize nw = CVALUE_NWORDS + NWORDS(sz); pcv = alloc_words(nw); pcv->type = type; pcv->data = pcv->_space; if(!nofinalize && type->vtable != nil && type->vtable->finalize != nil) add_finalizer(pcv); }else{ if(slvm.malloc_pressure > ALLOC_LIMIT_TRIGGER) sl_gc(false); pcv = alloc_words(CVALUE_NWORDS); pcv->type = type; pcv->data = MEM_ALLOC(sz); cv_autorelease(pcv); slvm.malloc_pressure += sz; } if(str){ ((char*)pcv->data)[--sz] = '\0'; if(!isinlined(pcv)){ pcv->startbytes = 0; pcv->startrune = 0; } } pcv->len = sz; return tagptr(pcv, TAG_CVALUE);} // this effectively dereferences a pointer// just like *p in C, it only removes a level of indirection from the type,// it doesn't copy any data.// this method of creating a cvalue only allocates metadata.// ptr is user-managed; we don't autorelease it unless the// user explicitly calls (autorelease ) on the result of this function.// 'parent' is an optional cvalue that this pointer is known to point// into; NIL if none.sl_vcvalue_from_ref(sl_type *type, void *ptr, usize sz){ sl_cv *pcv; assert(type != nil); assert(ptr != nil); pcv = alloc_words(CVALUE_NWORDS); pcv->data = ptr; pcv->len = sz; pcv->type = type; pcv->startbytes = 0; pcv->startrune = 0; return tagptr(pcv, TAG_CVALUE);} sl_vcvalue_str(usize sz){ if(sz == 0) return sl_emptystr; return cvalue(sl_strtype, sz);} sl_vcvalue_static_cstr(const char *str){ if(*str == 0) return sl_emptystr; return cvalue_from_ref(sl_strtype, (char*)str, strlen(str));} sl_vstr_from_cstrn(char *str, usize n){ sl_v v = cvalue_str(n); memcpy(cvalue_data(v), str, n); return v;} sl_vstr_from_cstr(char *str){ return str_from_cstrn(str, strlen(str));} boolisstr(sl_v v){ return iscvalue(v) && cv_isstr(ptr(v));} // convert to malloc representation (fixed address)voidcv_pin(sl_cv *cv){ if(!isinlined(cv)) return; usize sz = cv_len(cv); if(cv_isstr(cv)) sz++; void *data = MEM_ALLOC(sz); memcpy(data, cv_data(cv), sz); cv->data = data; cv_autorelease(cv);} static voidcvalue_rune_init(sl_type *type, sl_v a, void *dest){ Rune r; USED(type); if(isfixnum(a)) r = numval(a); else if(isrune(a)) r = torune(a); else if(iscvalue(a)) r = conv_to_u32(a, cv_data(ptr(a)), cv_numtype(ptr(a))); else if(isubnum(a)){ sl_fx v = ubnumval(a); sl_numtype nt = ubnumtype(a); r = conv_to_u32(a, ubnumptr(v, nt), nt); }else cthrow(type_error(nil, "num", a), type); if(r >= 0xd800 && r <= 0xdfff) cthrow(lerrorf(sl_errarg, "invalid rune: utf-16 surrogate pair: 0x%"PRIx32, (u32int)r), type); if(r > 0x10ffff) cthrow(lerrorf(sl_errarg, "invalid rune: outside of valid range: 0x%"PRIx32, (u32int)r), type); *((Rune*)dest) = r;} #define num_init(ctype, cnvt, tag) \ static void \ cvalue_##ctype##_init(sl_type *type, sl_v a, void *dest) \ { \ ctype n; \ USED(type); \ if(isfixnum(a)){ \ n = (ctype)numval(a); \ }else if(isubnum(a)){ \ sl_fx v = ubnumval(a); \ sl_numtype nt = ubnumtype(a); \ n = (ctype)conv_to_##cnvt(a, ubnumptr(v, nt), nt); \ }else if(iscvalue(a)){ \ n = (ctype)conv_to_##cnvt(a, cv_data(ptr(a)), cv_numtype(ptr(a))); \ }else \ cthrow(type_error(nil, "num", a), type); \ *((ctype*)dest) = n; \ } typedef u32int u32ptr;typedef u64int u64ptr;typedef float f32;typedef double f64; num_init(s8int, s32, T_S8)num_init(u8int, u32, T_U8)num_init(s16int, s32, T_S16)num_init(u16int, u32, T_U16)num_init(s32int, s32, T_S32)num_init(u32int, u32, T_U32)num_init(s64int, s64, T_S64)num_init(u64int, u64, T_U64)num_init(u32ptr, p32, T_P32)num_init(u64ptr, p64, T_P64)num_init(f32, double, T_F32)num_init(f64, double, T_F64) sl_purefnBUILTIN("rune", rune){ if(nargs == 0){ PUSH(fixnum(Runeerror)); args = sl.sp-1; }else argcount(nargs, 1); Rune r; cvalue_rune_init(sl_runetype, args[0], &r); return mk_rune(r);} #define num_ctor_init(typenam, ctype, tag) \ static \ BUILTIN(#typenam, typenam) \ { \ if(nargs == 0){ \ PUSH(fixnum(0)); \ args = sl.sp-1; \ }else \ argcount(nargs, 1); \ sl_v v = cvalue(sl_##typenam##type, sizeof(ctype)); \ cvalue_##ctype##_init(sl_##typenam##type, args[0], cvalue_data(v)); \ return v; \ } #define num_ctor_init_unboxed(typenam, ctype, tag) \ static \ BUILTIN(#typenam, typenam) \ { \ if(nargs == 0){ \ PUSH(fixnum(0)); \ args = sl.sp-1; \ }else \ argcount(nargs, 1); \ sl_v v; \ ctype n; \ cvalue_##ctype##_init(sl_##typenam##type, args[0], &n); \ if(tag < T_UNBOXED_NUM && \ (sizeof(n) < sizeof(sl_fx) || (sizeof(n) == sizeof(sl_fx) && fits_bits(n, UNBOXED_BITS-1)))){ \ v = (sl_v)n<<TAG_EXT_BITS | tag<<TAG_UBNUM_SHIFT | TAG_UNBOXED; \ }else{ \ v = cvalue(sl_##typenam##type, sizeof(n)); \ *(ctype*)cvalue_data(v) = n; \ } \ return v; \ } #define num_ctor_ctor(typenam, ctype, tag) \ sl_v \ mk_##typenam(ctype n) \ { \ sl_v v = cvalue(sl_##typenam##type, sizeof(n)); \ *(ctype*)cvalue_data(v) = n; \ return v; \ } #define num_ctor_ctor_unboxed(typenam, ctype, tag) \ sl_v \ mk_##typenam(ctype n) \ { \ sl_v v; \ if(tag < T_UNBOXED_NUM && \ (sizeof(n) < sizeof(sl_fx) || (sizeof(n) == sizeof(sl_fx) && fits_bits(n, UNBOXED_BITS-1)))){ \ v = (sl_v)n<<TAG_EXT_BITS | tag<<TAG_UBNUM_SHIFT | TAG_UNBOXED; \ }else{ \ v = cvalue(sl_##typenam##type, sizeof(n)); \ *(ctype*)cvalue_data(v) = n; \ } \ return v; \ } #define num_ctor(typenam, ctype, tag) \ num_ctor_ctor(typenam, ctype, tag) \ num_ctor_init(typenam, ctype, tag) \ #define num_ctor_unboxed(typenam, ctype, tag) \ num_ctor_ctor_unboxed(typenam, ctype, tag) \ num_ctor_init_unboxed(typenam, ctype, tag) \ #if defined(BITS64)#define sl_constfn64 sl_constfn#else#define sl_constfn64#endif sl_constfn num_ctor_unboxed(s8, s8int, T_S8)sl_constfn num_ctor_unboxed(u8, u8int, T_U8)sl_constfn num_ctor_unboxed(s16, s16int, T_S16)sl_constfn num_ctor_unboxed(u16, u16int, T_U16)sl_constfn64 num_ctor_unboxed(s32, s32int, T_S32)sl_constfn64 num_ctor_unboxed(u32, u32int, T_U32)sl_constfn64 num_ctor_unboxed(p32, u32ptr, T_P32)num_ctor_unboxed(s64, s64int, T_S64)num_ctor_unboxed(u64, u64int, T_U64)num_ctor_unboxed(p64, u64ptr, T_P64)num_ctor(f32, f32, T_F32)num_ctor(f64, f64, T_F64) static voidcvalue_bignum_init(sl_type *type, sl_v a, void *dest){ mpint *n; USED(type); if(isfixnum(a)) n = vtomp(numval(a), nil); else if(isubnum(a)){ sl_fx v = ubnumval(a); sl_numtype nt = ubnumtype(a); n = conv_to_bignum(a, ubnumptr(v, nt), nt); }else if(iscvalue(a)){ sl_cv *cv = ptr(a); void *p = cv_data(cv); n = conv_to_bignum(a, p, cv_numtype(cv)); }else cthrow(type_error(nil, "num", a), type); *((mpint**)dest) = n;} BUILTIN("bignum", bignum){ if(nargs == 0){ PUSH(fixnum(0)); args = sl.sp-1; }else argcount(nargs, 1); sl_v cv = cvalue(sl_bignumtype, sizeof(mpint*)); cvalue_bignum_init(sl_bignumtype, args[0], cvalue_data(cv)); return cv;} sl_vmk_bignum(mpint *n){ sl_v cv = cvalue(sl_bignumtype, sizeof(mpint*)); *(mpint**)cvalue_data(cv) = n; return cv;} static voidfree_bignum(sl_v self){ mpint **s = value2c(mpint**, self); if(*s != mpzero && *s != mpone && *s != mptwo) mpfree(*s);} static sl_cvtable bignum_vtable = { nil, nil, free_bignum, nil, nil }; sl_constfnsl_vsize_wrap(usize sz){ if(sizeof(usize) == 8) return fits_fixnum(sz) ? fixnum(sz): mk_u64(sz); else return fits_fixnum(sz) ? fixnum(sz): mk_u32(sz);} usizetosize(sl_v n){ if(sl_unlikely(iscvalue(n))){ if(sl_likely(numeric_compare(n, fixnum(0), false, true) >= 0)){ sl_cv *cv = ptr(n); if(sizeof(usize) > 4) return conv_to_u64(n, cv_data(cv), cv_numtype(cv)); return conv_to_u32(n, cv_data(cv), cv_numtype(cv)); } }else{ sl_fx x; if(sl_likely(isfixnum(n))) x = numval(n); else if(isubnum(n)) x = ubnumval(n); else cthrow(type_error(nil, "num", n), n); if(x >= 0) return x; } cthrow(lerrorf(sl_errarg, "tosize: negative value"), n);} soffsettooffset(sl_v n){ if(isfixnum(n)) return numval(n); if(isubnum(n)) return ubnumval(n); if(iscvalue(n)){ sl_cv *cv = ptr(n); if(sizeof(usize) > 4) return conv_to_s64(n, cv_data(cv), cv_numtype(cv)); return conv_to_s32(n, cv_data(cv), cv_numtype(cv)); } cthrow(type_error(nil, "num", n), n);} boolisarr(sl_v v){ return iscvalue(v) && cv_class(ptr(v))->eltype != nil;} static usizepredict_arrlen(sl_v arg){ if(isvec(arg)) return vec_size(arg); if(iscons(arg)) return llength(arg); if(arg == sl_nil) return 0; if(isarr(arg)) return cvalue_arrlen(arg); return 1;} Lines 1–500 of 1560. Load more
#include "sl.h" #include "operators.h" #include "cvalues.h" #include "types.h" #include "io.h" #include "equal.h" enum { MAX_INL_SIZE = 384, CVALUE_NWORDS = sizeof(sl_cv)/sizeof(sl_v), CV_OWNED = 1<<0, }; #define owned(cv) ((uintptr)(cv)->type & CV_OWNED) sl_type notype = {0}; sl_type *unboxedtypes[T_UNBOXED_NUM]; sl_v unboxedtypesyms[T_UNBOXED_NUM]; static void cvalue_init(sl_type *type, sl_v v, void *dest); void add_finalizer(sl_cv *cv) { if(slvm.nfinalizers == slvm.maxfinalizers){ slvm.maxfinalizers *= 2; slvm.finalizers = MEM_REALLOC(slvm.finalizers, slvm.maxfinalizers*sizeof(slvm.finalizers)); assert(slvm.finalizers != nil); } slvm.finalizers[slvm.nfinalizers++] = cv; } void sweep_cv(sl_cv *cv) { sl_type *t = cv_class(cv); if(t->vtable != nil && t->vtable->finalize != nil) t->vtable->finalize(tagptr(cv, TAG_CVALUE)); if(!isinlined(cv) && owned(cv)){ MEM_FREE(cv_data(cv)); } cv->type = ¬ype; } // remove dead objects from finalization list in-place void sweep_finalizers(void) { sl_cv **lst = slvm.finalizers; usize n = 0, ndel = 0, l = slvm.nfinalizers; sl_cv *tmp; #define SWAP_sf(a, b) (tmp = a, a = b, b = tmp, 1) if(l == 0) return; do{ tmp = lst[n]; if(isforwarded((sl_v)tmp)){ // object is alive lst[n] = ptr(forwardloc((sl_v)tmp)); n++; }else{ sweep_cv(tmp); ndel++; } }while((n < l-ndel) && SWAP_sf(lst[n], lst[n+ndel])); slvm.nfinalizers -= ndel; slvm.malloc_pressure = 0; } // compute the size of the metadata object for a cvalue static usize cv_nwords(sl_cv *cv) { if(!isinlined(cv)) return CVALUE_NWORDS; usize n = cv_len(cv); if(cv_isstr(cv)) n++; return CVALUE_NWORDS + NWORDS(n); } void cv_autorelease(sl_cv *cv) { cv->type = (sl_type*)(((uintptr)cv->type) | CV_OWNED); add_finalizer(cv); } void cvalue_cutdown(sl_v cv, usize nb) { sl_cv *pcv = ptr(cv); bool isstr = cv_isstr(pcv); if(isinlined(pcv)) pcv->len = nb; else pcv->data = MEM_REALLOC(pcv->data, nb+(isstr ? 1 : 0)); if(isstr) ((char*)pcv->data)[nb] = 0; } sl_v cvalue_(sl_type *type, usize sz, bool nofinalize) { assert(type != nil); bool str = false; if(type->eltype == sl_utf8type){ if(sz == 0) return sl_emptystr; sz++; str = true; } sl_cv *pcv; if(sz <= MAX_INL_SIZE){ usize nw = CVALUE_NWORDS + NWORDS(sz); pcv = alloc_words(nw); pcv->type = type; pcv->data = pcv->_space; if(!nofinalize && type->vtable != nil && type->vtable->finalize != nil) add_finalizer(pcv); }else{ if(slvm.malloc_pressure > ALLOC_LIMIT_TRIGGER) sl_gc(false); pcv = alloc_words(CVALUE_NWORDS); pcv->type = type; pcv->data = MEM_ALLOC(sz); cv_autorelease(pcv); slvm.malloc_pressure += sz; } if(str){ ((char*)pcv->data)[--sz] = '\0'; if(!isinlined(pcv)){ pcv->startbytes = 0; pcv->startrune = 0; } } pcv->len = sz; return tagptr(pcv, TAG_CVALUE); } // this effectively dereferences a pointer // just like *p in C, it only removes a level of indirection from the type, // it doesn't copy any data. // this method of creating a cvalue only allocates metadata. // ptr is user-managed; we don't autorelease it unless the // user explicitly calls (autorelease ) on the result of this function. // 'parent' is an optional cvalue that this pointer is known to point // into; NIL if none. sl_v cvalue_from_ref(sl_type *type, void *ptr, usize sz) { sl_cv *pcv; assert(type != nil); assert(ptr != nil); pcv = alloc_words(CVALUE_NWORDS); pcv->data = ptr; pcv->len = sz; pcv->type = type; pcv->startbytes = 0; pcv->startrune = 0; return tagptr(pcv, TAG_CVALUE); } sl_v cvalue_str(usize sz) { if(sz == 0) return sl_emptystr; return cvalue(sl_strtype, sz); } sl_v cvalue_static_cstr(const char *str) { if(*str == 0) return sl_emptystr; return cvalue_from_ref(sl_strtype, (char*)str, strlen(str)); } sl_v str_from_cstrn(char *str, usize n) { sl_v v = cvalue_str(n); memcpy(cvalue_data(v), str, n); return v; } sl_v str_from_cstr(char *str) { return str_from_cstrn(str, strlen(str)); } bool isstr(sl_v v) { return iscvalue(v) && cv_isstr(ptr(v)); } // convert to malloc representation (fixed address) void cv_pin(sl_cv *cv) { if(!isinlined(cv)) return; usize sz = cv_len(cv); if(cv_isstr(cv)) sz++; void *data = MEM_ALLOC(sz); memcpy(data, cv_data(cv), sz); cv->data = data; cv_autorelease(cv); } static void cvalue_rune_init(sl_type *type, sl_v a, void *dest) { Rune r; USED(type); if(isfixnum(a)) r = numval(a); else if(isrune(a)) r = torune(a); else if(iscvalue(a)) r = conv_to_u32(a, cv_data(ptr(a)), cv_numtype(ptr(a))); else if(isubnum(a)){ sl_fx v = ubnumval(a); sl_numtype nt = ubnumtype(a); r = conv_to_u32(a, ubnumptr(v, nt), nt); }else cthrow(type_error(nil, "num", a), type); if(r >= 0xd800 && r <= 0xdfff) cthrow(lerrorf(sl_errarg, "invalid rune: utf-16 surrogate pair: 0x%"PRIx32, (u32int)r), type); if(r > 0x10ffff) cthrow(lerrorf(sl_errarg, "invalid rune: outside of valid range: 0x%"PRIx32, (u32int)r), type); *((Rune*)dest) = r; } #define num_init(ctype, cnvt, tag) \ static void \ cvalue_##ctype##_init(sl_type *type, sl_v a, void *dest) \ { \ ctype n; \ USED(type); \ if(isfixnum(a)){ \ n = (ctype)numval(a); \ }else if(isubnum(a)){ \ sl_fx v = ubnumval(a); \ sl_numtype nt = ubnumtype(a); \ n = (ctype)conv_to_##cnvt(a, ubnumptr(v, nt), nt); \ }else if(iscvalue(a)){ \ n = (ctype)conv_to_##cnvt(a, cv_data(ptr(a)), cv_numtype(ptr(a))); \ }else \ cthrow(type_error(nil, "num", a), type); \ *((ctype*)dest) = n; \ } typedef u32int u32ptr; typedef u64int u64ptr; typedef float f32; typedef double f64; num_init(s8int, s32, T_S8) num_init(u8int, u32, T_U8) num_init(s16int, s32, T_S16) num_init(u16int, u32, T_U16) num_init(s32int, s32, T_S32) num_init(u32int, u32, T_U32) num_init(s64int, s64, T_S64) num_init(u64int, u64, T_U64) num_init(u32ptr, p32, T_P32) num_init(u64ptr, p64, T_P64) num_init(f32, double, T_F32) num_init(f64, double, T_F64) sl_purefn BUILTIN("rune", rune) { if(nargs == 0){ PUSH(fixnum(Runeerror)); args = sl.sp-1; }else argcount(nargs, 1); Rune r; cvalue_rune_init(sl_runetype, args[0], &r); return mk_rune(r); } #define num_ctor_init(typenam, ctype, tag) \ static \ BUILTIN(#typenam, typenam) \ { \ if(nargs == 0){ \ PUSH(fixnum(0)); \ args = sl.sp-1; \ }else \ argcount(nargs, 1); \ sl_v v = cvalue(sl_##typenam##type, sizeof(ctype)); \ cvalue_##ctype##_init(sl_##typenam##type, args[0], cvalue_data(v)); \ return v; \ } #define num_ctor_init_unboxed(typenam, ctype, tag) \ static \ BUILTIN(#typenam, typenam) \ { \ if(nargs == 0){ \ PUSH(fixnum(0)); \ args = sl.sp-1; \ }else \ argcount(nargs, 1); \ sl_v v; \ ctype n; \ cvalue_##ctype##_init(sl_##typenam##type, args[0], &n); \ if(tag < T_UNBOXED_NUM && \ (sizeof(n) < sizeof(sl_fx) || (sizeof(n) == sizeof(sl_fx) && fits_bits(n, UNBOXED_BITS-1)))){ \ v = (sl_v)n<<TAG_EXT_BITS | tag<<TAG_UBNUM_SHIFT | TAG_UNBOXED; \ }else{ \ v = cvalue(sl_##typenam##type, sizeof(n)); \ *(ctype*)cvalue_data(v) = n; \ } \ return v; \ } #define num_ctor_ctor(typenam, ctype, tag) \ sl_v \ mk_##typenam(ctype n) \ { \ sl_v v = cvalue(sl_##typenam##type, sizeof(n)); \ *(ctype*)cvalue_data(v) = n; \ return v; \ } #define num_ctor_ctor_unboxed(typenam, ctype, tag) \ sl_v \ mk_##typenam(ctype n) \ { \ sl_v v; \ if(tag < T_UNBOXED_NUM && \ (sizeof(n) < sizeof(sl_fx) || (sizeof(n) == sizeof(sl_fx) && fits_bits(n, UNBOXED_BITS-1)))){ \ v = (sl_v)n<<TAG_EXT_BITS | tag<<TAG_UBNUM_SHIFT | TAG_UNBOXED; \ }else{ \ v = cvalue(sl_##typenam##type, sizeof(n)); \ *(ctype*)cvalue_data(v) = n; \ } \ return v; \ } #define num_ctor(typenam, ctype, tag) \ num_ctor_ctor(typenam, ctype, tag) \ num_ctor_init(typenam, ctype, tag) \ #define num_ctor_unboxed(typenam, ctype, tag) \ num_ctor_ctor_unboxed(typenam, ctype, tag) \ num_ctor_init_unboxed(typenam, ctype, tag) \ #if defined(BITS64) #define sl_constfn64 sl_constfn #else #define sl_constfn64 #endif sl_constfn num_ctor_unboxed(s8, s8int, T_S8) sl_constfn num_ctor_unboxed(u8, u8int, T_U8) sl_constfn num_ctor_unboxed(s16, s16int, T_S16) sl_constfn num_ctor_unboxed(u16, u16int, T_U16) sl_constfn64 num_ctor_unboxed(s32, s32int, T_S32) sl_constfn64 num_ctor_unboxed(u32, u32int, T_U32) sl_constfn64 num_ctor_unboxed(p32, u32ptr, T_P32) num_ctor_unboxed(s64, s64int, T_S64) num_ctor_unboxed(u64, u64int, T_U64) num_ctor_unboxed(p64, u64ptr, T_P64) num_ctor(f32, f32, T_F32) num_ctor(f64, f64, T_F64) static void cvalue_bignum_init(sl_type *type, sl_v a, void *dest) { mpint *n; USED(type); if(isfixnum(a)) n = vtomp(numval(a), nil); else if(isubnum(a)){ sl_fx v = ubnumval(a); sl_numtype nt = ubnumtype(a); n = conv_to_bignum(a, ubnumptr(v, nt), nt); }else if(iscvalue(a)){ sl_cv *cv = ptr(a); void *p = cv_data(cv); n = conv_to_bignum(a, p, cv_numtype(cv)); }else cthrow(type_error(nil, "num", a), type); *((mpint**)dest) = n; } BUILTIN("bignum", bignum) { if(nargs == 0){ PUSH(fixnum(0)); args = sl.sp-1; }else argcount(nargs, 1); sl_v cv = cvalue(sl_bignumtype, sizeof(mpint*)); cvalue_bignum_init(sl_bignumtype, args[0], cvalue_data(cv)); return cv; } sl_v mk_bignum(mpint *n) { sl_v cv = cvalue(sl_bignumtype, sizeof(mpint*)); *(mpint**)cvalue_data(cv) = n; return cv; } static void free_bignum(sl_v self) { mpint **s = value2c(mpint**, self); if(*s != mpzero && *s != mpone && *s != mptwo) mpfree(*s); } static sl_cvtable bignum_vtable = { nil, nil, free_bignum, nil, nil }; sl_constfn sl_v size_wrap(usize sz) { if(sizeof(usize) == 8) return fits_fixnum(sz) ? fixnum(sz): mk_u64(sz); else return fits_fixnum(sz) ? fixnum(sz): mk_u32(sz); } usize tosize(sl_v n) { if(sl_unlikely(iscvalue(n))){ if(sl_likely(numeric_compare(n, fixnum(0), false, true) >= 0)){ sl_cv *cv = ptr(n); if(sizeof(usize) > 4) return conv_to_u64(n, cv_data(cv), cv_numtype(cv)); return conv_to_u32(n, cv_data(cv), cv_numtype(cv)); } }else{ sl_fx x; if(sl_likely(isfixnum(n))) x = numval(n); else if(isubnum(n)) x = ubnumval(n); else cthrow(type_error(nil, "num", n), n); if(x >= 0) return x; } cthrow(lerrorf(sl_errarg, "tosize: negative value"), n); } soffset tooffset(sl_v n) { if(isfixnum(n)) return numval(n); if(isubnum(n)) return ubnumval(n); if(iscvalue(n)){ sl_cv *cv = ptr(n); if(sizeof(usize) > 4) return conv_to_s64(n, cv_data(cv), cv_numtype(cv)); return conv_to_s32(n, cv_data(cv), cv_numtype(cv)); } cthrow(type_error(nil, "num", n), n); } bool isarr(sl_v v) { return iscvalue(v) && cv_class(ptr(v))->eltype != nil; } static usize predict_arrlen(sl_v arg) { if(isvec(arg)) return vec_size(arg); if(iscons(arg)) return llength(arg); if(arg == sl_nil) return 0; if(isarr(arg)) return cvalue_arrlen(arg); return 1; }