uCBQN/src/core/numarr.h
2022-01-06 01:17:10 +02:00

128 lines
4.2 KiB
C

typedef struct TyArr {
struct Arr;
char a[];
} TyArr;
typedef struct TySlice {
struct Slice;
void* a;
} TySlice;
#define TU I8
#define TP(W,X) W##i8##X
#include "tyarrTemplate.h"
#define TU I16
#define TP(W,X) W##i16##X
#include "tyarrTemplate.h"
#define TU I32
#define TP(W,X) W##i32##X
#include "tyarrTemplate.h"
#define TU F64
#define TP(W,X) W##f64##X
#include "tyarrTemplate.h"
typedef TyArr BitArr;
// bit array stuff
#define BIT_N(IA) (((IA)+63) >> 6) // u64 count needed to store IA bits
static inline void bitp_set(u64* arr, u64 n, bool v) {
u64 m = ((u64)1)<<(n&63);
if (v) arr[n>>6]|= m;
else arr[n>>6]&= ~m;
// arr[n>>6] = (arr[n>>6]&(~m)) | (((u64)v)<<(n&63));
}
static inline bool bitp_get(u64* arr, u64 n) {
return (arr[n>>6] >> (n&63)) & 1;
}
static inline u64 bitp_l0(u64* arr, u64 ia) { // last u64 of the array, with the tail set to 0s
return ia&63? arr[ia>>6]&((1ULL<<(ia&63))-1) : 0;
}
static inline u64 bitp_l1(u64* arr, u64 ia) { // last u64 of the array, with the tail set to 1s
return ia&63? arr[ia>>6]|~((1ULL<<(ia&63))-1) : ~0ULL;
}
static inline u64 bitx(B x) { // repeats the boolean across all 64 bits
return o2bu(x)? ~(u64)0 : 0;
}
// BitArr
#define BITARR_SZ(IA) fsizeof(BitArr, a, u64, BIT_N(IA))
static B m_bitarrv(u64** p, usz ia) {
BitArr* r = m_arr(BITARR_SZ(ia), t_bitarr, ia);
arr_shVec((Arr*)r);
*p = (u64*)r->a;
return taga(r);
}
static B m_bitarrc(u64** p, B x) { assert(isArr(x));
BitArr* r = m_arr(BITARR_SZ(a(x)->ia), t_bitarr, a(x)->ia);
*p = (u64*)r->a;
arr_shCopy((Arr*)r, x);
return taga(r);
}
static Arr* m_bitarrp(u64** p, usz ia) {
BitArr* r = m_arr(BITARR_SZ(ia), t_bitarr, ia);
*p = (u64*)r->a;
return (Arr*)r;
}
static u64* bitarr_ptr(B x) { VTY(x, t_bitarr); return (u64*)c(BitArr,x)->a; }
static u64* bitarrv_ptr(TyArr* x) { return (u64*)x->a; }
I8Arr* cpyI8Arr (B x); // consumes
I16Arr* cpyI16Arr(B x); // consumes
I32Arr* cpyI32Arr(B x); // consumes
F64Arr* cpyF64Arr(B x); // consumes
BitArr* cpyBitArr(B x); // consumes
// all consume x
static I8Arr* toI8Arr (B x) { return v(x)->type==t_i8arr ? c(I8Arr, x) : cpyI8Arr (x); }
static I16Arr* toI16Arr(B x) { return v(x)->type==t_i16arr? c(I16Arr,x) : cpyI16Arr(x); }
static I32Arr* toI32Arr(B x) { return v(x)->type==t_i32arr? c(I32Arr,x) : cpyI32Arr(x); }
static F64Arr* toF64Arr(B x) { return v(x)->type==t_f64arr? c(F64Arr,x) : cpyF64Arr(x); }
static BitArr* toBitArr(B x) { return v(x)->type==t_bitarr? c(BitArr,x) : cpyBitArr(x); }
static B toI8Any (B x) { u8 t=v(x)->type; return t==t_i8arr || t==t_i8slice ? x : taga(cpyI8Arr (x)); }
static B toI16Any(B x) { u8 t=v(x)->type; return t==t_i16arr || t==t_i16slice? x : taga(cpyI16Arr(x)); }
static B toI32Any(B x) { u8 t=v(x)->type; return t==t_i32arr || t==t_i32slice? x : taga(cpyI32Arr(x)); }
static B toF64Any(B x) { u8 t=v(x)->type; return t==t_f64arr || t==t_f64slice? x : taga(cpyF64Arr(x)); }
B m_cai32(usz ia, i32* a);
B m_caf64(usz sz, f64* a);
static i64 bit_sum(u64* x, u64 am) {
i64 r = 0;
for (u64 i = 0; i < (am>>6); i++) r+= POPC(x[i]);
if (am&63) r+= POPC(x[am>>6]<<(64-am & 63));
return r;
}
static u64 usum(B x) { // doesn't consume; may error
assert(isArr(x));
u64 r = 0;
usz xia = a(x)->ia;
u8 xe = TI(x,elType);
if (xe==el_bit) return bit_sum(bitarr_ptr(x), xia);
else if (xe==el_i8 ) { i8* p = i8any_ptr (x); for (usz i = 0; i < xia; i++) { if (RARE(p[i]<0)) goto neg; r+= p[i]; } }
else if (xe==el_i16) { i16* p = i16any_ptr(x); for (usz i = 0; i < xia; i++) { if (RARE(p[i]<0)) goto neg; if (addOn(r,p[i])) goto overflow; } }
else if (xe==el_i32) { i32* p = i32any_ptr(x); for (usz i = 0; i < xia; i++) { if (RARE(p[i]<0)) goto neg; if (addOn(r,p[i])) goto overflow; } }
else if (xe==el_f64) {
f64* p = f64any_ptr(x);
for (usz i = 0; i < xia; i++) {
f64 c = p[i];
u64 ci = (u64)c;
if (c!=ci) thrM("Expected integer");
if (ci<0) goto neg;
if (addOn(r,ci)) goto overflow;
}
} else {
SGetU(x)
for (usz i = 0; i < xia; i++) {
u64 c = o2u64(GetU(x,i));
if (c<0) thrM("Didn't expect negative integer");
if (addOn(r,c)) goto overflow;
}
}
return r;
overflow: thrM("Sum too big");
neg: thrM("Didn't expect negative integer");
}