Skip to content

Commit 0423596

Browse files
authored
Add Dict.has & improve Dict helpers performance (#7316)
* Optimise Dict.forEachWithKey * Speedup Dict.mapValues by 15% * Add Dict.has * Update changelog
1 parent e78c8cd commit 0423596

File tree

7 files changed

+98
-13
lines changed

7 files changed

+98
-13
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
#### :rocket: New Feature
1616

17+
- Add `Dict.has` and double `Dict.forEachWithKey`/`Dict.mapValues` performance. https://github.com/rescript-lang/rescript/pull/7316
1718
- Add popover attributes to JsxDOM.domProps. https://github.com/rescript-lang/rescript/pull/7317
1819

1920
#### :house: Internal

lib/es6/Stdlib_Dict.js

+6-2
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,25 @@ function forEach(dict, f) {
1010
}
1111

1212
function forEachWithKey(dict, f) {
13-
Object.entries(dict).forEach(param => f(param[1], param[0]));
13+
Object.keys(dict).forEach(key => f(dict[key], key));
1414
}
1515

1616
function mapValues(dict, f) {
1717
let target = {};
18-
forEachWithKey(dict, (value, key) => {
18+
Object.keys(dict).forEach(key => {
19+
let value = dict[key];
1920
target[key] = f(value);
2021
});
2122
return target;
2223
}
2324

25+
let has = ((dict, key) => key in dict);
26+
2427
export {
2528
$$delete$1 as $$delete,
2629
forEach,
2730
forEachWithKey,
2831
mapValues,
32+
has,
2933
}
3034
/* No side effect */

lib/js/Stdlib_Dict.js

+6-2
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,23 @@ function forEach(dict, f) {
1010
}
1111

1212
function forEachWithKey(dict, f) {
13-
Object.entries(dict).forEach(param => f(param[1], param[0]));
13+
Object.keys(dict).forEach(key => f(dict[key], key));
1414
}
1515

1616
function mapValues(dict, f) {
1717
let target = {};
18-
forEachWithKey(dict, (value, key) => {
18+
Object.keys(dict).forEach(key => {
19+
let value = dict[key];
1920
target[key] = f(value);
2021
});
2122
return target;
2223
}
2324

25+
let has = ((dict, key) => key in dict);
26+
2427
exports.$$delete = $$delete$1;
2528
exports.forEach = forEach;
2629
exports.forEachWithKey = forEachWithKey;
2730
exports.mapValues = mapValues;
31+
exports.has = has;
2832
/* No side effect */

runtime/Stdlib_Dict.res

+4-1
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@ let forEach = (dict, f) => {
2828
dict->valuesToArray->Stdlib_Array.forEach(value => f(value))
2929
}
3030

31+
@inline
3132
let forEachWithKey = (dict, f) => {
32-
dict->toArray->Stdlib_Array.forEach(((key, value)) => f(value, key))
33+
dict->keysToArray->Stdlib_Array.forEach(key => f(dict->getUnsafe(key), key))
3334
}
3435

3536
let mapValues = (dict, f) => {
@@ -39,3 +40,5 @@ let mapValues = (dict, f) => {
3940
})
4041
target
4142
}
43+
44+
let has: (dict<'a>, string) => bool = %raw(`(dict, key) => key in dict`)

runtime/Stdlib_Dict.resi

+22-7
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ Use `Dict.getUnsafe` only when you are sure the key exists (i.e. when iterating
1717

1818
## Examples
1919
```rescript
20-
let dict = Dict.fromArray([("key1", "value1"), ("key2", "value2")])
20+
let dict = dict{"key1": "value1", "key2": "value2"}
2121
let value = dict->Dict.getUnsafe("key1")
2222
Console.log(value) // value1
2323
```
@@ -30,7 +30,7 @@ Returns the value at the provided key, if it exists. Returns an option.
3030

3131
## Examples
3232
```rescript
33-
let dict = Dict.fromArray([("someKey", "someValue")])
33+
let dict = dict{"someKey": "someValue"}
3434

3535
switch dict->Dict.get("someKey") {
3636
| None => Console.log("Nope, didn't have the key.")
@@ -59,7 +59,7 @@ external set: (dict<'a>, string, 'a) => unit = ""
5959

6060
## Examples
6161
```rescript
62-
let dict = Dict.fromArray([("someKey", "someValue")])
62+
let dict = dict{"someKey": "someValue"}
6363

6464
dict->Dict.delete("someKey")
6565
```
@@ -189,7 +189,7 @@ external assign: (dict<'a>, dict<'a>) => dict<'a> = "Object.assign"
189189

190190
## Examples
191191
```rescript
192-
let dict = Dict.fromArray([("key1", "value1"), ("key2", "value2")])
192+
let dict = dict{"key1": "value1", "key2": "value2"}
193193
let dict2 = dict->Dict.copy
194194

195195
// Both log `["key1", "key2"]` here.
@@ -206,7 +206,7 @@ external copy: (@as(json`{}`) _, dict<'a>) => dict<'a> = "Object.assign"
206206

207207
## Examples
208208
```rescript
209-
let dict = Dict.fromArray([("key1", "value1"), ("key2", "value2")])
209+
let dict = dict{"key1": "value1", "key2": "value2"}
210210

211211
dict->Dict.forEach(value => {
212212
Console.log(value)
@@ -220,7 +220,7 @@ let forEach: (dict<'a>, 'a => unit) => unit
220220

221221
## Examples
222222
```rescript
223-
let dict = Dict.fromArray([("key1", "value1"), ("key2", "value2")])
223+
let dict = dict{"key1": "value1", "key2": "value2"}
224224

225225
dict->Dict.forEachWithKey((value, key) => {
226226
Console.log2(value, key)
@@ -235,10 +235,25 @@ let forEachWithKey: (dict<'a>, ('a, string) => unit) => unit
235235
## Examples
236236

237237
```rescript
238-
let dict = Dict.fromArray([("key1", 1), ("key2", 2)])
238+
let dict = dict{"key1": 1, "key2": 2}
239239

240240
dict->Dict.mapValues(v => v + 10)->Dict.toArray // [("key1", 11), ("key2", 12)]
241241
dict->Dict.mapValues(v => Int.toString(v))->Dict.toArray // [("key1", "1"), ("key2", "2")]
242242
```
243243
*/
244244
let mapValues: (dict<'a>, 'a => 'b) => dict<'b>
245+
246+
/**
247+
`has(dictionary, "key")` returns true if the "key" is present in the dictionary.
248+
249+
## Examples
250+
251+
```rescript
252+
let dict = dict{"key1": Some(1), "key2": None}
253+
254+
dict->Dict.has("key1") // true
255+
dict->Dict.has("key2") // true
256+
dict->Dict.has("key3") // false
257+
```
258+
*/
259+
let has: (dict<'a>, string) => bool

tests/tests/src/DictTests.mjs

+48-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// Generated by ReScript, PLEASE EDIT WITH CARE
22

3+
import * as Stdlib_Dict from "rescript/lib/es6/Stdlib_Dict.js";
34

45
let someString = "hello";
56

@@ -41,6 +42,51 @@ let PatternMatching = {
4142
constrainedAsDict: constrainedAsDict
4243
};
4344

45+
let dict = {
46+
key1: 1,
47+
key2: undefined
48+
};
49+
50+
if (Stdlib_Dict.has(dict, "key1") !== true) {
51+
throw {
52+
RE_EXN_ID: "Assert_failure",
53+
_1: [
54+
"DictTests.res",
55+
43,
56+
2
57+
],
58+
Error: new Error()
59+
};
60+
}
61+
62+
if (Stdlib_Dict.has(dict, "key2") !== true) {
63+
throw {
64+
RE_EXN_ID: "Assert_failure",
65+
_1: [
66+
"DictTests.res",
67+
44,
68+
2
69+
],
70+
Error: new Error()
71+
};
72+
}
73+
74+
if (Stdlib_Dict.has(dict, "key3") !== false) {
75+
throw {
76+
RE_EXN_ID: "Assert_failure",
77+
_1: [
78+
"DictTests.res",
79+
45,
80+
2
81+
],
82+
Error: new Error()
83+
};
84+
}
85+
86+
let DictHas = {
87+
dict: dict
88+
};
89+
4490
let three = 3;
4591

4692
export {
@@ -49,5 +95,6 @@ export {
4995
three,
5096
intDict,
5197
PatternMatching,
98+
DictHas,
5299
}
53-
/* No side effect */
100+
/* Not a pure module */

tests/tests/src/DictTests.res

+11
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,14 @@ module PatternMatching = {
3333
| _ => Js.log("not one")
3434
}
3535
}
36+
37+
module DictHas = {
38+
let dict = dict{
39+
"key1": Some(1),
40+
"key2": None,
41+
}
42+
43+
assert(dict->Dict.has("key1") === true)
44+
assert(dict->Dict.has("key2") === true)
45+
assert(dict->Dict.has("key3") === false)
46+
}

0 commit comments

Comments
 (0)