Skip to content

Commit a33e34e

Browse files
authored
Merge pull request #92 from evolvedbinary/7.x.x/feature/improved-custom-linked-list
[7.x.x] Replace the custom Linked List with a better implementation
2 parents 5a1c5e9 + 0fea51d commit a33e34e

File tree

5 files changed

+108
-539
lines changed

5 files changed

+108
-539
lines changed

exist-core/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,12 @@
211211
<version>${lz4-java.version}</version>
212212
</dependency>
213213

214+
<dependency>
215+
<groupId>com.evolvedbinary.j8cu</groupId>
216+
<artifactId>j8cu</artifactId>
217+
<version>3.0.0</version>
218+
</dependency>
219+
214220
<dependency>
215221
<groupId>com.evolvedbinary.j8fu</groupId>
216222
<artifactId>j8fu</artifactId>

exist-core/src/main/java/org/exist/dom/persistent/SortedNodeSet.java

Lines changed: 102 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,13 @@
4848
import antlr.RecognitionException;
4949
import antlr.TokenStreamException;
5050
import antlr.collections.AST;
51+
import com.evolvedbinary.j8cu.list.linked.BoundedDoublyLinkedList;
52+
import com.evolvedbinary.j8cu.list.linked.OrderedDoublyLinkedList;
5153
import org.exist.EXistException;
5254
import org.exist.numbering.NodeId;
5355
import org.exist.security.Subject;
5456
import org.exist.storage.BrokerPool;
5557
import org.exist.storage.DBBroker;
56-
import org.exist.util.OrderedLinkedList;
5758
import org.exist.xquery.*;
5859
import org.exist.xquery.parser.XQueryLexer;
5960
import org.exist.xquery.parser.XQueryParser;
@@ -64,15 +65,16 @@
6465
import org.w3c.dom.Node;
6566
import org.w3c.dom.NodeList;
6667

68+
import javax.annotation.Nullable;
6769
import java.io.StringReader;
68-
import java.util.Iterator;
69-
import java.util.NoSuchElementException;
70-
import java.util.Optional;
70+
import java.util.*;
71+
72+
import static com.evolvedbinary.j8cu.list.linked.Bounded.bound;
7173

7274

