forked from eXist-db/exist
/
AbstractArrayNodeSet.java
267 lines (224 loc) · 6.74 KB
/
AbstractArrayNodeSet.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
/*
* eXist Open Source Native XML Database
* Copyright (C) 2001-2014 The eXist Project
* http://exist-db.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $Id$
*/
package org.exist.dom.persistent;
import org.exist.xquery.Constants;
import org.exist.xquery.value.Item;
import org.exist.xquery.value.Type;
import org.w3c.dom.Node;
/**
* Removes duplication between NewArrayNodeSet
* and ExtArrayNodeSet
*
* @author Adam Retter <adam@exist-db.org>
*/
public abstract class AbstractArrayNodeSet extends AbstractNodeSet implements DocumentSet {
protected static final int INITIAL_SIZE = 64;
protected int size = 0;
protected boolean isSorted = false;
protected boolean hasOne = false;
protected int state = 0;
private NodeProxy lastAdded = null;
// used to keep track of the type of added items.
protected int itemType = Type.ANY_TYPE;
/**
* Reset the ArrayNodeSet so that it
* may be reused
*/
public abstract void reset();
@Override
public boolean isEmpty() {
return size == 0;
}
@Override
public boolean hasOne() {
return hasOne;
}
@Override
public void add(final NodeProxy proxy) {
add(proxy, Constants.NO_SIZE_HINT);
}
/**
* Add a new node to the set. If a new array of nodes has to be allocated
* for the document, use the sizeHint parameter to determine the size of
* the newly allocated array. This will overwrite the default array size.
*
* If the size hint is correct, no further reallocations will be required.
*/
@Override
public void add(final NodeProxy proxy, final int sizeHint) {
if(size > 0) {
if(hasOne) {
if(isSorted) {
this.hasOne = get(proxy) != null;
} else {
this.hasOne = lastAdded == null || lastAdded.compareTo(proxy) == 0;
}
}
} else {
this.hasOne = true;
}
addInternal(proxy, sizeHint);
this.isSorted = false;
setHasChanged();
checkItemType(proxy.getType());
this.lastAdded = proxy;
}
/**
* Just add the node to this set
* all of the checks have been
* done in @see AbstractArrayNodeSet#add(NodeProxy, int)
*/
protected abstract void addInternal(final NodeProxy proxy, final int sizeHint);
@Override
public void addAll(final NodeSet other) {
if(other.isEmpty()) {
return;
} else if(other.hasOne()) {
add((NodeProxy) other.itemAt(0));
} else {
for(final NodeProxy node : other) {
add(node);
}
}
}
/**
* The method <code>getItemType</code>
*
* @return an <code>int</code> value
*/
@Override
public int getItemType() {
return itemType;
}
private void checkItemType(final int type) {
if(itemType == Type.NODE || itemType == type) {
return;
}
if(itemType == Type.ANY_TYPE) {
itemType = type;
} else {
itemType = Type.NODE;
}
}
private void setHasChanged() {
this.state = (state == Integer.MAX_VALUE ? 0 : state + 1);
}
@Override
public int getLength() {
if(!isSorted()) {
// sort to remove duplicates
sort();
}
return size;
}
@Override
public long getItemCountLong() {
return getLength();
}
@Override
public Node item(final int pos) {
sortInDocumentOrder();
final NodeProxy p = get(pos);
return p == null ? null : p.getNode();
}
@Override
public Item itemAt(final int pos) {
sortInDocumentOrder();
return get(pos);
}
@Override
public NodeSet selectParentChild(final NodeSet al, final int mode,
final int contextId) {
sort();
if(al instanceof VirtualNodeSet) {
return super.selectParentChild(al, mode, contextId);
}
return getDescendantsInSet(al, true, false, mode, contextId, true);
}
@Override
public NodeSet selectAncestorDescendant(final NodeSet al, final int mode,
final boolean includeSelf, int contextId, boolean copyMatches) {
sort();
if(al instanceof VirtualNodeSet) {
return super.selectAncestorDescendant(al, mode, includeSelf,
contextId, copyMatches);
}
return getDescendantsInSet(al, false, includeSelf, mode, contextId, copyMatches);
}
@Override
public NodeSet selectAncestors(final NodeSet al, final boolean includeSelf, final int contextId) {
sort();
return super.selectAncestors(al, includeSelf, contextId);
}
protected abstract NodeSet getDescendantsInSet(final NodeSet al,
final boolean childOnly, final boolean includeSelf, final int mode,
final int contextId, final boolean copyMatches);
@Override
public DocumentSet getDocumentSet() {
return this;
}
protected boolean isSorted() {
return isSorted;
}
/**
* Remove all duplicate nodes, but merge their
* contexts.
*/
public void mergeDuplicates() {
sort(true);
}
/**
* Sorts the nodes in the set
* into document order.
*
* Same as calling @see #sort(false)
*/
public void sortInDocumentOrder() {
sort(false);
}
/**
* Sorts the nodes in the set
* without merging their contexts.
*
* Same as calling @see #sort(false)
*/
public void sort() {
sort(false);
}
public abstract void sort(final boolean mergeContexts);
@Override
public boolean hasChanged(final int previousState) {
return state != previousState;
}
@Override
public int getState() {
return state;
}
@Override
public boolean isCacheable() {
return true;
}
@Override
public String toString() {
return "ArrayNodeSet#" + super.toString();
}
}