Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
掘金者说
vscode
提交
35e5c9af
V
vscode
项目概览
掘金者说
/
vscode
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
V
vscode
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
35e5c9af
编写于
5月 02, 2016
作者:
B
Benjamin Pasero
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #6031 from Microsoft/ben/cache
LinkedMap for bounded caches (#5621)
上级
f2dbc16b
b77fc081
变更
5
隐藏空白更改
内联
并排
Showing
5 changed file
with
448 addition
and
57 deletion
+448
-57
src/vs/base/common/filters.ts
src/vs/base/common/filters.ts
+4
-3
src/vs/base/common/glob.ts
src/vs/base/common/glob.ts
+50
-46
src/vs/base/common/map.ts
src/vs/base/common/map.ts
+179
-0
src/vs/base/common/strings.ts
src/vs/base/common/strings.ts
+6
-8
src/vs/base/test/common/map.test.ts
src/vs/base/test/common/map.test.ts
+209
-0
未找到文件。
src/vs/base/common/filters.ts
浏览文件 @
35e5c9af
...
...
@@ -5,6 +5,7 @@
'
use strict
'
;
import
strings
=
require
(
'
vs/base/common/strings
'
);
import
{
LinkedMap
}
from
'
vs/base/common/map
'
;
export
interface
IFilter
{
// Returns null if word doesn't match.
...
...
@@ -298,7 +299,7 @@ export enum SubstringMatching {
export
const
fuzzyContiguousFilter
=
or
(
matchesPrefix
,
matchesCamelCase
,
matchesContiguousSubString
);
const
fuzzySeparateFilter
=
or
(
matchesPrefix
,
matchesCamelCase
,
matchesSubString
);
const
fuzzyRegExpCache
:
{
[
key
:
string
]:
RegExp
;
}
=
{};
const
fuzzyRegExpCache
=
new
LinkedMap
<
RegExp
>
(
10000
);
// bounded to 10000 elements
export
function
matchesFuzzy
(
word
:
string
,
wordToMatchAgainst
:
string
,
enableSeparateSubstringMatching
=
false
):
IMatch
[]
{
if
(
typeof
word
!==
'
string
'
||
typeof
wordToMatchAgainst
!==
'
string
'
)
{
...
...
@@ -306,10 +307,10 @@ export function matchesFuzzy(word: string, wordToMatchAgainst: string, enableSep
}
// Form RegExp for wildcard matches
let
regexp
=
fuzzyRegExpCache
[
word
]
;
let
regexp
=
fuzzyRegExpCache
.
get
(
word
)
;
if
(
!
regexp
)
{
regexp
=
new
RegExp
(
strings
.
convertSimple2RegExpPattern
(
word
),
'
i
'
);
fuzzyRegExpCache
[
word
]
=
regexp
;
fuzzyRegExpCache
.
set
(
word
,
regexp
)
;
}
// RegExp Filter
...
...
src/vs/base/common/glob.ts
浏览文件 @
35e5c9af
...
...
@@ -6,9 +6,7 @@
import
strings
=
require
(
'
vs/base/common/strings
'
);
import
paths
=
require
(
'
vs/base/common/paths
'
);
const
CACHE
:
{
[
glob
:
string
]:
RegExp
}
=
Object
.
create
(
null
);
const
MAX_CACHED
=
10000
;
import
{
LinkedMap
}
from
'
vs/base/common/map
'
;
export
interface
IExpression
{
[
pattern
:
string
]:
boolean
|
SiblingClause
|
any
;
...
...
@@ -212,7 +210,25 @@ function parseRegExp(pattern: string): string {
return
regEx
;
}
function
globToRegExp
(
pattern
:
string
):
RegExp
{
// regexes to check for trival glob patterns that just check for String#endsWith
const
T1
=
/^
\*\*\/\*\.[\w\.
-
]
+$/
;
// **/*.something
const
T2
=
/^
\*\*\/[\w\.
-
]
+$/
;
// **/something
const
T3
=
/^{
\*\*\/\*\.[\w\.
-
]
+
(
,
\*\*\/\*\.[\w\.
-
]
+
)
*}$/
;
// {**/*.something,**/*.else}
enum
Trivia
{
T1
,
// **/*.something
T2
,
// **/something
T3
// {**/*.something,**/*.else}
}
interface
IParsedPattern
{
regexp
?:
RegExp
;
trivia
?:
Trivia
;
}
const
CACHE
=
new
LinkedMap
<
IParsedPattern
>
(
10000
);
// bounded to 10000 elements
function
parsePattern
(
pattern
:
string
):
IParsedPattern
{
if
(
!
pattern
)
{
return
null
;
}
...
...
@@ -221,27 +237,35 @@ function globToRegExp(pattern: string): RegExp {
pattern
=
pattern
.
trim
();
// Check cache
if
(
CACHE
[
pattern
])
{
let
cached
=
CACHE
[
pattern
];
cached
.
lastIndex
=
0
;
// reset RegExp to its initial state to reuse it!
let
parsedPattern
=
CACHE
.
get
(
pattern
);
if
(
parsedPattern
)
{
if
(
parsedPattern
.
regexp
)
{
parsedPattern
.
regexp
.
lastIndex
=
0
;
// reset RegExp to its initial state to reuse it!
}
return
cached
;
return
parsedPattern
;
}
let
regEx
=
parseRegExp
(
pattern
);
// Wrap it
regEx
=
'
^
'
+
regEx
+
'
$
'
;
parsedPattern
=
Object
.
create
(
null
);
// Convert to regexp and be ready for errors
let
result
=
toRegExp
(
regEx
);
// Check for Trivias
if
(
T1
.
test
(
pattern
))
{
parsedPattern
.
trivia
=
Trivia
.
T1
;
}
else
if
(
T2
.
test
(
pattern
))
{
parsedPattern
.
trivia
=
Trivia
.
T2
;
}
else
if
(
T3
.
test
(
pattern
))
{
parsedPattern
.
trivia
=
Trivia
.
T3
;
}
//
Make sure to cache (bounded)
if
(
Object
.
getOwnPropertyNames
(
CACHE
).
length
<
MAX_CACHED
)
{
CACHE
[
pattern
]
=
result
;
//
Otherwise convert to pattern
else
{
parsedPattern
.
regexp
=
toRegExp
(
`^
${
parseRegExp
(
pattern
)}
$`
)
;
}
return
result
;
// Cache
CACHE
.
set
(
pattern
,
parsedPattern
);
return
parsedPattern
;
}
function
toRegExp
(
regEx
:
string
):
RegExp
{
...
...
@@ -252,28 +276,6 @@ function toRegExp(regEx: string): RegExp {
}
}
function
testWithCache
(
glob
:
string
,
pattern
:
RegExp
,
cache
:
{
[
glob
:
string
]:
boolean
}):
boolean
{
let
res
=
cache
[
glob
];
if
(
typeof
res
!==
'
boolean
'
)
{
res
=
pattern
.
test
(
glob
);
// Make sure to cache (bounded)
if
(
Object
.
getOwnPropertyNames
(
cache
).
length
<
MAX_CACHED
)
{
cache
[
glob
]
=
res
;
}
}
return
res
;
}
// regexes to check for trival glob patterns that just check for String#endsWith
const
trivia1
=
/^
\*\*\/\*\.[\w\.
-
]
+$/
;
// **/*.something
const
trivia2
=
/^
\*\*\/[\w\.
-
]
+$/
;
// **/something
const
trivia3
=
/^{
\*\*\/\*\.[\w\.
-
]
+
(
,
\*\*\/\*\.[\w\.
-
]
+
)
*}$/
;
// {**/*.something,**/*.else}
const
T1_CACHE
:
{
[
glob
:
string
]:
boolean
}
=
Object
.
create
(
null
);
const
T2_CACHE
:
{
[
glob
:
string
]:
boolean
}
=
Object
.
create
(
null
);
const
T3_CACHE
:
{
[
glob
:
string
]:
boolean
}
=
Object
.
create
(
null
);
/**
* Simplified glob matching. Supports a subset of glob patterns:
* - * matches anything inside a path segment
...
...
@@ -291,27 +293,29 @@ export function match(arg1: string | IExpression, path: string, siblings?: strin
// Glob with String
if
(
typeof
arg1
===
'
string
'
)
{
const
parsedPattern
=
parsePattern
(
arg1
);
if
(
!
parsedPattern
)
{
return
false
;
}
// common pattern: **/*.txt just need endsWith check
if
(
testWithCache
(
arg1
,
trivia1
,
T1_CACHE
)
)
{
if
(
parsedPattern
.
trivia
===
Trivia
.
T1
)
{
return
strings
.
endsWith
(
path
,
arg1
.
substr
(
4
));
// '**/*'.length === 4
}
// common pattern: **/some.txt just need basename check
if
(
testWithCache
(
arg1
,
trivia2
,
T2_CACHE
)
)
{
if
(
parsedPattern
.
trivia
===
Trivia
.
T2
)
{
const
base
=
arg1
.
substr
(
3
);
// '**/'.length === 3
return
path
===
base
||
strings
.
endsWith
(
path
,
`/
${
base
}
`
)
||
strings
.
endsWith
(
path
,
`\
\$
{base}`
);
}
// repetition of common patterns (see above) {**/*.txt,**/*.png}
if
(
testWithCache
(
arg1
,
trivia3
,
T3_CACHE
)
)
{
if
(
parsedPattern
.
trivia
===
Trivia
.
T3
)
{
return
arg1
.
slice
(
1
,
-
1
).
split
(
'
,
'
).
some
(
pattern
=>
match
(
pattern
,
path
));
}
const
regExp
=
globToRegExp
(
arg1
);
return
regExp
&&
regExp
.
test
(
path
);
return
parsedPattern
.
regexp
.
test
(
path
);
}
// Glob with Expression
...
...
src/vs/base/common/map.ts
0 → 100644
浏览文件 @
35e5c9af
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'
use strict
'
;
export
interface
Entry
<
T
>
{
next
?:
Entry
<
T
>
;
prev
?:
Entry
<
T
>
;
key
:
string
;
value
:
T
;
}
/**
* A simple Map<T> that optionally allows to set a limit of entries to store. Once the limit is hit,
* the cache will remove the entry that was last recently added. Or, if a ratio is provided below 1,
* all elements will be removed until the ratio is full filled (e.g. 0.75 to remove 25% of old elements).
*/
export
class
LinkedMap
<
T
>
{
protected
map
:
{
[
key
:
string
]:
Entry
<
T
>
};
private
head
:
Entry
<
T
>
;
private
tail
:
Entry
<
T
>
;
private
_size
:
number
;
private
ratio
:
number
;
constructor
(
private
limit
=
Number
.
MAX_VALUE
,
ratio
=
1
)
{
this
.
map
=
Object
.
create
(
null
);
this
.
_size
=
0
;
this
.
ratio
=
limit
*
ratio
;
}
public
get
size
():
number
{
return
this
.
_size
;
}
public
set
(
key
:
string
,
value
:
T
):
boolean
{
if
(
this
.
map
[
key
])
{
return
false
;
// already present!
}
const
entry
:
Entry
<
T
>
=
{
key
,
value
};
this
.
push
(
entry
);
if
(
this
.
_size
>
this
.
limit
)
{
this
.
trim
();
}
return
true
;
}
public
get
(
key
:
string
):
T
{
const
entry
=
this
.
map
[
key
];
return
entry
?
entry
.
value
:
null
;
}
public
delete
(
key
:
string
):
T
{
const
entry
=
this
.
map
[
key
];
if
(
entry
)
{
this
.
map
[
key
]
=
void
0
;
this
.
_size
--
;
if
(
entry
.
next
)
{
entry
.
next
.
prev
=
entry
.
prev
;
// [A]<-[x]<-[C] = [A]<-[C]
}
else
{
this
.
head
=
entry
.
prev
;
// [A]-[x] = [A]
}
if
(
entry
.
prev
)
{
entry
.
prev
.
next
=
entry
.
next
;
// [A]->[x]->[C] = [A]->[C]
}
else
{
this
.
tail
=
entry
.
next
;
// [x]-[A] = [A]
}
return
entry
.
value
;
}
return
null
;
}
public
has
(
key
:
string
):
boolean
{
return
!!
this
.
map
[
key
];
}
public
clear
():
void
{
this
.
map
=
Object
.
create
(
null
);
this
.
_size
=
0
;
this
.
head
=
null
;
this
.
tail
=
null
;
}
protected
push
(
entry
:
Entry
<
T
>
):
void
{
if
(
this
.
head
)
{
// [A]-[B] = [A]-[B]->[X]
entry
.
prev
=
this
.
head
;
this
.
head
.
next
=
entry
;
}
if
(
!
this
.
tail
)
{
this
.
tail
=
entry
;
}
this
.
head
=
entry
;
this
.
map
[
entry
.
key
]
=
entry
;
this
.
_size
++
;
}
private
trim
():
void
{
if
(
this
.
tail
)
{
// Remove all elements until ratio is reached
if
(
this
.
ratio
<
this
.
limit
)
{
let
index
=
0
;
let
current
=
this
.
tail
;
while
(
current
.
next
)
{
// Remove the entry
this
.
map
[
current
.
key
]
=
void
0
;
this
.
_size
--
;
// if we reached the element that overflows our ratio condition
// make its next element the new tail of the Map and adjust the size
if
(
index
===
this
.
ratio
)
{
this
.
tail
=
current
.
next
;
this
.
tail
.
prev
=
null
;
break
;
}
// Move on
current
=
current
.
next
;
index
++
;
}
}
// Just remove the tail element
else
{
this
.
map
[
this
.
tail
.
key
]
=
void
0
;
this
.
_size
--
;
// [x]-[B] = [B]
this
.
tail
=
this
.
tail
.
next
;
this
.
tail
.
prev
=
null
;
}
}
}
}
/**
* A subclass of Map<T> that makes an entry the MRU entry as soon
* as it is being accessed. In combination with the limit for the
* maximum number of elements in the cache, it helps to remove those
* entries from the cache that are LRU.
*/
export
class
LRUCache
<
T
>
extends
LinkedMap
<
T
>
{
constructor
(
limit
:
number
)
{
super
(
limit
);
}
public
get
(
key
:
string
):
T
{
// Upon access of an entry, make it the head of
// the linked map so that it is the MRU element
const
entry
=
this
.
map
[
key
];
if
(
entry
)
{
this
.
delete
(
key
);
this
.
push
(
entry
);
return
entry
.
value
;
}
return
null
;
}
}
\ No newline at end of file
src/vs/base/common/strings.ts
浏览文件 @
35e5c9af
...
...
@@ -4,6 +4,8 @@
*--------------------------------------------------------------------------------------------*/
'
use strict
'
;
import
{
LinkedMap
}
from
'
vs/base/common/map
'
;
/**
* The empty string.
*/
...
...
@@ -247,14 +249,13 @@ export function regExpLeadsToEndlessLoop(regexp: RegExp): boolean {
*/
export
let
canNormalize
=
typeof
((
<
any
>
''
).
normalize
)
===
'
function
'
;
const
nonAsciiCharactersPattern
=
/
[^\u
0000-
\u
0080
]
/
;
const
normalizedCache
=
Object
.
create
(
null
);
let
cacheCounter
=
0
;
const
normalizedCache
=
new
LinkedMap
<
string
>
(
10000
);
// bounded to 10000 elements
export
function
normalizeNFC
(
str
:
string
):
string
{
if
(
!
canNormalize
||
!
str
)
{
return
str
;
}
const
cached
=
normalizedCache
[
str
]
;
const
cached
=
normalizedCache
.
get
(
str
)
;
if
(
cached
)
{
return
cached
;
}
...
...
@@ -266,11 +267,8 @@ export function normalizeNFC(str: string): string {
res
=
str
;
}
// Use the cache for fast lookup but do not let it grow unbounded
if
(
cacheCounter
<
10000
)
{
normalizedCache
[
str
]
=
res
;
cacheCounter
++
;
}
// Use the cache for fast lookup
normalizedCache
.
set
(
str
,
res
);
return
res
;
}
...
...
src/vs/base/test/common/map.test.ts
0 → 100644
浏览文件 @
35e5c9af
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'
use strict
'
;
import
{
LinkedMap
,
LRUCache
}
from
'
vs/base/common/map
'
;
import
*
as
assert
from
'
assert
'
;
suite
(
'
Map
'
,
()
=>
{
test
(
'
LinkedMap - basics
'
,
function
()
{
const
map
=
new
LinkedMap
<
any
>
();
assert
.
equal
(
map
.
size
,
0
);
map
.
set
(
'
1
'
,
1
);
map
.
set
(
'
2
'
,
'
2
'
);
map
.
set
(
'
3
'
,
true
);
const
obj
=
Object
.
create
(
null
);
map
.
set
(
'
4
'
,
obj
);
const
date
=
Date
.
now
();
map
.
set
(
'
5
'
,
date
);
assert
.
equal
(
map
.
size
,
5
);
assert
.
equal
(
map
.
get
(
'
1
'
),
1
);
assert
.
equal
(
map
.
get
(
'
2
'
),
'
2
'
);
assert
.
equal
(
map
.
get
(
'
3
'
),
true
);
assert
.
equal
(
map
.
get
(
'
4
'
),
obj
);
assert
.
equal
(
map
.
get
(
'
5
'
),
date
);
assert
.
ok
(
!
map
.
get
(
'
6
'
));
map
.
delete
(
'
6
'
);
assert
.
equal
(
map
.
size
,
5
);
assert
.
equal
(
map
.
delete
(
'
1
'
),
1
);
assert
.
equal
(
map
.
delete
(
'
2
'
),
'
2
'
);
assert
.
equal
(
map
.
delete
(
'
3
'
),
true
);
assert
.
equal
(
map
.
delete
(
'
4
'
),
obj
);
assert
.
equal
(
map
.
delete
(
'
5
'
),
date
);
assert
.
equal
(
map
.
size
,
0
);
assert
.
ok
(
!
map
.
get
(
'
5
'
));
assert
.
ok
(
!
map
.
get
(
'
4
'
));
assert
.
ok
(
!
map
.
get
(
'
3
'
));
assert
.
ok
(
!
map
.
get
(
'
2
'
));
assert
.
ok
(
!
map
.
get
(
'
1
'
));
map
.
set
(
'
1
'
,
1
);
map
.
set
(
'
2
'
,
'
2
'
);
assert
.
ok
(
map
.
set
(
'
3
'
,
true
));
// adding an element returns true
assert
.
ok
(
!
map
.
set
(
'
3
'
,
true
));
// adding it again returns false
assert
.
ok
(
map
.
has
(
'
1
'
));
assert
.
equal
(
map
.
get
(
'
1
'
),
1
);
assert
.
equal
(
map
.
get
(
'
2
'
),
'
2
'
);
assert
.
equal
(
map
.
get
(
'
3
'
),
true
);
map
.
clear
();
assert
.
equal
(
map
.
size
,
0
);
assert
.
ok
(
!
map
.
get
(
'
1
'
));
assert
.
ok
(
!
map
.
get
(
'
2
'
));
assert
.
ok
(
!
map
.
get
(
'
3
'
));
assert
.
ok
(
!
map
.
has
(
'
1
'
));
});
test
(
'
LinkedMap - bounded
'
,
function
()
{
const
map
=
new
LinkedMap
<
number
>
(
5
);
assert
.
equal
(
0
,
map
.
size
);
map
.
set
(
'
1
'
,
1
);
map
.
set
(
'
2
'
,
2
);
map
.
set
(
'
3
'
,
3
);
map
.
set
(
'
4
'
,
4
);
map
.
set
(
'
5
'
,
5
);
assert
.
equal
(
5
,
map
.
size
);
assert
.
equal
(
map
.
get
(
'
1
'
),
1
);
assert
.
equal
(
map
.
get
(
'
2
'
),
2
);
assert
.
equal
(
map
.
get
(
'
3
'
),
3
);
assert
.
equal
(
map
.
get
(
'
4
'
),
4
);
assert
.
equal
(
map
.
get
(
'
5
'
),
5
);
map
.
set
(
'
6
'
,
6
);
assert
.
equal
(
5
,
map
.
size
);
assert
.
ok
(
!
map
.
get
(
'
1
'
));
assert
.
equal
(
map
.
get
(
'
2
'
),
2
);
assert
.
equal
(
map
.
get
(
'
3
'
),
3
);
assert
.
equal
(
map
.
get
(
'
4
'
),
4
);
assert
.
equal
(
map
.
get
(
'
5
'
),
5
);
assert
.
equal
(
map
.
get
(
'
6
'
),
6
);
map
.
set
(
'
7
'
,
7
);
map
.
set
(
'
8
'
,
8
);
map
.
set
(
'
9
'
,
9
);
assert
.
equal
(
5
,
map
.
size
);
assert
.
ok
(
!
map
.
get
(
'
1
'
));
assert
.
ok
(
!
map
.
get
(
'
2
'
));
assert
.
ok
(
!
map
.
get
(
'
3
'
));
assert
.
ok
(
!
map
.
get
(
'
4
'
));
assert
.
equal
(
map
.
get
(
'
5
'
),
5
);
assert
.
equal
(
map
.
get
(
'
6
'
),
6
);
assert
.
equal
(
map
.
get
(
'
7
'
),
7
);
assert
.
equal
(
map
.
get
(
'
8
'
),
8
);
assert
.
equal
(
map
.
get
(
'
9
'
),
9
);
map
.
delete
(
'
5
'
);
map
.
delete
(
'
7
'
);
assert
.
equal
(
3
,
map
.
size
);
assert
.
ok
(
!
map
.
get
(
'
5
'
));
assert
.
ok
(
!
map
.
get
(
'
7
'
));
assert
.
equal
(
map
.
get
(
'
6
'
),
6
);
assert
.
equal
(
map
.
get
(
'
8
'
),
8
);
assert
.
equal
(
map
.
get
(
'
9
'
),
9
);
map
.
set
(
'
10
'
,
10
);
map
.
set
(
'
11
'
,
11
);
map
.
set
(
'
12
'
,
12
);
map
.
set
(
'
13
'
,
13
);
map
.
set
(
'
14
'
,
14
);
assert
.
equal
(
5
,
map
.
size
);
assert
.
equal
(
map
.
get
(
'
10
'
),
10
);
assert
.
equal
(
map
.
get
(
'
11
'
),
11
);
assert
.
equal
(
map
.
get
(
'
12
'
),
12
);
assert
.
equal
(
map
.
get
(
'
13
'
),
13
);
assert
.
equal
(
map
.
get
(
'
14
'
),
14
);
});
test
(
'
LinkedMap - bounded with ratio
'
,
function
()
{
const
map
=
new
LinkedMap
<
number
>
(
6
,
0.5
);
assert
.
equal
(
0
,
map
.
size
);
map
.
set
(
'
1
'
,
1
);
map
.
set
(
'
2
'
,
2
);
map
.
set
(
'
3
'
,
3
);
map
.
set
(
'
4
'
,
4
);
map
.
set
(
'
5
'
,
5
);
map
.
set
(
'
6
'
,
6
);
assert
.
equal
(
6
,
map
.
size
);
map
.
set
(
'
7
'
,
7
);
assert
.
equal
(
3
,
map
.
size
);
assert
.
ok
(
!
map
.
has
(
'
1
'
));
assert
.
ok
(
!
map
.
has
(
'
2
'
));
assert
.
ok
(
!
map
.
has
(
'
3
'
));
assert
.
ok
(
!
map
.
has
(
'
4
'
));
assert
.
equal
(
map
.
get
(
'
5
'
),
5
);
assert
.
equal
(
map
.
get
(
'
6
'
),
6
);
assert
.
equal
(
map
.
get
(
'
7
'
),
7
);
map
.
set
(
'
8
'
,
8
);
map
.
set
(
'
9
'
,
9
);
map
.
set
(
'
10
'
,
10
);
assert
.
equal
(
6
,
map
.
size
);
assert
.
equal
(
map
.
get
(
'
5
'
),
5
);
assert
.
equal
(
map
.
get
(
'
6
'
),
6
);
assert
.
equal
(
map
.
get
(
'
7
'
),
7
);
assert
.
equal
(
map
.
get
(
'
8
'
),
8
);
assert
.
equal
(
map
.
get
(
'
9
'
),
9
);
assert
.
equal
(
map
.
get
(
'
10
'
),
10
);
});
test
(
'
LRUCache
'
,
function
()
{
const
cache
=
new
LRUCache
<
number
>
(
3
);
assert
.
equal
(
0
,
cache
.
size
);
cache
.
set
(
'
1
'
,
1
);
cache
.
set
(
'
2
'
,
2
);
cache
.
set
(
'
3
'
,
3
);
assert
.
equal
(
3
,
cache
.
size
);
assert
.
equal
(
cache
.
get
(
'
1
'
),
1
);
assert
.
equal
(
cache
.
get
(
'
2
'
),
2
);
assert
.
equal
(
cache
.
get
(
'
3
'
),
3
);
cache
.
set
(
'
4
'
,
4
);
assert
.
equal
(
3
,
cache
.
size
);
assert
.
equal
(
cache
.
get
(
'
4
'
),
4
);
// this changes MRU order
assert
.
equal
(
cache
.
get
(
'
3
'
),
3
);
assert
.
equal
(
cache
.
get
(
'
2
'
),
2
);
cache
.
set
(
'
5
'
,
5
);
cache
.
set
(
'
6
'
,
6
);
assert
.
equal
(
3
,
cache
.
size
);
assert
.
equal
(
cache
.
get
(
'
2
'
),
2
);
assert
.
equal
(
cache
.
get
(
'
5
'
),
5
);
assert
.
equal
(
cache
.
get
(
'
6
'
),
6
);
assert
.
ok
(
!
cache
.
has
(
'
3
'
));
assert
.
ok
(
!
cache
.
has
(
'
4
'
));
});
});
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录