Skip to content
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

feat(stdlib): Add lookupCI for assocarray and Node #639

Merged
merged 14 commits into from
Apr 30, 2021

Conversation

Vasya-M
Copy link
Contributor

@Vasya-M Vasya-M commented Apr 8, 2021

solution $629 issue
what were done:

  • fixed CreateObject("roSGNode", "node")
  • added support for lookupCI for AA and Nodes
  • added UT and e2e tests

resolves #629

UPD:

  • Fixed logic of using/saving keys in AA (saving last key used by [], or lowercase key if accessed by .)

Copy link
Collaborator

@lkipke lkipke left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the lookupCI code looks great, but let's pull out the case-sensitive createObject code into its own PR 🙂

src/brsTypes/components/ComponentFactory.ts Outdated Show resolved Hide resolved
@lkipke lkipke added e2e Affects this project's end-to-end test cases (the BrightScript sample files executed during testing) enhancement Any addition to this project's existing capabilities stdlib Affects the standard library included with this BrightScript implementation labels Apr 8, 2021
@Vasya-M Vasya-M requested a review from lkipke April 8, 2021 14:42
Copy link
Collaborator

@lkipke lkipke left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great, thanks for the updates!

Copy link
Collaborator

@alimnios72 alimnios72 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

overall looks good, a few comments below

src/brsTypes/components/RoAssociativeArray.ts Show resolved Hide resolved
src/brsTypes/components/RoSGNode.ts Show resolved Hide resolved
Vasyl Martynych added 2 commits April 9, 2021 21:23
…h creating fields on Node by []. Fixed logic of using/saving keys in AA
@Vasya-M Vasya-M requested a review from alimnios72 April 9, 2021 18:29
field = new Field(value, fieldType, alwaysNotify);
this.fields.set(mapKey, field);
}
// TODO: change to using interpreter.stderr
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If having this creates issues int the current PR (which I think it's breaking unit tests right now) I'm ok with opening a github issue and tackling this work in a separate PR

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep, did it

@Vasya-M Vasya-M requested a review from alimnios72 April 9, 2021 19:36
Copy link
Collaborator

@alimnios72 alimnios72 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few last comments below

* @returns the element at `index` if one exists, otherwise throws an Error.
*/
get(index: BrsType): BrsType;
get(index: BrsType, isCaseSensitiveGet?: boolean): BrsType;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can remove Get and Set from the end of this variables as this can be inferred from the name of the function

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

src/brsTypes/components/RoAssociativeArray.ts Show resolved Hide resolved
@@ -77,7 +76,7 @@ export class RoAssociativeArray extends BrsComponent implements BrsValue, BrsIte
.map((value: BrsType) => value);
}

get(index: BrsType) {
get(index: BrsType, isCaseSensitiveGet = false) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same suggestion for the name of the variables here and in line 102

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

let indexValue = this.modeCaseSensitive ? index.value : index.value.toLowerCase();
return this.elements.get(indexValue) || this.getMethod(index.value) || BrsInvalid.Instance;
return (
this.findElement(index.value, isCaseSensitiveGet) ||
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can get rid of findElement function and just do the following:

this.elements.get(this.findElementKey(index.value), isCaseSensitiveGet)

because if the key is undefined the map should return that as well

Copy link
Contributor Author

@Vasya-M Vasya-M Apr 14, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image
looks like it can not accept undefined

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

Copy link
Owner

@sjbarag sjbarag left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good start, @Vasya-M! I'm a bit worried by the O(n) lookups this introduces in case-insensitive mode, so let's see what we can do to keep that from being an exhaustive search 😃

Comment on lines 126 to 131
for (let key of this.elements.keys()) {
if ((useCaseSensitiveSearch ? key : key.toLowerCase()) === elementKey) {
realElementKey = key;
break;
}
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems less than ideal, as it'll cause an O(n) lookup for every access once setCaseInsensitive is called. I'm curious if there's an alternative solution we can take that won't require us to iterate across every element every time. Could we maintain a case-insensitive Map next to the case-sensitive one, and write to both for every set()? It'd of course require twice as much memory, but would maintain constant time lookups.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey, I even forget about it, a great catch.
So I've taken your idea of using a second map and used it for mapping lower case keys to case sensitive keys. so it will not consume so much memory, will not introduce additional computation and almost saves previous performance.

but there is still be O(n) when we delete keys in case sensitive mode, cuz we can delete key that was used as alias in KeysMap

returns: ValueKind.Dynamic,
},
impl: (interpreter: Interpreter, key: BrsString) => {
let lKey = key.value;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps I've missed something — why's this variable lKey while the rest are key?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

idk why, but it was as is before my changes

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

@lkipke lkipke self-requested a review April 14, 2021 23:21
@Vasya-M Vasya-M requested a review from sjbarag April 16, 2021 22:35
Copy link
Collaborator

@lkipke lkipke left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall, looks great! Thanks for all the hard work here!

src/brsTypes/components/RoAssociativeArray.ts Outdated Show resolved Hide resolved
src/brsTypes/components/RoAssociativeArray.ts Outdated Show resolved Hide resolved
src/brsTypes/components/RoAssociativeArray.ts Outdated Show resolved Hide resolved
src/brsTypes/components/RoAssociativeArray.ts Show resolved Hide resolved
@Vasya-M Vasya-M requested a review from alimnios72 April 19, 2021 22:36
Copy link
Collaborator

@alimnios72 alimnios72 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Other than the already given feedback this looks good to me

Copy link
Owner

@sjbarag sjbarag left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're really close! I've got one last idea to avoid an O(n) operation for every .delete() call, but otherwise this is looking really good :) Thanks for sticking with it, @Vasya-M!

Comment on lines 163 to 164
// if we have {"DD": 0, "dD": 0}, keyMap["dd"] is pointed to "DD",
// and we delete it, then we should find another value for case insensitive accessing ("dD")
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for calling this out! This is an interesting case, and feels like keyMap should be Map<string, Set<string>>: a map of lowercase keys to all encountered cases of that key. In your example with { "DD": 0, "dD": 1}, keyMap.get("dd") would be the set ("DD", "dD"). When someAA.delete("DD") is called from BrightScript, this function removes the first element from that set (something like let newSet = new Set([ ...keyMap.get(lKey) ].slice(1));) in case-sensitive mode, and removes the entire entry (this.keyMap.delete(lKey)) in case-insensitive mode.

Lookups become pretty similar, using the element at index zero of this Set<string>.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@Vasya-M Vasya-M requested a review from sjbarag April 21, 2021 11:54
Copy link
Owner

@sjbarag sjbarag left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great! Thanks for the changes @Vasya-M 😃

@sjbarag sjbarag changed the title Issue 629 add lookupCI method feat(stdlib): Add lookupCI for assocarray and Node Apr 30, 2021
@sjbarag sjbarag merged commit 08baf5e into sjbarag:main Apr 30, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
e2e Affects this project's end-to-end test cases (the BrightScript sample files executed during testing) enhancement Any addition to this project's existing capabilities stdlib Affects the standard library included with this BrightScript implementation
Projects
None yet
Development

Successfully merging this pull request may close these issues.

lookupCI() is not supported
4 participants