001/* 002 * Shredzone Commons 003 * 004 * Copyright (C) 2014 Richard "Shred" Körber 005 * http://commons.shredzone.org 006 * 007 * This program is free software: you can redistribute it and/or modify 008 * it under the terms of the GNU Library General Public License as 009 * published by the Free Software Foundation, either version 3 of the 010 * License, or (at your option) any later version. 011 * 012 * This program is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 015 * GNU General Public License for more details. 016 * 017 * You should have received a copy of the GNU Library General Public License 018 * along with this program. If not, see <http://www.gnu.org/licenses/>. 019 */ 020package org.shredzone.commons.xml; 021 022import java.util.Spliterator; 023import java.util.function.Consumer; 024import java.util.stream.Stream; 025import java.util.stream.StreamSupport; 026 027import javax.annotation.Nonnull; 028import javax.annotation.ParametersAreNonnullByDefault; 029 030import org.w3c.dom.Node; 031import org.w3c.dom.NodeList; 032 033/** 034 * A {@link Spliterator} for {@link NodeList}. Used internally by {@link XQuery}. 035 * 036 * @author Richard "Shred" Körber 037 */ 038@ParametersAreNonnullByDefault 039public class NodeListSpliterator implements Spliterator<Node> { 040 041 private final NodeList list; 042 private int pos; 043 private int end; 044 045 /** 046 * Creates a new {@link NodeListSpliterator}. 047 * 048 * @param list 049 * {@link NodeList} to create a {@link NodeListSpliterator} of 050 */ 051 public NodeListSpliterator(NodeList list) { 052 this(list, 0, list.getLength()); 053 } 054 055 /** 056 * Creates a new {@link NodeListSpliterator} with limited range. Used internally for 057 * splitting. 058 * 059 * @param list 060 * {@link NodeList} 061 * @param pos 062 * Beginning of range, inclusive 063 * @param end 064 * Ending of range, exlusive 065 */ 066 private NodeListSpliterator(NodeList list, int pos, int end) { 067 this.list = list; 068 this.pos = pos; 069 this.end = end; 070 } 071 072 /** 073 * Creates a new {@link Stream} of {@link Node} for this spliterator. 074 * <p> 075 * This is a convenience call. It just invokes 076 * {@link StreamSupport#stream(Spliterator, boolean)}. 077 * 078 * @return {@link Stream} of nodes 079 */ 080 public @Nonnull Stream<Node> stream() { 081 return StreamSupport.stream(this, false); 082 } 083 084 @Override 085 public boolean tryAdvance(Consumer<? super Node> action) { 086 if (pos < end) { 087 action.accept(list.item(pos)); 088 pos++; 089 return true; 090 } 091 092 return false; 093 } 094 095 @Override 096 public Spliterator<Node> trySplit() { 097 int remain = end - pos; 098 if (remain > 1) { 099 int half = remain >> 1; 100 int split = pos + half; 101 Spliterator<Node> result = new NodeListSpliterator(list, split, end); 102 end = split; 103 return result; 104 } 105 return null; 106 } 107 108 @Override 109 public long estimateSize() { 110 return ((long) end) - ((long) pos); 111 } 112 113 @Override 114 public int characteristics() { 115 return ORDERED | DISTINCT | SIZED | NONNULL | SUBSIZED; 116 } 117 118}