http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/iterator/IteratorArray.java
----------------------------------------------------------------------
diff --git 
a/jena-base/src/main/java/org/apache/jena/atlas/iterator/IteratorArray.java 
b/jena-base/src/main/java/org/apache/jena/atlas/iterator/IteratorArray.java
new file mode 100644
index 0000000..ee45935
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/iterator/IteratorArray.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.iterator;
+
+import java.util.Iterator ;
+import java.util.NoSuchElementException ;
+
+/** Iterator over a Java base array */
+public final class IteratorArray<T> implements Iterator<T>
+{
+    /** Iterator over all the array elements */ 
+    public static <T> IteratorArray<T> create(T[] array)
+    { return new IteratorArray<>(array, 0, array.length) ; }
+    
+    /** Iterator over array elements from start (inclusive) to finish 
(exclusive) */ 
+    public static <T> IteratorArray<T> create(T[] array, int start, int finish)
+    { return new IteratorArray<>(array, start, finish) ; }
+    
+    private int idx ;
+    private int finishIdx ;
+    private T[] array ;
+    
+    private IteratorArray(T[] array, int start, int finish) 
+    {
+        if ( start < 0 )
+            throw new IllegalArgumentException("Start: "+start) ;
+
+        if ( start > finish )
+            throw new IllegalArgumentException("Start >= finish: "+start+" >= 
"+finish) ;
+
+// Instead: truncate to array length          
+//        if ( finish > array.length )
+//            throw new IllegalArgumentException("Finish outside array") ;
+//        
+// Instead: immediate end iterator                
+//        if ( start >= array.length )
+//            throw new IllegalArgumentException("Start outside array") ;
+
+        this.array = array ;
+        idx = start ;
+        finishIdx = finish ;
+        if ( idx < 0 )
+            idx = 0 ;
+        if ( finishIdx > array.length ) 
+            finishIdx = array.length ;
+    }
+
+    @Override
+    public boolean hasNext()
+    {
+//        if ( idx < 0 )
+//            return false ;
+        if ( idx >= finishIdx )
+            return false ;
+        return true ;
+    }
+
+    public T current()
+    {
+        if ( idx >= finishIdx )
+            throw new NoSuchElementException() ;
+        return array[idx] ;
+    }
+    
+    @Override
+    public T next()
+    {
+        if ( ! hasNext() )
+            throw new NoSuchElementException() ; 
+        return array[idx++] ;
+    }
+
+    @Override
+    public void remove()
+    { throw new UnsupportedOperationException("ArrayIterator") ; }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/iterator/IteratorBlockingQueue.java
----------------------------------------------------------------------
diff --git 
a/jena-base/src/main/java/org/apache/jena/atlas/iterator/IteratorBlockingQueue.java
 
b/jena-base/src/main/java/org/apache/jena/atlas/iterator/IteratorBlockingQueue.java
new file mode 100644
index 0000000..c11b262
--- /dev/null
+++ 
b/jena-base/src/main/java/org/apache/jena/atlas/iterator/IteratorBlockingQueue.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.iterator;
+
+import java.util.Iterator ;
+import java.util.NoSuchElementException ;
+import java.util.concurrent.BlockingQueue ;
+
+/** Iterator over a blocking queue until queue end seen */
+
+public class IteratorBlockingQueue<T> implements Iterator<T>
+{
+    private BlockingQueue<T> queue ;
+    private boolean finished = false ;
+    private T slot = null ;
+    private T endMarker ; 
+
+    public IteratorBlockingQueue(BlockingQueue<T> queue, T endMarker) { 
this.queue = queue ; this.endMarker = endMarker ; }
+    
+    @Override
+    public boolean hasNext()
+    {
+        if ( finished ) return false ;
+        if ( slot != null ) return true ;
+        try
+        {
+            slot = queue.take() ;
+            if ( slot == endMarker )
+            {
+                finished = true ;
+                slot = null ;
+                return false ;
+            }
+            return true ;
+            
+        } catch (InterruptedException ex)
+        {
+            ex.printStackTrace();
+            
+        }
+        return false ;
+    }
+
+    @Override
+    public T next()
+    {
+        if ( ! hasNext() )
+            throw new NoSuchElementException() ;
+        T item = slot ;
+        slot = null ;
+        return item ;
+    }
+
+    @Override
+    public void remove()
+    { throw new UnsupportedOperationException() ; }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/iterator/IteratorConcat.java
----------------------------------------------------------------------
diff --git 
a/jena-base/src/main/java/org/apache/jena/atlas/iterator/IteratorConcat.java 
b/jena-base/src/main/java/org/apache/jena/atlas/iterator/IteratorConcat.java
new file mode 100644
index 0000000..65e6430
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/iterator/IteratorConcat.java
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.iterator;
+
+import java.util.Iterator ;
+import java.util.List ;
+import java.util.NoSuchElementException ;
+
+import org.apache.jena.atlas.lib.DS ;
+
+/** Iterator of Iterators
+ *  IteratorConcat is better when there are lots of iterators to be joined.
+ *  IteratorCons is slightly better for two iterators. 
+ */
+
+public class IteratorConcat<T> implements Iterator<T>
+{
+    private List<Iterator<T>> iterators = DS.list(); 
+    int idx = -1 ;
+    private Iterator<T> current = null ;
+    private Iterator<T> removeFrom = null ;
+    boolean finished = false ;
+    
+    /** 
+     * Usually, it is better to create an IteratorConcat explicitly and add 
iterator if there are going to be many.
+     * @param iter1
+     * @param iter2
+     * @return Iterator
+     * @see IteratorCons
+     */
+    public static <T> Iterator<T> concat(Iterator<T> iter1, Iterator<T> iter2)
+    {
+        if (iter2 == null) return iter1 ;
+        if (iter1 == null) return iter2 ;
+        IteratorConcat<T> c = new IteratorConcat<>() ;
+        c.add(iter1) ;
+        c.add(iter2) ;
+        return c ;
+    }
+ 
+    public IteratorConcat() {}
+
+    
+    public void add(Iterator<T> iter) { iterators.add(iter) ; }
+    
+    @Override
+    public boolean hasNext()
+    {
+        if ( finished )
+            return false ;
+
+        if ( current != null && current.hasNext() )
+            return true ;
+        
+        while ( idx < iterators.size()-1 )
+        {
+            idx++ ;
+            current = iterators.get(idx) ;
+            if ( current.hasNext() )
+                return true ;
+            // Nothing here - move on.
+            current = null ;
+        }
+        // idx has run off the end.
+        return false ;
+    }
+
+    @Override
+    public T next()
+    {
+        if ( ! hasNext() )
+            throw new NoSuchElementException() ; 
+        removeFrom = current ;
+        return current.next();
+    }
+
+    @Override
+    public void remove()
+    { 
+        if ( null == removeFrom )
+            throw new IllegalStateException("no calls to next() since last 
call to remove()") ;
+        
+        removeFrom.remove() ;
+        removeFrom = null ;
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/iterator/IteratorCons.java
----------------------------------------------------------------------
diff --git 
a/jena-base/src/main/java/org/apache/jena/atlas/iterator/IteratorCons.java 
b/jena-base/src/main/java/org/apache/jena/atlas/iterator/IteratorCons.java
new file mode 100644
index 0000000..c6cfd61
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/iterator/IteratorCons.java
@@ -0,0 +1,122 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.iterator;
+
+import java.util.Iterator ;
+import java.util.NoSuchElementException ;
+
+/** IteratorCons : the concatenation of two iterators.
+ * See also {@link IteratorConcat}.
+ * If there potentially many iterators to be joined, it is better to 
+ *  create an IteratorConcat explicitly and add each iterator.
+ *  IteratorCons is slightly better in the two iterator case.
+ */
+public class IteratorCons<T> implements Iterator<T>, Iterable<T>
+{
+    // No - we don't really need IteratorCons and IteratorConcat
+    // Historical - IteratorCons came first.
+    // IteratorConcat is nearly as good as IteratorCons in the small when it
+    // it is hard to see when it woudl matter much.
+    
+    private Iterator<? extends T> iter1 ;
+    private Iterator<? extends T> iter2 ;
+    private Iterator<? extends T> removeFrom ;
+
+    public static <X> Iterator<X> create(Iterator<? extends X> iter1, 
Iterator<? extends X> iter2)
+    {
+        if ( iter1 == null && iter2 == null )
+            return Iter.nullIterator() ;
+        
+        // The casts are safe because an iterator can only return X, and does 
not take an X an an assignment.  
+        if ( iter1 == null )
+        {
+            @SuppressWarnings("unchecked")
+            Iterator<X> x = (Iterator<X>)iter2 ;
+            return x ;
+        }
+        
+        if ( iter2 == null )
+        {
+            @SuppressWarnings("unchecked")
+            Iterator<X> x = (Iterator<X>)iter1 ;
+            return x ;
+        }
+        
+        return new IteratorCons<>(iter1, iter2) ;
+    }
+    
+    private IteratorCons(Iterator<? extends T> iter1, Iterator<? extends T> 
iter2)
+    {
+        this.iter1 = iter1 ;
+        this.iter2 = iter2 ;
+    }
+
+    @Override
+    public boolean hasNext()
+    {
+        if ( iter1 != null )
+        {
+            if ( iter1.hasNext() ) return true ;
+            // Iter1 ends
+            iter1 = null ;
+        }
+        
+        if ( iter2 != null )
+        {
+            if ( iter2.hasNext() ) return true ;
+            // Iter2 ends
+            iter2 = null ;
+        }
+        return false ; 
+    }
+
+    @Override
+    public T next()
+    {
+        if ( ! hasNext() )
+            throw new NoSuchElementException("Iterator2.next") ;
+        if ( iter1 != null )
+        {
+            removeFrom = iter1 ;
+            return iter1.next();
+        }
+        if ( iter2 != null )
+        {
+            removeFrom = iter2 ;
+            return iter2.next();
+        }
+        throw new Error("Iterator2.next") ;
+    }
+
+    @Override
+    public void remove()
+    {
+        if ( null == removeFrom )
+            throw new IllegalStateException("no calls to next() since last 
call to remove()") ;
+        
+        removeFrom.remove() ;
+        removeFrom = null ;
+    }
+
+    @Override
+    public Iterator<T> iterator()
+    {
+        return this ;
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/iterator/IteratorDelayedInitialization.java
----------------------------------------------------------------------
diff --git 
a/jena-base/src/main/java/org/apache/jena/atlas/iterator/IteratorDelayedInitialization.java
 
b/jena-base/src/main/java/org/apache/jena/atlas/iterator/IteratorDelayedInitialization.java
new file mode 100644
index 0000000..807105e
--- /dev/null
+++ 
b/jena-base/src/main/java/org/apache/jena/atlas/iterator/IteratorDelayedInitialization.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.iterator;
+
+import java.util.Iterator ;
+import java.util.NoSuchElementException ;
+
+import org.apache.jena.atlas.lib.Closeable ;
+
+/** Class to delay the initialization of an iterator until first call of an 
Iterator operation. */
+
+public abstract class IteratorDelayedInitialization<T> implements Iterator<T>, 
Closeable
+{
+    private boolean initialized = false ;
+    private Iterator<T> iterator ; 
+    
+    public IteratorDelayedInitialization() {}
+
+    private void init()
+    {
+        if ( ! initialized )
+        {
+            initialized = true ;
+            iterator = initializeIterator() ;
+        }
+    }
+    
+    // Called exactly once
+    protected abstract Iterator<T> initializeIterator() ;
+    
+    @Override
+    public boolean hasNext()
+    {
+        init() ;
+        boolean b = iterator.hasNext() ;
+        if ( ! b )
+            close() ;
+        return b ;
+    }
+
+    @Override
+    public T next()
+    {
+        init() ;
+        try { return iterator.next() ; }
+        catch (NoSuchElementException ex) { close() ; throw(ex) ; }
+    }
+
+    @Override
+    public void remove()
+    {
+        init() ;
+        iterator.remove() ;
+    }
+    
+    @Override
+    public void close()
+    {
+        Iter.close(iterator) ;
+        iterator = null ;
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/iterator/IteratorInteger.java
----------------------------------------------------------------------
diff --git 
a/jena-base/src/main/java/org/apache/jena/atlas/iterator/IteratorInteger.java 
b/jena-base/src/main/java/org/apache/jena/atlas/iterator/IteratorInteger.java
new file mode 100644
index 0000000..6fff27c
--- /dev/null
+++ 
b/jena-base/src/main/java/org/apache/jena/atlas/iterator/IteratorInteger.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.iterator;
+
+import java.util.Iterator ;
+
+public class IteratorInteger implements Iterator<Long>
+{
+    private final long start ;
+    private final long finish ;
+    private long current ;
+
+    public static IteratorInteger range(long start, long finish)
+    {
+        return new IteratorInteger(start, finish) ;
+    }
+    
+    
+    /** [start, finish) */
+    public IteratorInteger(long start, long finish)
+    {
+        this.start = start ;
+        this.finish = finish ;
+        this.current = start ;
+    }
+    
+    @Override
+    public boolean hasNext()
+    {
+        return ( current < finish ) ;
+    }
+
+    @Override
+    public Long next()
+    {
+        Long v = current;
+        current++ ;
+        return v ;
+    }
+
+    @Override
+    public void remove()
+    { throw new UnsupportedOperationException() ; }
+
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/iterator/IteratorResourceClosing.java
----------------------------------------------------------------------
diff --git 
a/jena-base/src/main/java/org/apache/jena/atlas/iterator/IteratorResourceClosing.java
 
b/jena-base/src/main/java/org/apache/jena/atlas/iterator/IteratorResourceClosing.java
new file mode 100644
index 0000000..89a54aa
--- /dev/null
+++ 
b/jena-base/src/main/java/org/apache/jena/atlas/iterator/IteratorResourceClosing.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.iterator;
+
+import java.util.Iterator;
+
+import org.apache.jena.atlas.AtlasException ;
+import org.apache.jena.atlas.io.IO ;
+import org.apache.jena.atlas.lib.Closeable ;
+
+/**
+ * This iterator will automatically close a {@link 
org.apache.jena.atlas.lib.Closeable} or {@link java.io.Closeable}
+ * resource when the iterator is exhausted.  Alternatively, the resource will 
be closed when {@link #close()} is
+ * called.  An {@link AtlasException} will be thrown if access is attempted 
after {@link #close()} has been called.
+ */
+public class IteratorResourceClosing<T> implements Iterator<T>, Closeable
+{
+    private final Iterator<T> iter ;
+    private final Object resource ;
+    private boolean finished;
+    
+    public IteratorResourceClosing(Iterator<T> iter, Closeable resource)
+    {
+        this.iter = iter;
+        this.resource = resource;
+        this.finished = false;
+    }
+    
+    public IteratorResourceClosing(Iterator<T> iter, java.io.Closeable 
resource)
+    {
+        this.iter = iter;
+        this.resource = resource ;
+        this.finished = false;
+    }
+    
+    private void checkFinished()
+    {
+        if (finished) throw new AtlasException("IteratorResourceClosing is 
closed, no further operations can be performed on it.") ;
+    }
+
+    @Override
+    public boolean hasNext()
+    {
+        if (finished)
+            return false;
+        
+        boolean toReturn = iter.hasNext();
+        
+        // Clean up if we are done
+        if (!toReturn)
+        {
+            close();
+        }
+        return toReturn ;
+    }
+
+    @Override
+    public T next()
+    {
+        checkFinished();
+        return iter.next() ;
+    }
+
+    @Override
+    public void remove()
+    {
+        checkFinished();
+        iter.remove() ;
+    }
+
+    @Override
+    public void close()
+    {
+        if (!finished)
+        {
+            Iter.close(iter) ;
+            if (null != resource)
+            {
+                if (resource instanceof Closeable)
+                {
+                    ((Closeable)resource).close() ;
+                }
+                else
+                {
+                    IO.close((java.io.Closeable)resource) ;
+                }
+            }
+            finished = true;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/iterator/IteratorSlotted.java
----------------------------------------------------------------------
diff --git 
a/jena-base/src/main/java/org/apache/jena/atlas/iterator/IteratorSlotted.java 
b/jena-base/src/main/java/org/apache/jena/atlas/iterator/IteratorSlotted.java
new file mode 100644
index 0000000..fd846dc
--- /dev/null
+++ 
b/jena-base/src/main/java/org/apache/jena/atlas/iterator/IteratorSlotted.java
@@ -0,0 +1,117 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.iterator;
+
+import java.util.Iterator ;
+import java.util.NoSuchElementException ;
+
+import org.apache.jena.atlas.lib.Lib ;
+
+/** An Iterator with a one slot lookahead. */  
+public abstract class IteratorSlotted<T> implements Iterator<T>
+{
+    private boolean finished = false ;
+    private boolean slotIsSet = false ;
+    private T slot = null ; 
+
+    protected IteratorSlotted() { }
+
+    // -------- The contract with the subclasses 
+    
+    /** Implement this, not next() or nextBinding() */
+    protected abstract T moveToNext() ;
+    
+    /** Can return true here then null from moveToNext() to indicate end. */ 
+    protected abstract boolean hasMore() ;
+    // alter add a flag to say if null is a legal value.
+    
+    /** Close the iterator. */
+    protected void closeIterator() { }
+   
+    // -------- The contract with the subclasses 
+
+    protected boolean isFinished() { return finished ; }
+
+    @Override
+    public final boolean hasNext()
+    {
+        if ( finished )
+            return false ;
+        if ( slotIsSet )
+            return true ;
+
+        boolean r = hasMore() ;
+        if ( ! r )
+        {
+            close() ;
+            return false ;
+        }
+        
+        slot = moveToNext() ;
+        if ( slot == null ) {
+            close() ;
+            return false ;
+        }
+            
+        slotIsSet = true ;
+        return true ;
+    }
+    
+    /** final - autoclose and registration relies on it - implement 
moveToNextBinding() */
+    @Override
+    public final T next()
+    {
+        if ( ! hasNext() ) throw new 
NoSuchElementException(Lib.className(this)) ;
+        
+        T obj = slot ;
+        slot = null ;
+        slotIsSet = false ;
+        return obj ;
+    }
+
+    /** Look at the next element - returns null when there is no element */
+    public final T peek()
+    {
+        return peek(null) ;
+    }
+    
+    /** Look at the next element - returns dft when there is no element */
+    public final T peek(T dft)
+    {
+        hasNext() ;
+        if ( ! slotIsSet ) return dft ;
+        return slot ;
+    }
+    
+    @Override
+    public final void remove()
+    {
+        throw new UnsupportedOperationException(Lib.className(this)+".remove") 
;
+    }
+    
+    public final void close()
+    {
+        if ( finished )
+            return ;
+        closeIterator() ;
+        slotIsSet = false ;
+        slot = null ;
+        finished = true ;
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/iterator/IteratorTruncate.java
----------------------------------------------------------------------
diff --git 
a/jena-base/src/main/java/org/apache/jena/atlas/iterator/IteratorTruncate.java 
b/jena-base/src/main/java/org/apache/jena/atlas/iterator/IteratorTruncate.java
new file mode 100644
index 0000000..86ef52e
--- /dev/null
+++ 
b/jena-base/src/main/java/org/apache/jena/atlas/iterator/IteratorTruncate.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.iterator;
+
+import java.util.Iterator ;
+import java.util.NoSuchElementException ;
+
+/** Iterate while a condition return true, then stop */
+public class IteratorTruncate<T> implements Iterator<T>
+{
+    static public interface Test { boolean accept(Object object) ; }
+    private Test test ;
+    private T slot = null ;
+    private boolean active = true ;
+    private Iterator<T> iter ;
+
+    public IteratorTruncate (Test test, Iterator<T> iter)
+    { this.test = test ; this.iter = iter ; }
+
+    @Override
+    public boolean hasNext()
+    {
+        if ( ! active ) return false ;
+        if ( slot != null )
+            return true ;
+
+        if ( ! iter.hasNext() )
+        {
+            active = false ;
+            return false ;
+        }
+
+        slot = iter.next() ;
+        if ( test.accept(slot) )
+            return true ;
+        // Once the test goes false, no longer yield anything.
+        Iter.close(iter) ;
+        active = false ;
+        iter = null ;
+        slot = null ;
+        return false ;
+    }
+
+    @Override
+    public T next()
+    {
+        if ( ! hasNext() )
+            throw new NoSuchElementException("IteratorTruncate.next") ;    
+        T x = slot ;
+        slot = null ;
+        return x ;
+    }
+
+    @Override
+    public void remove()
+    { throw new UnsupportedOperationException("IteratorTruncate.remove"); }
+
+    public void close() {
+        if ( iter != null )
+            Iter.close(iter) ; 
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/iterator/IteratorWithBuffer.java
----------------------------------------------------------------------
diff --git 
a/jena-base/src/main/java/org/apache/jena/atlas/iterator/IteratorWithBuffer.java
 
b/jena-base/src/main/java/org/apache/jena/atlas/iterator/IteratorWithBuffer.java
new file mode 100644
index 0000000..7af9ac8
--- /dev/null
+++ 
b/jena-base/src/main/java/org/apache/jena/atlas/iterator/IteratorWithBuffer.java
@@ -0,0 +1,132 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.iterator ;
+
+import java.util.ArrayList ;
+import java.util.Iterator ;
+import java.util.List ;
+import java.util.NoSuchElementException ;
+
+/**
+ * Iterator that delays output by N slots so you can react to the output before
+ * it's yielded. See also {@link PeekIterator} (which predates this code). See 
also
+ * {@link IteratorWithHistory} for an iterator that remembers what it has 
yielded.
+ * 
+ * @see PeekIterator
+ * @see PushbackIterator
+ * @see IteratorWithHistory
+ */
+public class IteratorWithBuffer<T> implements Iterator<T> {
+    private List<T>     lookahead ;
+    private Iterator<T> iter ;
+    private int         capacity ;
+    private boolean     innerHasEnded = false ;
+
+    public IteratorWithBuffer(Iterator<T> iter, int N) {
+        if ( N < 0 )
+            throw new IllegalArgumentException("Buffering size < 0") ;
+        this.iter = iter ;
+        this.lookahead = new ArrayList<>(N) ;
+        this.capacity = N ;
+        // Fill the lookahead.
+        for ( int i = 0 ; i < N ; i++ ) {
+            if ( !iter.hasNext() ) {
+                atEndInner() ;
+                break ;
+            }
+            T nextItem = iter.next() ;
+            // System.out.println("Fill: "+nextItem) ;
+            lookahead.add(nextItem) ;
+        }
+    }
+
+    @Override
+    public boolean hasNext() {
+        return lookahead.size() > 0 ;
+    }
+
+    @Override
+    public T next() {
+        if ( !hasNext() )
+            throw new NoSuchElementException(this.getClass().getName()) ;
+
+        if ( !iter.hasNext() )
+            atEndInner() ;
+
+        T item = lookahead.remove(0) ;
+        // System.out.println("remove: "+item) ;
+        if ( iter.hasNext() ) {
+            // Should not throw NoSuchElementException.
+            T nextItem = iter.next() ;
+            // System.out.println("add   : "+nextItem) ;
+            lookahead.add(nextItem) ;
+        }
+        return item ;
+    }
+
+    @Override
+    public void remove() {
+        throw new UnsupportedOperationException("remove") ;
+    }
+
+    /**
+     * Look at elements that will be returned by a subsequnet call of .next().
+     * The next element is index 0, then index 1 etc. This operation is valid
+     * immediately after the constructor returns. Returns null for no such
+     * element (underlying iterator didn't yeild enough elements). Throws
+     * IndexOutOfBoundsException if an attempt i smade to go beyond the
+     * buffering window.
+     */
+    public T peek(int idx) {
+        if ( idx < 0 || idx >= capacity )
+            throw new IndexOutOfBoundsException("Index: " + idx) ;
+        if ( idx >= lookahead.size() )
+            return null ;
+        return lookahead.get(idx) ;
+    }
+
+    /**
+     * Return the current size of the lookahead. This can be used to tell the
+     * difference between an iterator returning null and an iterator that is
+     * just short.
+     */
+    public int currentSize() {
+        return lookahead.size() ;
+    }
+
+    /**
+     * Set the element to be returned by a subsequent .next(). Use with care.
+     * The original element to be returned at this position is lost.
+     */
+    public void set(int idx, T item) {
+        lookahead.set(idx, item) ;
+    }
+
+    /** Called when the underlying iterator ends */
+    private void atEndInner() {
+        if ( !innerHasEnded ) {
+            innerHasEnded = true ;
+            endReachedInner() ;
+        }
+    }
+
+    /** Called, once, at the end of the wrapped iterator. */
+    protected void endReachedInner() {}
+
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/iterator/IteratorWithHistory.java
----------------------------------------------------------------------
diff --git 
a/jena-base/src/main/java/org/apache/jena/atlas/iterator/IteratorWithHistory.java
 
b/jena-base/src/main/java/org/apache/jena/atlas/iterator/IteratorWithHistory.java
new file mode 100644
index 0000000..b5b800a
--- /dev/null
+++ 
b/jena-base/src/main/java/org/apache/jena/atlas/iterator/IteratorWithHistory.java
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.iterator;
+
+import java.util.ArrayList ;
+import java.util.Iterator ;
+import java.util.List ;
+import java.util.NoSuchElementException ;
+
+/** Remembers the last N yields.
+ * See also {@link IteratorWithBuffer}, for an iterator that looks ahead to 
what it will yield.
+ * @see IteratorWithBuffer
+ * @see PeekIterator
+ * @see PushbackIterator
+ */
+public class IteratorWithHistory<T> implements Iterator<T>
+{
+    private List<T> history ;
+    private Iterator<T> iter ;
+    private int capacity ;
+    private boolean hasEnded = false ;
+    
+    public IteratorWithHistory(Iterator<T> iter, int N) {
+        this.iter = iter ;
+        this.history = new ArrayList<>(N) ;
+        this.capacity = N ;
+    }
+
+    @Override
+    public boolean hasNext() {
+        boolean b = iter.hasNext() ;
+        if ( !b )
+            atEnd() ;
+        return b ;
+    }
+
+    @Override
+    public T next() {
+        T item = null ;
+        try {
+            item = iter.next() ;
+        }
+        catch (NoSuchElementException ex) {
+            atEnd() ;
+        }
+        // Shuffle up, add at bottom.
+        if ( history.size() >= capacity )
+            history.remove(history.size() - 1) ;
+        history.add(0, item) ;
+        return item ;
+    }
+
+    @Override
+    public void remove()
+    { throw new UnsupportedOperationException("remove") ; }
+
+    /**
+     * return the previous i'th element returned by next(). 0 means last call 
of
+     * next. History is retained after the end of iteration.
+     * 
+     * @return Element or null for no such element (that is for haven't yielded
+     *         that many elements).
+     * @throws IndexOutOfBoundsException
+     *             if index is negative.
+     */
+    public T getPrevious(int idx) {
+        if ( idx >= capacity || idx < 0 )
+            throw new IndexOutOfBoundsException("Index: " + idx) ;
+        if ( idx >= history.size() )
+            return null ;
+        return history.get(idx) ;
+    }
+
+    /**
+     * Return the current size of the histiory. This can be used to tell the
+     * difference between an iterator returning null and an iterator that is
+     * just short.
+     */
+    public int currentSize() {
+        return history.size() ;
+    }
+
+    /** Called when the underlying iterator ends */
+    protected void atEnd() {
+        if ( !hasEnded ) {
+            hasEnded = true ;
+            endReached() ;
+        }
+    }
+    
+    /** Called, once, at the end */ 
+    protected void endReached() { }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/iterator/IteratorWrapper.java
----------------------------------------------------------------------
diff --git 
a/jena-base/src/main/java/org/apache/jena/atlas/iterator/IteratorWrapper.java 
b/jena-base/src/main/java/org/apache/jena/atlas/iterator/IteratorWrapper.java
new file mode 100644
index 0000000..83901f2
--- /dev/null
+++ 
b/jena-base/src/main/java/org/apache/jena/atlas/iterator/IteratorWrapper.java
@@ -0,0 +1,41 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.iterator;
+
+import java.util.Iterator ;
+
+public class IteratorWrapper<T> implements Iterator<T>
+{
+    protected final Iterator<T> iterator ;
+
+    public IteratorWrapper(Iterator<T> iterator)
+    {
+        this.iterator = iterator ;
+    }
+
+    @Override
+    public boolean hasNext()        { return iterator.hasNext() ; }
+
+    @Override
+    public T next()                 { return iterator.next() ; }
+    
+    @Override
+    public void remove()            { iterator.remove() ; }
+}
+

http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/iterator/MapUtils.java
----------------------------------------------------------------------
diff --git 
a/jena-base/src/main/java/org/apache/jena/atlas/iterator/MapUtils.java 
b/jena-base/src/main/java/org/apache/jena/atlas/iterator/MapUtils.java
new file mode 100644
index 0000000..3c6492e
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/iterator/MapUtils.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.iterator;
+
+import java.util.Map ;
+
+import org.apache.jena.atlas.lib.ActionKeyValue ;
+
+
+
+public class MapUtils
+{
+     // Map specific operations
+    
+    public static <K, V> void apply(Map<K, V> map, ActionKeyValue<K, V> action)
+    {
+        for ( Map.Entry<K,V> entry : map.entrySet() )
+            action.apply(entry.getKey(), entry.getValue()) ;
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/iterator/NullIterator.java
----------------------------------------------------------------------
diff --git 
a/jena-base/src/main/java/org/apache/jena/atlas/iterator/NullIterator.java 
b/jena-base/src/main/java/org/apache/jena/atlas/iterator/NullIterator.java
new file mode 100644
index 0000000..ff2b2f1
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/iterator/NullIterator.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.iterator;
+
+import java.util.Iterator ;
+import java.util.NoSuchElementException ;
+
+/** Null Iterator - also guaranteed sharable and immutable */
+public class NullIterator<T> implements Iterator<T>, Iterable<T>
+{
+    @Override
+    public boolean hasNext()
+    {
+        return false ;
+    }
+
+    @Override
+    public T next()
+    {
+        throw new NoSuchElementException("NullIterator.next") ;
+    }
+
+    @Override
+    public void remove()
+    { throw new NoSuchElementException("NullIterator.remove") ;}
+
+    @Override
+    public Iterator<T> iterator()
+    {
+        return this ;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/iterator/PeekIterator.java
----------------------------------------------------------------------
diff --git 
a/jena-base/src/main/java/org/apache/jena/atlas/iterator/PeekIterator.java 
b/jena-base/src/main/java/org/apache/jena/atlas/iterator/PeekIterator.java
new file mode 100644
index 0000000..d9c0d2e
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/iterator/PeekIterator.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.iterator;
+
+import java.util.Iterator ;
+import java.util.NoSuchElementException ;
+import java.util.Queue ;
+
+/** PeekIterator - is one slot ahead from the wrapped iterator */ 
+public class PeekIterator<T> implements Iterator<T>
+{
+    private final Iterator<T> iter ;
+    private boolean finished = false ;
+    // Slot always full when iterator active.  Null is a a valid element.
+    private T slot ;
+    
+    public static <T> PeekIterator<T> create(PeekIterator<T> iter) { return 
iter ; }
+    public static <T> PeekIterator<T> create(Iterator<T> iter)
+    { 
+        if ( iter instanceof PeekIterator<?> )
+            return (PeekIterator<T>)iter ;
+        return new PeekIterator<>(iter) ;
+    }
+
+    public PeekIterator(Iterator<T> iter)
+    {
+        this.iter = iter ;
+        fill() ;
+    }
+    
+    private void fill()
+    {
+        if ( finished ) return ;
+        if ( iter.hasNext() )
+            slot = iter.next();
+        else
+        {
+            finished = true ;
+            slot = null ;
+        }
+    }
+
+    @Override
+    public boolean hasNext()
+    {
+        if ( finished )
+            return false ;
+        return true ;
+    }
+
+    /** Peek the next element or return null
+     *  @see Queue#peek
+     */
+    public T peek()
+    {
+        if ( finished )
+            return null  ;
+        return slot ;
+    }
+    
+    /** Peek the next element or throw  NoSuchElementException */
+    public T element()
+    {
+        if ( finished )
+            throw new NoSuchElementException() ;
+        return slot ;
+    }
+    
+    @Override
+    public T next()
+    {
+        if ( finished )
+            throw new NoSuchElementException() ;
+        T x = slot ;
+        // Move on now so the slot is loaded for peek.
+        fill() ;
+        return x ;
+    }
+
+    @Override
+    public void remove()
+    { throw new UnsupportedOperationException() ; }
+
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/iterator/PushbackIterator.java
----------------------------------------------------------------------
diff --git 
a/jena-base/src/main/java/org/apache/jena/atlas/iterator/PushbackIterator.java 
b/jena-base/src/main/java/org/apache/jena/atlas/iterator/PushbackIterator.java
new file mode 100644
index 0000000..355c563
--- /dev/null
+++ 
b/jena-base/src/main/java/org/apache/jena/atlas/iterator/PushbackIterator.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.iterator ;
+
+import java.util.ArrayDeque ;
+import java.util.Deque ;
+import java.util.Iterator ;
+
+/** An iterator where you can push items backinto the iterator, to be yielded 
(LIFO) next time.
+ *  @see PeekIterator
+ */
+public class PushbackIterator<T> implements Iterator<T> {
+    private Deque<T>    items = new ArrayDeque<>() ;
+    private Iterator<T> iter ;
+
+    public PushbackIterator(Iterator<T> iter) {
+        if ( iter == null )
+            throw new IllegalArgumentException("Wrapped iterator can't be 
null") ;
+        this.iter = iter ;
+    }
+
+    public void pushback(T item) {
+        items.push(item) ;
+    }
+
+    @Override
+    public boolean hasNext() {
+        if ( !items.isEmpty() )
+            return true ;
+        return iter.hasNext() ;
+    }
+
+    @Override
+    public T next() {
+        if ( !items.isEmpty() )
+            return items.pop() ;
+        return iter.next() ;
+    }
+
+    @Override
+    public void remove() {
+        // Need to track if last next() was from the stack or not.
+        throw new UnsupportedOperationException() ;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/iterator/RepeatApplyIterator.java
----------------------------------------------------------------------
diff --git 
a/jena-base/src/main/java/org/apache/jena/atlas/iterator/RepeatApplyIterator.java
 
b/jena-base/src/main/java/org/apache/jena/atlas/iterator/RepeatApplyIterator.java
new file mode 100644
index 0000000..e504265
--- /dev/null
+++ 
b/jena-base/src/main/java/org/apache/jena/atlas/iterator/RepeatApplyIterator.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.iterator;
+
+import java.util.Iterator ;
+import java.util.NoSuchElementException ;
+
+import org.apache.jena.atlas.lib.Closeable ;
+import org.apache.jena.atlas.lib.Lib ;
+
+public abstract class RepeatApplyIterator<T> implements Iterator<T>, Closeable
+{
+    private Iterator<T> input ;
+    private boolean finished = false ;
+    private Iterator<T> currentStage = null ;
+
+    protected RepeatApplyIterator(Iterator<T> input)
+    {
+        this.input = input ;
+    }
+
+    @Override
+    public boolean hasNext()
+    {
+        if  ( finished )
+            return false ;
+        for ( ;; )
+        {
+            if ( currentStage == null && input.hasNext() )
+            {
+                T nextItem = input.next();
+                currentStage = makeNextStage(nextItem) ;
+            }
+            
+            if ( currentStage == null  )
+            {
+                hasFinished() ;
+                finished = true ;
+                return false ;
+            }
+            
+            if ( currentStage.hasNext() )
+                return true ;
+            
+            currentStage = null ;
+        }
+    }
+
+    protected abstract Iterator<T> makeNextStage(T t) ;
+    
+    protected void hasFinished() {} 
+    
+    @Override
+    public T next()
+    {
+        if ( ! hasNext() )
+            throw new 
NoSuchElementException(Lib.className(this)+".next()/finished") ;
+        return currentStage.next() ;
+    }
+
+    @Override
+    public final void remove()
+    { throw new UnsupportedOperationException() ; }
+    
+    @Override
+    public void close()
+    {
+        Iter.close(input) ;
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/iterator/SingletonIterator.java
----------------------------------------------------------------------
diff --git 
a/jena-base/src/main/java/org/apache/jena/atlas/iterator/SingletonIterator.java 
b/jena-base/src/main/java/org/apache/jena/atlas/iterator/SingletonIterator.java
new file mode 100644
index 0000000..9c49e48
--- /dev/null
+++ 
b/jena-base/src/main/java/org/apache/jena/atlas/iterator/SingletonIterator.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.iterator;
+
+import java.util.Iterator ;
+import java.util.NoSuchElementException ;
+
+public class SingletonIterator<T> implements Iterator<T>
+{
+    private T thing = null ;
+    private boolean yielded = false ;
+    
+    public static <T> SingletonIterator<T> create(T thing) { return new 
SingletonIterator<>(thing) ; }
+    
+    public SingletonIterator(T thing) { this.thing = thing ; }
+    
+    @Override
+    public boolean hasNext()
+    {
+        return ! yielded ;
+    }
+
+    @Override
+    public T next()
+    {
+        if ( yielded )
+            throw new NoSuchElementException("SingletonIterator.next") ;
+        yielded = true ;
+        return thing ;
+    }
+
+    @Override
+    public void remove()
+    { throw new NoSuchElementException("SingletonIterator.remove") ;}
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/iterator/Transform.java
----------------------------------------------------------------------
diff --git 
a/jena-base/src/main/java/org/apache/jena/atlas/iterator/Transform.java 
b/jena-base/src/main/java/org/apache/jena/atlas/iterator/Transform.java
new file mode 100644
index 0000000..d5d6a0a
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/iterator/Transform.java
@@ -0,0 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.iterator;
+
+public interface Transform <T, R> { R convert(T item) ; }

http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/iterator/WrapperIterator.java
----------------------------------------------------------------------
diff --git 
a/jena-base/src/main/java/org/apache/jena/atlas/iterator/WrapperIterator.java 
b/jena-base/src/main/java/org/apache/jena/atlas/iterator/WrapperIterator.java
new file mode 100644
index 0000000..0a8a0b0
--- /dev/null
+++ 
b/jena-base/src/main/java/org/apache/jena/atlas/iterator/WrapperIterator.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.iterator;
+
+import java.util.Iterator ;
+
+public class WrapperIterator<T> implements Iterator<T>
+{
+    private final Iterator<T> iter ;
+
+    public WrapperIterator(Iterator<T> iter) { this.iter = iter ; }
+    
+    @Override
+    public boolean hasNext()
+    {
+        return iter.hasNext() ;
+    }
+
+    @Override
+    public T next()
+    {
+        return iter.next() ;
+    }
+
+    @Override
+    public void remove()
+    { iter.remove() ; }
+
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/ActionKeyValue.java
----------------------------------------------------------------------
diff --git 
a/jena-base/src/main/java/org/apache/jena/atlas/lib/ActionKeyValue.java 
b/jena-base/src/main/java/org/apache/jena/atlas/lib/ActionKeyValue.java
new file mode 100644
index 0000000..894107a
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/ActionKeyValue.java
@@ -0,0 +1,24 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.lib;
+
+public interface ActionKeyValue<KeyType, ValueType>
+{
+    public void apply(KeyType key, ValueType value) ;
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/AlarmClock.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/AlarmClock.java 
b/jena-base/src/main/java/org/apache/jena/atlas/lib/AlarmClock.java
new file mode 100644
index 0000000..6210bf1
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/AlarmClock.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.lib ;
+
+import java.util.concurrent.ScheduledThreadPoolExecutor ;
+import java.util.concurrent.TimeUnit ;
+
+/**
+ * An AlarmClock is an object that will make a callback (with a value) at a
+ * preset time. Simple abstraction of add/reset/cancel of a Runnable. 
Currently,
+ * backed by {@link ScheduledThreadPoolExecutor}
+ */
+public class AlarmClock {
+    private ScheduledThreadPoolExecutor timer = new 
ScheduledThreadPoolExecutor(1) ;
+
+    /* package */AlarmClock() {}
+
+    static private AlarmClock singleton = new AlarmClock() ;
+
+    /** Global singleton for general use */
+    static public AlarmClock get() {
+        return singleton ;
+    }
+
+    /** Add a task to be called after a delay (in milliseconds) */
+    public void add(Runnable task, long delay) {
+        if ( task == null )
+            throw new IllegalArgumentException("Task is null") ;
+        timer.schedule(task, delay, TimeUnit.MILLISECONDS) ;
+    }
+
+    /** Reschedule a task to now run after a different delay from now (in 
milliseconds) */
+    public void reset(Runnable task, long delay) {
+        if ( task == null )
+            throw new IllegalArgumentException("Task is null") ;
+        cancel(task) ;
+        add(task, delay) ;
+    }
+
+    /** Cancel a task  */
+    public void cancel(Runnable task) {
+        if ( task == null )
+            throw new IllegalArgumentException("Task is null") ;
+        timer.remove(task) ;
+    }
+
+    // public int getCount() { return timer.getQueue().size(); }
+
+    /** Clean up */
+    public void release() {
+        timer.shutdownNow() ;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/Alg.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/Alg.java 
b/jena-base/src/main/java/org/apache/jena/atlas/lib/Alg.java
new file mode 100644
index 0000000..3a3dacb
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/Alg.java
@@ -0,0 +1,239 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.lib;
+
+import java.nio.IntBuffer ;
+import java.util.Comparator ;
+import java.util.List ;
+
+public class Alg
+{
+    // Linear search is really there to test binary search.
+    static int linearSearch(IntBuffer buff, int key)
+    { 
+        return linearSearch(buff, 0, buff.limit(), key) ;
+    }
+
+    static int linearSearch(IntBuffer buff, int low, int high, int key)
+    {
+        int len = buff.limit(); // In int units.
+        check(len, low, high) ;
+        for ( int i = low ; i < high ; i++ )
+        {
+            int k2 = buff.get(i) ;
+            if ( k2 == key )
+                return i ;
+            if ( k2 > key )
+                return encodeIndex(i) ;
+        }
+        return encodeIndex(high) ;
+    }
+    
+    // The encoded offset (insertion point) when not found.
+    public static final int encodeIndex(int i) { return -(i+1) ; } 
+    public static final int decodeIndex(int i) { return -(i+1) ; } 
+
+    
+    /* Both Arrays and Collections have a binary search implementation.
+     * Arrays searches Object[] arrays, and Collections searches List<T>
+     *
+     * But sometime things are not so easy, and it isn't neat as to
+     * what is being searched, like a slice of an NIO Buffer
+     * 
+     * http://en.wikipedia.org/wiki/Binary_search
+     */
+    
+    public static int binarySearch(IntBuffer buff, int value)
+    {
+        return  binarySearch(buff, 0, buff.limit(), value) ;
+    }
+    
+    public static int binarySearch(IntBuffer buff, int low, int high, int 
value)
+    {
+        // Low is inclusive, high is exclusive.
+        check(buff.limit(), low, high) ;
+        high -- ;   // Convert high to inclusive.
+
+        // Non-tail-recursive form, because tail-recursion removal
+        // is not required by java (unlike scheme).
+        
+        while (low <= high)
+        {
+            int mid = (low + high) >>> 1 ;  // int divide by 2 : better: mid = 
low + ((high - low) / 2)
+            int k = buff.get(mid) ;
+            
+            // Two comparisons : see wikipedia for one comparison version.
+            if (k < value)
+                low = mid + 1 ;
+            else if ( k > value)
+                high = mid - 1 ;
+            else
+                return mid ;
+        }
+        // On exit, when not finding, low is the least value
+        // above, including off the end of the array.  
+        return encodeIndex(low) ;
+    }
+    
+    // Alt form - no early termination.
+//    public static int binarySearch2(IntBuffer buff, int value, int low, int 
high)
+//    {
+//        // Low is inclusive, high is exclusive
+//        check(buff.limit(), low, high) ;
+//        int N = high ;
+//        
+//        // Uses high as exclusive index
+//        while (low < high)
+//        {
+//            int mid = (low + high) >>> 1 ;  // int divide by 2 : better: mid 
= low + ((high - low) / 2)
+//            int k = buff.get(mid) ;
+//            
+//            // Two comparisons : see wikipedia for one comparison version.
+//            if ( k < value)
+//                low = mid + 1 ;
+//            else 
+//                //can't be high = mid-1: here A[mid] >= value,
+//                //so high can't be < mid if A[mid] == value
+//                high = mid;
+//        }
+//        if (low < N && buff.get(low) == value )
+//            return low ;
+//        else
+//            return enc(low) ;
+//    }
+        
+    private static void check(int len, int low, int high)
+    {
+        if ( low > high )
+            throw new IllegalArgumentException("Low index ("+low+") is not 
less than high index ("+high+")") ; 
+        if ( low < 0 )
+            throw new ArrayIndexOutOfBoundsException("Low index is negative: 
"+low) ; 
+        if ( high > len )
+            throw new ArrayIndexOutOfBoundsException("High index is too large: 
"+high) ;
+    }
+
+    // Why isn't this in the java RT?
+    public static <T> int binarySearch( List<T> array, int low, int high, T 
value, Comparator<T> comparator )
+    {
+        check(array.size(), low, high) ;
+        high -- ;
+
+        while( low <= high )
+        {
+            int mid = ( low + high ) >>> 1 ;
+
+            T k = array.get(mid) ;
+            
+            int x = comparator.compare(k, value) ;
+            if ( x < 0 )
+                low = mid + 1 ;
+            else if ( x > 0 )
+                high = mid - 1 ;
+            else
+                return mid ;
+        }
+        return encodeIndex(low) ;
+    }
+
+    // Why isn't this in the java RT?
+    public static <T extends Comparable<? super T>>
+    int binarySearch(T[] array, int low, int high, T value)
+    {
+        check(array.length, low, high) ;
+        high -- ;
+
+        while( low <= high )
+        {
+            int mid = ( low + high ) >>> 1 ;
+
+            T k = array[mid] ;
+            
+            int x = k.compareTo(value) ; // comparator.compare(k, value) ;
+            if ( x < 0 )
+                low = mid + 1 ;
+            else if ( x > 0 )
+                high = mid - 1 ;
+            else
+                return mid ;
+        }
+        return encodeIndex(low) ;
+    }
+    
+    
+    // Use Arrays.binarySearch functions
+    
+//    public static int binarySearch(int buff[], int value)
+//    { return binarySearch(buff, value, 0, buff.length) ; } 
+//
+//    public static int binarySearch(int buff[], int low, int high, int value)
+//    {
+//        check(buff.length, low, high) ;
+//        // Low is inclusive, high is exclusive.
+//        high -- ;   // Convert high to inclusive.
+//
+//        // Non-tail-recursive form, because tail-recursion removal
+//        // is not required by java (unlike scheme).
+//        
+//        while (low <= high)
+//        {
+//            int mid = (low + high) >>> 1 ;  // int divide by 2 
+//            int k = buff[mid] ;
+//
+//            if (k < value)
+//                low = mid + 1 ;
+//            else if ( k > value)
+//                high = mid - 1 ;
+//            else
+//                return mid ;
+//        }
+//        // On exit, when not finding, low is the least value
+//        // above, including off the end of the array.  
+//        return encodeIndex(low) ;
+//    }
+//
+//    
+//    public static int binarySearch(long buff[], int value)
+//    { return binarySearch(buff, value, 0, buff.length) ; } 
+//    
+//    public static int binarySearch(long buff[], int low, int high, long 
value)
+//    {
+//        check(buff.length, low, high) ;
+//        // Low is inclusive, high is exclusive.
+//        high -- ;   // Convert high to inclusive.
+//
+//        // Non-tail-recursive form, because tail-recursion removal
+//        // is not required by java (unlike scheme).
+//        
+//        while (low <= high)
+//        {
+//            int mid = (low + high) >>> 1 ;  // int divide by 2 
+//            long k = buff[mid] ;
+//
+//            if (k < value)
+//                low = mid + 1 ;
+//            else if ( k > value)
+//                high = mid - 1 ;
+//            else
+//                return mid ;
+//        }
+//        // On exit, when not finding, low is the least value
+//        // above, including off the end of the array.  
+//        return encodeIndex(low) ;
+//    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/Allocator.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/Allocator.java 
b/jena-base/src/main/java/org/apache/jena/atlas/lib/Allocator.java
new file mode 100644
index 0000000..84005de
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/Allocator.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.lib;
+
+public interface Allocator<T>
+{
+    /** Allocate a new T, different from others allocated */ 
+    public T create() ;
+    
+//    /** Reset the process of allocation - may cause equivalent objects to be 
created from before the reset */  
+//    public void reset() ;
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/ArrayUtils.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/ArrayUtils.java 
b/jena-base/src/main/java/org/apache/jena/atlas/lib/ArrayUtils.java
new file mode 100644
index 0000000..d45a107
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/ArrayUtils.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.lib;
+
+import java.lang.reflect.Array ;
+import java.util.Arrays ;
+
+/** Collection of array-related operations */
+public class ArrayUtils
+{
+    private ArrayUtils() {}
+    
+    /** Allocate an array of generic type T (initialized to null) */
+    @SuppressWarnings("unchecked")
+    public static <T> T[] alloc(Class<T> cls, int n)
+    {
+        return (T[])Array.newInstance(cls, n) ;
+    }
+    
+ // Compiles but fails at runtime (class cast exception if the reuls is 
assigned or accessed)
+//        @SuppressWarnings("unchecked")
+//        T[] array = (T[])new Object[n] ;
+// or is T known 
+//        @SuppressWarnings("unchecked")
+//        Set<T> x[] = new Set[length] ;
+//        return array ;
+        
+    /** Allocation space and copy */ 
+    public static <T> T[] copy(T[] array)
+    {
+        return copy(array, 0, array.length) ;
+    }
+    
+    /** Allocation space and copy */ 
+    public static <T> T[] copy(T[] array, int start, int finish)
+    {    
+        return Arrays.copyOfRange(array, start, finish) ;
+
+//        // Java5.
+//        // Fails for arrays of length 0;
+//        if ( array.length <= start )
+//            throw new IllegalArgumentException("Zero length array not 
supported") ;
+//        @SuppressWarnings("unchecked")
+//        T[] array2 = (T[])Array.newInstance(array[start].getClass(), 
finish-start) ;
+//        System.arraycopy(array, start, array2, 0, finish-start) ;
+//        return array2 ;
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/BitsInt.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/BitsInt.java 
b/jena-base/src/main/java/org/apache/jena/atlas/lib/BitsInt.java
new file mode 100644
index 0000000..1e112a0
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/BitsInt.java
@@ -0,0 +1,309 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.lib;
+
+// NB shifting is "mod 32" -- <<32 is a no-op (not a clear).
+// http://mindprod.com/jgloss/masking.html
+
+/** Utilities for manipulating a bit pattern which are held in a 32 bit int.
+ *  @see BitsLong
+ */ 
+public final class BitsInt
+{
+    private BitsInt() {}
+    
+    private static int IntLen = Integer.SIZE ;
+    
+    /** Extract the value packed into bits start (inclusive) and finish 
(exclusive).
+     *  The value is returned in the low part of the returned int.
+     *  The low bit is bit zero.
+     * @param bits
+     * @param start
+     * @param finish
+     * @return int  
+     */ 
+    
+    public static final
+    int unpack(int bits, int start, int finish)
+    {
+        check(start, finish) ;
+        if ( finish == 0 ) return 0 ;
+        // Remove top bits by moving up.  Clear bottom bits by them moving 
down.
+        return (bits<<(IntLen-finish)) >>> ((IntLen-finish)+start) ;
+    }
+
+    /** Place the value into the bit pattern between start and finish
+     *  and returns the new int. 
+     * @param bits
+     * @param value
+     * @param start
+     * @param finish
+     * @return int
+     */
+    public static final
+    int pack(int bits, int value, int start, int finish)
+    {
+        check(start, finish) ;
+        bits = clear$(bits, start, finish) ;
+        bits = bits | (value<<start) ;
+        return bits ;
+    }
+
+    /** Get bits from a hex string.
+     * 
+     * @param str
+     * @param startChar     Index of first character (counted from the left, 
string style). 
+     * @param finishChar    Index after the last character (counted from the 
left, string style).
+     * @return int
+     */
+    
+    public static final
+    int unpack(String str, int startChar, int finishChar)
+    {
+        String s = str.substring(startChar, finishChar) ;
+        return Integer.parseInt(s, 16) ;
+    }
+
+    /** Set the bits specificied.
+     * 
+     * @param bits      Pattern
+     * @param bitIndex 
+     * @return          Modified pattern
+     */
+    public static final
+    int set(int bits, int bitIndex)
+    { 
+        check(bitIndex) ;
+        return set$(bits, bitIndex) ;
+    }
+
+    /** Set the bits from start (inc) to finish (exc) to one
+     * 
+     * @param bits      Pattern
+     * @param start     start  (inclusive)
+     * @param finish    finish (exclusive)
+     * @return          Modified pattern
+     */
+    public static final
+    int set(int bits, int start, int finish)
+    { 
+        check(start, finish) ;
+        return set$(bits, start, finish) ;
+    }
+
+    /** Test whether a bit is the same as isSet 
+     * @param bits      Pattern
+     * @param isSet     Test whether is set or not. 
+     * @param bitIndex  Bit index
+     * @return          Boolean
+     */
+    public static final
+    boolean test(int bits, boolean isSet, int bitIndex)
+    {
+        check(bitIndex) ;
+        return test$(bits, isSet, bitIndex) ;
+    }
+    
+    /** Test whether a bit is set 
+     * @param bits      Pattern
+     * @param bitIndex  Bit index
+     * @return          Boolean
+     */
+    public static final
+    boolean isSet(int bits, int bitIndex)
+    {
+        check(bitIndex) ;
+        return test$(bits, true, bitIndex) ;
+    }
+    
+    /** Test whether a range has a specific value or not   
+     * @param bits      Pattern
+     * @param value     Value to test for
+     * @param start     start  (inclusive)
+     * @param finish    finish (exclusive)
+     * @return          Boolean
+     */
+    public static final
+    boolean test(int bits, int value, int start, int finish)
+    {
+        check(start, finish) ;
+        return test$(bits, value, start, finish) ;
+    }
+    
+    /** Get the bits from start (inclusive) to finish (exclusive),
+     *  leaving them aligned in the int.  See also unpack, returns
+     *  the value found at that place.
+     *  @see #unpack(int, int, int)
+     *  @param bits
+     *  @param start
+     *  @param finish
+     *  @return int
+     */
+    
+    public static final
+    int access(int bits, int start, int finish)
+    {
+        check(start, finish) ;
+        return access$(bits, start, finish) ; 
+    }
+    
+    /**
+     * Clear the bits specified.
+     *  @param bits
+     *  @param start
+     *  @param finish
+     *  @return int
+     */
+    public static final
+    int clear(int bits, int start, int finish)
+    {
+        check(start, finish) ;
+        return clear$(bits, start, finish) ;
+    }
+
+    /**
+     * Create a mask that has ones between bit positions start (inc) and 
finish (exc),
+     * and zeros elsewhere.
+     * @param start
+     * @param finish
+     * @return int
+     */
+    public static final
+    int mask(int start, int finish)
+    {
+        check(start, finish) ;
+        return mask$(start, finish) ;
+    }
+    
+    /**
+     * Create a mask that has zeros between bit positions start (inc) and 
finish (exc),
+     * and ones elsewhere
+     * @param start
+     * @param finish
+     * @return int
+     */
+    public static final
+    int maskZero(int start, int finish)
+    {
+        check(start, finish) ;
+        return maskZero$(start, finish) ;
+    }
+    
+    private static final
+    int clear$(int bits, int start, int finish)
+    {
+        int mask = maskZero$(start, finish) ;
+        bits = bits & mask ;
+        return bits ;
+    }
+
+    private static final
+    int set$(int bits, int bitIndex)
+    { 
+        int mask = mask$(bitIndex) ;
+        return bits | mask ;
+    }
+
+    private static final
+    int set$(int bits, int start, int finish)
+    { 
+        int mask = mask$(start, finish) ;
+        return bits | mask ;
+    }
+
+    private static
+    boolean test$(int bits, boolean isSet, int bitIndex)
+    {
+        return isSet == access$(bits, bitIndex) ;
+    }
+
+    private static
+    boolean test$(int bits, int value, int start, int finish)
+    {
+        int v = access$(bits, start, finish) ;
+        return v == value ;
+    }
+
+
+    
+    private static final
+    boolean access$(int bits, int bitIndex)
+    {
+        int mask = mask$(bitIndex) ;
+        return (bits & mask) != 0L ;
+    }
+    
+    private static final
+    int access$(int bits, int start, int finish)
+    {
+        // Two ways:
+//        int mask = mask$(start, finish) ;
+//        return bits & mask ;
+        
+        return ( (bits<<(IntLen-finish)) >>> (IntLen-finish+start) ) << start  
;
+    }
+    
+
+    private static final
+    int mask$(int bitIndex)
+    {
+        return 1 << bitIndex ;
+    }
+
+    private static final
+    int mask$(int start, int finish)
+    {
+    //        int mask = 0 ;
+    //        if ( finish == int.SIZE )
+    //            // <<int.SIZE is a no-op 
+    //            mask = -1 ;
+    //        else
+    //            mask = (1L<<finish)-1 ;
+        if ( finish == 0 )
+            // So start is zero and so the mask is zero.
+            return 0 ;
+
+        
+        int mask = -1 ;
+//        mask = mask << (IntLen-finish) >>> (intLen-finish) ;      // Clear 
the top bits
+//        return mask >>> start << start ;                  // Clear the 
bottom bits
+        return mask << (IntLen-finish) >>> (IntLen-finish+start) << start ; 
+    }
+
+    private static final
+    int maskZero$(int start, int finish)
+    {
+        return ~mask$(start, finish) ;
+    }
+    
+    private static final
+    void check(int bitIndex)
+    {
+        if ( bitIndex < 0 || bitIndex >= IntLen ) throw new 
IllegalArgumentException("Illegal bit index: "+bitIndex) ;
+    }
+
+    private static final
+    void check(int start, int finish)
+    {
+        if ( start < 0 || start >= IntLen ) throw new 
IllegalArgumentException("Illegal start: "+start) ;
+        if ( finish < 0 || finish > IntLen ) throw new 
IllegalArgumentException("Illegal finish: "+finish) ;
+        if ( start > finish )  throw new IllegalArgumentException("Illegal 
range: ("+start+", "+finish+")") ;
+    }
+    
+}

Reply via email to