summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Mikkelsen <petermikkelsen10@gmail.com>2022-01-29 18:35:50 +0000
committerPeter Mikkelsen <petermikkelsen10@gmail.com>2022-01-29 18:35:50 +0000
commit219e5103271f439ab9ed64ae892e4ab6096bb236 (patch)
tree997ee57079447e7266b5d04889d21e06f12453e5
parent1ea2f6f8af7ef012005d46fd13acd082628f7295 (diff)
Rewrite replicate in C. The implementation is much like that of expand
-rw-r--r--hybrids.c71
1 files changed, 65 insertions, 6 deletions
diff --git a/hybrids.c b/hybrids.c
index 601898f..8042e5d 100644
--- a/hybrids.c
+++ b/hybrids.c
@@ -36,12 +36,71 @@ fnExpandLast(Array *left, Array *right)
Array *
fnReplicateFirst(Array *left, Array *right)
{
- Rune *code =
- L"(0=≢⍴⍵)∧⍺∧.=0: 0⍴⍵ ⋄"
- L"⍺∧.=0: (((1,¯1+≢⍴⍵)⌿¯1 1)⌿⍴⍵)⍴⍵ ⋄"
- L"1=×⌿⍴,⍵: ↑⍪⌿(+⌿⍺)⍴⊂⍵ ⋄"
- L"↑↑⍪⌿⍺ (⍵{e←⊂⍵⌷⍶ ⋄ ⍺>0: ⍺⍴e ⋄ (|⍺)⍴⎕PROTO e})¨⍳≢⍵";
- return rundfn(code, nil, nil, left, right);
+ if(left->type != AtypeInt)
+ throwerror(nil, EType);
+ if(left->rank > 1)
+ throwerror(nil, ERank);
+
+ /* Reshape right if scalar */
+ if(right->size == 1){
+ Array *shape = right->rank == 0 ? mkscalarint(1) : fnShape(right);
+ shape->intdata[0] = left->size;
+ right = fnReshape(shape, right);
+ freearray(shape);
+ }else
+ right = fnSame(right);
+
+ int nsize = right->shape[0];
+ int cellsize = nsize == 0 ? 1 : right->size / nsize;
+ int i;
+ if(left->size == 1){
+ Array *shape = mkscalarint(nsize);
+ left = fnReshape(shape, left);
+ }else
+ left = fnSame(left);
+
+ if(left->size != nsize){
+ freearray(left);
+ freearray(right);
+ throwerror(nil, ELength);
+ }
+
+ nsize = 0;
+ for(i = 0; i < left->size; i++){
+ vlong n = left->intdata[i];
+ nsize += n > 0 ? n : -n;
+ }
+
+ Array *result = allocarray(right->type, right->rank, nsize * cellsize);
+ result->shape[0] = nsize;
+ for(i = 1; i < result->rank; i++)
+ result->shape[i] = right->shape[i];
+
+ Array *fill = fillelement(right);
+ int from, to;
+ int npos;
+ for(from = 0, to = 0; to < nsize; from++, to += npos){
+ int neg = left->intdata[from] < 0;
+ npos = left->intdata[from];
+ if(neg){
+ npos = -npos;
+ for(int j = 0; j < npos*cellsize; j++)
+ memcpy(result->rawdata + (to*cellsize+j)*datasizes[result->type],
+ fill->rawdata, datasizes[result->type]);
+ }else{
+ for(int j = 0; j < npos; j++)
+ memcpy(result->rawdata + (to+j)*cellsize*datasizes[result->type],
+ right->rawdata + from*cellsize*datasizes[result->type],
+ cellsize*datasizes[result->type]);
+ }
+ if(result->type == AtypeArray)
+ for(int j = 0; j < npos*cellsize; j++)
+ incref(result->arraydata[to*cellsize+j]);
+ }
+ freearray(fill);
+ freearray(left);
+ freearray(right);
+ return result;
}
Array *