You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
349 lines
9.6 KiB
349 lines
9.6 KiB
var iota = require("iota-array")
|
|
var isBuffer = require("is-buffer")
|
|
|
|
var hasTypedArrays = ((typeof Float64Array) !== "undefined")
|
|
|
|
function compare1st(a, b) {
|
|
return a[0] - b[0]
|
|
}
|
|
|
|
function order() {
|
|
var stride = this.stride
|
|
var terms = new Array(stride.length)
|
|
var i
|
|
for(i=0; i<terms.length; ++i) {
|
|
terms[i] = [Math.abs(stride[i]), i]
|
|
}
|
|
terms.sort(compare1st)
|
|
var result = new Array(terms.length)
|
|
for(i=0; i<result.length; ++i) {
|
|
result[i] = terms[i][1]
|
|
}
|
|
return result
|
|
}
|
|
|
|
function compileConstructor(dtype, dimension) {
|
|
var className = ["View", dimension, "d", dtype].join("")
|
|
if(dimension < 0) {
|
|
className = "View_Nil" + dtype
|
|
}
|
|
var useGetters = (dtype === "generic")
|
|
|
|
if(dimension === -1) {
|
|
//Special case for trivial arrays
|
|
var code =
|
|
"function "+className+"(a){this.data=a;};\
|
|
var proto="+className+".prototype;\
|
|
proto.dtype='"+dtype+"';\
|
|
proto.index=function(){return -1};\
|
|
proto.size=0;\
|
|
proto.dimension=-1;\
|
|
proto.shape=proto.stride=proto.order=[];\
|
|
proto.lo=proto.hi=proto.transpose=proto.step=\
|
|
function(){return new "+className+"(this.data);};\
|
|
proto.get=proto.set=function(){};\
|
|
proto.pick=function(){return null};\
|
|
return function construct_"+className+"(a){return new "+className+"(a);}"
|
|
var procedure = new Function(code)
|
|
return procedure()
|
|
} else if(dimension === 0) {
|
|
//Special case for 0d arrays
|
|
var code =
|
|
"function "+className+"(a,d) {\
|
|
this.data = a;\
|
|
this.offset = d\
|
|
};\
|
|
var proto="+className+".prototype;\
|
|
proto.dtype='"+dtype+"';\
|
|
proto.index=function(){return this.offset};\
|
|
proto.dimension=0;\
|
|
proto.size=1;\
|
|
proto.shape=\
|
|
proto.stride=\
|
|
proto.order=[];\
|
|
proto.lo=\
|
|
proto.hi=\
|
|
proto.transpose=\
|
|
proto.step=function "+className+"_copy() {\
|
|
return new "+className+"(this.data,this.offset)\
|
|
};\
|
|
proto.pick=function "+className+"_pick(){\
|
|
return TrivialArray(this.data);\
|
|
};\
|
|
proto.valueOf=proto.get=function "+className+"_get(){\
|
|
return "+(useGetters ? "this.data.get(this.offset)" : "this.data[this.offset]")+
|
|
"};\
|
|
proto.set=function "+className+"_set(v){\
|
|
return "+(useGetters ? "this.data.set(this.offset,v)" : "this.data[this.offset]=v")+"\
|
|
};\
|
|
return function construct_"+className+"(a,b,c,d){return new "+className+"(a,d)}"
|
|
var procedure = new Function("TrivialArray", code)
|
|
return procedure(CACHED_CONSTRUCTORS[dtype][0])
|
|
}
|
|
|
|
var code = ["'use strict'"]
|
|
|
|
//Create constructor for view
|
|
var indices = iota(dimension)
|
|
var args = indices.map(function(i) { return "i"+i })
|
|
var index_str = "this.offset+" + indices.map(function(i) {
|
|
return "this.stride[" + i + "]*i" + i
|
|
}).join("+")
|
|
var shapeArg = indices.map(function(i) {
|
|
return "b"+i
|
|
}).join(",")
|
|
var strideArg = indices.map(function(i) {
|
|
return "c"+i
|
|
}).join(",")
|
|
code.push(
|
|
"function "+className+"(a," + shapeArg + "," + strideArg + ",d){this.data=a",
|
|
"this.shape=[" + shapeArg + "]",
|
|
"this.stride=[" + strideArg + "]",
|
|
"this.offset=d|0}",
|
|
"var proto="+className+".prototype",
|
|
"proto.dtype='"+dtype+"'",
|
|
"proto.dimension="+dimension)
|
|
|
|
//view.size:
|
|
code.push("Object.defineProperty(proto,'size',{get:function "+className+"_size(){\
|
|
return "+indices.map(function(i) { return "this.shape["+i+"]" }).join("*"),
|
|
"}})")
|
|
|
|
//view.order:
|
|
if(dimension === 1) {
|
|
code.push("proto.order=[0]")
|
|
} else {
|
|
code.push("Object.defineProperty(proto,'order',{get:")
|
|
if(dimension < 4) {
|
|
code.push("function "+className+"_order(){")
|
|
if(dimension === 2) {
|
|
code.push("return (Math.abs(this.stride[0])>Math.abs(this.stride[1]))?[1,0]:[0,1]}})")
|
|
} else if(dimension === 3) {
|
|
code.push(
|
|
"var s0=Math.abs(this.stride[0]),s1=Math.abs(this.stride[1]),s2=Math.abs(this.stride[2]);\
|
|
if(s0>s1){\
|
|
if(s1>s2){\
|
|
return [2,1,0];\
|
|
}else if(s0>s2){\
|
|
return [1,2,0];\
|
|
}else{\
|
|
return [1,0,2];\
|
|
}\
|
|
}else if(s0>s2){\
|
|
return [2,0,1];\
|
|
}else if(s2>s1){\
|
|
return [0,1,2];\
|
|
}else{\
|
|
return [0,2,1];\
|
|
}}})")
|
|
}
|
|
} else {
|
|
code.push("ORDER})")
|
|
}
|
|
}
|
|
|
|
//view.set(i0, ..., v):
|
|
code.push(
|
|
"proto.set=function "+className+"_set("+args.join(",")+",v){")
|
|
if(useGetters) {
|
|
code.push("return this.data.set("+index_str+",v)}")
|
|
} else {
|
|
code.push("return this.data["+index_str+"]=v}")
|
|
}
|
|
|
|
//view.get(i0, ...):
|
|
code.push("proto.get=function "+className+"_get("+args.join(",")+"){")
|
|
if(useGetters) {
|
|
code.push("return this.data.get("+index_str+")}")
|
|
} else {
|
|
code.push("return this.data["+index_str+"]}")
|
|
}
|
|
|
|
//view.index:
|
|
code.push(
|
|
"proto.index=function "+className+"_index(", args.join(), "){return "+index_str+"}")
|
|
|
|
//view.hi():
|
|
code.push("proto.hi=function "+className+"_hi("+args.join(",")+"){return new "+className+"(this.data,"+
|
|
indices.map(function(i) {
|
|
return ["(typeof i",i,"!=='number'||i",i,"<0)?this.shape[", i, "]:i", i,"|0"].join("")
|
|
}).join(",")+","+
|
|
indices.map(function(i) {
|
|
return "this.stride["+i + "]"
|
|
}).join(",")+",this.offset)}")
|
|
|
|
//view.lo():
|
|
var a_vars = indices.map(function(i) { return "a"+i+"=this.shape["+i+"]" })
|
|
var c_vars = indices.map(function(i) { return "c"+i+"=this.stride["+i+"]" })
|
|
code.push("proto.lo=function "+className+"_lo("+args.join(",")+"){var b=this.offset,d=0,"+a_vars.join(",")+","+c_vars.join(","))
|
|
for(var i=0; i<dimension; ++i) {
|
|
code.push(
|
|
"if(typeof i"+i+"==='number'&&i"+i+">=0){\
|
|
d=i"+i+"|0;\
|
|
b+=c"+i+"*d;\
|
|
a"+i+"-=d}")
|
|
}
|
|
code.push("return new "+className+"(this.data,"+
|
|
indices.map(function(i) {
|
|
return "a"+i
|
|
}).join(",")+","+
|
|
indices.map(function(i) {
|
|
return "c"+i
|
|
}).join(",")+",b)}")
|
|
|
|
//view.step():
|
|
code.push("proto.step=function "+className+"_step("+args.join(",")+"){var "+
|
|
indices.map(function(i) {
|
|
return "a"+i+"=this.shape["+i+"]"
|
|
}).join(",")+","+
|
|
indices.map(function(i) {
|
|
return "b"+i+"=this.stride["+i+"]"
|
|
}).join(",")+",c=this.offset,d=0,ceil=Math.ceil")
|
|
for(var i=0; i<dimension; ++i) {
|
|
code.push(
|
|
"if(typeof i"+i+"==='number'){\
|
|
d=i"+i+"|0;\
|
|
if(d<0){\
|
|
c+=b"+i+"*(a"+i+"-1);\
|
|
a"+i+"=ceil(-a"+i+"/d)\
|
|
}else{\
|
|
a"+i+"=ceil(a"+i+"/d)\
|
|
}\
|
|
b"+i+"*=d\
|
|
}")
|
|
}
|
|
code.push("return new "+className+"(this.data,"+
|
|
indices.map(function(i) {
|
|
return "a" + i
|
|
}).join(",")+","+
|
|
indices.map(function(i) {
|
|
return "b" + i
|
|
}).join(",")+",c)}")
|
|
|
|
//view.transpose():
|
|
var tShape = new Array(dimension)
|
|
var tStride = new Array(dimension)
|
|
for(var i=0; i<dimension; ++i) {
|
|
tShape[i] = "a[i"+i+"]"
|
|
tStride[i] = "b[i"+i+"]"
|
|
}
|
|
code.push("proto.transpose=function "+className+"_transpose("+args+"){"+
|
|
args.map(function(n,idx) { return n + "=(" + n + "===undefined?" + idx + ":" + n + "|0)"}).join(";"),
|
|
"var a=this.shape,b=this.stride;return new "+className+"(this.data,"+tShape.join(",")+","+tStride.join(",")+",this.offset)}")
|
|
|
|
//view.pick():
|
|
code.push("proto.pick=function "+className+"_pick("+args+"){var a=[],b=[],c=this.offset")
|
|
for(var i=0; i<dimension; ++i) {
|
|
code.push("if(typeof i"+i+"==='number'&&i"+i+">=0){c=(c+this.stride["+i+"]*i"+i+")|0}else{a.push(this.shape["+i+"]);b.push(this.stride["+i+"])}")
|
|
}
|
|
code.push("var ctor=CTOR_LIST[a.length+1];return ctor(this.data,a,b,c)}")
|
|
|
|
//Add return statement
|
|
code.push("return function construct_"+className+"(data,shape,stride,offset){return new "+className+"(data,"+
|
|
indices.map(function(i) {
|
|
return "shape["+i+"]"
|
|
}).join(",")+","+
|
|
indices.map(function(i) {
|
|
return "stride["+i+"]"
|
|
}).join(",")+",offset)}")
|
|
|
|
//Compile procedure
|
|
var procedure = new Function("CTOR_LIST", "ORDER", code.join("\n"))
|
|
return procedure(CACHED_CONSTRUCTORS[dtype], order)
|
|
}
|
|
|
|
function arrayDType(data) {
|
|
if(isBuffer(data)) {
|
|
return "buffer"
|
|
}
|
|
if(hasTypedArrays) {
|
|
switch(Object.prototype.toString.call(data)) {
|
|
case "[object Float64Array]":
|
|
return "float64"
|
|
case "[object Float32Array]":
|
|
return "float32"
|
|
case "[object Int8Array]":
|
|
return "int8"
|
|
case "[object Int16Array]":
|
|
return "int16"
|
|
case "[object Int32Array]":
|
|
return "int32"
|
|
case "[object Uint8Array]":
|
|
return "uint8"
|
|
case "[object Uint16Array]":
|
|
return "uint16"
|
|
case "[object Uint32Array]":
|
|
return "uint32"
|
|
case "[object Uint8ClampedArray]":
|
|
return "uint8_clamped"
|
|
case "[object BigInt64Array]":
|
|
return "bigint64"
|
|
case "[object BigUint64Array]":
|
|
return "biguint64"
|
|
}
|
|
}
|
|
if(Array.isArray(data)) {
|
|
return "array"
|
|
}
|
|
return "generic"
|
|
}
|
|
|
|
var CACHED_CONSTRUCTORS = {
|
|
"float32":[],
|
|
"float64":[],
|
|
"int8":[],
|
|
"int16":[],
|
|
"int32":[],
|
|
"uint8":[],
|
|
"uint16":[],
|
|
"uint32":[],
|
|
"array":[],
|
|
"uint8_clamped":[],
|
|
"bigint64": [],
|
|
"biguint64": [],
|
|
"buffer":[],
|
|
"generic":[]
|
|
}
|
|
|
|
;(function() {
|
|
for(var id in CACHED_CONSTRUCTORS) {
|
|
CACHED_CONSTRUCTORS[id].push(compileConstructor(id, -1))
|
|
}
|
|
});
|
|
|
|
function wrappedNDArrayCtor(data, shape, stride, offset) {
|
|
if(data === undefined) {
|
|
var ctor = CACHED_CONSTRUCTORS.array[0]
|
|
return ctor([])
|
|
} else if(typeof data === "number") {
|
|
data = [data]
|
|
}
|
|
if(shape === undefined) {
|
|
shape = [ data.length ]
|
|
}
|
|
var d = shape.length
|
|
if(stride === undefined) {
|
|
stride = new Array(d)
|
|
for(var i=d-1, sz=1; i>=0; --i) {
|
|
stride[i] = sz
|
|
sz *= shape[i]
|
|
}
|
|
}
|
|
if(offset === undefined) {
|
|
offset = 0
|
|
for(var i=0; i<d; ++i) {
|
|
if(stride[i] < 0) {
|
|
offset -= (shape[i]-1)*stride[i]
|
|
}
|
|
}
|
|
}
|
|
var dtype = arrayDType(data)
|
|
var ctor_list = CACHED_CONSTRUCTORS[dtype]
|
|
while(ctor_list.length <= d+1) {
|
|
ctor_list.push(compileConstructor(dtype, ctor_list.length-1))
|
|
}
|
|
var ctor = ctor_list[d+1]
|
|
return ctor(data, shape, stride, offset)
|
|
}
|
|
|
|
module.exports = wrappedNDArrayCtor
|
|
|