Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
M
Molstar
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package Registry
Container Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Michal Malý
Molstar
Commits
f9419bb4
Commit
f9419bb4
authored
7 years ago
by
David Sehnal
Browse files
Options
Downloads
Patches
Plain Diff
collections
parent
a0ee98a7
No related branches found
No related tags found
No related merge requests found
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
src/perf-tests/chunked-array-vs-native.ts
+44
-0
44 additions, 0 deletions
src/perf-tests/chunked-array-vs-native.ts
src/structure/collections/ordered-set.ts
+11
-16
11 additions, 16 deletions
src/structure/collections/ordered-set.ts
src/utils/chunked-array.ts
+87
-83
87 additions, 83 deletions
src/utils/chunked-array.ts
with
142 additions
and
99 deletions
src/perf-tests/chunked-array-vs-native.ts
0 → 100644
+
44
−
0
View file @
f9419bb4
import
*
as
B
from
'
benchmark
'
import
ChunkedArray
from
'
../utils/chunked-array
'
function
testNative
(
size
:
number
)
{
const
xs
=
new
Array
(
size
);
for
(
let
i
=
0
;
i
<
size
;
i
++
)
xs
[
i
]
=
i
*
i
;
return
xs
;
}
function
testChunkedTyped
(
size
:
number
,
chunk
:
number
,
linear
:
boolean
)
{
const
xs
=
ChunkedArray
.
create
(
s
=>
new
Int32Array
(
s
),
1
,
chunk
,
linear
);
for
(
let
i
=
0
;
i
<
size
;
i
++
)
ChunkedArray
.
add
(
xs
,
i
*
i
);
return
ChunkedArray
.
compact
(
xs
);
}
function
testChunkedNative
(
size
:
number
,
chunk
:
number
)
{
const
xs
=
ChunkedArray
.
create
(
s
=>
[],
1
,
chunk
,
false
);
for
(
let
i
=
0
;
i
<
size
;
i
++
)
ChunkedArray
.
add
(
xs
,
i
*
i
);
return
ChunkedArray
.
compact
(
xs
);
}
const
suite
=
new
B
.
Suite
();
const
N
=
70000
;
suite
.
add
(
'
native
'
,
()
=>
testNative
(
N
))
.
add
(
'
chunkedT 0.1k
'
,
()
=>
testChunkedTyped
(
N
,
100
,
false
))
.
add
(
'
chunkedT 4k
'
,
()
=>
testChunkedTyped
(
N
,
4096
,
false
))
.
add
(
'
chunkedT 4k lin
'
,
()
=>
testChunkedTyped
(
N
,
4096
,
true
))
.
add
(
'
chunkedT N / 2
'
,
()
=>
testChunkedTyped
(
N
,
N
/
2
,
false
))
.
add
(
'
chunkedT N
'
,
()
=>
testChunkedTyped
(
N
,
N
,
false
))
.
add
(
'
chunkedT 2 * N
'
,
()
=>
testChunkedTyped
(
N
,
2
*
N
,
false
))
.
add
(
'
chunkedN N
'
,
()
=>
testChunkedNative
(
N
,
N
))
.
add
(
'
chunkedN 0.1k
'
,
()
=>
testChunkedNative
(
N
,
100
))
.
add
(
'
chunkedN N / 2
'
,
()
=>
testChunkedNative
(
N
,
N
/
2
))
.
add
(
'
chunkedN 2 * N
'
,
()
=>
testChunkedNative
(
N
,
2
*
N
))
.
on
(
'
cycle
'
,
(
e
:
any
)
=>
{
console
.
log
(
String
(
e
.
target
));
})
.
run
();
//console.log(testChunkedTyped(10, 16));
This diff is collapsed.
Click to expand it.
src/structure/collections/ordered-set.ts
+
11
−
16
View file @
f9419bb4
...
...
@@ -24,11 +24,6 @@ class RangeImpl implements Impl {
size
:
number
;
has
(
x
:
number
)
{
return
x
>=
this
.
min
&&
x
<=
this
.
max
;
}
indexOf
(
x
:
number
)
{
return
x
>=
this
.
min
&&
x
<=
this
.
max
?
x
-
this
.
min
:
-
1
;
}
toArray
()
{
const
ret
=
new
Array
(
this
.
size
);
for
(
let
i
=
0
;
i
<
this
.
size
;
i
++
)
ret
[
i
]
=
i
+
this
.
min
;
return
ret
;
}
elementAt
(
i
:
number
)
{
return
this
.
min
+
i
;
}
elements
()
{
return
Iterator
.
Range
(
this
.
min
,
this
.
max
);
}
...
...
@@ -54,6 +49,17 @@ class ArrayImpl implements Impl {
}
namespace
OrderedSet
{
export
function
ofSingleton
(
value
:
number
):
OrderedSet
{
return
new
RangeImpl
(
value
,
value
);
}
export
function
ofRange
(
min
:
number
,
max
:
number
):
OrderedSet
{
return
max
<
min
?
Empty
:
new
RangeImpl
(
min
,
max
);
}
/** It is the responsibility of the caller to ensure the array is sorted and contains unique values. */
export
function
ofSortedArray
(
xs
:
ArrayLike
<
number
>
):
OrderedSet
{
if
(
!
xs
.
length
)
return
Empty
;
// check if the array is just a range
if
(
xs
[
xs
.
length
-
1
]
-
xs
[
0
]
+
1
===
xs
.
length
)
return
ofRange
(
xs
[
0
],
xs
[
xs
.
length
-
1
]);
return
new
ArrayImpl
(
xs
);
}
export
const
Empty
=
new
RangeImpl
(
0
,
-
1
);
export
function
isEmpty
(
a
:
OrderedSet
)
{
return
a
.
size
===
0
;
}
export
function
hashCode
(
a
:
OrderedSet
)
{
...
...
@@ -117,17 +123,6 @@ namespace OrderedSet {
return
intersectAA
((
a
as
ArrayImpl
).
values
,
(
b
as
ArrayImpl
).
values
);
}
}
export
function
ofSingleton
(
value
:
number
):
OrderedSet
{
return
new
RangeImpl
(
value
,
value
);
}
export
function
ofRange
(
min
:
number
,
max
:
number
):
OrderedSet
{
return
max
<
min
?
Empty
:
new
RangeImpl
(
min
,
max
);
}
/** It is the responsibility of the caller to ensure the array is sorted and contains unique values. */
export
function
ofSortedArray
(
xs
:
ArrayLike
<
number
>
):
OrderedSet
{
if
(
!
xs
.
length
)
return
Empty
;
// check if the array is just a range
if
(
xs
[
xs
.
length
-
1
]
-
xs
[
0
]
+
1
===
xs
.
length
)
return
ofRange
(
xs
[
0
],
xs
[
xs
.
length
-
1
]);
return
new
ArrayImpl
(
xs
);
}
export
const
Empty
=
new
RangeImpl
(
0
,
-
1
);
}
function
min
(
a
:
OrderedSet
)
{
return
(
a
as
Impl
).
min
;
}
...
...
This diff is collapsed.
Click to expand it.
src/utils/chunked-array.ts
+
87
−
83
View file @
f9419bb4
...
...
@@ -9,125 +9,129 @@
* A generic chunked array builder.
*
* When adding elements, the array growns by a specified number
* of elements
and no copying is d
one
u
ntil
ChunkedArray.compact
* is called.
* of elements
(either linear or exp
onenti
a
l
growth) and no copying
* is
done until ChunkedArray.compact is
called.
*/
export
interface
ChunkedArray
<
T
>
{
creator
:
(
size
:
number
)
=>
any
;
elementSize
:
number
;
chunkSize
:
number
;
current
:
any
;
currentIndex
:
number
;
parts
:
any
[];
elementCount
:
number
;
interface
ChunkedArray
<
T
>
{
ctor
:
(
size
:
number
)
=>
any
,
elementSize
:
number
,
linearGrowth
:
boolean
,
initialSize
:
number
,
allocatedSize
:
number
,
elementCount
:
number
,
currentSize
:
number
,
currentChunk
:
any
,
currentIndex
:
number
,
chunks
:
any
[]
}
export
namespace
ChunkedArray
{
// TODO: better api, write tests
namespace
ChunkedArray
{
export
function
is
(
x
:
any
):
x
is
ChunkedArray
<
any
>
{
return
x
.
creator
&&
x
.
chunkSize
;
}
export
function
add4
<
T
>
(
array
:
ChunkedArray
<
T
>
,
x
:
T
,
y
:
T
,
z
:
T
,
w
:
T
)
{
if
(
array
.
currentIndex
>=
array
.
chunkSize
)
{
array
.
currentIndex
=
0
;
array
.
current
=
array
.
creator
(
array
.
chunkSize
);
array
.
parts
[
array
.
parts
.
length
]
=
array
.
current
;
}
function
allocateNext
(
array
:
ChunkedArray
<
any
>
)
{
let
nextSize
=
!
array
.
allocatedSize
||
array
.
linearGrowth
?
array
.
initialSize
*
array
.
elementSize
:
Math
.
max
(
Math
.
ceil
(
0.61
*
array
.
allocatedSize
),
1
);
if
(
nextSize
%
array
.
elementSize
!==
0
)
nextSize
+=
nextSize
%
array
.
elementSize
;
array
.
currentSize
=
nextSize
;
array
.
currentIndex
=
0
;
array
.
currentChunk
=
array
.
ctor
(
nextSize
);
array
.
allocatedSize
+=
nextSize
;
array
.
chunks
[
array
.
chunks
.
length
]
=
array
.
currentChunk
;
}
array
.
current
[
array
.
currentIndex
++
]
=
x
;
array
.
current
[
array
.
currentIndex
++
]
=
y
;
array
.
current
[
array
.
currentIndex
++
]
=
z
;
array
.
current
[
array
.
currentIndex
++
]
=
w
;
export
function
add4
<
T
>
(
array
:
ChunkedArray
<
T
>
,
x
:
T
,
y
:
T
,
z
:
T
,
w
:
T
)
{
if
(
array
.
currentIndex
>=
array
.
currentSize
)
allocateNext
(
array
);
const
c
=
array
.
currentChunk
;
c
[
array
.
currentIndex
++
]
=
x
;
c
[
array
.
currentIndex
++
]
=
y
;
c
[
array
.
currentIndex
++
]
=
z
;
c
[
array
.
currentIndex
++
]
=
w
;
return
array
.
elementCount
++
;
}
export
function
add3
<
T
>
(
array
:
ChunkedArray
<
T
>
,
x
:
T
,
y
:
T
,
z
:
T
)
{
if
(
array
.
currentIndex
>=
array
.
chunkSize
)
{
array
.
currentIndex
=
0
;
array
.
current
=
array
.
creator
(
array
.
chunkSize
);
array
.
parts
[
array
.
parts
.
length
]
=
array
.
current
;
}
array
.
current
[
array
.
currentIndex
++
]
=
x
;
array
.
current
[
array
.
currentIndex
++
]
=
y
;
array
.
current
[
array
.
currentIndex
++
]
=
z
;
if
(
array
.
currentIndex
>=
array
.
currentSize
)
allocateNext
(
array
);
const
c
=
array
.
currentChunk
;
c
[
array
.
currentIndex
++
]
=
x
;
c
[
array
.
currentIndex
++
]
=
y
;
c
[
array
.
currentIndex
++
]
=
z
;
return
array
.
elementCount
++
;
}
export
function
add2
<
T
>
(
array
:
ChunkedArray
<
T
>
,
x
:
T
,
y
:
T
)
{
if
(
array
.
currentIndex
>=
array
.
chunkSize
)
{
array
.
currentIndex
=
0
;
array
.
current
=
array
.
creator
(
array
.
chunkSize
);
array
.
parts
[
array
.
parts
.
length
]
=
array
.
current
;
}
array
.
current
[
array
.
currentIndex
++
]
=
x
;
array
.
current
[
array
.
currentIndex
++
]
=
y
;
if
(
array
.
currentIndex
>=
array
.
currentSize
)
allocateNext
(
array
);
const
c
=
array
.
currentChunk
;
c
[
array
.
currentIndex
++
]
=
x
;
c
[
array
.
currentIndex
++
]
=
y
;
return
array
.
elementCount
++
;
}
export
function
add
<
T
>
(
array
:
ChunkedArray
<
T
>
,
x
:
T
)
{
if
(
array
.
currentIndex
>=
array
.
chunkSize
)
{
array
.
currentIndex
=
0
;
array
.
current
=
array
.
creator
(
array
.
chunkSize
);
array
.
parts
[
array
.
parts
.
length
]
=
array
.
current
;
}
array
.
current
[
array
.
currentIndex
++
]
=
x
;
if
(
array
.
currentIndex
>=
array
.
currentSize
)
allocateNext
(
array
);
array
.
currentChunk
[
array
.
currentIndex
++
]
=
x
;
return
array
.
elementCount
++
;
}
export
function
compact
<
T
>
(
array
:
ChunkedArray
<
T
>
):
T
[]
{
const
ret
=
array
.
creator
(
array
.
elementSize
*
array
.
elementCount
)
const
offset
=
(
array
.
parts
.
length
-
1
)
*
array
.
chunkSize
let
offsetInner
=
0
let
part
:
any
export
function
compact
<
T
>
(
array
:
ChunkedArray
<
T
>
):
ArrayLike
<
T
>
{
const
{
ctor
,
chunks
,
currentIndex
}
=
array
;
if
(
array
.
parts
.
length
>
1
)
{
if
(
array
.
parts
[
0
].
buffer
)
{
for
(
let
i
=
0
;
i
<
array
.
parts
.
length
-
1
;
i
++
)
{
ret
.
set
(
array
.
parts
[
i
],
array
.
chunkSize
*
i
);
}
}
else
{
if
(
!
chunks
.
length
)
return
ctor
(
0
);
if
(
chunks
.
length
===
1
&&
currentIndex
===
array
.
allocatedSize
)
{
return
chunks
[
0
];
}
for
(
let
i
=
0
;
i
<
array
.
parts
.
length
-
1
;
i
++
)
{
offsetInner
=
array
.
chunkSize
*
i
;
part
=
array
.
parts
[
i
];
const
ret
=
ctor
(
array
.
elementSize
*
array
.
elementCount
);
let
offset
=
0
;
for
(
l
et
j
=
0
;
j
<
array
.
chunkSize
;
j
++
)
{
ret
[
offsetInner
+
j
]
=
part
[
j
];
}
}
if
(
r
et
.
buffer
)
{
for
(
let
i
=
0
,
_i
=
chunks
.
length
-
1
;
i
<
_i
;
i
++
)
{
ret
.
set
(
chunks
[
i
],
offset
);
offset
+=
chunks
[
i
].
length
;
}
}
if
(
array
.
current
.
buffer
&&
array
.
currentIndex
>=
array
.
chunkSize
)
{
ret
.
set
(
array
.
current
,
array
.
chunkSize
*
(
array
.
parts
.
length
-
1
));
}
else
{
for
(
let
i
=
0
;
i
<
array
.
currentIndex
;
i
++
)
{
ret
[
offset
+
i
]
=
array
.
current
[
i
];
for
(
let
i
=
0
,
_i
=
chunks
.
length
-
1
;
i
<
_i
;
i
++
)
{
const
chunk
=
chunks
[
i
];
for
(
let
j
=
0
,
_j
=
chunk
.
length
;
j
<
_j
;
j
++
)
ret
[
offset
+
j
]
=
chunk
[
j
];
offset
+=
chunk
.
length
;
}
}
return
ret
as
any
;
}
export
function
create
<
T
>
(
creator
:
(
size
:
number
)
=>
any
,
chunkElementCount
:
number
,
elementSize
:
number
):
ChunkedArray
<
T
>
{
chunkElementCount
=
chunkElementCount
|
0
;
if
(
chunkElementCount
<=
0
)
chunkElementCount
=
1
;
const
lastChunk
=
chunks
[
chunks
.
length
-
1
];
if
(
ret
.
buffer
&&
currentIndex
>=
array
.
currentSize
)
{
ret
.
set
(
lastChunk
,
offset
);
}
else
{
for
(
let
j
=
0
,
_j
=
lastChunk
.
length
;
j
<
_j
;
j
++
)
ret
[
offset
+
j
]
=
lastChunk
[
j
];
}
l
et
chunkSize
=
chunkElementCount
*
elementSize
;
let
current
=
creator
(
chunkSize
)
r
et
urn
ret
;
}
export
function
create
<
T
>
(
ctor
:
(
size
:
number
)
=>
any
,
elementSize
:
number
,
initialSize
:
number
,
linearGrowth
:
boolean
):
ChunkedArray
<
T
>
{
return
{
ctor
,
elementSize
,
chunkSize
,
creator
,
current
,
parts
:
[
current
],
linearGrowth
,
initialSize
,
allocatedSize
:
0
,
elementCount
:
0
,
currentSize
:
0
,
currentChunk
:
void
0
,
currentIndex
:
0
,
elementCount
:
0
}
as
ChunkedArray
<
T
>
chunks
:
[]
}
as
ChunkedArray
<
T
>
;
}
}
export
default
ChunkedArray
\ No newline at end of file
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment