Memory allocation issue in Haxe using Enum as Map key type - haxe

I follow a 2D GPU library and saw an issue someone was having with memory allocation. An Array<Map> of enums is called every frame via setBlendMode, ultimately calling Haxe's Type.enumParameters each time.
class GBlendModeFunc
{
private static var blendFactors:Array<Map<GBlendMode,Array<Context3DBlendFactor>>> = [
[
GBlendMode.NONE => [Context3DBlendFactor.ONE, Context3DBlendFactor.ZERO],
GBlendMode.NORMAL => [Context3DBlendFactor.SOURCE_ALPHA, Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA],
GBlendMode.ADD => [Context3DBlendFactor.SOURCE_ALPHA, Context3DBlendFactor.DESTINATION_ALPHA],
GBlendMode.MULTIPLY => [Context3DBlendFactor.DESTINATION_COLOR, Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA],
GBlendMode.SCREEN => [Context3DBlendFactor.SOURCE_ALPHA, Context3DBlendFactor.ONE],
GBlendMode.ERASE => [Context3DBlendFactor.ZERO, Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA],
],
[
GBlendMode.NONE => [Context3DBlendFactor.ONE, Context3DBlendFactor.ZERO],
GBlendMode.NORMAL => [Context3DBlendFactor.ONE, Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA],
GBlendMode.ADD => [Context3DBlendFactor.ONE, Context3DBlendFactor.ONE],
GBlendMode.MULTIPLY => [Context3DBlendFactor.DESTINATION_COLOR, Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA],
GBlendMode.SCREEN => [Context3DBlendFactor.ONE, Context3DBlendFactor.ONE_MINUS_SOURCE_COLOR],
GBlendMode.ERASE => [Context3DBlendFactor.ZERO, Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA],
]
];
static public function setBlendMode(p_context:Context3D, p_mode:GBlendMode, p_premultiplied:Bool):Void {
var p:Int = (p_premultiplied) ? 1 : 0;
p_context.setBlendFactors(blendFactors[p][p_mode][0], blendFactors[p][p_mode][1]);
}
}
The issue here is that Type.enumParameters creates a new Array each time it checks the values of enum array from setBlendMode, quickly adding tens of thousands of variables that trigger GC frequently.
I'm not familiar with best Haxe practices and not sure how to reorganize. Is there a more performant way to store the enums that won't create an allocation issue?
Edit: The GBlendMode enums cannot be converted to abstract enums because it breaks other functions.
Edit 2: A solution was proposed: https://github.com/pshtif/Genome2D-ContextFlash/issues/17

I see this looks like Genome2D code.
But I don't see any code for the GBlendMode enum - and this whole thing hinges on that code. If enum GBlendMode is a normal enum, then at runtime they're arrays. The map getter function has to call Type.enumParameters to compare the keys -- I screen-shot a nodejs callstack to prove this to myself:
However, if GBlendMode is an abstract enum over String, like this:
enum abstract GBlendMode(String) {
var NONE;
var NORMAL;
var ADD;
var MULTIPLY;
var SCREEN;
var ERASE;
}
Then the keys are simple strings, and there is no enum comparison, and there are no intermediate arrays created.

Related

how to use shift on behaviorSubject?

