Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changes/cache-nested-none-markers.polish.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Reuse one object per depth for nested `None` (`Some(None)`, `Some(Some(None))`, …), so creating one no longer allocates and `Some(None) === Some(None)` holds.
26 changes: 23 additions & 3 deletions packages/@rescript/runtime/Primitive_option.res
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,32 @@ let isNested = (x: Obj.t): bool => {
Obj.repr((Obj.magic(x): nested).depth) !== Obj.repr(Primitive_js_extern.undefined)
}

external getUnsafe: (array<'a>, int) => 'a = "%array_unsafe_get"
external setUnsafe: (array<'a>, int, 'a) => unit = "%array_unsafe_set"
@scope("Object") external freeze: nested => nested = "freeze"

/* One frozen representation per depth, created on first use, so that
wrapping and unwrapping a nested [None] does not allocate and
[Some(None) === Some(None)] holds */
let markers: array<nested> = []

let marker = (depth: int): Obj.t => {
let m = getUnsafe(markers, depth)
if Obj.repr(m) !== Obj.repr(Primitive_js_extern.undefined) {
Obj.repr(m)
} else {
let m = freeze({depth: depth})
setUnsafe(markers, depth, m)
Obj.repr(m)
}
}

let some = (x: Obj.t): Obj.t =>
if Obj.magic(x) == None {
Obj.repr({depth: 0})
marker(0)
} /* [x] is neither None nor null so it is safe to do property access */
else if x !== Obj.repr(Primitive_js_extern.null) && isNested(x) {
Obj.repr({depth: (Obj.magic(x): nested).depth + 1})
marker((Obj.magic(x): nested).depth + 1)
} else {
x
}
Expand Down Expand Up @@ -48,7 +68,7 @@ let valFromOption = (x: Obj.t): Obj.t =>
if depth == 0 {
Obj.magic(None)
} else {
Obj.repr({depth: depth - 1})
marker(depth - 1)
}
} else {
Obj.magic(x)
Expand Down
26 changes: 17 additions & 9 deletions packages/@rescript/runtime/lib/es6/Primitive_option.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,25 @@ function isNested(x) {
return x.BS_PRIVATE_NESTED_SOME_NONE !== undefined;
}

let markers = [];

function marker(depth) {
let m = markers[depth];
if (m !== undefined) {
return m;
}
let m$1 = Object.freeze({
BS_PRIVATE_NESTED_SOME_NONE: depth
});
markers[depth] = m$1;
return m$1;
}

function some(x) {
if (x === undefined) {
return {
BS_PRIVATE_NESTED_SOME_NONE: 0
};
return marker(0);
} else if (x !== null && x.BS_PRIVATE_NESTED_SOME_NONE !== undefined) {
return {
BS_PRIVATE_NESTED_SOME_NONE: x.BS_PRIVATE_NESTED_SOME_NONE + 1 | 0
};
return marker(x.BS_PRIVATE_NESTED_SOME_NONE + 1 | 0);
} else {
return x;
}
Expand Down Expand Up @@ -43,9 +53,7 @@ function valFromOption(x) {
if (depth === 0) {
return;
} else {
return {
BS_PRIVATE_NESTED_SOME_NONE: depth - 1 | 0
};
return marker(depth - 1 | 0);
}
}

Expand Down
26 changes: 17 additions & 9 deletions packages/@rescript/runtime/lib/js/Primitive_option.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,25 @@ function isNested(x) {
return x.BS_PRIVATE_NESTED_SOME_NONE !== undefined;
}

let markers = [];

function marker(depth) {
let m = markers[depth];
if (m !== undefined) {
return m;
}
let m$1 = Object.freeze({
BS_PRIVATE_NESTED_SOME_NONE: depth
});
markers[depth] = m$1;
return m$1;
}

function some(x) {
if (x === undefined) {
return {
BS_PRIVATE_NESTED_SOME_NONE: 0
};
return marker(0);
} else if (x !== null && x.BS_PRIVATE_NESTED_SOME_NONE !== undefined) {
return {
BS_PRIVATE_NESTED_SOME_NONE: x.BS_PRIVATE_NESTED_SOME_NONE + 1 | 0
};
return marker(x.BS_PRIVATE_NESTED_SOME_NONE + 1 | 0);
} else {
return x;
}
Expand Down Expand Up @@ -43,9 +53,7 @@ function valFromOption(x) {
if (depth === 0) {
return;
} else {
return {
BS_PRIVATE_NESTED_SOME_NONE: depth - 1 | 0
};
return marker(depth - 1 | 0);
}
}

Expand Down
72 changes: 72 additions & 0 deletions tests/tests/src/option_nested_marker_test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Generated by ReScript, PLEASE EDIT WITH CARE

import * as Mocha from "mocha";
import * as Test_utils from "./test_utils.mjs";
import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.mjs";
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.mjs";

function wrap(x) {
return Primitive_option.some(x);
}

function unwrap(x) {
if (x !== undefined) {
return Primitive_option.valFromOption(x);
}
throw {
RE_EXN_ID: "Assert_failure",
_1: [
"option_nested_marker_test.res",
11,
12
],
Error: new Error()
};
}

function depth(x) {
if (x === undefined) {
return 0;
}
let match = Primitive_option.valFromOption(x);
if (match !== undefined) {
if (Primitive_option.valFromOption(match) !== undefined) {
return 3;
} else {
return 2;
}
} else {
return 1;
}
}

Mocha.describe("Option_nested_marker_test", () => {
Mocha.test("a nested None is the same object at each depth", () => {
Test_utils.eq("File \"option_nested_marker_test.res\", line 25, characters 7-14", true, Primitive_option.some(undefined) === Primitive_option.some(undefined));
Test_utils.eq("File \"option_nested_marker_test.res\", line 26, characters 7-14", true, Primitive_option.some(Primitive_option.some(undefined)) === Primitive_option.some(Primitive_option.some(undefined)));
Test_utils.eq("File \"option_nested_marker_test.res\", line 27, characters 7-14", false, Primitive_option.some(undefined) === Primitive_option.some(Primitive_option.some(undefined)));
});
Mocha.test("unwrapping gives the marker one level down", () => {
Test_utils.eq("File \"option_nested_marker_test.res\", line 31, characters 7-14", true, unwrap(Primitive_option.some(Primitive_option.some(undefined))) === Primitive_option.some(undefined));
Test_utils.eq("File \"option_nested_marker_test.res\", line 32, characters 7-14", true, unwrap(unwrap(Primitive_option.some(Primitive_option.some(undefined)))) === undefined);
});
Mocha.test("markers are frozen", () => {
Test_utils.eq("File \"option_nested_marker_test.res\", line 36, characters 7-14", true, Object.isFrozen(Primitive_option.some(undefined)));
Test_utils.eq("File \"option_nested_marker_test.res\", line 37, characters 7-14", true, Object.isFrozen(Primitive_option.some(Primitive_option.some(undefined))));
});
Mocha.test("matching and equality are unchanged", () => {
Test_utils.eq("File \"option_nested_marker_test.res\", line 42, characters 7-14", 0, depth(undefined));
Test_utils.eq("File \"option_nested_marker_test.res\", line 43, characters 7-14", 1, depth(Primitive_option.some(undefined)));
Test_utils.eq("File \"option_nested_marker_test.res\", line 44, characters 7-14", 2, depth(Primitive_option.some(Primitive_option.some(undefined))));
Test_utils.eq("File \"option_nested_marker_test.res\", line 45, characters 7-14", 3, depth(Primitive_option.some(Primitive_option.some(1))));
Test_utils.eq("File \"option_nested_marker_test.res\", line 46, characters 7-14", Primitive_option.some(Primitive_option.some(undefined)), Primitive_option.some(Primitive_option.some(undefined)));
Test_utils.eq("File \"option_nested_marker_test.res\", line 47, characters 7-14", true, Primitive_object.equal(Primitive_option.some(Primitive_option.some(undefined)), Primitive_option.some(Primitive_option.some(undefined))));
});
});

export {
wrap,
unwrap,
depth,
}
/* Not a pure module */
49 changes: 49 additions & 0 deletions tests/tests/src/option_nested_marker_test.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
open Mocha
open Test_utils

@scope("Object") external isFrozen: 'a => bool = "isFrozen"

let wrap = x => Some(x)

let unwrap = (x: option<'a>) =>
switch x {
| Some(v) => v
| None => assert(false)
}

let depth = (x: option<option<option<int>>>) =>
switch x {
| None => 0
| Some(None) => 1
| Some(Some(None)) => 2
| Some(Some(Some(_))) => 3
}

describe(__MODULE__, () => {
test("a nested None is the same object at each depth", () => {
let none: option<int> = None
eq(__LOC__, true, wrap(none) === wrap(none))
eq(__LOC__, true, wrap(wrap(none)) === wrap(wrap(none)))
eq(__LOC__, false, wrap(none) === Obj.magic(wrap(wrap(none))))
})
test("unwrapping gives the marker one level down", () => {
let none: option<int> = None
eq(__LOC__, true, unwrap(wrap(wrap(none))) === wrap(none))
eq(__LOC__, true, unwrap(unwrap(wrap(wrap(none)))) === none)
})
test("markers are frozen", () => {
let none: option<int> = None
eq(__LOC__, true, isFrozen(wrap(none)))
eq(__LOC__, true, isFrozen(wrap(wrap(none))))
})
test("matching and equality are unchanged", () => {
let none: option<int> = None
let none2: option<option<int>> = None
eq(__LOC__, 0, depth(None))
eq(__LOC__, 1, depth(wrap(none2)))
eq(__LOC__, 2, depth(wrap(wrap(none))))
eq(__LOC__, 3, depth(wrap(wrap(Some(1)))))
eq(__LOC__, Some(Some(None)), wrap(wrap(none)))
eq(__LOC__, true, wrap(wrap(none)) == Some(Some(None)))
})
})
Loading