jena-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From a...@apache.org
Subject [01/12] jena git commit: JENA-1107: Rework Tuple
Date Tue, 29 Dec 2015 21:23:22 GMT
Repository: jena
Updated Branches:
  refs/heads/master 6fbecf1e3 -> d36034820


JENA-1107: Rework Tuple

Project: http://git-wip-us.apache.org/repos/asf/jena/repo
Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/571e9755
Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/571e9755
Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/571e9755

Branch: refs/heads/master
Commit: 571e97553c9d5ccb29818ed85afb70e4fe0318c2
Parents: c81557a
Author: Andy Seaborne <andy@seaborne.org>
Authored: Mon Dec 28 16:27:01 2015 +0000
Committer: Andy Seaborne <andy@seaborne.org>
Committed: Mon Dec 28 16:27:01 2015 +0000

----------------------------------------------------------------------
 .../java/org/apache/jena/atlas/lib/FileOps.java |   7 +-
 .../java/org/apache/jena/atlas/lib/Tuple.java   | 131 ------
 .../org/apache/jena/atlas/lib/tuple/Tuple.java  |  63 +++
 .../org/apache/jena/atlas/lib/tuple/Tuple0.java |  37 ++
 .../org/apache/jena/atlas/lib/tuple/Tuple1.java |  42 ++
 .../org/apache/jena/atlas/lib/tuple/Tuple2.java |  46 +++
 .../org/apache/jena/atlas/lib/tuple/Tuple3.java |  49 +++
 .../org/apache/jena/atlas/lib/tuple/Tuple4.java |  52 +++
 .../org/apache/jena/atlas/lib/tuple/Tuple5.java |  55 +++
 .../org/apache/jena/atlas/lib/tuple/Tuple6.java |  58 +++
 .../org/apache/jena/atlas/lib/tuple/Tuple7.java |  61 +++
 .../org/apache/jena/atlas/lib/tuple/Tuple8.java |  64 +++
 .../apache/jena/atlas/lib/tuple/TupleBase.java  |  73 ++++
 .../jena/atlas/lib/tuple/TupleFactory.java      | 122 ++++++
 .../apache/jena/atlas/lib/tuple/TupleList.java  |  43 ++
 .../apache/jena/atlas/lib/tuple/TupleMap.java   | 404 +++++++++++++++++++
 .../org/apache/jena/atlas/lib/tuple/TupleN.java |  55 +++
 .../jena/atlas/lib/tuple/package-info.java      |  34 ++
 .../java/org/apache/jena/atlas/TC_Atlas.java    |   2 +
 .../org/apache/jena/atlas/lib/TestFileOps.java  |   2 +-
 .../apache/jena/atlas/lib/tuple/TS_Tuple.java   |  32 ++
 .../apache/jena/atlas/lib/tuple/TestTuple.java  | 201 +++++++++
 .../jena/atlas/lib/tuple/TestTupleMap.java      | 186 +++++++++
 23 files changed, 1685 insertions(+), 134 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jena/blob/571e9755/jena-base/src/main/java/org/apache/jena/atlas/lib/FileOps.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/FileOps.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/FileOps.java
index cf2e6ee..8ede725 100644
--- a/jena-base/src/main/java/org/apache/jena/atlas/lib/FileOps.java
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/FileOps.java
@@ -21,8 +21,11 @@ package org.apache.jena.atlas.lib ;
 import java.io.File ;
 import java.io.IOException ;
 import java.nio.file.Files;
+
 import org.apache.jena.atlas.AtlasException ;
 import org.apache.jena.atlas.io.IO ;
+import org.apache.jena.atlas.lib.tuple.Tuple ;
+import org.apache.jena.atlas.lib.tuple.TupleFactory ;
 import org.apache.jena.atlas.logging.Log ;
 
 /** A library of utility operations on files and the filing system */
@@ -146,7 +149,7 @@ public class FileOps {
             basename = basename.substring(0, i) ;
         }
 
-        return Tuple.createTuple(path, basename, ext) ;
+        return TupleFactory.tuple(path, basename, ext) ;
     }
 
     /**
@@ -165,7 +168,7 @@ public class FileOps {
             path = filename.substring(0, j) ;
             fn = filename.substring(j + 1) ;
         }
-        return Tuple.createTuple(path, fn) ;
+        return TupleFactory.tuple(path, fn) ;
     }
 
     /** Return the basename (no path, no extension) */

http://git-wip-us.apache.org/repos/asf/jena/blob/571e9755/jena-base/src/main/java/org/apache/jena/atlas/lib/Tuple.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/Tuple.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/Tuple.java
deleted file mode 100644
index ec0e420..0000000
--- a/jena-base/src/main/java/org/apache/jena/atlas/lib/Tuple.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * 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.Arrays ;
-import java.util.Iterator ;
-import java.util.List ;
-import java.util.Objects;
-import java.util.function.Function;
-
-import org.apache.jena.atlas.iterator.Iter ;
-
-/** Tuple class - tuples are immutable and must be created initialized */
-public class Tuple<T> implements Iterable<T> {
-    // Interface this?
-    // Classes: TupleImpl, TupleSlice
-    public static <X> Tuple<X> createTuple(@SuppressWarnings("unchecked") X... elements) {
-        X[] els = elements ; // ArrayUtils.copy(elements) ;
-        return create(els) ;
-    }
-
-    /**
-     * Create a tuple from an array of elements. The array is not copied and
-     * should not be modified after this call.
-     */
-    public static <X> Tuple<X> create(X[] elements) {
-        return new Tuple<>(elements) ;
-    }
-
-    // TupleLib??
-    public static <T> Iterator<T> project(final int slot, Iterator<Tuple<T>> iter) {
-        return Iter.map(iter, t -> t.get(slot)) ;
-    }
-
-    public static <T> Iterator<Tuple<T>> prefix(final int prefixLength, Iterator<Tuple<T>> iter) {
-        Function<Tuple<T>, Tuple<T>> sub = t -> {
-                T[] x = ArrayUtils.copy(t.tuple, 0, prefixLength) ;
-                return Tuple.create(x) ;    
-        } ;
-        return Iter.map(iter, sub) ;
-    }
-
-    protected final T[] tuple ;
-
-    protected Tuple(@SuppressWarnings("unchecked") T... tuple) {
-        this.tuple = tuple ;
-    }
-
-    public T get(int idx) {
-        return tuple[idx] ;
-    }
-
-    public int countNotNull() {
-        int x = 0 ;
-        for ( T item : tuple )
-            if ( item != null )
-                x++ ;
-        return x ;
-    }
-
-    public List<T> asList() {
-        return Arrays.asList(tuple) ;
-    }
-
-    public T[] tuple() {
-        return tuple ;
-    }
-
-    public T[] tupleCopy() {
-        return ArrayUtils.copy(tuple) ;
-    }
-
-    @Override
-    public Iterator<T> iterator() {
-        return Arrays.asList(tuple).iterator() ;
-    }
-
-    public int size() {
-        return tuple.length ;
-    }
-
-    @Override
-    public int hashCode() {
-        int x = 99 ;
-        for ( T n : tuple ) {
-            if ( n != null )
-                x = x << 1 ^ n.hashCode() ;
-        }
-        return x ;
-    }
-
-    /** Equality of tuples is based on equality of the elements in the tuple */
-    @Override
-    public boolean equals(Object other) {
-        if ( this == other )
-            return true ;
-        if ( !(other instanceof Tuple<? >) )
-            return false ;
-        Tuple<? > x = (Tuple<? >)other ;
-        if ( x.size() != this.size() )
-            return false ;
-        for ( int i = 0 ; i < tuple.length ; i++ ) {
-            Object obj1 = tuple[i] ;
-            Object obj2 = x.tuple[i] ;
-            if ( !Objects.equals(obj1, obj2) )
-                return false ;
-        }
-        return true ;
-    }
-
-    @Override
-    public String toString() {
-        return "[" + Iter.asString(iterator(), ", ") + "]" ;
-    }
-}

