Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
49b85b79
提交
49b85b79
authored
10月 27, 2012
作者:
Thomas Mueller
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
A persistent multi-version map: simplified cursor
上级
4b20cf9b
隐藏空白字符变更
内嵌
并排
正在显示
7 个修改的文件
包含
273 行增加
和
320 行删除
+273
-320
MVRTreeMap.java
h2/src/test/org/h2/test/store/MVRTreeMap.java
+5
-60
TestMVStore.java
h2/src/test/org/h2/test/store/TestMVStore.java
+4
-4
ChangeCursor.java
h2/src/tools/org/h2/dev/store/btree/ChangeCursor.java
+188
-29
Cursor.java
h2/src/tools/org/h2/dev/store/btree/Cursor.java
+47
-69
MVMap.java
h2/src/tools/org/h2/dev/store/btree/MVMap.java
+11
-69
Page.java
h2/src/tools/org/h2/dev/store/btree/Page.java
+18
-1
RangeCursor.java
h2/src/tools/org/h2/dev/store/btree/RangeCursor.java
+0
-88
没有找到文件。
h2/src/test/org/h2/test/store/MVRTreeMap.java
浏览文件 @
49b85b79
...
...
@@ -7,11 +7,9 @@
package
org
.
h2
.
test
.
store
;
import
java.util.ArrayList
;
import
org.h2.dev.store.btree.DataType
;
import
org.h2.dev.store.btree.MVMap
;
import
org.h2.dev.store.btree.MVStore
;
import
org.h2.dev.store.btree.Cursor
;
import
org.h2.dev.store.btree.CursorPos
;
import
org.h2.dev.store.btree.DataType
;
import
org.h2.dev.store.btree.Page
;
import
org.h2.util.New
;
...
...
@@ -399,63 +397,6 @@ public class MVRTreeMap<K, V> extends MVMap<K, V> {
}
}
/**
* Go to the first element for the given key.
*
* @param p the current page
* @param cursor the cursor
* @param key the key
* @return the cursor position
*/
protected
CursorPos
min
(
Page
p
,
Cursor
<
K
,
V
>
cursor
,
Object
key
)
{
if
(
p
==
null
)
{
return
null
;
}
while
(
true
)
{
CursorPos
c
=
new
CursorPos
(
p
,
0
,
null
);
if
(
p
.
isLeaf
())
{
return
c
;
}
cursor
.
push
(
c
);
p
=
p
.
getChildPage
(
0
);
}
}
/**
* Get the next key.
*
* @param p the cursor position
* @param cursor the cursor
* @return the next key
*/
protected
Object
nextKey
(
CursorPos
p
,
Cursor
<
K
,
V
>
cursor
)
{
while
(
p
!=
null
)
{
int
index
=
p
.
index
++;
Page
x
=
p
.
page
;
if
(
index
<
x
.
getKeyCount
())
{
return
x
.
getKey
(
index
);
}
while
(
true
)
{
p
=
cursor
.
pop
();
if
(
p
==
null
)
{
break
;
}
index
=
++
p
.
index
;
x
=
p
.
page
;
// this is different from a b-tree:
// we have one less child
if
(
index
<
x
.
getKeyCount
())
{
cursor
.
push
(
p
);
p
=
cursor
.
visitChild
(
x
,
index
);
if
(
p
!=
null
)
{
break
;
}
}
}
}
return
null
;
}
public
boolean
isQuadraticSplit
()
{
return
quadraticSplit
;
}
...
...
@@ -464,4 +405,8 @@ public class MVRTreeMap<K, V> extends MVMap<K, V> {
this
.
quadraticSplit
=
quadraticSplit
;
}
protected
int
getChildPageCount
(
Page
p
)
{
return
p
.
getChildPageCount
()
-
1
;
}
}
h2/src/test/org/h2/test/store/TestMVStore.java
浏览文件 @
49b85b79
...
...
@@ -184,21 +184,21 @@ public class TestMVStore extends TestBase {
for
(
int
i
=
20
;
i
<
40
;
i
++)
{
assertEquals
(
"Hi"
,
m
.
put
(
i
,
"Hello"
));
}
s
.
incrementVersion
();
long
old
=
s
.
incrementVersion
();
for
(
int
i
=
10
;
i
<
15
;
i
++)
{
m
.
put
(
i
,
"Hallo"
);
}
m
.
put
(
50
,
"Hallo"
);
for
(
int
i
=
90
;
i
<
100
;
i
++)
{
for
(
int
i
=
90
;
i
<
93
;
i
++)
{
assertEquals
(
"Hi"
,
m
.
remove
(
i
));
}
assertEquals
(
null
,
m
.
put
(
100
,
"Hallo"
));
Iterator
<
Integer
>
it
=
m
.
changeIterator
(
s
.
getCurrentVersion
()
);
Iterator
<
Integer
>
it
=
m
.
changeIterator
(
old
);
ArrayList
<
Integer
>
list
=
New
.
arrayList
();
while
(
it
.
hasNext
())
{
list
.
add
(
it
.
next
());
}
assertEquals
(
"[
9, 10, 11, 12, 13, 14, 48, 49, 50, 87, 88, 89, 100
]"
,
list
.
toString
());
assertEquals
(
"[
10, 11, 12, 13, 14, 50, 100, 90, 91, 92
]"
,
list
.
toString
());
s
.
close
();
}
...
...
h2/src/tools/org/h2/dev/store/btree/ChangeCursor.java
浏览文件 @
49b85b79
...
...
@@ -6,57 +6,216 @@
*/
package
org
.
h2
.
dev
.
store
.
btree
;
import
java.util.Iterator
;
/**
* A cursor to iterate over all keys in new pages.
*
* @param <K> the key type
* @param <V> the value type
*/
public
class
ChangeCursor
<
K
,
V
>
extends
Cursor
<
K
,
V
>
{
public
class
ChangeCursor
<
K
,
V
>
implements
Iterator
<
K
>
{
private
final
MVMap
<
K
,
V
>
map
;
private
final
Page
root1
,
root2
;
private
final
long
minVersion
;
/**
* The state of this cursor.
* 0: not initialized
* 1: reading from root1
* 2: reading from root2
* 3: closed
*/
private
int
state
;
private
CursorPos
pos1
,
pos2
;
private
K
current
;
ChangeCursor
(
MVMap
<
K
,
V
>
map
,
Page
root
,
K
from
,
long
minVersion
)
{
super
(
map
,
root
,
from
);
this
.
minVersion
=
minVersion
;
ChangeCursor
(
MVMap
<
K
,
V
>
map
,
Page
root1
,
Page
root2
)
{
this
.
map
=
map
;
this
.
root1
=
root1
;
this
.
root2
=
root2
;
}
public
CursorPos
min
(
Page
p
,
K
from
)
{
while
(
p
!=
null
&&
p
.
getVersion
()
>=
minVersion
)
{
if
(
p
.
isLeaf
())
{
return
new
CursorPos
(
p
,
0
,
null
);
public
K
next
()
{
K
c
=
current
;
fetchNext
();
return
c
;
}
public
boolean
hasNext
()
{
if
(
state
==
0
)
{
pos1
=
new
CursorPos
(
root1
,
0
,
null
);
pos1
=
min
(
pos1
);
state
=
1
;
fetchNext
();
}
return
current
!=
null
;
}
public
void
remove
()
{
throw
new
UnsupportedOperationException
();
}
private
void
fetchNext
()
{
while
(
fetchNextKey
())
{
if
(
pos1
==
null
||
pos2
==
null
)
{
break
;
}
@SuppressWarnings
(
"unchecked"
)
V
v1
=
(
V
)
map
.
binarySearch
(
root1
,
current
);
@SuppressWarnings
(
"unchecked"
)
V
v2
=
(
V
)
map
.
binarySearch
(
root2
,
current
);
if
(!
v1
.
equals
(
v2
))
{
break
;
}
}
}
private
boolean
fetchNextKey
()
{
while
(
true
)
{
if
(
state
==
3
)
{
return
false
;
}
for
(
int
i
=
0
;
i
<
p
.
getChildPageCount
();
i
++)
{
if
(
isChildOld
(
p
,
i
))
{
if
(
state
==
1
)
{
// read from root1
pos1
=
fetchNext
(
pos1
);
if
(
pos1
==
null
)
{
// reached the end of pos1
state
=
2
;
pos2
=
null
;
continue
;
}
CursorPos
c
=
new
CursorPos
(
p
,
i
,
null
);
push
(
c
);
p
=
p
.
getChildPage
(
i
);
break
;
pos2
=
find
(
root2
,
current
);
if
(
pos2
==
null
)
{
// not found in root2
return
true
;
}
if
(!
pos1
.
page
.
equals
(
pos2
.
page
))
{
// the page is different,
// so the entry has possibly changed
return
true
;
}
while
(
true
)
{
pos1
=
pos1
.
parent
;
if
(
pos1
==
null
)
{
// reached end of pos1
state
=
2
;
pos2
=
null
;
break
;
}
pos2
=
pos2
.
parent
;
if
(
pos2
==
null
||
!
pos1
.
page
.
equals
(
pos2
.
page
.
getPos
()))
{
if
(
pos1
.
index
+
1
<
map
.
getChildPageCount
(
pos1
.
page
))
{
pos1
=
new
CursorPos
(
pos1
.
page
.
getChildPage
(++
pos1
.
index
),
0
,
pos1
);
pos1
=
min
(
pos1
);
break
;
}
}
}
}
if
(
state
==
2
)
{
if
(
pos2
==
null
)
{
// init reading from root2
pos2
=
new
CursorPos
(
root2
,
0
,
null
);
pos2
=
min
(
pos2
);
}
// read from root2
pos2
=
fetchNext
(
pos2
);
if
(
pos2
==
null
)
{
// reached the end of pos2
state
=
3
;
current
=
null
;
continue
;
}
pos1
=
find
(
root1
,
current
);
if
(
pos1
!=
null
)
{
// found a corresponding record
// so it was not deleted
// but now we may need to skip pages
if
(!
pos1
.
page
.
equals
(
pos2
.
page
))
{
// the page is different
pos1
=
null
;
continue
;
}
while
(
true
)
{
pos2
=
pos2
.
parent
;
if
(
pos2
==
null
)
{
// reached end of pos1
state
=
3
;
current
=
null
;
pos1
=
null
;
break
;
}
pos1
=
pos1
.
parent
;
if
(
pos1
==
null
||
!
pos2
.
page
.
equals
(
pos1
.
page
.
getPos
()))
{
if
(
pos2
.
index
+
1
<
map
.
getChildPageCount
(
pos2
.
page
))
{
pos2
=
new
CursorPos
(
pos2
.
page
.
getChildPage
(++
pos2
.
index
),
0
,
pos2
);
pos2
=
min
(
pos2
);
break
;
}
}
}
pos1
=
null
;
continue
;
}
// found no corresponding record
// so it was deleted
return
true
;
}
}
}
private
CursorPos
find
(
Page
p
,
K
key
)
{
// TODO combine with RangeCursor.min
// possibly move to MVMap
CursorPos
pos
=
null
;
while
(
true
)
{
if
(
p
.
isLeaf
())
{
int
x
=
key
==
null
?
0
:
p
.
binarySearch
(
key
);
if
(
x
<
0
)
{
return
null
;
}
return
new
CursorPos
(
p
,
x
,
pos
);
}
int
x
=
key
==
null
?
-
1
:
p
.
binarySearch
(
key
);
if
(
x
<
0
)
{
x
=
-
x
-
1
;
}
else
{
x
++;
}
pos
=
new
CursorPos
(
p
,
x
,
pos
);
p
=
p
.
getChildPage
(
x
);
}
return
null
;
}
public
CursorPos
visitChild
(
Page
p
,
int
childIndex
)
{
if
(
isChildOld
(
p
,
childIndex
))
{
return
null
;
@SuppressWarnings
(
"unchecked"
)
private
CursorPos
fetchNext
(
CursorPos
p
)
{
while
(
p
!=
null
)
{
if
(
p
.
index
<
p
.
page
.
getKeyCount
())
{
current
=
(
K
)
p
.
page
.
getKey
(
p
.
index
++);
return
p
;
}
p
=
p
.
parent
;
if
(
p
==
null
)
{
break
;
}
if
(
p
.
index
+
1
<
map
.
getChildPageCount
(
p
.
page
))
{
p
=
new
CursorPos
(
p
.
page
.
getChildPage
(++
p
.
index
),
0
,
p
);
p
=
min
(
p
);
}
}
return
super
.
visitChild
(
p
,
childIndex
);
current
=
null
;
return
p
;
}
private
boolean
isChildOld
(
Page
p
,
int
childIndex
)
{
long
pos
=
p
.
getChildPagePos
(
childIndex
);
if
(
pos
==
0
)
{
Page
c
=
p
.
getChildPage
(
childIndex
);
if
(
c
.
getVersion
()
<
minVersion
)
{
return
true
;
private
static
CursorPos
min
(
CursorPos
p
)
{
while
(
true
)
{
if
(
p
.
page
.
isLeaf
())
{
return
p
;
}
}
else
if
(
map
.
getStore
().
getChunk
(
pos
).
version
<
minVersion
)
{
return
true
;
Page
c
=
p
.
page
.
getChildPage
(
0
);
p
=
new
CursorPos
(
c
,
0
,
p
)
;
}
return
false
;
}
}
h2/src/tools/org/h2/dev/store/btree/Cursor.java
浏览文件 @
49b85b79
...
...
@@ -6,7 +6,6 @@
*/
package
org
.
h2
.
dev
.
store
.
btree
;
import
java.util.ArrayList
;
import
java.util.Iterator
;
/**
...
...
@@ -17,12 +16,11 @@ import java.util.Iterator;
*/
public
class
Cursor
<
K
,
V
>
implements
Iterator
<
K
>
{
protected
final
MVMap
<
K
,
V
>
map
;
protected
final
Page
root
;
protected
final
K
from
;
protected
ArrayList
<
CursorPos
>
parents
;
protected
CursorPos
currentPos
;
protected
K
current
;
private
final
MVMap
<
K
,
V
>
map
;
private
final
K
from
;
private
Page
root
;
private
CursorPos
pos
;
private
K
current
;
Cursor
(
MVMap
<
K
,
V
>
map
,
Page
root
,
K
from
)
{
this
.
map
=
map
;
...
...
@@ -31,32 +29,17 @@ public class Cursor<K, V> implements Iterator<K> {
}
public
K
next
()
{
if
(!
hasNext
())
{
return
null
;
}
K
c
=
current
;
if
(
c
!=
null
)
{
fetchNext
();
}
return
c
==
null
?
null
:
c
;
}
/**
* Fetch the next key.
*/
@SuppressWarnings
(
"unchecked"
)
protected
void
fetchNext
()
{
current
=
(
K
)
map
.
nextKey
(
currentPos
,
this
);
fetchNext
();
return
c
;
}
public
boolean
hasNext
()
{
if
(
parents
==
null
)
{
// not initialized yet: fetch the first key
parents
=
new
ArrayList
<
CursorPos
>();
currentPos
=
min
(
root
,
from
);
if
(
currentPos
!=
null
)
{
fetchNext
();
}
if
(
root
!=
null
)
{
// initialize
min
(
root
,
from
);
root
=
null
;
fetchNext
();
}
return
current
!=
null
;
}
...
...
@@ -65,48 +48,43 @@ public class Cursor<K, V> implements Iterator<K> {
throw
new
UnsupportedOperationException
();
}
/**
* Add a cursor position to the stack.
*
* @param p the cursor position
*/
public
void
push
(
CursorPos
p
)
{
parents
.
add
(
p
);
}
/**
* Remove the latest cursor position from the stack and return it.
*
* @return the cursor position, or null if none
*/
public
CursorPos
pop
()
{
int
size
=
parents
.
size
();
return
size
==
0
?
null
:
parents
.
remove
(
size
-
1
);
}
/**
* Visit the first key that is greater or equal the given key.
*
* @param p the page
* @param from the key, or null
* @return the cursor position
*/
public
CursorPos
min
(
Page
p
,
K
from
)
{
return
map
.
min
(
p
,
this
,
from
);
private
void
min
(
Page
p
,
K
from
)
{
while
(
true
)
{
if
(
p
.
isLeaf
())
{
int
x
=
from
==
null
?
0
:
p
.
binarySearch
(
from
);
if
(
x
<
0
)
{
x
=
-
x
-
1
;
}
pos
=
new
CursorPos
(
p
,
x
,
pos
);
break
;
}
int
x
=
from
==
null
?
-
1
:
p
.
binarySearch
(
from
);
if
(
x
<
0
)
{
x
=
-
x
-
1
;
}
else
{
x
++;
}
pos
=
new
CursorPos
(
p
,
x
+
1
,
pos
);
p
=
p
.
getChildPage
(
x
);
}
}
/**
* Visit the first key within this child page.
*
* @param p the page
* @param childIndex the child index
* @return the cursor position
*/
public
CursorPos
visitChild
(
Page
p
,
int
childIndex
)
{
p
=
p
.
getChildPage
(
childIndex
);
currentPos
=
min
(
p
,
null
);
return
currentPos
;
@SuppressWarnings
(
"unchecked"
)
private
void
fetchNext
()
{
while
(
pos
!=
null
)
{
if
(
pos
.
index
<
pos
.
page
.
getKeyCount
())
{
current
=
(
K
)
pos
.
page
.
getKey
(
pos
.
index
++);
return
;
}
pos
=
pos
.
parent
;
if
(
pos
==
null
)
{
break
;
}
if
(
pos
.
index
<
map
.
getChildPageCount
(
pos
.
page
))
{
min
(
pos
.
page
.
getChildPage
(
pos
.
index
++),
null
);
}
}
current
=
null
;
}
}
h2/src/tools/org/h2/dev/store/btree/MVMap.java
浏览文件 @
49b85b79
...
...
@@ -137,68 +137,6 @@ public class MVMap<K, V> extends AbstractMap<K, V> {
return
(
V
)
binarySearch
(
root
,
key
);
}
/**
* Go to the first element for the given key.
*
* @param p the current page
* @param cursor the cursor
* @param key the key
* @return the cursor position
*/
protected
CursorPos
min
(
Page
p
,
Cursor
<
K
,
V
>
cursor
,
Object
key
)
{
while
(
true
)
{
if
(
p
.
isLeaf
())
{
int
x
=
key
==
null
?
0
:
p
.
binarySearch
(
key
);
if
(
x
<
0
)
{
x
=
-
x
-
1
;
}
return
new
CursorPos
(
p
,
x
,
null
);
}
int
x
=
key
==
null
?
-
1
:
p
.
binarySearch
(
key
);
if
(
x
<
0
)
{
x
=
-
x
-
1
;
}
else
{
x
++;
}
CursorPos
c
=
new
CursorPos
(
p
,
x
,
null
);
cursor
.
push
(
c
);
p
=
p
.
getChildPage
(
x
);
}
}
/**
* Get the next key.
*
* @param p the cursor position
* @param cursor the cursor
* @return the next key
*/
protected
Object
nextKey
(
CursorPos
p
,
Cursor
<
K
,
V
>
cursor
)
{
while
(
p
!=
null
)
{
int
index
=
p
.
index
++;
Page
x
=
p
.
page
;
if
(
index
<
x
.
getKeyCount
())
{
return
x
.
getKey
(
index
);
}
while
(
true
)
{
p
=
cursor
.
pop
();
if
(
p
==
null
)
{
break
;
}
index
=
++
p
.
index
;
x
=
p
.
page
;
if
(
index
<=
x
.
getKeyCount
())
{
cursor
.
push
(
p
);
p
=
cursor
.
visitChild
(
x
,
index
);
if
(
p
!=
null
)
{
break
;
}
}
}
}
return
null
;
}
/**
* Get the value for the given key, or null if not found.
*
...
...
@@ -443,20 +381,20 @@ public class MVMap<K, V> extends AbstractMap<K, V> {
*/
public
Iterator
<
K
>
keyIterator
(
K
from
)
{
checkOpen
();
return
new
RangeCursor
<
K
,
V
>(
root
,
from
);
return
new
Cursor
<
K
,
V
>(
this
,
root
,
from
);
// return new Cursor<K, V>(this, root, from);
}
/**
* Iterate over all keys in changed pages.
* This does not include deleted deleted pages.
*
* @param
minVersion the minimum
version
* @param
version the old
version
* @return the iterator
*/
public
Iterator
<
K
>
changeIterator
(
long
minV
ersion
)
{
public
Iterator
<
K
>
changeIterator
(
long
v
ersion
)
{
checkOpen
();
return
new
ChangeCursor
<
K
,
V
>(
this
,
root
,
null
,
minVersion
);
MVMap
<
K
,
V
>
old
=
openVersion
(
version
);
return
new
ChangeCursor
<
K
,
V
>(
this
,
root
,
old
.
root
);
}
public
Set
<
Map
.
Entry
<
K
,
V
>>
entrySet
()
{
...
...
@@ -469,13 +407,13 @@ public class MVMap<K, V> extends AbstractMap<K, V> {
public
Set
<
K
>
keySet
()
{
checkOpen
();
final
MVMap
<
K
,
V
>
map
=
this
;
final
Page
root
=
this
.
root
;
return
new
AbstractSet
<
K
>()
{
@Override
public
Iterator
<
K
>
iterator
()
{
return
new
RangeCursor
<
K
,
V
>(
root
,
null
);
// return new Cursor<K, V>(MVMap.this, root, null);
return
new
Cursor
<
K
,
V
>(
map
,
root
,
null
);
}
@Override
...
...
@@ -701,4 +639,8 @@ public class MVMap<K, V> extends AbstractMap<K, V> {
return
root
.
getVersion
();
}
protected
int
getChildPageCount
(
Page
p
)
{
return
p
.
getChildPageCount
();
}
}
h2/src/tools/org/h2/dev/store/btree/Page.java
浏览文件 @
49b85b79
...
...
@@ -788,8 +788,25 @@ public class Page {
return
version
;
}
int
getChildPageCount
()
{
public
int
getChildPageCount
()
{
return
children
.
length
;
}
public
boolean
equals
(
Object
other
)
{
if
(
other
==
this
)
{
return
true
;
}
if
(
other
instanceof
Page
)
{
if
(
pos
!=
0
&&
((
Page
)
other
).
pos
==
pos
)
{
return
true
;
}
return
this
==
other
;
}
return
false
;
}
public
int
hashCode
()
{
return
pos
!=
0
?
(
int
)
(
pos
|
(
pos
>>>
32
))
:
super
.
hashCode
();
}
}
h2/src/tools/org/h2/dev/store/btree/RangeCursor.java
deleted
100644 → 0
浏览文件 @
4b20cf9b
/*
* Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License,
* Version 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package
org
.
h2
.
dev
.
store
.
btree
;
import
java.util.Iterator
;
/**
* A cursor to iterate over elements in ascending order.
*
* @param <K> the key type
* @param <V> the value type
*/
public
class
RangeCursor
<
K
,
V
>
implements
Iterator
<
K
>
{
protected
final
K
from
;
protected
Page
root
;
protected
CursorPos
pos
;
protected
K
current
;
RangeCursor
(
Page
root
,
K
from
)
{
this
.
root
=
root
;
this
.
from
=
from
;
}
public
K
next
()
{
K
c
=
current
;
fetchNext
();
return
c
;
}
public
boolean
hasNext
()
{
if
(
root
!=
null
)
{
// initialize
min
(
root
,
from
);
root
=
null
;
fetchNext
();
}
return
current
!=
null
;
}
public
void
remove
()
{
throw
new
UnsupportedOperationException
();
}
private
void
min
(
Page
p
,
K
from
)
{
while
(
true
)
{
if
(
p
.
isLeaf
())
{
int
x
=
from
==
null
?
0
:
p
.
binarySearch
(
from
);
if
(
x
<
0
)
{
x
=
-
x
-
1
;
}
pos
=
new
CursorPos
(
p
,
x
,
pos
);
break
;
}
int
x
=
from
==
null
?
-
1
:
p
.
binarySearch
(
from
);
if
(
x
<
0
)
{
x
=
-
x
-
1
;
}
else
{
x
++;
}
pos
=
new
CursorPos
(
p
,
x
+
1
,
pos
);
p
=
p
.
getChildPage
(
x
);
}
}
@SuppressWarnings
(
"unchecked"
)
private
void
fetchNext
()
{
while
(
pos
!=
null
)
{
if
(
pos
.
index
<
pos
.
page
.
getKeyCount
())
{
current
=
(
K
)
pos
.
page
.
getKey
(
pos
.
index
++);
return
;
}
pos
=
pos
.
parent
;
if
(
pos
==
null
)
{
break
;
}
if
(
pos
.
index
<
pos
.
page
.
getChildPageCount
())
{
min
(
pos
.
page
.
getChildPage
(
pos
.
index
++),
null
);
}
}
current
=
null
;
}
}
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论