-
-
Notifications
You must be signed in to change notification settings - Fork 667
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
%TypedArray%.prototype.map #349
Conversation
std/assembly/internal/typedarray.ts
Outdated
var length = this.length; | ||
var byteLength = this.byteLength; | ||
var byteOffset = this.byteOffset; | ||
var newbuff = allocateUnsafe(byteLength); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why just not create var result = new TypedArray<T,V>(this.length)
and result.byteOffset = this.byteOffset
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's in the definition of the class
export abstract class TypedArray<T,V>
I can't create an abstract class with new
, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, now I see
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TypedArray
is abstract because you'd lose the subarray
implementation on the concrete class. Though I agree that this should be easier, somehow, because as it stands it is missing GC registration.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh wait! I have an idea.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe a built-in helper instantiate<T>(...constructorArgs)
(here: T
is this
) that is able to instantiate anything, given the class as a type argument?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dcodeIO I can implement the method on each subclass using the new
keyword. Let me submit changes.
Okay so this totally works. It feels a bit hacky, but the code is very clear and does the job. Is there a way to make this method more generic? |
store<i32>(changetype<usize>(result), this.byteOffset, offsetof<this>("byteOffset")); |
@dcodeIO for better design I think make sense use getter for |
And for testing, how should I verify the map method works? Is there a place to modify the test suite? |
One last question, I'm looking through the spec and can't find the reason why we must copy the byteOffset to a new TypedArray. Is there a reason I'm missing? |
see how implemented |
Not sure about setting `byteOffset´, as you are dealing with an entirely new array with a new backing buffer. Modifying byteOffset there might actually lead to out of bounds loads and stores. |
@dcodeIO yeah, you are right |
Yeah this pull request isn't gonna be easy. |
Looks like something is broken. Can someone help me identify the problem? |
Now it looks like I have a problem with the function callbacks.
I went to check out how map<U>(callbackfn: (value: T, index: i32, array: Array<T>) => U): Array<U> { Am I missing something? |
Yes, currently signature of callback should fully declare. Change: function squarei8(val: i8, index: i32): i8 { ... } to function squarei8(val: i8, index: i32, array: i8[]): i8 { ... } |
Okay. It looks like I've gotten it to the point where the tests look like they are supposed to look. There's still some issues though. |
std/assembly/typedarray.ts
Outdated
var length = this.length; | ||
var result = new Int8Array(this.length); | ||
for (let i = 0; i < length; ++i) { | ||
result.__unchecked_set(i, callbackfn(this.__unchecked_get(i), i, this)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can also be written as unchecked(result[i] = callbackfn(this.__unchecked_get(i), i, this))
, which will ensure that it still works whenever indexed access becomes more optimized or changes otherwise.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be a TS error that results from the .d.ts not having it, but should compile with AS.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried compiling with AS and it fails when trying to run the tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, that's strange. Really shouldn't use __unchecked_set
here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For reference, the low-level way to write this is:
import { HEADER_SIZE } from "./internal/arraybuffer";
map(callbackfn: (value: i8, index: i32, array: Int8Array) => i8): Int8Array {
var length = this.length;
var result = new Int8Array(length);
var src = changetype<usize>(this.buffer) + HEADER_SIZE + this.byteOffset;
var dst = changetype<usize>(result.buffer) + HEADER_SIZE; // byteOffset is 0 for a new array
for (let i = 0; i < length; ++i) {
let off = <usize>i << alignof<i8>();
store<i8>(dst + off, callbackfn(load<i8>(src + off), i, this));
// can actually skip alignof<T> for i8/u8 because it's 0 anyway, but added it for clarity
}
return result;
}
@MaxGraey please correct me if I made a mistake :)
Also you should run |
I somehow broke the |
It seems you need use
and
later. |
@MaxGraey Okay. What do you mean by disclude dist folder? Should I delete it and commit with empty dist folder? |
@MaxGraey I'm confused by what this means. Should I leave the dist files as they are, from when I cloned the repo? When I ran the build to do the testing it updated the files and I can't disclude them. Should I use this?
|
When working on the compiler, make sure to run |
Okay. So all the tests pass. Pushing now. Please check my work, because it modified the dist folder. |
Modifying the dist folder will make CI fail automatically, unfortunately. Let me suggest that you |
@dcodeIO sorry about this. When I was asked to run npm build, it caused the dist folder to be overwritten. Is it possible to restore the files back to their original contents by just copy/pasting them instead? I'm afraid of git magic right now and I don't want to lose all my work :) Edit: It does look like the files are diffed using git, so I restored their contents manually. |
What you'd usually do in such a scenario is, for example
that keeps your local changes but resets the tree to the state before you made your first commit, followed by a
to add your changes back, except those to the dist files. Then creating a new first commit on your branch through
and force-pushing it to your branch, effectively replacing the chain of commits that was there before with your new single one
Hope that helps :) |
Yeah thanks for the tip. It all seems to work now. Should I change the documentation, add some comments? It didn't seem like I needed any since it was all very obvious what the code was doing. |
std/assembly/typedarray.ts
Outdated
} | ||
|
||
export class Uint8ClampedArray extends TypedArray<u8,u32> { | ||
static readonly BYTES_PER_ELEMENT: usize = sizeof<u8>(); | ||
|
||
@inline @operator("[]=") | ||
protected __set(index: i32, value: i32): void { | ||
super.__set(index, max(min(value, 255), 0)); | ||
super.__unchecked_set(index, max(min(value, 255), 0)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why did this change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I must have accidentally replaced this. I am sorry. Let me change it back.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changing this function back to super.__set
causes this error to occur when testing compiler/std/typedarray.ts
Fatal: Module::addFunction: $~lib/internal/typedarray/TypedArray<u8,u32>#__set already exists
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Try renaming the function itself to __setClamped
as a workaround.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
may be you forget replace result.__set
to result.__setClamped
for map
inside Uint8ClampedArray
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, this is most likely a compiler bug that involves super
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where can I look to help?
The "Operation not supported" issue on |
Seems to originate from |
Actually I think the typescript compiler throws the error from within tslint. It says specifically:
This is a TypeScript error. Not a tslint one. |
Well, while I hoped we could have avoided it, it appears that using |
We still need to figure out what the problem with is with the unclamped array problem anyway.
If I am not mistaken, perhaps there's a problem with operator overriding? I think it might have something to do with using the parent class's function name because I've renamed the functions in the @inline @operator("[]=")
protected __setClamped(index: i32, value: i32): void {
super.__set(index, max(min(value, 255), 0));
}
@inline @operator("{}=")
protected __unchecked_setClamped(index: i32, value: i32): void {
super.__unchecked_set(index, max(min(value, 255), 0));
} The only place that uses the identifier |
I think the problem is that through calling |
Can't I just make a generic export abstract class TypedArray<T, V> {
map(callbackfn: (value: T, index: i32, array: Int16Array) => T): this {
var length = this.length;
var result = instantiate<this>(length);
for (let i = 0; i < length; ++i) {
result.__unchecked_set(i, callbackfn(this.__unchecked_get(i), i, this));
}
return result;
}
} |
Problem is that |
One solution could be to check whether a function makes use of the |
@dcodeIO I can implement this no problem! Also, we need to override the default functionality for |
I just realized something. |
The idea behind the unconvenient Maybe renaming |
// in internal/typedarray.ts
map(callbackfn: (value: T, index: i32) => V): TypedArray<T, V> {
var length = this.length;
var result = instantiate<TypedArray<T, V>>(length);
for (let i = 0; i < length; ++i) {
result.__unchecked_set(
i,
callbackfn(this.__unchecked_get(i), i),
);
}
return result;
}
// for Int8Array
map(callbackfn: (value: i8, index: i32, array: Int8Array) => i8): Int8Array {
return <Int8Array>super.map((input: i8, idx: i32) => <i32>callbackfn(input, idx, this));
} |
So far this is the best I have for implementing map.
This is my first pull request and I hope to contribute much more if this turns out well.