I have a class with BehaviorSubject:
export class WordsService {
private words = new BehaviorSubject<WordType[]>([]);
It was fed with subscription:
init() {
this.databaseService.fetchWords().subscribe(
(listaWords: WordType[]) => {
this.words.next(listaWords);
},
errors => console.error('err'),
() => console.log('suceed')
)
}
And as I'm refactoring this code:
private fetchWord(): void{
this.word = this.wordService.getWords().shift();
}
I'm trying to get variable word to have data with .shift so it can take one element from observable at once, and when it will take all elements fetching's done.
It looks like you are trying to transform the results from a WordType[] to a single WordType.
You can do this by applying the map() operator like this:
init(){
this.databaseService.fetchWords().pipe(
map(words => words.shift())
)
.subscribe(
(listaWords: WordType[]) => {
this.words.next(listaWords);
},
errors => console.error('err'),
() => console.log('suceed')
)
}
However, you don't actually need a BehaviorSubject to do this, you can simply declare your observable directly from your service call:
public word: Observable<WordType> = this.databaseService.fetchWords().pipe(
map(words => words.shift()),
catchError(error => console.log(error))
);
Now, the word observable will only emit the value you are interested in.
This allows you to possibly use the async pipe in your template to manage the subscription and not need to do it yourself in the controller.
I would do it without shifting.
Imagine you have any observable value, for each emition of this observable value you want to pull a word. In my example this observable value is a page click.
Then you can do something like this:
const clicked$ = fromEvent(document, 'click');
const words$ = of(['AA', 'BB', 'CC', 'XX']);
const wordToPrint$ = zip(
clicked$,
words$.pipe(concatAll()),
).pipe(
map(([,word]) => word),
);
wordToPrint$.subscribe(console.log);
See stackblitz: https://stackblitz.com/edit/rxjs-ep1k3v?file=index.ts

Typescript - Nested arrow function typing

I have this code for deferring the execution of a function
export type DeferredFunction<T> = () => T | PromiseLike<T>;
export class Deferrable<T> {
protected df: DeferredFunction<T>;
constructor(df: DeferredFunction<T>) {
this.df = df;
}
public async execute(): Promise<T> {
return this.df();
}
}
export const defer = <T>(df: DeferredFunction<T>): Deferrable<T> => new Deferrable<T>(df);
That works fine and I can run code like
await defer(() => someFunction('foo', 'bar')).execute();
but I what I want to do is type DeferredFunction in a way that I can specify the inner function's signature but I can't get it working. In generic cases the above works but when I want to limit the arguments such that they are specific to a certain type of function I don't have that kind of control.
For clarity, I want to be able to type the inner function's inputs like (as an example)
export type InnerDeferredFunction<T> = (a: string, b: number, c: SomeObjectType) => T | PromiseLike<T>
Any help would be greatly appreciated!
What "inner function" are you talking about? Is it someFunction? If so then the type of DeferredFunction<T> has no handle on it, since it's a function called by the implementation of DeferredFunction<T>. There's no way in TypeScript to specify "a function whose implementation must call a function of type (x: string, y: number, z: boolean) => string". Implementation details are not part of a function's call signature.
The only way I can imagine to begin to approach this would be for DeferredFunction<T> to accept as a parameter the inner function you want to call, along with the list of arguments to call it with. This might not be what you're looking for, but it's the closest that the type system can represent.
Something like this:
export type InnerDeferredFunction<T, A extends any[]> = (...args: A) => T | PromiseLike<T>;
export type ZeroArgDeferredFunction<T> = InnerDeferredFunction<T, []>
Here I'm keeping A generic but you can specify it to some hardcoded list of arguments. I've renamed your DeferredFunction to ZeroArgDeferredFunction to be explicit that it doesn't need arguments.
But now Deferrable needs to know about T and A:
export class Deferrable<T, A extends any[]> {
protected df: ZeroArgDeferredFunction<T>;
constructor(df: InnerDeferredFunction<T, A>, ...args: A) {
this.df = () => df(...args);
}
public async execute(): Promise<T> {
return this.df();
}
}
And you can see that you have to construct one by passing it the inner function and its arguments, and the ZeroArgDeferredFunction is built inside the constructor and is not passed in.
There are different ways to define defer(). It could be a thin wrapper around new Deferrable the way you had it, or you could imagine splitting it up so that the args come first:
export const defer = <A extends any[]>(...args: A) => <T>(
df: InnerDeferredFunction<T, A>): Deferrable<T, A> => new Deferrable<T, A>(df, ...args);
And then you can test it like this:
function someFunction(x: string, y: string) {
return (x + y).length;
}
function anotherFunction(x: number, y: number) {
return (x * y).toFixed()
}
const deferFooBar = defer('foo', 'bar');
await deferFooBar(someFunction).execute(); // okay
await deferFooBar(anotherFunction); // error! string is not assignable to number
Once you call deferFooBar('foo', 'bar'), the returned value will only accept functions that can be safely called with the arguments foo and 'bar'. That means someFunction will be accepted and anotherFunction will be rejected.
Okay, hope that helps; good luck!
Playground link to code

Define the type of an object with string keys and function values

I have a node JS function with one parameter that is an object with keys and the values are functions that then resolve to the underlying values.
We have just switched over to TS and I don't know how to define the key:value types of a parameter and further I don't know how to define a function as the value type?
The TS function looks like this...
const myJSFunction = o => input => ...
Where o is the string:function object. And input is then passed into each of the function values of o.
So I was thinking of having some signature along the lines of...
// define the generic <R> function as <U => any>
// define the generic <T> as an object of { string : R }
const myTSFunction = (o: T) => (input: U) => ...
Or something? I'm clutching at straws here as I don't know Typescript well enough to know what is possible with generics.
Thanks
What about something like this :
// We define what the type o is
// key: string means "any key should ..."
interface Obj<T> {
[key: string]: (input: T) => void,
};
// We instantiate an object for the test
const o: Obj<string> = {
a: (input) => { },
b: (input) => { },
};
// We define the function to work with any type of value of obj
// and call it for the test
function myTSFunction<T>(obj: Obj<T>, val: T): void {
obj[0](val);
}
Grégory NEUT answer helped a lot but there were some other constraints that I discovered on the way (that JS had been hiding away). I'm using Lodash so my object was not just an object but a type that they had defined.
So I defined some new types...
type TransformerFunction<T> = (o: T) => any;
type TransformerObject<T> = Dictionary<TransformerFunction<T>>;
And then the function became like...
export const objectTransform = <T extends any>(o: TransformerObject<T>) => <U extends T>(json: U): Dictionary<any> => _.flow(
_.mapValues((f: TransformerFunction<T>) => f(json)),
_.omitBy(_.isUndefined),
_.omit('undefined'),
)(o);
This is how I have been transforming JSON in JS and now moving it over to TS and loving the generics.

how to turn the flattenObj function from the ramda cookbook into an iterative function

I'm dealing with a test environment nodejs/sequelize/mocha/chai.
I find this flattenObj extremely useful
when testing objects, generated by sequelize for instance.
It makes those structures digestible for chai and the results become more concise
Too bad it's implemented in a recursive way :( .Especially in Javascript this spells doom, as there is always a call stack limit lurking.
Hacks like wrapping the recursive function in a setTimeout doesn't seem to work for me and are kind of ugly.
I'm currently trying to figure out to rewrite it in an iterative way, but that's quite a brain teaser, at least for me.
Dealing with while loops inside a ramda function doesn't feel right.
Is there a way of doing this in a call stack friendly way without breaking ramda conventions?
const go = obj_ => chain(([k, v]) => {
if (type(v) === 'Object' || type(v) === 'Array') {
return pipe(
tap(console.log),
map(([k_, v_]) => [`${k}.${k_}`, v_])
)(go(v))
} else {
return [[k, v]]
}
}, toPairs(obj_))
const flattenObj = obj => {
return fromPairs(go(obj))
}
flattenObj({a:1, b:{c:3}, d:{e:{f:6}, g:[{h:8, i:9}, 0]}})
{
"a": 1,
"b.c": 3,
"d.e.f": 6,
"d.g.0.h": 8,
"d.g.0.i": 9,
"d.g.1": 0
}
this works as expected, but it breaks down causing a call stack exceeded error, because of the recursive go function, when the object becomes too complex.
This would be super useful if it's applicable on more complex structures as well.
I don't think it's a bad thing that it's implemented in a recursive way. That's the best way to deal with recursive data structures such as JS objects.
But you can always convert recursive solutions to iterative ones if you want to manage your own stack. Here's a fairly ugly approach, but which seems to work for that simple test case:
const flattenObj = (obj) => {
const results = [];
const steps = Object.entries(obj)
while (steps.length) {
const [key, val] = steps.splice(0, 1)[0]
if (typeof val == 'object') {
Array.prototype.push.apply(steps, Object.entries(val).map(
([k, v]) => [key + '.' + k, v]
))
} else {
results.push([key, val])
}
}
return results.reduce((a, [k, v]) => ({...a, [k]: v}), {})
}
const foo = {a:1, b:{c:3}, d:{e:{f:6}, g:[{h:8, i:9}, 0]}}
console.log(flattenObj(foo))
This will not work with cyclical structures, but the cookbook version would not have either, presumably.
I wrote this originally using some Ramda functions (toPairs in place of Object.entries, is(Object, val) in place of typeof val == 'object' and return fromPairs(results) in place of return results.reduce(...).) But with all the mutation going on (splice and push), it feels a very unRamda-ish solution, and I removed them. (Ramda functions, you understand, don't want to be associated with gauche mutability!)
I don't know if this will solve your problem. I've only used flattenObj a few times, although I can see the utility in tests. But it strikes me that if this is causing recursion problems, cyclical data structures are a more likely issue than actual depth. But of course I don't know your data, so who knows?

Angular 7 HttpClient get - can you access and process the return object?

I know this is a general question but I have exhausted google and tried many approaches.Any feedback is appreciated.
The HTTPClient is Angular 5+ so it returns an object created from the response JSON data. I get a massive JSON response from an endpoint I have no control over and I want to use about 20% of the response in my app and ignore the rest.
I am really trying hard to avoid using a series of templates or export objects or whatever and trying to force this massive untyped Observable into a typed object with hundreds of fields many being Arrays. All I need for the app is just a Array of very small objects with 3 fields per object. The 3 fields are all over within the JSON response and I want to map them to my object .map only seems to work when you are using the full response object and I can't find an example where .map does custom work besides in the case where you are mapping a few fields to 1 object and I am trying to map to an Array of my small objects.
UPDATED
Basically I want this service to return an object of Type DislayData to the module that subscribes to it but I get just an Object back. This is not what I ultimately need to do but if I can prove I can map the body of the response to my needed return type I can then start to break down the response body and return an Array of the Type I really need based on my silly DisplayData object. Thanks again!
export interface DislayData {
body: any;
}
...
export class DataService {
constructor(private http: HttpClient) { }
/** GET data from the black box */
getData(): Observable<DislayData> {
return this.http.get<HttpResponse<any>>(searchUrl, { observe: 'response' })
.pipe(
map(res => {
return res.body as DislayData;
}
tap(res => console.log(//do stuff with entire respoonse also)),
catchError(err => this.handleError(err)));
}
private handleError(error: HttpErrorResponse) {
...
Do you know the structure of the answering object?
If yes, you can do something like this:
item$ = new BehaviorSubject<any>({});
item = {
foo: 'a',
bar: 'b',
iton: [1, 2, 3],
boo: {
far: 'c'
}
};
logNewItem() {
this.item$
.pipe(
map(response => {
if (response.foo
&& response.iton
&& response.iton.length >= 3
&& response.boo
&& response.boo.far) {
let newItem = {
foo: response.foo,
iton2: response.iton[2],
far: response.boo.far
};
console.log(newItem); // output: Object { foo: "a", iton2: 3, far: "c" }
}
})
)
.subscribe();
this.item$.next(this.item);
}
Basically, you can simply make sure the properties exist, call them directly and map them to a better fitting object.
I heavily recommend creating an interface for the object you're receiving and an interface or class for the object you're mapping to. In that case you can also write the code more compact like this:
[...]
map(response: MyAPIResponse => {
let newItem = new NewItem(response);
console.log(newItem); // output: Object { foo: "a", iton2: 3, far: "c" }
}
})
[...]
class NewItem {
foo: string;
iton2: string;
far: string;
constructor(apiResponse: MyAPIResponse) {
//Validate parameter first
this.foo = apiResponse.foo;
this.iton2 = apiResponse.iton[2];
this.far = apiResponse.boo.far;
and make your code a lot more readable.

Resources