http://git-wip-us.apache.org/repos/asf/jena/blob/571e9755/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/Tuple.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/Tuple.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/Tuple.java
new file mode 100644
index 0000000..ec818b2
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/Tuple.java
@@ -0,0 +1,63 @@
+/*
+ * 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.tuple;
+
+import java.util.List ;
+import java.util.function.Consumer ;
+import java.util.stream.Stream ;
+
+/** A Tuple is the same class of item */
+public interface Tuple<X> extends Iterable<X> {
+    /** Get the i'th element, for i in the range 0 to len()-1 
+     * @throws IndexOutOfBoundsException for i out of range 
+     */
+    public X get(int i) ;
+    
+    /** length : elements are 0 to len()-1 */ 
+    public int len() ;
+
+    /** Convert to a List */
+    public default List<X> asList() {
+        return new TupleList<>(this) ;
+    }
+    
+    /** stream */
+    public default Stream<X> stream() { 
+        return asList().stream() ;
+    }
+    
+    /** forEach */
+    @Override
+    public default void forEach(Consumer<? super X> action) { 
+        asList().forEach(action) ;
+    }
+    
+    /** Copy the Tuple into the array */ 
+    public default void copyInto(X[] array) {
+        copyInto(array, 0, len());
+    }
+
+    /** Copy the Tuple into the array */ 
+    public default void copyInto(X[] array, int start) {
+        copyInto(array, start, len());
+    }
+    
+    /** Copy the Tuple into the array */ 
+    public void copyInto(X[] array, int start, int length) ;
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/571e9755/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/Tuple0.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/Tuple0.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/Tuple0.java
new file mode 100644
index 0000000..534bd50
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/Tuple0.java
@@ -0,0 +1,37 @@
+/*
+ * 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.tuple;
+
+/**
+ * A tuple of 0 items.
+ */
+public class Tuple0<X> extends TupleBase<X> {
+    
+    protected Tuple0() { }
+    
+    @Override
+    public final X get(int i) {
+        throw new IndexOutOfBoundsException() ;
+    }
+    
+    @Override
+    public final int len() {
+        return 0 ;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jena/blob/571e9755/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/Tuple1.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/Tuple1.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/Tuple1.java
new file mode 100644
index 0000000..9490732
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/Tuple1.java
@@ -0,0 +1,42 @@
+/*
+ * 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.tuple;
+
+/**
+ * A tuple of 1 item.
+ */
+public class Tuple1<X> extends TupleBase<X> {
+    protected final X x1 ; 
+    
+    protected Tuple1(X x1) {
+        this.x1 = x1 ;
+    }
+    
+    @Override
+    public final X get(int i) {
+        if ( i == 0 )
+            return x1 ;
+        throw new IndexOutOfBoundsException() ;
+    }
+    
+    @Override
+    public final int len() {
+        return 1 ;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jena/blob/571e9755/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/Tuple2.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/Tuple2.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/Tuple2.java
new file mode 100644
index 0000000..d90b730
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/Tuple2.java
@@ -0,0 +1,46 @@
+/*
+ * 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.tuple;
+
+/**
+ * A tuple of 2 items.
+ */
+public class Tuple2<X> extends TupleBase<X> {
+    protected final X x1 ; 
+    protected final X x2 ;
+    
+    protected Tuple2(X x1, X x2) {
+        this.x1 = x1 ;
+        this.x2 = x2 ;
+    }
+    
+    @Override
+    public final X get(int i) {
+        switch (i) {
+            case 0: return x1 ;
+            case 1: return x2 ;
+        }
+        throw new IndexOutOfBoundsException() ;
+    }
+    
+    @Override
+    public final int len() {
+        return 2 ;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jena/blob/571e9755/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/Tuple3.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/Tuple3.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/Tuple3.java
new file mode 100644
index 0000000..fceac41
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/Tuple3.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.lib.tuple;
+
+/**
+ * A tuple of 3 items.
+ */
+public class Tuple3<X> extends TupleBase<X> {
+    protected final X x1 ; 
+    protected final X x2 ;
+    protected final X x3 ;
+    
+    protected Tuple3(X x1, X x2, X x3) {
+        this.x1 = x1 ;
+        this.x2 = x2 ;
+        this.x3 = x3 ;
+    }
+    
+    @Override
+    public final X get(int i) {
+        switch (i) {
+            case 0: return x1 ;
+            case 1: return x2 ;
+            case 2: return x3 ;
+        }
+        throw new IndexOutOfBoundsException() ;
+    }
+    
+    @Override
+    public final int len() {
+        return 3 ;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jena/blob/571e9755/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/Tuple4.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/Tuple4.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/Tuple4.java
new file mode 100644
index 0000000..04d5fe8
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/Tuple4.java
@@ -0,0 +1,52 @@
+/*
+ * 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.tuple;
+
+/**
+ * A tuple of 4 items.
+ */
+public class Tuple4<X> extends TupleBase<X> {
+    protected final X x1 ; 
+    protected final X x2 ;
+    protected final X x3 ;
+    protected final X x4 ;
+    
+    protected Tuple4(X x1, X x2, X x3, X x4) {
+        this.x1 = x1 ;
+        this.x2 = x2 ;
+        this.x3 = x3 ;
+        this.x4 = x4 ;
+    }
+    
+    @Override
+    public final X get(int i) {
+        switch (i) {
+            case 0: return x1 ;
+            case 1: return x2 ;
+            case 2: return x3 ;
+            case 3: return x4 ;
+        }
+        throw new IndexOutOfBoundsException() ;
+    }
+
+    @Override
+    public final int len() {
+        return 4 ;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jena/blob/571e9755/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/Tuple5.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/Tuple5.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/Tuple5.java
new file mode 100644
index 0000000..5c465464
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/Tuple5.java
@@ -0,0 +1,55 @@
+/*
+ * 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.tuple;
+
+/**
+ * A tuple of 5 items.
+ */
+public class Tuple5<X> extends TupleBase<X> {
+    protected final X x1 ; 
+    protected final X x2 ;
+    protected final X x3 ;
+    protected final X x4 ;
+    protected final X x5 ;
+    
+    protected Tuple5(X x1, X x2, X x3, X x4, X x5) {
+        this.x1 = x1 ;
+        this.x2 = x2 ;
+        this.x3 = x3 ;
+        this.x4 = x4 ;
+        this.x5 = x5 ;
+    }
+    
+    @Override
+    public final X get(int i) {
+        switch (i) {
+            case 0: return x1 ;
+            case 1: return x2 ;
+            case 2: return x3 ;
+            case 3: return x4 ;
+            case 4: return x5 ;
+        }
+        throw new IndexOutOfBoundsException() ;
+    }
+
+    @Override
+    public final int len() {
+        return 5 ;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jena/blob/571e9755/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/Tuple6.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/Tuple6.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/Tuple6.java
new file mode 100644
index 0000000..c3faf3a
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/Tuple6.java
@@ -0,0 +1,58 @@
+/*
+ * 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.tuple;
+
+/**
+ * A tuple of 6 items.
+ */
+public class Tuple6<X> extends TupleBase<X> {
+    protected final X x1 ; 
+    protected final X x2 ;
+    protected final X x3 ;
+    protected final X x4 ;
+    protected final X x5 ;
+    protected final X x6 ;
+    
+    protected Tuple6(X x1, X x2, X x3, X x4, X x5, X x6) {
+        this.x1 = x1 ;
+        this.x2 = x2 ;
+        this.x3 = x3 ;
+        this.x4 = x4 ;
+        this.x5 = x5 ;
+        this.x6 = x6 ;
+    }
+    
+    @Override
+    public final X get(int i) {
+        switch (i) {
+            case 0: return x1 ;
+            case 1: return x2 ;
+            case 2: return x3 ;
+            case 3: return x4 ;
+            case 4: return x5 ;
+            case 5: return x6 ;
+        }
+        throw new IndexOutOfBoundsException() ;
+    }
+
+    @Override
+    public final int len() {
+        return 6 ;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jena/blob/571e9755/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/Tuple7.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/Tuple7.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/Tuple7.java
new file mode 100644
index 0000000..c13d60c
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/Tuple7.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.lib.tuple;
+
+/**
+ * A tuple of 7 items.
+ */
+public class Tuple7<X> extends TupleBase<X> {
+    protected final X x1 ; 
+    protected final X x2 ;
+    protected final X x3 ;
+    protected final X x4 ;
+    protected final X x5 ;
+    protected final X x6 ;
+    protected final X x7 ;
+    
+    protected Tuple7(X x1, X x2, X x3, X x4, X x5, X x6, X x7) {
+        this.x1 = x1 ;
+        this.x2 = x2 ;
+        this.x3 = x3 ;
+        this.x4 = x4 ;
+        this.x5 = x5 ;
+        this.x6 = x6 ;
+        this.x7 = x7 ;
+    }
+    
+    @Override
+    public final X get(int i) {
+        switch (i) {
+            case 0: return x1 ;
+            case 1: return x2 ;
+            case 2: return x3 ;
+            case 3: return x4 ;
+            case 4: return x5 ;
+            case 5: return x6 ;
+            case 6: return x7 ;
+        }
+        throw new IndexOutOfBoundsException() ;
+    }
+
+    @Override
+    public final int len() {
+        return 7 ;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jena/blob/571e9755/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/Tuple8.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/Tuple8.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/Tuple8.java
new file mode 100644
index 0000000..c233646
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/Tuple8.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.tuple;
+
+/**
+ * A tuple of 8 items.
+ */
+public class Tuple8<X> extends TupleBase<X> {
+    protected final X x1 ; 
+    protected final X x2 ;
+    protected final X x3 ;
+    protected final X x4 ;
+    protected final X x5 ;
+    protected final X x6 ;
+    protected final X x7 ;
+    protected final X x8 ;
+    
+    protected Tuple8(X x1, X x2, X x3, X x4, X x5, X x6, X x7, X x8) {
+        this.x1 = x1 ;
+        this.x2 = x2 ;
+        this.x3 = x3 ;
+        this.x4 = x4 ;
+        this.x5 = x5 ;
+        this.x6 = x6 ;
+        this.x7 = x7 ;
+        this.x8 = x8 ;
+    }
+    
+    @Override
+    public final X get(int i) {
+        switch (i) {
+            case 0: return x1 ;
+            case 1: return x2 ;
+            case 2: return x3 ;
+            case 3: return x4 ;
+            case 4: return x5 ;
+            case 5: return x6 ;
+            case 6: return x7 ;
+            case 7: return x8 ;
+        }
+        throw new IndexOutOfBoundsException() ;
+    }
+    
+   @Override
+    public final int len() {
+        return 8 ;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jena/blob/571e9755/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/TupleBase.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/TupleBase.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/TupleBase.java
new file mode 100644
index 0000000..9291137
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/TupleBase.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.lib.tuple;
+
+import java.util.Iterator ;
+import java.util.Objects ;
+
+abstract class TupleBase<X> implements Tuple<X> {
+    protected TupleBase() {}
+
+    /** Iterable */
+    @Override
+    public Iterator<X> iterator() {
+        return asList().iterator() ;
+    }
+    
+
+    @Override
+    public void copyInto(X[] array, int start, int length) {
+        for ( int i = 0 ; i < Math.min(length, len()) ; i++ )
+            array[i+start] = get(i) ;
+    }
+
+    @Override
+    public final
+    int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        for ( int i = 0 ; i < len() ; i++ )
+            result = prime * result + Objects.hashCode(get(i)) ;
+        return result;
+    }
+    
+    @Override
+    public final
+    boolean equals(Object obj) {
+        if ( this == obj )
+            return true;
+        if ( obj == null )
+            return false ;
+        if ( ! ( obj instanceof Tuple<?> ) ) 
+            return false ;
+        Tuple<?> other = (Tuple<?>)obj ;
+        if ( this.len() != other.len() )
+            return false ;
+        for ( int i = 0 ; i < this.len() ; i++ )
+            if ( ! Objects.equals(this.get(i), other.get(i)) ) 
+                return false ;
+        return true;
+    }
+    
+    @Override
+    public final String toString() {
+        return asList().toString() ;
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/jena/blob/571e9755/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/TupleFactory.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/TupleFactory.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/TupleFactory.java
new file mode 100644
index 0000000..04ca9c0
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/TupleFactory.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.lib.tuple;
+
+import java.util.List ;
+
+/** Tuple creation */
+public class TupleFactory {
+    
+    private TupleFactory() {}
+    
+    /** Create a Tuple */ 
+    @SafeVarargs
+    public static <X> Tuple<X> tuple(X...xs) {
+        switch(xs.length) {
+            case 0 : return create0() ;
+            case 1 : return create1(xs[0]) ;
+            case 2 : return create2(xs[0], xs[1]) ;
+            case 3 : return create3(xs[0], xs[1], xs[2]) ;
+            case 4 : return create4(xs[0], xs[1], xs[2], xs[3]) ;
+            case 5 : return create5(xs[0], xs[1], xs[2], xs[3], xs[4]) ;
+            case 6 : return create6(xs[0], xs[1], xs[2], xs[3], xs[4], xs[5]) ;
+            case 7 : return create7(xs[0], xs[1], xs[2], xs[3], xs[4], xs[5], xs[6]) ;
+            case 8 : return create8(xs[0], xs[1], xs[2], xs[3], xs[4], xs[5], xs[6], xs[7]) ;
+            default:
+                // No need to copy.
+                return asTuple(xs) ;
+        }
+    }
+    
+    /** Create a Tuple from an array */ 
+    public static <X> Tuple<X> create(X[] xs) {
+        switch(xs.length) {
+            case 0 : return create0() ;
+            case 1 : return create1(xs[0]) ;
+            case 2 : return create2(xs[0], xs[1]) ;
+            case 3 : return create3(xs[0], xs[1], xs[2]) ;
+            case 4 : return create4(xs[0], xs[1], xs[2], xs[3]) ;
+            case 5 : return create5(xs[0], xs[1], xs[2], xs[3], xs[4]) ;
+            case 6 : return create6(xs[0], xs[1], xs[2], xs[3], xs[4], xs[5]) ;
+            case 7 : return create7(xs[0], xs[1], xs[2], xs[3], xs[4], xs[5], xs[6]) ;
+            case 8 : return create8(xs[0], xs[1], xs[2], xs[3], xs[4], xs[5], xs[6], xs[7]) ;
+            default:
+                return TupleN.create(xs) ;
+        }
+    }
+
+    /** Treat an array as a Tuple.  The array must not be mutated */ 
+    public static <X> Tuple<X> asTuple(X[] xs) {
+        return TupleN.wrap(xs) ;
+    }
+    
+    /** Create a Tuple from a list */ 
+    public static <X> Tuple<X> create(List<X> xs) {
+        @SuppressWarnings("unchecked")
+        X[] xa = (X[])(new Object[xs.size()]) ;
+        return TupleFactory.tuple(xs.toArray(xa)) ;
+    }
+
+    /** Create a Tuple of length 0 */
+    public static <X> Tuple0<X> create0() {
+        return new Tuple0<>() ;
+    }
+    
+    /** Create a Tuple of length 1 */
+    public static <X> Tuple1<X> create1(X x1) {
+        return new Tuple1<>(x1) ;
+    }
+
+    /** Create a Tuple of length 2 */
+    public static <X> Tuple2<X> create2(X x1, X x2) {
+        return new Tuple2<>(x1, x2) ;
+    }
+
+    /** Create a Tuple of length 3 */
+    public static <X> Tuple3<X> create3(X x1, X x2, X x3) {
+        return new Tuple3<>(x1, x2, x3) ;
+    }
+
+    /** Create a Tuple of length 4 */
+    public static <X> Tuple4<X> create4(X x1, X x2, X x3, X x4) {
+        return new Tuple4<>(x1, x2, x3, x4) ;
+    }
+    
+    /** Create a Tuple of length 5 */
+    public static <X> Tuple5<X> create5(X x1, X x2, X x3, X x4, X x5) {
+        return new Tuple5<>(x1, x2, x3, x4, x5) ;
+    }
+
+    /** Create a Tuple of length 6 */
+    public static <X> Tuple6<X> create6(X x1, X x2, X x3, X x4, X x5, X x6) {
+        return new Tuple6<>(x1, x2, x3, x4, x5, x6) ;
+    }
+
+    /** Create a Tuple of length 7 */
+    public static <X> Tuple7<X> create7(X x1, X x2, X x3, X x4, X x5, X x6, X x7) {
+        return new Tuple7<>(x1, x2, x3, x4, x5, x6, x7) ;
+    }
+
+    /** Create a Tuple of length 8 */
+    public static <X> Tuple8<X> create8(X x1, X x2, X x3, X x4, X x5, X x6, X x7, X x8) {
+        return new Tuple8<>(x1, x2, x3, x4, x5, x6, x7, x8) ;
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/571e9755/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/TupleList.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/TupleList.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/TupleList.java
new file mode 100644
index 0000000..9e166cd
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/TupleList.java
@@ -0,0 +1,43 @@
+/*
+ * 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.tuple;
+
+import java.util.AbstractList ;
+import java.util.List ;
+import java.util.RandomAccess ;
+
+/** Wrap a {@link Tuple} as an immutable Java collection {@link List} */
+public class TupleList<X> extends AbstractList<X> implements RandomAccess {
+
+    private final Tuple<X> tuple;
+
+    public TupleList(Tuple<X> tuple) {
+        this.tuple = tuple ;
+    }
+    
+    @Override
+    public X get(int index) {
+        return tuple.get(index) ;
+    }
+
+    @Override
+    public int size() {
+        return tuple.len() ;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jena/blob/571e9755/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/TupleMap.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/TupleMap.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/TupleMap.java
new file mode 100644
index 0000000..2a220ed
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/TupleMap.java
@@ -0,0 +1,404 @@
+/*
+ * 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.tuple;
+
+import static java.lang.String.format;
+
+import java.util.ArrayList ;
+import java.util.Arrays;
+import java.util.Collections ;
+import java.util.List;
+
+import org.apache.jena.atlas.AtlasException;
+import org.apache.jena.atlas.lib.ListUtils ;
+import org.apache.jena.atlas.lib.StrUtils ;
+
+/**
+ * General descriptor of a reordering (mapping) of slots in tuples
+ * <p>
+ * Naming: map is convert to the reordered form, unmap is get back.
+ * <p>
+ * 
+ * <pre>
+ * map(tuple) is equivalent to
+ *   create tuple(getSlotIdx(0) , getSlotIdx(1), ... getSlotIdx(n-1)) ;    
+ * </pre>
+ * 
+ * A {@code TupleMap} holds twp maps: the "getTransform" and the "putTransform".
+ * The "getTransform" is here to get the item from in the mapper Tuple.
+ * In the case is {@code SPO->POS} this is 
+ * {@code 0<-1, 1<-2, 2<-0} 
+ * and the "putTransform" is where to place the items: {@code 0->2, 1->0, 2->1}.
+ */
+final
+public class TupleMap {
+    /*
+     * Naming.  getTransform (from src), putTransform(into dst)
+     * And these are mutual inverses: unmap process is to swap use of getTransform and putTransform
+     * See getSlotIdx and putSlotIdx
+     * 
+     * These are then equivalent
+     * 
+     * int j = getTransform[i] ; elts[i] = src.get(j) ;
+     * int j = putTransform[i] ; elts[j] = src.get(i) ;
+     * 
+     * The code tends to use this style (getTransform)
+     *     int j = getTransform[i] ;
+     *     dst[i] = src[j] ;
+     * 
+     * See apply and applyArray
+     * 
+     * Warning : map and unmap here do not correspond to fetch and map in
+     * ColumnMap. That has confusing/inconsistent usage.
+     */
+    
+    // SPO->POS: get:{0<-1, 1<-2, 2<-0} put:{0->2, 1->0, 2->1}
+    
+    // Map by where to fetch from source.
+    // For SPO -> POS, get from 1 to go into 0 so (0->, 1->0 2->   
+    // POS->SPO, is (0->1, 1->2, 2->0)
+    // i.e. the location to fetch the mapped element from.
+    private final int[]  getTransform ;
+    
+    // Map by insertion into destination.
+    // So SPO->POS is (0->2, 1->0, 2->1)
+    // i.e. the location of the element after mapping.
+    private final int[]  putTransform ; // putTransform, insertOrder
+
+    private final int len ;
+    private final String label;
+
+    /**
+     * Construct a mapping that maps the input (one col, one char) to the output
+     */
+    public static TupleMap create(String input, String output) {
+        return new TupleMap(input + "->" + output, compileMapping(input, output));
+    }
+
+    /**
+     * Construct a mapping, with label, that maps the input (one col, one char) to the output
+     */
+    public static TupleMap create(String label, String input, String output) {
+        return new TupleMap(label, compileMapping(input, output));
+    }
+
+    /**
+     * Construct a mapping that maps the input to the output
+     */
+    public static <T> TupleMap create(String label, List<T> input, List<T> output) {
+        return new TupleMap(label, compileMapping(input, output));
+    }
+
+    /**
+     * Construct a mapping that maps the input to the output
+     */
+    public static <T> TupleMap create(String label, T[] input, T[] output) {
+        return new TupleMap(label, compileMapping(input, output));
+    }
+    
+    /**
+     * Construct a mapping - the elements are the mappings of a tuple
+     * originally in the order 0,1,2,... so SPO->POS is 2,0,1 (SPO->POS so S->2,
+     * P->0, O->1) and not 1,2,0 (which is the extraction mapping). The label is
+     * just a label and is not interpretted here.
+     */
+    private TupleMap(String label, int... elements) {
+        this.len = elements.length ; 
+        this.label = label;
+
+        this.putTransform = new int[elements.length];
+        Arrays.fill(putTransform, -1);
+
+        this.getTransform = new int[elements.length];
+        Arrays.fill(getTransform, -1);
+
+        for ( int i = 0 ; i < elements.length ; i++ ) {
+            int x = elements[i];
+            if ( x < 0 || x >= elements.length )
+                throw new IllegalArgumentException("Out of range: " + x);
+            // Checking
+            if ( putTransform[i] != -1 || getTransform[x] != -1 )
+                throw new IllegalArgumentException("Inconsistent: " + ListUtils.str(elements));
+
+            putTransform[i] = x;    // The elements are the putTransform.
+            getTransform[x] = i;
+        }
+    }
+
+    /** Length of mapping */
+    public int length() {
+        return len;
+    }
+
+    /** 
+     * Get the index of the i'th slot as it appears from a mapping : for
+     * SPO->POS : 0'th slot is P so 0 returns 1 (the location in the tuple before mapping)
+     * The 0'th mapped slot is {@code tuple.get(tupleMap.getSlotIdx(0))}.
+     */
+    public int getSlotIdx(int idx) {
+        return getTransform[idx];
+    }
+
+    /**
+     * Get the index of the i'th slot as it appears after unmapping : SPO->POS :
+     * 0'th slot is S from POS so 0 returns 2
+     */
+    public int putSlotIdx(int idx) {
+        return putTransform[idx]; 
+    }
+    
+    /** 
+     * Get the index of the i'th slot as it appears from a mapping : for
+     * SPO->POS : 0'th slot is P so 0 returns 1 (the location in the tuple before mapping)
+     * Equivalent to {@link #getSlotIdx}.
+     * The 0'th mapped slot is {@code tuple.get(tupleMap.mapIdx(0))}.
+     */
+    public int mapIdx(int idx) {
+        return getSlotIdx(idx) ;
+    }
+
+    /**
+     * Get the index of the i'th slot as it appears after unmapping : SPO->POS :
+     * 0'th slot is S from POS so 0 returns 2
+     * Equivalent to {@link #putSlotIdx}.
+     * The 0'th unmapped slot is {@code tuple.get(tupleMap.unmapIdx(0))}.
+     */
+    public int unmapIdx(int idx) {
+        return putSlotIdx(idx) ; 
+    }
+    
+    /** Apply to an <em>unmapped</em> tuple to get a tuple with the tuple mapping applied.
+     */
+    public <T> Tuple<T> map(Tuple<T> src) {
+        return apply(src, getTransform) ;
+    }
+
+    /** Apply to a <em>mapped</em> tuple to get a tuple with the tuple mapping reverse-applied. */
+    public <T> Tuple<T> unmap(Tuple<T> src) {
+        return apply(src, putTransform) ;
+    }
+
+    // Does not work (java8) - assigning the return causes a runtime case exception 
+//    /** Apply to an <em>unmapped</em> tuple to get a tuple with the tuple mapping applied */
+//    public <T> T[] map(T[] src) {
+//        @SuppressWarnings("unchecked")
+//        T[]dst = (T[])new Object[src.length] ;
+//        applyArray(src, dst, getTransform) ;
+//        return dst ;
+//    }
+
+    /** Apply to an <em>unmapped</em> tuple to get a tuple with the tuple mapping applied.
+     * Returns the destination array.
+     */
+    public <T> T[] map(T[] src, T[] dst) {
+        if ( src == dst )
+            throw new IllegalArgumentException("Source and destination are the same array") ;
+        applyArray(src, dst, getTransform) ;
+        return dst ;
+    }
+
+    // Does not work (java8) - assigning the return causes a runtime case exception 
+//    /** Apply to a <em>mapped</em> tuple to get a tuple with the tuple mapping reverse-applied */
+//    public <T> T[] unmap(T[] src) {
+//        @SuppressWarnings("unchecked")
+//        T[]dst = (T[])new Object[src.length] ;
+//        applyArray(src, dst, putTransform) ;
+//        return dst ;
+//    }
+
+    /** Apply to a <em>mapped</em> tuple to get a tuple with the tuple mapping reverse-applied.
+     * Returns the destination array.
+     */
+    public <T> T[] unmap(T[] src, T[] dst) {
+        if ( src == dst )
+            throw new IllegalArgumentException("Source and destination are the same array") ;
+        applyArray(src, dst, putTransform) ;
+        return dst ;
+    }
+
+    /** Apply an index transformation
+     */
+    private static <T> Tuple<T> apply(Tuple<T> src, int[] getTransform) {
+        if ( src.len() != getTransform.length )
+            throw new IllegalArgumentException("Lengths do not match: Tuple:"+src.len()+"; transform:"+getTransform.length) ;
+        // Fast-track 1,2,3,4 ?
+//        // All this to avoid the temp array.
+//        switch(src.len()) {
+//            case 0: return src ;
+//            case 1: return src ;
+//            case 2: {
+//                T x1 = src.get(getTransform[0]);
+//                T x2 = src.get(getTransform[1]);
+//                return TupleFactory.create2(x1, x2) ;
+//            }
+//            case 3: {
+//                T x1 = src.get(getTransform[0]);
+//                T x2 = src.get(getTransform[1]);
+//                T x3 = src.get(getTransform[2]);
+//                return TupleFactory.create3(x1, x2, x3) ;
+//            }
+//            case 4: {
+//                T x1 = src.get(getTransform[0]);
+//                T x2 = src.get(getTransform[1]);
+//                T x3 = src.get(getTransform[2]);
+//                T x4 = src.get(getTransform[3]);
+//                return TupleFactory.create4(x1, x2, x3, x4) ;
+//            }
+//        }
+        
+        @SuppressWarnings("unchecked")
+        T[] elts = (T[])new Object[src.len()] ;
+        
+        for ( int i = 0 ; i < src.len() ; i++ ) {
+            int j = getTransform[i] ;
+            elts[i] = src.get(j) ;
+        }
+        return TupleFactory.tuple(elts) ;
+    }
+    
+    /** Apply an index transformation */
+    private <T> void applyArray(T[] src, T[] dst, int[] transform) {
+        for ( int i = 0 ; i < src.length ; i++ ) {
+            int j = transform[i] ;
+            dst[i] = src[j] ;
+        }
+    }
+    
+    /**
+     * Apply to an <em>unmapped</em> tuple to get the i'th slot after mapping :
+     * SPO->POS : 0'th slot is P from SPO
+     */
+    public <T> T mapSlot(int idx, Tuple<T> tuple) {
+        checkLength(tuple) ;
+        idx = getSlotIdx(idx) ;
+        return tuple.get(idx) ;
+    }
+
+    /**
+     * Apply to a <em>mapped</em> tuple to get the i'th slot as it appears after
+     * mapping : SPO->POS : 0'th slot is S from POS
+     */
+    public <T> T unmapSlot(int idx, Tuple<T> tuple) {
+        checkLength(tuple) ;
+        idx = putSlotIdx(idx) ;
+        return tuple.get(idx);
+    }
+
+    /**
+     * Apply to an <em>unmapped</em> tuple to get the i'th slot after mapping :
+     * SPO->POS : 0'th slot is P from SPO
+     */
+    public <T> T mapSlot(int idx, T[] tuple) {
+        return tuple[getSlotIdx(idx)] ;
+    }
+
+    /**
+     * Apply to a <em>mapped</em> tuple to get the i'th slot as it appears after
+     * mapping : SPO->POS : 0'th slot is S from POS
+     */
+    public <T> T unmapSlot(int idx, T[] tuple) {
+        return tuple[putSlotIdx(idx)] ;
+    }
+
+    /** Compile a mapping encoded as single charcaters e.g. "SPO", "POS" */
+    private static int[] compileMapping(String domain, String range) {
+        List<Character> input = StrUtils.toCharList(domain);
+        List<Character> output = StrUtils.toCharList(range);
+        return compileMapping(input, output);
+    }
+
+    /**
+     * Compile a mapping, encoded two list, the domain and range of the mapping
+     * function
+     */
+    private static <T> int[] compileMapping(T[] domain, T[] range) {
+        return compileMapping(Arrays.asList(domain), Arrays.asList(range));
+    }
+
+    /** Compile a mapping */
+    private static <T> int[] compileMapping(List<T> domain, List<T> range) {
+        if ( domain.size() != range.size() )
+            throw new AtlasException("Bad mapping: lengths not the same: " + domain + " -> " + range);
+
+        int[] cols = new int[domain.size()];
+        boolean[] mapped = new boolean[domain.size()];
+        // Arrays.fill(mapped, false) ;
+
+        for ( int i = 0 ; i < domain.size() ; i++ ) {
+            T input = domain.get(i);
+            int j = range.indexOf(input);
+            if ( j < 0 )
+                throw new AtlasException("Bad mapping: missing mapping: " + domain + " -> " + range);
+            if ( mapped[j] )
+                throw new AtlasException("Bad mapping: duplicate: " + domain + " -> " + range);
+            cols[i] = j;
+            mapped[j] = true;
+        }
+        return cols;
+    }
+
+    /** Access to the getTransform */
+    /*package-testing*/ List<Integer> transformGet() {
+        return arrayToList(getTransform) ;
+    }
+
+    /** Access to the putTransform */
+    /*package-testing*/ List<Integer> transformPut() {
+        return arrayToList(putTransform) ;
+    }
+
+    private List<Integer> arrayToList(int[] array) {
+        List<Integer> list = new ArrayList<>(array.length) ;
+        for ( int x : array ) 
+            list.add(x) ;
+        return  Collections.unmodifiableList(list) ;
+    }
+
+    @Override
+    public String toString() {
+        // return label ;
+        return format("%s:%s:%s", label, mapStr(putTransform, "->"), mapStr(getTransform, "<-"));
+    }
+
+    private Object mapStr(int[] map, String arrow) {
+        StringBuilder buff = new StringBuilder();
+        String sep = "{";
+
+        for ( int i = 0 ; i < map.length ; i++ ) {
+            buff.append(sep);
+            sep = ", ";
+            buff.append(format("%d%s%d", i, arrow, map[i]));
+        }
+        buff.append("}");
+
+        return buff.toString();
+    }
+
+    public String getLabel() {
+        return label;
+    }
+
+    private static boolean CHECKING = true ; 
+    private final void checkLength(Tuple<?> tuple) {
+        if ( CHECKING ) {
+            if ( tuple.len() != length() )
+                throw new IllegalArgumentException("Tuple length "+tuple.len()+": not of length "+length()) ;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/571e9755/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/TupleN.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/TupleN.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/TupleN.java
new file mode 100644
index 0000000..58e455e
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/TupleN.java
@@ -0,0 +1,55 @@
+/*
+ * 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.tuple;
+
+import java.util.Arrays ;
+
+/** A Tuple of N items */
+public class TupleN<X> extends TupleBase<X> {
+    private final X[] tuple ;
+
+    /** Create a TupleN - safely copy the input */ 
+    @SafeVarargs
+    public static <X> TupleN<X> create(X... xs) {
+        X[] xs2 = Arrays.copyOf(xs, xs.length) ;
+        return new TupleN<>(xs2) ;
+    }
+    
+    // When the array will not be modified.
+    /*package*/ static <X> TupleN<X> wrap(X[] xs) {
+        return new TupleN<>(xs) ;
+    }
+    
+    /** Put a TupleN wrapper around a X[].
+     * The statics {@link #create} and {@link wrap} determine whether to copy or not.
+     */
+    private TupleN(X[] xs) {
+        tuple = xs ;
+    }
+
+    @Override
+    public final X get(int i) {
+        return tuple[i] ;
+    }
+
+    @Override
+    public int len() {
+        return tuple.length;
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/571e9755/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/package-info.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/package-info.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/package-info.java
new file mode 100644
index 0000000..4028b2d
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/tuple/package-info.java
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+/**
+ * Tuples.
+ * <p>
+ * A Tuple is a fixed length sequence of the objects of the same type. They are
+ * immutable and provide value-based {@code hashCode} and {@code .equals()}.
+ * <p>
+ * There are space-saving implementations for tuples of length 0 to small N and
+ * a general purpose implementation.
+ * <ul>
+ * <li>{@code Tuple} -- the interface 
+ * <li>{@code TupleFactory} -- creates {@code Tuples} 
+ * <li>{@code TupleMap} -- provides transformations of order of elements
+ * </ul>
+ */
+
+package org.apache.jena.atlas.lib.tuple;

http://git-wip-us.apache.org/repos/asf/jena/blob/571e9755/jena-base/src/test/java/org/apache/jena/atlas/TC_Atlas.java
----------------------------------------------------------------------
diff --git a/jena-base/src/test/java/org/apache/jena/atlas/TC_Atlas.java b/jena-base/src/test/java/org/apache/jena/atlas/TC_Atlas.java
index cbe2b33..1f3ddc5 100644
--- a/jena-base/src/test/java/org/apache/jena/atlas/TC_Atlas.java
+++ b/jena-base/src/test/java/org/apache/jena/atlas/TC_Atlas.java
@@ -22,6 +22,7 @@ import org.apache.jena.atlas.io.TS_IO ;
 import org.apache.jena.atlas.iterator.TS_Iterator ;
 import org.apache.jena.atlas.lib.TS_Lib ;
 import org.apache.jena.atlas.lib.persistent.TS_Persistent;
+import org.apache.jena.atlas.lib.tuple.TS_Tuple ;
 import org.junit.runner.RunWith ;
 import org.junit.runners.Suite ;
 
@@ -29,6 +30,7 @@ import org.junit.runners.Suite ;
 @Suite.SuiteClasses( {
     // Library
       TS_Lib.class
+    , TS_Tuple.class
     , TS_Iterator.class
     , TS_IO.class
     , TS_Persistent.class

http://git-wip-us.apache.org/repos/asf/jena/blob/571e9755/jena-base/src/test/java/org/apache/jena/atlas/lib/TestFileOps.java
----------------------------------------------------------------------
diff --git a/jena-base/src/test/java/org/apache/jena/atlas/lib/TestFileOps.java b/jena-base/src/test/java/org/apache/jena/atlas/lib/TestFileOps.java
index 92538f7..272d169 100644
--- a/jena-base/src/test/java/org/apache/jena/atlas/lib/TestFileOps.java
+++ b/jena-base/src/test/java/org/apache/jena/atlas/lib/TestFileOps.java
@@ -20,7 +20,7 @@ package org.apache.jena.atlas.lib;
 
 import org.apache.jena.atlas.junit.BaseTest ;
 import org.apache.jena.atlas.lib.FileOps ;
-import org.apache.jena.atlas.lib.Tuple ;
+import org.apache.jena.atlas.lib.tuple.Tuple ;
 import org.junit.Test ;
 
 public class TestFileOps extends BaseTest

http://git-wip-us.apache.org/repos/asf/jena/blob/571e9755/jena-base/src/test/java/org/apache/jena/atlas/lib/tuple/TS_Tuple.java
----------------------------------------------------------------------
diff --git a/jena-base/src/test/java/org/apache/jena/atlas/lib/tuple/TS_Tuple.java b/jena-base/src/test/java/org/apache/jena/atlas/lib/tuple/TS_Tuple.java
new file mode 100644
index 0000000..30ba125
--- /dev/null
+++ b/jena-base/src/test/java/org/apache/jena/atlas/lib/tuple/TS_Tuple.java
@@ -0,0 +1,32 @@
+/*
+ * 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.tuple;
+
+import org.junit.runner.RunWith ;
+import org.junit.runners.Suite ;
+
+@RunWith(Suite.class)
+@Suite.SuiteClasses( {
+    TestTuple.class
+    , TestTupleMap.class
+})
+
+public class TS_Tuple {
+}
+

http://git-wip-us.apache.org/repos/asf/jena/blob/571e9755/jena-base/src/test/java/org/apache/jena/atlas/lib/tuple/TestTuple.java
----------------------------------------------------------------------
diff --git a/jena-base/src/test/java/org/apache/jena/atlas/lib/tuple/TestTuple.java b/jena-base/src/test/java/org/apache/jena/atlas/lib/tuple/TestTuple.java
new file mode 100644
index 0000000..4c31746
--- /dev/null
+++ b/jena-base/src/test/java/org/apache/jena/atlas/lib/tuple/TestTuple.java
@@ -0,0 +1,201 @@
+/*
+ * 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.tuple;
+
+import static org.junit.Assert.assertEquals ;
+import static org.junit.Assert.assertNotEquals ;
+import static org.junit.Assert.fail ;
+
+import java.util.ArrayList ;
+import java.util.List ;
+
+import org.junit.Test ;
+
+public class TestTuple {
+    @Test public void tuple_0() {
+        Tuple<Integer> tuple = TupleFactory.create0() ;
+        assertEquals(0, tuple.len()) ;
+        check(tuple) ;
+    }
+
+    @Test public void tuple_1() {
+        Tuple<Integer> tuple = TupleFactory.create1(9) ;
+        assertEquals(1, tuple.len()) ;
+        check(tuple) ;
+    }
+
+    @Test public void tuple_2() {
+        Tuple<Integer> tuple = TupleFactory.create2(9,8) ;
+        assertEquals(2, tuple.len()) ;
+        check(tuple) ;
+    }
+
+    @Test public void tuple_3() {
+        Tuple<Integer> tuple = TupleFactory.create3(9,8,7) ;
+        assertEquals(3, tuple.len()) ;
+        check(tuple) ;
+    }
+
+    @Test public void tuple_4() {
+        Tuple<Integer> tuple = TupleFactory.create4(9,8,7,6) ;
+        assertEquals(4, tuple.len()) ;
+        check(tuple) ;
+    }
+
+    @Test public void tuple_5() {
+        Tuple<Integer> tuple = TupleFactory.create5(9,8,7,6,5) ;
+        assertEquals(5, tuple.len()) ;
+        check(tuple) ;
+    }
+
+    @Test public void tuple_6() {
+        Tuple<Integer> tuple = TupleFactory.create6(9,8,7,6,5,4) ;
+        assertEquals(6, tuple.len()) ;
+        check(tuple) ;
+    }
+
+    @Test public void tuple_7() {
+        Tuple<Integer> tuple = TupleFactory.create7(9,8,7,6,5,4,3) ;
+        assertEquals(7, tuple.len()) ;
+        check(tuple) ;
+    }
+
+    @Test public void tuple_8() {
+        Tuple<Integer> tuple = TupleFactory.create8(9,8,7,6,5,4,3,2) ;
+        assertEquals(8, tuple.len()) ;
+        check(tuple) ;
+    }
+
+    @Test public void tuple_N0() {
+        Tuple<Integer> tuple = TupleFactory.tuple() ;
+        assertEquals(0, tuple.len()) ;
+        assertEquals(Tuple0.class, tuple.getClass()) ;
+        check(tuple) ;
+    }
+
+    @Test public void tuple_N1() {
+        Tuple<Integer> tuple = TupleFactory.tuple(9) ;
+        assertEquals(1, tuple.len()) ;
+        assertEquals(Tuple1.class, tuple.getClass()) ;
+        check(tuple) ;
+    }
+
+    @Test public void tuple_N2() {
+        Tuple<Integer> tuple = TupleFactory.tuple(9,8) ;
+        assertEquals(2, tuple.len()) ;
+        assertEquals(Tuple2.class, tuple.getClass()) ;
+        check(tuple) ;
+    }
+
+    @Test public void tuple_N3() {
+        Tuple<Integer> tuple = TupleFactory.tuple(9,8,7) ;
+        assertEquals(3, tuple.len()) ;
+        assertEquals(Tuple3.class, tuple.getClass()) ;
+        check(tuple) ;
+    }
+
+    @Test public void tuple_N4() {
+        Tuple<Integer> tuple = TupleFactory.tuple(9,8,7,6) ;
+        assertEquals(4, tuple.len()) ;
+        assertEquals(Tuple4.class, tuple.getClass()) ;
+        check(tuple) ;
+    }
+
+    @Test public void tuple_N5() {
+        Tuple<Integer> tuple = TupleFactory.tuple(9,8,7,6,5) ;
+        assertEquals(5, tuple.len()) ;
+        assertEquals(Tuple5.class, tuple.getClass()) ;
+        check(tuple) ;
+    }
+
+    @Test public void tuple_N6() {
+        Tuple<Integer> tuple = TupleFactory.tuple(9,8,7,6,5,4) ;
+        assertEquals(6, tuple.len()) ;
+        assertEquals(Tuple6.class, tuple.getClass()) ;
+        check(tuple) ;
+    }
+
+    @Test public void tuple_N7() {
+        Tuple<Integer> tuple = TupleFactory.tuple(9,8,7,6,5,4,3) ;
+        assertEquals(7, tuple.len()) ;
+        assertEquals(Tuple7.class, tuple.getClass()) ;
+        check(tuple) ;
+    }
+
+    @Test public void tuple_N8() {
+        Tuple<Integer> tuple = TupleFactory.tuple(9,8,7,6,5,4,3,2) ;
+        assertEquals(8, tuple.len()) ;
+        assertEquals(Tuple8.class, tuple.getClass()) ;
+        check(tuple) ;
+    }
+
+    @Test public void tuple_N() {
+        Tuple<Integer> tuple = TupleFactory.tuple(9,8,7,6,5,4,3,2,1,0) ;
+        assertEquals(10, tuple.len()) ;
+        assertEquals(TupleN.class, tuple.getClass()) ;
+        check(tuple) ;
+    }
+
+    @Test public void tuple_equals_1() {
+        Tuple<Integer> tuple1 = TupleFactory.tuple(9,8,7) ;
+        Tuple<Integer> tuple2 = TupleN.create(9,8,7) ;
+        assertEquals(tuple1.hashCode(), tuple2.hashCode()) ;
+        assertEquals(tuple1, tuple2) ;
+    }
+
+    @Test public void tuple_not_equals_1() {
+        Tuple<Integer> tuple1 = TupleFactory.tuple(9,8,7) ;
+        Tuple<Integer> tuple2 = TupleFactory.tuple(7,8,9) ;
+        assertNotEquals(tuple1.hashCode(), tuple2.hashCode()) ;
+        assertNotEquals(tuple1, tuple2) ;
+    }
+
+    @Test public void tuple_not_equals_2() {
+        Tuple<Integer> tuple1 = TupleFactory.tuple(9,8,7) ;
+        Tuple<Integer> tuple2 = TupleFactory.tuple(9,8) ;
+        assertNotEquals(tuple1.hashCode(), tuple2.hashCode()) ;
+        assertNotEquals(tuple1, tuple2) ;
+    }
+
+    private void check(Tuple<Integer> tuple) {
+        int val = 9 ;
+        for ( int i = 0 ; i < tuple.len() ; i++ ) {
+            assertEquals(val-i, tuple.get(i).intValue()) ; 
+        }
+        List<Integer> list = tuple.asList() ;
+        for ( int i = 0 ; i < tuple.len() ; i++ ) {
+            assertEquals(val-i, list.get(i).intValue()) ; 
+        }
+        try { tuple.get(-1) ; fail("Index -1 did not throw an exception") ; }
+        catch(IndexOutOfBoundsException ex) {}
+        try { tuple.get(tuple.len()) ; fail("Index len() did not throw an exception") ; }
+        catch(IndexOutOfBoundsException ex) {}
+
+        // Other constructors
+        List<Integer> list2 = new ArrayList<>(list) ;
+        Tuple<Integer> tuple2 = TupleFactory.create(list2) ;
+        assertEquals(tuple.hashCode(), tuple2.hashCode()) ;
+        assertEquals(tuple, tuple2) ;
+
+        // Other constructors
+        List<Integer> list3 = new ArrayList<>(list) ;
+        Tuple<Integer> tuple3 = TupleFactory.tuple(list3.toArray(new Integer[0])) ;
+        assertEquals(tuple, tuple3) ;
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/571e9755/jena-base/src/test/java/org/apache/jena/atlas/lib/tuple/TestTupleMap.java
----------------------------------------------------------------------
diff --git a/jena-base/src/test/java/org/apache/jena/atlas/lib/tuple/TestTupleMap.java b/jena-base/src/test/java/org/apache/jena/atlas/lib/tuple/TestTupleMap.java
new file mode 100644
index 0000000..75e1a05
--- /dev/null
+++ b/jena-base/src/test/java/org/apache/jena/atlas/lib/tuple/TestTupleMap.java
@@ -0,0 +1,186 @@
+/*
+ * 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.tuple;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+
+import java.util.Arrays ;
+import java.util.List ;
+
+import org.apache.jena.atlas.lib.tuple.Tuple ;
+import org.apache.jena.atlas.lib.tuple.TupleFactory ;
+import org.apache.jena.atlas.lib.tuple.TupleMap ;
+import org.junit.Test;
+
+public class TestTupleMap {
+    // Check coverage
+    
+    @Test
+    public void map_tuple_01() {
+        TupleMap tmap = TupleMap.create("SPO", "POS");
+        Tuple<String> tuple = TupleFactory.tuple("S", "P", "O");
+        Tuple<String> tuple2 = tmap.map(tuple);
+        assertEquals(tuple2.get(0), "P");
+        assertEquals(tuple2.get(1), "O");
+        assertEquals(tuple2.get(2), "S");
+
+        Tuple<String> tuple3 = tmap.unmap(tuple2);
+        assertEquals(tuple, tuple3);
+    }
+
+
+    @Test
+    public void map_tuple_02() {
+        TupleMap x = TupleMap.create("SPO", "POS");
+        Tuple<String> tuple = TupleFactory.tuple("S", "P", "O");
+        Tuple<String> mapped = x.map(tuple);
+        Tuple<String> expected = TupleFactory.tuple("P", "O", "S");
+        assertEquals(expected, mapped);
+    }
+
+    @Test
+    public void map_tuple_03() {
+        TupleMap tmap = TupleMap.create("GSPO", "OSPG");
+        Tuple<String> tuple = TupleFactory.tuple("G", "S", "P", "O");
+        Tuple<String> mapped = tmap.map(tuple);
+        Tuple<String> expected = TupleFactory.tuple("O", "S", "P", "G");
+        assertEquals(expected, mapped);
+        Tuple<String> unmapped = tmap.unmap(mapped);
+        assertEquals(TupleFactory.tuple("G", "S", "P", "O"), unmapped);
+    }
+
+    @Test
+    public void map_tuple_04() {
+        String[] x = {"G", "S", "P", "O"};
+        String[] y = {"O", "S", "P", "G"};
+
+        TupleMap tmap = TupleMap.create("Test", x, y);
+        Tuple<String> tuple = TupleFactory.tuple(x);
+        Tuple<String> mapped = tmap.map(tuple);
+
+        Tuple<String> expected = TupleFactory.tuple(y);
+        assertEquals(expected, mapped);
+        Tuple<String> unmapped = tmap.unmap(mapped);
+        assertEquals(TupleFactory.tuple(x), unmapped);
+    }
+
+    @Test
+    public void compile1() {
+        TupleMap map = TupleMap.create("SPO", "POS");
+        // SPO -> POS 
+        // col 0 goes to col 2
+        // col 1 goes to col 0
+        // col 2 goes to col 1
+        Integer[] expectedPut = {2, 0, 1};
+        assertEquals(Arrays.asList(expectedPut), map.transformPut());
+        Integer[] expectedGet = {1, 2, 0};
+        assertEquals(Arrays.asList(expectedGet), map.transformGet());
+    }
+
+    @Test
+    public void compile2() {
+        TupleMap map = TupleMap.create("SPOG", "GOPS");
+        Integer[] expected = {3, 2, 1, 0};
+        assertEquals(Arrays.asList(expected), map.transformPut());
+    }
+
+    @Test
+    public void map_slot_01() {
+        TupleMap tmap = TupleMap.create("SPO", "POS");
+        Tuple<String> tuple = TupleFactory.tuple("S", "P", "O");
+        assertEquals("P", tmap.mapSlot(0, tuple));
+        assertEquals("O", tmap.mapSlot(1, tuple));
+        assertEquals("S", tmap.mapSlot(2, tuple));
+
+        Tuple<String> tuple1 = tmap.map(tuple);
+        assertEquals("S", tmap.unmapSlot(0, tuple1));
+        assertEquals("P", tmap.unmapSlot(1, tuple1));
+        assertEquals("O", tmap.unmapSlot(2, tuple1));
+    }
+
+    @Test
+    public void map_slot_02() {
+        TupleMap tmap = TupleMap.create("SPO", "POS");
+        Tuple<String> tuple = TupleFactory.tuple("S", "P", "O");
+        Tuple<String> tuple1 = TupleFactory.tuple
+            (tuple.get(tmap.mapIdx(0))
+            ,tuple.get(tmap.mapIdx(1))
+            ,tuple.get(tmap.mapIdx(2)) ) ;
+        Tuple<String> tuple2 = tmap.map(tuple);
+        assertEquals(tuple2, tuple1) ;
+    }        
+
+    @Test
+    public void map_slot_03() {
+        TupleMap tmap = TupleMap.create("POS", "SPO");
+        Tuple<String> tuple = TupleFactory.tuple("P", "O", "S");
+        Tuple<String> tuple1 = TupleFactory.tuple
+            (tuple.get(tmap.unmapIdx(0))
+            ,tuple.get(tmap.unmapIdx(1))
+            ,tuple.get(tmap.unmapIdx(2)) ) ;
+        Tuple<String> tuple2 = tmap.unmap(tuple);
+        assertEquals(tuple2, tuple1) ;
+    }        
+
+    @Test
+    public void map_transforms() {
+        TupleMap x = TupleMap.create("SPO","POS"); 
+        List<Integer> listGet = x.transformPut() ;
+        List<Integer> listGetExpected = Arrays.asList(2, 0, 1) ;
+        assertEquals(listGetExpected, listGet) ;
+
+        List<Integer> listPut = x.transformGet() ;
+        List<Integer> listPutExpected = Arrays.asList(1, 2, 0) ;
+        assertEquals(listGetExpected, listGet) ;
+        
+    }
+    
+    @Test
+    public void map_array_01() {
+        TupleMap x = TupleMap.create("SPO","POS"); 
+        Tuple<Integer> t = TupleFactory.tuple(2, 0, 1);
+        Tuple<Integer> t1 = x.map(t);
+
+        String[] array = {"X", "Y", "Z"};
+        
+        assertEquals("Y", x.mapSlot(0, array)); // The 0th item after mapping is the "1"
+        assertEquals("Z", x.mapSlot(1, array));
+        assertEquals("X", x.mapSlot(2, array));
+        
+        String[] array2 = new String[array.length] ;
+        x.map(array, array2) ;
+        assertArrayEquals(new String[] {"Y", "Z", "X"}, array2) ;
+        String[] array3 = new String[array.length] ;
+        x.unmap(array2, array3) ;
+        
+        assertArrayEquals(array, array3) ;
+    }
+    
+    @Test
+    public void map_array_02() {
+        // (0,1,2) -> (2,0,1) S->2 etc
+        // so (0,1,2) <- (1,2,0)
+        TupleMap x = TupleMap.create("SPO","POS");
+        String[] array = {"Y", "Z", "X"};
+        assertEquals("X", x.unmapSlot(0, array)); // The index 0 comes from position 3.
+        assertEquals("Y", x.unmapSlot(1, array));
+        assertEquals("Z", x.unmapSlot(2, array));
+    }
+}


Mime
View raw message