7375
public class SortedNodeSet extends AbstractNodeSet {
7476

75-
private final OrderedLinkedList list = new OrderedLinkedList();
77+
private final BoundedDoublyLinkedList<IteratorItem> list = bound(new OrderedDoublyLinkedList<IteratorItem>(), Long.MAX_VALUE);
7678

7779
private final String sortExpr;
7880
private final BrokerPool pool;
@@ -86,7 +88,7 @@ public SortedNodeSet(final BrokerPool pool, final Subject user, final String sor
8688

8789
@Override
8890
public boolean isEmpty() {
89-
return list.size() == 0;
91+
return list.isEmpty();
9092
}
9193

9294
@Override
@@ -120,37 +122,64 @@ public void addAll(final NodeSet other) {
120122
}
121123
final AST ast = parser.getAST();
122124
LOG.debug("generated AST: {}", ast.toStringTree());
123-
final PathExpr expr = new PathExpr(context);
124-
treeParser.xpath(ast, expr);
125-
if(treeParser.foundErrors()) {
126-
LOG.debug(treeParser.getErrorMessage());
127-
}
128-
expr.analyze(new AnalyzeContextInfo());
129-
for(final SequenceIterator i = other.iterate(); i.hasNext(); ) {
130-
final NodeProxy p = (NodeProxy) i.nextItem();
131-
final IteratorItem item = new IteratorItem(p, expr);
132-
list.add(item);
125+
final PathExpr sortExpression = new PathExpr(context);
126+
try {
127+
treeParser.xpath(ast, sortExpression);
128+
if (treeParser.foundErrors()) {
129+
LOG.debug(treeParser.getErrorMessage());
130+
}
131+
sortExpression.analyze(new AnalyzeContextInfo());
132+
for (final SequenceIterator i = other.iterate(); i.hasNext(); ) {
133+
final NodeProxy p = (NodeProxy) i.nextItem();
134+
final IteratorItem item = createIteratorItem(sortExpression, p);
135+
list.add(item);
136+
}
137+
} finally {
138+
sortExpression.getContext().runCleanupTasks();
139+
sortExpression.getContext().reset();
133140
}
134141
} catch(final RecognitionException | TokenStreamException re) {
135142
LOG.debug(re); //TODO : throw exception ! -pb
136143
} catch(final EXistException | XPathException e) {
137-
LOG.debug("Exception during sort", e); //TODO : throw exception ! -pb
144+
LOG.debug("Exception during sort: " + e.getMessage(), e); //TODO : throw exception ! -pb
138145
}
139146
LOG.debug("sort-expression found {} in {}ms.", list.size(), System.currentTimeMillis() - start);
140147
}
141148

149+
private IteratorItem createIteratorItem(final Expression sortExpression, final NodeProxy nodeProxy) throws XPathException {
150+
final Sequence seq = sortExpression.eval(nodeProxy, null);
151+
152+
// copy string values of items into an array
153+
int sbCapacity = 0;
154+
final String[] strings = new String[seq.getItemCount()];
155+
for (int i = 0; i < strings.length; i++) {
156+
final String strItem = seq.itemAt(i).getStringValue().toUpperCase();
157+
sbCapacity += strItem.length();
158+
strings[i] = strItem;
159+
}
160+
161+
// sort and then concatenate strings
162+
Arrays.sort(strings);
163+
final StringBuilder buf = new StringBuilder(sbCapacity);
164+
for (int i = 0; i < strings.length; i++) {
165+
buf.append(strings[i]);
166+
}
167+
168+
return new IteratorItem(nodeProxy, buf.toString());
169+
}
170+
142171
public void addAll(final NodeList other) {
143-
if(!(other instanceof NodeSet)) {
172+
if (!(other instanceof NodeSet)) {
144173
throw new RuntimeException("not implemented!");
145174
}
146175
addAll((NodeSet) other);
147176
}
148177

149178
@Override
150179
public boolean contains(final NodeProxy proxy) {
151-
for(final Iterator<IteratorItem> i = list.iterator(); i.hasNext(); ) {
152-
final NodeProxy p = (i.next()).proxy;
153-
if(p.compareTo(proxy) == 0) {
180+
for (final IteratorItem iteratorItem : list) {
181+
final NodeProxy p = iteratorItem.proxy;
182+
if (p.compareTo(proxy) == 0) {
154183
return true;
155184
}
156185
}
@@ -159,8 +188,8 @@ public boolean contains(final NodeProxy proxy) {
159188

160189
@Override
161190
public boolean containsReference(final Item item) {
162-
for (final Iterator<IteratorItem> i = list.iterator(); i.hasNext();) {
163-
final NodeProxy p = (i.next()).proxy;
191+
for (final IteratorItem iteratorItem : list) {
192+
final NodeProxy p = iteratorItem.proxy;
164193
if (p == item) {
165194
return true;
166195
}
@@ -170,8 +199,8 @@ public boolean containsReference(final Item item) {
170199

171200
@Override
172201
public boolean contains(final Item item) {
173-
for (final Iterator<IteratorItem> i = list.iterator(); i.hasNext();) {
174-
final NodeProxy p = (i.next()).proxy;
202+
for (final IteratorItem iteratorItem : list) {
203+
final NodeProxy p = iteratorItem.proxy;
175204
if (p.equals(item)) {
176205
return true;
177206
}
@@ -181,15 +210,15 @@ public boolean contains(final Item item) {
181210

182211
@Override
183212
public NodeProxy get(final int pos) {
184-
final IteratorItem item = (IteratorItem) list.get(pos);
213+
final IteratorItem item = list.get(pos);
185214
return item == null ? null : item.proxy;
186215
}
187216

188217
public NodeProxy get(final DocumentImpl doc, final NodeId nodeId) {
189218
final NodeProxy proxy = new NodeProxy(null, doc, nodeId);
190-
for(final Iterator<IteratorItem> i = list.iterator(); i.hasNext(); ) {
191-
final NodeProxy p = (i.next()).proxy;
192-
if(p.compareTo(proxy) == 0) {
219+
for (final IteratorItem iteratorItem : list) {
220+
final NodeProxy p = iteratorItem.proxy;
221+
if (p.compareTo(proxy) == 0) {
193222
return p;
194223
}
195224
}
@@ -198,9 +227,9 @@ public NodeProxy get(final DocumentImpl doc, final NodeId nodeId) {
198227

199228
@Override
200229
public NodeProxy get(final NodeProxy proxy) {
201-
for(final Iterator<IteratorItem> i = list.iterator(); i.hasNext(); ) {
202-
final NodeProxy p = (i.next()).proxy;
203-
if(p.compareTo(proxy) == 0) {
230+
for (final IteratorItem iteratorItem : list) {
231+
final NodeProxy p = iteratorItem.proxy;
232+
if (p.compareTo(proxy) == 0) {
204233
return p;
205234
}
206235
}
@@ -209,7 +238,7 @@ public NodeProxy get(final NodeProxy proxy) {
209238

210239
@Override
211240
public int getLength() {
212-
return list.size();
241+
return (int) list.size();
213242
}
214243

215244
@Override
@@ -219,15 +248,21 @@ public long getItemCountLong() {
219248

220249
@Override
221250
public Node item(final int pos) {
222-
final NodeProxy p = ((IteratorItem) list.get(pos)).proxy;
223-
return p == null ? null : p.getNode();
251+
final IteratorItem iteratorItem = list.get(pos);
252+
if (iteratorItem != null) {
253+
final NodeProxy p = iteratorItem.proxy;
254+
if (p != null) {
255+
return p.getOwnerDocument().getNode(p);
256+
}
257+
}
258+
return null;
224259
}
225260

226261
//TODO : evaluate both semantics (item/itemAt)
227262
@Override
228263
public Item itemAt(final int pos) {
229-
final NodeProxy p = ((IteratorItem) list.get(pos)).proxy;
230-
return p == null ? null : p;
264+
final IteratorItem iteratorItem = list.get(pos);
265+
return iteratorItem == null ? null : iteratorItem.proxy;
231266
}
232267

233268
@Override
@@ -245,101 +280,89 @@ public SequenceIterator unorderedIterator() {
245280
return new SortedNodeSetIterator(list.iterator());
246281
}
247282

248-
private static final class SortedNodeSetIterator implements NodeSetIterator, SequenceIterator {
249-
283+
private static class SortedNodeSetIterator implements NodeSetIterator, SequenceIterator {
250284
private final Iterator<IteratorItem> ii;
251285

252286
public SortedNodeSetIterator(final Iterator<IteratorItem> i) {
253287
ii = i;
254288
}
255289

256-
public final boolean hasNext() {
290+
public boolean hasNext() {
257291
return ii.hasNext();
258292
}
259293

260294
@Override
261-
public final NodeProxy next() {
262-
if(!ii.hasNext()) {
295+
public NodeProxy next() {
296+
if (!ii.hasNext()) {
263297
throw new NoSuchElementException();
264298
} else {
265299
return ii.next().proxy;
266300
}
267301
}
268302

269303
@Override
270-
public final void remove() {
304+
public void remove() {
271305
throw new UnsupportedOperationException();
272306
}
273307

274308
@Override
275-
public final NodeProxy peekNode() {
309+
public NodeProxy peekNode() {
276310
return null;
277311
}
278312

279313
@Override
280-
public final Item nextItem() {
281-
if(!ii.hasNext()) {
314+
public Item nextItem() {
315+
if (!ii.hasNext()) {
282316
return null;
283317
} else {
284318
return ii.next().proxy;
285319
}
286320
}
287321

288322
@Override
289-
public final void setPosition(final NodeProxy proxy) {
323+
public void setPosition(final NodeProxy proxy) {
290324
throw new UnsupportedOperationException("NodeSetIterator.setPosition() is not supported by SortedNodeSetIterator");
291325
}
292326
}
293327

294-
private static final class IteratorItem extends OrderedLinkedList.Node {
328+
private static class IteratorItem implements Comparable<IteratorItem> {
295329
private final NodeProxy proxy;
296-
private String value = null;
330+
private @Nullable final String value;
297331

298-
public IteratorItem(final NodeProxy proxy, final PathExpr expr) {
332+
public IteratorItem(final NodeProxy proxy, final String value) {
299333
this.proxy = proxy;
300-
try {
301-
final Sequence seq = expr.eval(proxy, null);
302-
final StringBuilder buf = new StringBuilder();
303-
final OrderedLinkedList strings = new OrderedLinkedList();
304-
Item item;
305-
for(final SequenceIterator i = seq.iterate(); i.hasNext(); ) {
306-
item = i.nextItem();
307-
strings.add(new OrderedLinkedList.SimpleNode(item.getStringValue().toUpperCase()));
308-
}
309-
for(final Iterator<OrderedLinkedList.SimpleNode> j = strings.iterator(); j.hasNext(); ) {
310-
buf.append((j.next()).getData());
311-
}
312-
value = buf.toString();
313-
} catch(final XPathException e) {
314-
LOG.warn(e.getMessage(), e); //TODO : throw exception ! -pb
315-
} finally {
316-
expr.getContext().runCleanupTasks();
317-
expr.getContext().reset();
318-
}
334+
this.value = value;
319335
}
320336

321337
@Override
322-
public int compareTo(final OrderedLinkedList.Node other) {
323-
final IteratorItem o = (IteratorItem) other;
324-
if(value == null) {
325-
return o.value == null ? Constants.EQUAL : Constants.SUPERIOR;
326-
} else if(o.value == null) {
338+
public int compareTo(final IteratorItem other) {
339+
if (value == null) {
340+
return other.value == null ? Constants.EQUAL : Constants.SUPERIOR;
341+
} else if (other.value == null) {
327342
return Constants.INFERIOR;
328343
} else {
329-
return value.compareTo(o.value);
344+
return value.compareTo(other.value);
330345
}
331346
}
332347

333348
@Override
334-
public boolean equals(final OrderedLinkedList.Node other) {
335-
final IteratorItem o = (IteratorItem) other;
336-
return value.equals(o.value);
349+
public boolean equals(final Object other) {
350+
if (!(other instanceof IteratorItem)) {
351+
return false;
352+
}
353+
354+
final IteratorItem otherIteratorItem = (IteratorItem) other;
355+
return Objects.equals(value, otherIteratorItem.value);
356+
}
357+
358+
@Override
359+
public int hashCode() {
360+
return Objects.hashCode(value);
337361
}
338362
}
339363

340364
@Override
341365
public void add(final NodeProxy proxy) {
342366
LOG.info("Called SortedNodeSet.add()");
343367
}
344-
345368
}

0 commit comments

Comments
 (0)