You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jena.apache.org by an...@apache.org on 2015/04/28 23:03:31 UTC
[4/9] jena git commit: Import of lib, io,
logging and iterator packages
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/SetUtils.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/SetUtils.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/SetUtils.java
new file mode 100644
index 0000000..f4e561d
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/SetUtils.java
@@ -0,0 +1,84 @@
+/*
+ * 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.HashSet ;
+import java.util.Set ;
+
+public class SetUtils
+{
+ private SetUtils() {}
+
+ public static <X> Set<X> setOfOne(X element) { return DS.setOfOne(element) ; }
+
+ // Set specific operations
+
+ public static <T> Set<T> intersection(Set<? extends T> setLeft, Set<? extends T> setRight)
+ {
+ Set<T> results = new HashSet<>(setLeft) ;
+ results.retainAll(setRight) ;
+ return results ;
+ }
+
+ public static <T> boolean intersectionP(Set<? extends T> s1, Set<? extends T> s2)
+ {
+ for( T elt : s1 )
+ {
+ if ( s2.contains(elt) )
+ return true ;
+ }
+ return false ;
+ }
+
+ public static <T> Set<T> union(Set<? extends T> s1, Set<? extends T> s2)
+ {
+ Set<T> s3 = new HashSet<>(s1) ;
+ s3.addAll(s2) ;
+ return s3 ;
+ }
+
+ /** Return is s1 \ s2 */
+
+ public static <T> Set<T> difference(Set<? extends T> s1, Set<? extends T> s2)
+ {
+ Set<T> s3 = new HashSet<>(s1) ;
+ s3.removeAll(s2) ;
+ return s3 ;
+ }
+
+ /** Return true if s1 and s2 are disjoint */
+ public static <T> boolean isDisjoint(Set<? extends T> s1, Set<? extends T> s2)
+ {
+ Set<? extends T> x = s1 ;
+ Set<? extends T> y = s2 ;
+ if ( s1.size() < s2.size() )
+ {
+ x = s2 ;
+ y = s1 ;
+ }
+
+ for ( T item : x )
+ {
+ if ( y.contains(item))
+ return false ;
+ }
+ return true ;
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/Sink.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/Sink.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/Sink.java
new file mode 100644
index 0000000..01bb809
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/Sink.java
@@ -0,0 +1,29 @@
+/*
+ * 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;
+
+
+/** Interface for the destination of things */
+public interface Sink<T> extends Closeable
+{
+ // Can't help but think it should be "Pipe"
+ // If Sync looses Sync(boolean), then make this "extends Sync"
+ void send(T item) ;
+ void flush() ;
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/SinkCounting.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/SinkCounting.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/SinkCounting.java
new file mode 100644
index 0000000..62c6e43
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/SinkCounting.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.lib;
+
+
+
+public final class SinkCounting<T> extends SinkWrapper<T>
+{
+ private long count = 0 ;
+
+ public SinkCounting(Sink<T> output)
+ { super(output) ; }
+
+ public SinkCounting()
+ { super(new SinkNull<T>()) ; }
+
+ @Override
+ public void send(T thing)
+ {
+ count++ ;
+ super.send(thing) ;
+ }
+
+ public long getCount() { return count ; }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/SinkLogging.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/SinkLogging.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/SinkLogging.java
new file mode 100644
index 0000000..e6928de
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/SinkLogging.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.lib;
+
+import org.slf4j.Logger ;
+
+public class SinkLogging<T> implements Sink<T>
+{
+ private Logger log ;
+
+ public SinkLogging(Logger log) { this.log = log ; }
+
+ @Override
+ public void send(T item)
+ {
+ log.info("Sink: "+item) ;
+ }
+
+ @Override
+ public void flush() { }
+
+ @Override
+ public void close() {}
+
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/SinkNull.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/SinkNull.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/SinkNull.java
new file mode 100644
index 0000000..9242c97
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/SinkNull.java
@@ -0,0 +1,33 @@
+/*
+ * 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 class SinkNull<T> implements Sink<T>
+{
+ public static <X> SinkNull<X> create() { return new SinkNull<>() ; }
+
+ /*@Override*/ @Override
+ public void send(T thing) {}
+ /*@Override*/ @Override
+ public void close() {}
+ /*@Override*/ @Override
+ public void flush() { }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/SinkPrint.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/SinkPrint.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/SinkPrint.java
new file mode 100644
index 0000000..4fc694d
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/SinkPrint.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.lib;
+
+import java.io.PrintStream ;
+
+public class SinkPrint<T> implements Sink<T>
+{
+
+ private PrintStream out ;
+
+ public SinkPrint()
+ { this(System.out); }
+
+ public SinkPrint(PrintStream out)
+ { this.out = out ; }
+
+ @Override
+ public void send(T item)
+ {
+ out.println("Sink: "+item) ;
+ }
+
+ @Override
+ public void flush() { }
+
+ @Override
+ public void close() {}
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/SinkSplit.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/SinkSplit.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/SinkSplit.java
new file mode 100644
index 0000000..8d50ee4
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/SinkSplit.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;
+
+/** Split a sink stream and duplicate the operations onto two sinks
+ * See also: {@link SinkWrapper}
+ */
+public class SinkSplit<T> implements Sink<T>
+{
+ private final Sink<T> sink1 ;
+ private final Sink<T> sink2 ;
+
+ public SinkSplit(Sink<T> sink1, Sink<T> sink2)
+ {
+ this.sink1 = sink1 ;
+ this.sink2 = sink2 ;
+ }
+
+ @Override
+ public void flush()
+ {
+ sink1.flush();
+ sink2.flush();
+ }
+
+ @Override
+ public void send(T item)
+ {
+ sink1.send(item) ;
+ sink2.send(item) ;
+ }
+
+ @Override
+ public void close()
+ {
+ sink1.close();
+ sink2.close();
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/SinkToCollection.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/SinkToCollection.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/SinkToCollection.java
new file mode 100644
index 0000000..d7e04ba
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/SinkToCollection.java
@@ -0,0 +1,38 @@
+/**
+ * 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.Collection;
+
+/** Send items to a collection */
+public class SinkToCollection<T> implements Sink<T>
+{
+ private final Collection<T> c ;
+
+ public SinkToCollection(Collection<T> c) { this.c = c ; }
+
+ @Override
+ public void send(T item) { c.add(item); }
+
+ @Override
+ public void flush() {}
+
+ @Override
+ public void close() {}
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/SinkToQueue.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/SinkToQueue.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/SinkToQueue.java
new file mode 100644
index 0000000..f7e5dff
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/SinkToQueue.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;
+
+import java.util.concurrent.BlockingQueue ;
+import java.util.concurrent.CancellationException ;
+
+/** Send items to a blocking queue */
+public class SinkToQueue<T> implements Sink<T>
+{
+ private final BlockingQueue<T> queue ;
+
+ public SinkToQueue(BlockingQueue<T> queue) { this.queue = queue ; }
+
+ @Override
+ public void send(T item)
+ {
+ try
+ {
+ if (Thread.interrupted()) throw new InterruptedException();
+ // Hopefully we'll never get passed null... but just in case
+ if (null == item) return;
+ queue.put(item);
+ }
+ catch (InterruptedException e)
+ {
+ throw new CancellationException();
+ }
+ }
+
+ @Override
+ public void flush() {}
+
+ @Override
+ public void close() {}
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/SinkWrapper.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/SinkWrapper.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/SinkWrapper.java
new file mode 100644
index 0000000..c6632ba
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/SinkWrapper.java
@@ -0,0 +1,44 @@
+/*
+ * 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;
+
+/** Wrap one sink in another - to pass on behaviour, the derived Sink must call super.operation
+ * See also: {@link SinkSplit}
+ */
+public class SinkWrapper<T> implements Sink<T>
+{
+ protected final Sink<T> sink ;
+
+ public SinkWrapper(Sink<T> sink)
+ {
+ this.sink = sink ;
+ }
+
+ @Override
+ public void flush()
+ { sink.flush(); }
+
+ @Override
+ public void send(T item)
+ { sink.send(item) ; }
+
+ @Override
+ public void close()
+ { sink.close(); }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/StrUtils.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/StrUtils.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/StrUtils.java
new file mode 100644
index 0000000..9a9be76
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/StrUtils.java
@@ -0,0 +1,292 @@
+/*
+ * 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.io.UnsupportedEncodingException ;
+import java.util.ArrayList ;
+import java.util.List ;
+import java.util.Map ;
+
+
+public class StrUtils //extends StringUtils
+{
+ private StrUtils() {}
+
+ /** strjoin with a newline as the separator */
+ public static String strjoinNL(String... args)
+ {
+ return join("\n", args) ;
+ }
+
+ /** strjoin with a newline as the separator */
+ public static String strjoinNL(List<String> args)
+ {
+ return join("\n", args) ;
+ }
+
+ /** Concatentate strings, using a separator */
+ public static String strjoin(String sep, String... args)
+ {
+ return join(sep, args) ;
+ }
+
+ /** Concatentate string, using a separator */
+ public static String strjoin(String sep, List<String> args)
+ {
+ return join(sep, args) ;
+ }
+
+ private static String join(String sep, List<String> a)
+ {
+ return join(sep, a.toArray(new String[0])) ;
+ }
+
+ private static String join(String sep, String...a)
+ {
+ if ( a.length == 0 )
+ return "" ;
+
+ if ( a.length == 1)
+ return a[0] ;
+
+ StringBuilder sbuff = new StringBuilder() ;
+ sbuff.append(a[0]) ;
+
+ for ( int i = 1 ; i < a.length ; i++ )
+ {
+ if ( sep != null )
+ sbuff.append(sep) ;
+ sbuff.append(a[i]) ;
+ }
+ return sbuff.toString() ;
+ }
+
+ public static final int CMP_GREATER = +1 ;
+ public static final int CMP_EQUAL = 0 ;
+ public static final int CMP_LESS = -1 ;
+
+ public static final int CMP_UNEQUAL = -9 ;
+ public static final int CMP_INDETERMINATE = 2 ;
+
+ public static int strCompare(String s1, String s2)
+ {
+ // Value is the difference of the first differing chars
+ int x = s1.compareTo(s2) ;
+ if ( x < 0 ) return CMP_LESS ;
+ if ( x > 0 ) return CMP_GREATER ;
+ if ( x == 0 ) return CMP_EQUAL ;
+ throw new InternalErrorException("String comparison failure") ;
+ }
+
+ public static int strCompareIgnoreCase(String s1, String s2)
+ {
+ // Value is the difference of the first differing chars
+ int x = s1.compareToIgnoreCase(s2) ;
+ if ( x < 0 ) return CMP_LESS ;
+ if ( x > 0 ) return CMP_GREATER ;
+ if ( x == 0 ) return CMP_EQUAL ;
+ throw new InternalErrorException("String comparison failure") ;
+ }
+
+ public static byte[] asUTF8bytes(String s)
+ {
+ try { return s.getBytes("UTF-8") ; }
+ catch (UnsupportedEncodingException ex)
+ { throw new InternalErrorException("UTF-8 not supported!") ; }
+ }
+
+ public static String fromUTF8bytes(byte[] bytes)
+ {
+ try { return new String(bytes, "UTF-8") ; }
+ catch (UnsupportedEncodingException ex)
+ { throw new InternalErrorException("UTF-8 not supported!") ; }
+ }
+
+ public static String str(Object x)
+ {
+ if ( x == null ) return "<null>" ;
+ return x.toString() ;
+ }
+
+ /** Split but also trim whiespace. */
+ public static String[] split(String s, String splitStr)
+ {
+ String[] x = s.split(splitStr) ;
+ for ( int i = 0 ; i < x.length ; i++ )
+ {
+ x[i] = x[i].trim() ;
+ }
+ return x ;
+ }
+
+ /** Does one string contain another string?
+ * @param str1
+ * @param str2
+ * @return true if str1 contains str2
+ */
+ public final static boolean contains(String str1, String str2)
+ {
+ return str1.contains(str2) ;
+ }
+
+ public final static String replace(String string, String target, String replacement)
+ {
+ return string.replace(target, replacement) ;
+ }
+
+ public static String substitute(String str, Map<String, String>subs)
+ {
+ for ( Map.Entry<String, String> e : subs.entrySet() )
+ {
+ String param = e.getKey() ;
+ if ( str.contains(param) )
+ str = str.replace(param, e.getValue()) ;
+ }
+ return str ;
+ }
+
+ public static String strform(Map<String, String>subs, String... args)
+ {
+ return substitute(strjoinNL(args),subs) ;
+ }
+
+ public static String chop(String x)
+ {
+ if ( x.length() == 0 )
+ return x ;
+ return x.substring(0, x.length()-1) ;
+ }
+
+ public static String noNewlineEnding(String x)
+ {
+ while ( x.endsWith("\n") || x.endsWith("\r") )
+ x = StrUtils.chop(x) ;
+ return x ;
+ }
+
+ public static List<Character> toCharList(String str)
+ {
+ List<Character> characters = new ArrayList<>(str.length()) ;
+ for ( Character ch : str.toCharArray() )
+ characters.add(ch) ;
+ return characters ;
+ }
+
+ // ==== Encoding and decoding strings based on a marker character (e.g. %)
+ // and then the hexadecimal representation of the character.
+ // Only characters 0-255 can be encoded.
+
+ /** Encode a string using hex values e.g. %20
+ *
+ * @param str String to encode
+ * @param marker Marker character
+ * @param escapees Characters to encode (must include the marker)
+ * @return Encoded string (returns input object if no change)
+ */
+ public static String encodeHex(String str, char marker, char[] escapees)
+ {
+ // We make a first pass to see if there is anything to do.
+ // This is assuming
+ // (1) the string is shortish (e.g. fits in L1)
+ // (2) necessary escaping is not common
+
+ int N = str.length();
+ int idx = 0 ;
+ // Scan stage.
+ for ( ; idx < N ; idx++ )
+ {
+ char ch = str.charAt(idx) ;
+ if ( Chars.charInArray(ch, escapees) )
+ break ;
+ }
+ if ( idx == N )
+ return str ;
+
+ // At least one char to convert
+ StringBuilder buff = new StringBuilder() ;
+ buff.append(str, 0, idx) ; // Insert first part.
+ for ( ; idx < N ; idx++ )
+ {
+ char ch = str.charAt(idx) ;
+ if ( Chars.charInArray(ch, escapees) )
+ {
+ Chars.encodeAsHex(buff, marker, ch) ;
+ continue ;
+ }
+ buff.append(ch) ;
+ }
+ return buff.toString();
+ }
+
+ /** Decode a string using marked hex values e.g. %20
+ *
+ * @param str String to decode
+ * @param marker The marker charcater
+ * @return Decoded string (returns input object on no change)
+ */
+ public static String decodeHex(String str, char marker)
+ {
+ int idx = str.indexOf(marker) ;
+ if ( idx == -1 )
+ return str ;
+ StringBuilder buff = new StringBuilder() ;
+
+ buff.append(str, 0, idx) ;
+ int N = str.length() ;
+
+ for ( ; idx < N ; idx++ )
+ {
+ char ch = str.charAt(idx) ;
+ // First time through this is true, always.
+ if ( ch != marker )
+ buff.append(ch) ;
+ else
+ {
+ char hi = str.charAt(idx+1) ;
+ char lo = str.charAt(idx+2) ; // exceptions.
+ char ch2 = (char)(hexDecode(hi)<<4 | hexDecode(lo)) ;
+ buff.append(ch2) ;
+ idx += 2 ;
+ }
+ }
+ return buff.toString() ;
+ }
+
+ // Encoding is table-driven but for decode, we use code.
+ static private int hexDecode(char ch) {
+ if (ch >= '0' && ch <= '9' )
+ return ch - '0' ;
+ if ( ch >= 'A' && ch <= 'F' )
+ return ch - 'A' + 10 ;
+ if ( ch >= 'a' && ch <= 'f' )
+ return ch - 'a' + 10 ;
+ return -1 ;
+ }
+
+ public static String escapeString(String x)
+ {
+ return EscapeStr.stringEsc(x) ;
+ }
+
+ public static String unescapeString(String x)
+ {
+ return EscapeStr.unescapeStr(x) ;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/Sync.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/Sync.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/Sync.java
new file mode 100644
index 0000000..c8e549b
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/Sync.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 Sync
+{
+ public void sync() ;
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/SystemUtils.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/SystemUtils.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/SystemUtils.java
new file mode 100644
index 0000000..fa208f8
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/SystemUtils.java
@@ -0,0 +1,57 @@
+/*
+ * 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 org.apache.jena.atlas.AtlasException ;
+import org.slf4j.Logger ;
+import org.slf4j.LoggerFactory ;
+
+public class SystemUtils
+{
+ private static Logger log = LoggerFactory.getLogger(SystemUtils.class.getName());
+ // Unfortunately, this tends to cause confusing logging.
+ private static boolean logging = false ;
+
+ static public ClassLoader chooseClassLoader()
+ {
+ ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+
+ if ( logging && classLoader != null )
+ log.trace("Using thread classloader") ;
+
+// if (classLoader == null)
+// {
+// classLoader = this.getClass().getClassLoader();
+// if ( classLoader != null )
+// logger.trace("Using 'this' classloader") ;
+// }
+
+ if ( classLoader == null )
+ {
+ classLoader = ClassLoader.getSystemClassLoader() ;
+ if ( logging && classLoader != null )
+ log.trace("Using system classloader") ;
+ }
+
+ if ( classLoader == null )
+ throw new AtlasException("Failed to find a classloader") ;
+ return classLoader ;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/Timer.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/Timer.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/Timer.java
new file mode 100644
index 0000000..304e086
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/Timer.java
@@ -0,0 +1,72 @@
+/*
+ * 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 org.apache.jena.atlas.AtlasException ;
+
+/** A Timer of operations */
+public class Timer {
+
+ protected long timeFinish = -1 ;
+ protected boolean inTimer = false ;
+ protected long timeStart = 0 ;
+
+ public Timer() {}
+
+ public void startTimer() {
+ if ( inTimer )
+ throw new AtlasException("Already in timer") ;
+
+ timeStart = System.currentTimeMillis() ;
+ timeFinish = -1 ;
+ inTimer = true ;
+ }
+
+ /** Return time in millisecods */
+ public long endTimer() {
+ if ( !inTimer )
+ throw new AtlasException("Not in timer") ;
+ timeFinish = System.currentTimeMillis() ;
+ inTimer = false ;
+ return getTimeInterval() ;
+ }
+
+ public long readTimer() {
+ if ( !inTimer )
+ throw new AtlasException("Not in timer") ;
+ return System.currentTimeMillis() - timeStart ;
+ }
+
+ public long getTimeInterval() {
+ if ( inTimer )
+ throw new AtlasException("Still timing") ;
+ if ( timeFinish == -1 )
+ throw new AtlasException("No valid interval") ;
+
+ return timeFinish - timeStart ;
+ }
+
+ static public String timeStr(long timeInterval) {
+ return String.format("%.3f", timeInterval / 1000.0) ;
+ }
+
+ protected String timeStr(long timePoint, long startTimePoint) {
+ return timeStr(timePoint - startTimePoint) ;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/Trie.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/Trie.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/Trie.java
new file mode 100644
index 0000000..0d823bc
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/Trie.java
@@ -0,0 +1,407 @@
+/*
+ * 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.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * An implementation of a classic Trie, this is a mapping from strings to some
+ * value type optimized for fast prefix search and match. If you do not need
+ * prefix search then you should typically use a standard {@link Map} instead.
+ * <p>
+ * The empty or null string may be used as a special key to refer to the root
+ * node of the trie.
+ * </p>
+ * <p>
+ * A Trie cannot store null values since null is used as an internal marker to
+ * indicate that there is no value associated with a key. This is necessary
+ * because the nature of the data structure means that adding a key potentially
+ * adds multiple keys many of which will not be associated with a value.
+ * </p>
+ *
+ * @param <T>
+ * Type of the value stored.
+ */
+public final class Trie<T> {
+
+ private TrieNode<T> root = new TrieNode<>(null);
+
+ /**
+ * Adds a value to the trie overwriting any existing value
+ * <p>
+ * Note that a null value is treated as if the key does not actually exist
+ * in the tree so trying to add a null is a no-op. If you want to remove a
+ * key use the {@link #remove(String)} method instead.
+ * </p>
+ *
+ * @param key
+ * Key
+ * @param value
+ * Value
+ */
+ public void add(String key, T value) {
+ if (value == null)
+ return;
+ TrieNode<T> n = this.moveToNode(key);
+ n.setValue(value);
+ }
+
+ /**
+ * Move to a node creating new nodes if necessary
+ *
+ * @param key
+ * Key
+ * @return Node
+ */
+ private TrieNode<T> moveToNode(String key) {
+ TrieNode<T> current = this.root;
+ if (key == null)
+ return current;
+ for (int i = 0; i < key.length(); i++) {
+ current = current.moveToChild(key.charAt(i));
+ }
+ return current;
+ }
+
+ /**
+ * Try to find a node in the trie
+ *
+ * @param key
+ * Key
+ * @return Node or null if not found
+ */
+ private TrieNode<T> find(String key) {
+ TrieNode<T> current = this.root;
+ if (key == null)
+ return current;
+ for (int i = 0; i < key.length(); i++) {
+ current = current.getChild(key.charAt(i));
+ if (current == null)
+ break;
+ }
+ return current;
+ }
+
+ /**
+ * Removes a value from the trie
+ * <p>
+ * This doesn't actually remove the key per-se rather sets the value
+ * associated with the key to null.
+ * </p>
+ *
+ * @param key
+ * Key
+ */
+ public void remove(String key) {
+ TrieNode<T> n = this.find(key);
+ if (n != null) {
+ n.setValue(null);
+ }
+ }
+
+ /**
+ * Gets whether a key exists in the trie and has a non-null value mapped to
+ * it
+ *
+ * @param key
+ * Key
+ * @return True if the key exists and has a non-null value mapped to it
+ */
+ public boolean contains(String key) {
+ return this.contains(key, true);
+ }
+
+ /**
+ * Gets whether a key exists in the trie and meets the given value criteria
+ *
+ * @param key
+ * Key
+ * @param requireValue
+ * If true a key must have a non-null value associated with it to
+ * be considered to be contained in the tree, if false then the
+ * key must merely map to a node in the trie
+ * @return True if the key exists and the value criteria is met, false
+ * otherwise
+ */
+ public boolean contains(String key, boolean requireValue) {
+ TrieNode<T> n = this.find(key);
+ if (n == null)
+ return false;
+ if (requireValue) {
+ return n.hasValue();
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * Gets whether a key value pair are present in the trie
+ *
+ * @param key
+ * Key
+ * @param value
+ * Value
+ * @return True if the key value pair exists in the trie, false otherwise
+ */
+ public boolean contains(String key, T value) {
+ TrieNode<T> n = this.find(key);
+ if (n == null)
+ return false;
+ if (value == null && !n.hasValue())
+ return true;
+ return value.equals(n.getValue());
+ }
+
+ /**
+ * Gets the value associated with a key
+ *
+ * @param key
+ * Key
+ * @return Value
+ */
+ public T get(String key) {
+ TrieNode<T> n = this.find(key);
+ if (n == null)
+ return null;
+ return n.getValue();
+ }
+
+ /**
+ * Performs a prefix search and returns all values mapped under the given
+ * prefix. The entirety of the prefix must be matches, if you only want part
+ * of the prefix to be matched use the {@link #partialSearch(String)} method
+ * instead.
+ *
+ * @param prefix
+ * Prefix
+ * @return List of values associated with the given key
+ */
+ public List<T> prefixSearch(String prefix) {
+ TrieNode<T> n = this.find(prefix);
+ if (n == null)
+ return new ArrayList<>();
+ return Collections.unmodifiableList(n.getValues());
+ }
+
+ /**
+ * Performs a search and returns any value associated with any partial or
+ * whole prefix of the key
+ *
+ * @param key
+ * Key
+ * @return List of values associated with any partial prefix of the key
+ */
+ public List<T> partialSearch(String key) {
+ List<T> values = new ArrayList<>();
+ TrieNode<T> current = this.root;
+ if (key == null) {
+ if (current.hasValue())
+ values.add(current.getValue());
+ } else {
+ for (int i = 0; i < key.length(); i++) {
+ if (current.hasValue())
+ values.add(current.getValue());
+ current = current.getChild(key.charAt(i));
+ if (current == null)
+ return Collections.unmodifiableList(values);
+ }
+
+ // If we reach here current is the complete key match
+ // so make sure to include it in the values list
+ if (current.hasValue()) {
+ values.add(current.getValue());
+ }
+
+ }
+ return Collections.unmodifiableList(values);
+ }
+
+ /**
+ * Finds the shortest match for a given key i.e. returns the value
+ * associated with the shortest prefix of the key that has a value
+ *
+ * @param key
+ * Key
+ * @return Shortest Match or null if no possible matches
+ */
+ public T shortestMatch(String key) {
+ TrieNode<T> current = this.root;
+ if (key == null)
+ return current.getValue();
+ for (int i = 0; i < key.length(); i++) {
+ if (current.hasValue())
+ break;
+ current = current.getChild(key.charAt(i));
+ if (current == null)
+ return null;
+ }
+ return current.getValue();
+ }
+
+ /**
+ * Finds the longest match for a given key i.e. returns the value associated
+ * with the longest prefix of the key that has a value
+ *
+ * @param key
+ * Key
+ * @return Longest Match or null if no possible matches
+ */
+ public T longestMatch(String key) {
+ T value = null;
+ TrieNode<T> current = this.root;
+ if (key == null) {
+ return current.getValue();
+ } else {
+ for (int i = 0; i < key.length(); i++) {
+ if (current.hasValue())
+ value = current.getValue();
+ current = current.getChild(key.charAt(i));
+ if (current == null)
+ return value;
+ }
+ // If we reach here current is the complete key match
+ // so return its value if it has one
+ if (current.hasValue()) {
+ return current.getValue();
+ }
+ }
+ return value;
+ }
+
+ /**
+ * Represents a node in the Trie
+ * <p>
+ * The implementation is designed to be sparse such that we delay creation
+ * of things at both leafs and interior nodes until they are actually needed
+ * </p>
+ *
+ */
+ private static class TrieNode<T> {
+ private Map<Character, TrieNode<T>> children = null;
+ private Character singletonChildChar = null;
+ private TrieNode<T> singletonChild = null;
+ private T value;
+
+ /**
+ * Creates a Trie Node
+ *
+ * @param value
+ * Value
+ */
+ public TrieNode(T value) {
+ this.value = value;
+ }
+
+ /**
+ * Gets the value
+ *
+ * @return Value
+ */
+ public T getValue() {
+ return this.value;
+ }
+
+ /**
+ * Sets the value
+ *
+ * @param value
+ * Value
+ */
+ public void setValue(T value) {
+ this.value = value;
+ }
+
+ /**
+ * Returns whether a non-null value is associated with this node
+ *
+ * @return True if there is a non-null value, false otherwise
+ */
+ public boolean hasValue() {
+ return this.value != null;
+ }
+
+ /**
+ * Gets the child (if it exists)
+ *
+ * @param c
+ * Character to move to
+ * @return Child
+ */
+ public TrieNode<T> getChild(Character c) {
+ if (this.children != null) {
+ return this.children.get(c);
+ } else if (c.equals(this.singletonChildChar)) {
+ return this.singletonChild;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Moves to a child (creating a new node if necessary)
+ *
+ * @param c
+ * Character to move to
+ * @return Child
+ */
+ public TrieNode<T> moveToChild(Character c) {
+ TrieNode<T> n = this.getChild(c);
+ if (n == null) {
+ n = new TrieNode<>(null);
+ if (this.children != null) {
+ // Add to existing map
+ this.children.put(c, n);
+ } else if (this.singletonChildChar != null) {
+ // Need to lazily create map
+ this.children = new HashMap<>();
+ this.children.put(this.singletonChildChar, this.singletonChild);
+ this.children.put(c, n);
+ } else {
+ // Singleton child
+ this.singletonChildChar = c;
+ this.singletonChild = n;
+ }
+ }
+ return n;
+ }
+
+ /**
+ * Gets all values from a given node and its descendants
+ *
+ * @return Values
+ */
+ public List<T> getValues() {
+ List<T> values = new ArrayList<>();
+ if (this.hasValue()) {
+ values.add(this.value);
+ }
+ if (this.children != null) {
+ for (TrieNode<T> child : this.children.values()) {
+ values.addAll(child.getValues());
+ }
+ } else if (this.singletonChild != null) {
+ values.addAll(this.singletonChild.getValues());
+ }
+ return values;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/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
new file mode 100644
index 0000000..ae944a7
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/Tuple.java
@@ -0,0 +1,153 @@
+/*
+ * 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 org.apache.jena.atlas.iterator.Iter ;
+import org.apache.jena.atlas.iterator.IteratorArray ;
+import org.apache.jena.atlas.iterator.Transform ;
+
+/** 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.
+ * <p>
+ * There is also a {@link TupleBuilder} which does create an idendent
+ * copy, in case that style is preferrable for creating tuples.
+ */
+ 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) {
+ Transform<Tuple<T>, T> projection = new Transform<Tuple<T>, T>() {
+ @Override
+ public T convert(Tuple<T> tuple) {
+ return tuple.get(slot) ;
+ }
+ } ;
+ return Iter.map(iter, projection) ;
+ }
+
+ public static <T> Iterator<Tuple<T>> prefix(final int prefixLength, Iterator<Tuple<T>> iter) {
+ Transform<Tuple<T>, Tuple<T>> sub = new Transform<Tuple<T>, Tuple<T>>() {
+ @Override
+ public Tuple<T> convert(Tuple<T> tuple) {
+ T[] x = ArrayUtils.copy(tuple.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 IteratorArray.create(tuple) ;
+ }
+
+ /** Return a tuple with the column mapping applied */
+ public Tuple<T> map(ColumnMap colMap) {
+ return colMap.map(this) ;
+ }
+
+ /** Return a tuple with the column mapping reversed */
+ public Tuple<T> unmap(ColumnMap colMap) {
+ return colMap.unmap(this) ;
+ }
+
+ 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 ( !Lib.equal(obj1, obj2) )
+ return false ;
+ }
+ return true ;
+ }
+
+ @Override
+ public String toString() {
+ return "[" + Iter.asString(iterator(), ", ") + "]" ;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/TupleBuilder.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/TupleBuilder.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/TupleBuilder.java
new file mode 100644
index 0000000..278334d
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/TupleBuilder.java
@@ -0,0 +1,50 @@
+/*
+ * 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.ArrayList ;
+import java.util.List ;
+
+/** Tuple builder class - tuples are immutable, this is how to create them in the builder style */
+public class TupleBuilder<T>
+{
+ private List<T> x = new ArrayList<>() ;
+
+ public TupleBuilder() { }
+
+ public TupleBuilder<T> add(T element) {
+ x.add(element) ;
+ return this ;
+ }
+
+ public TupleBuilder<T> reset() {
+ x.clear() ;
+ return this ;
+ }
+
+ public Tuple<T> build() {
+ @SuppressWarnings("unchecked")
+ T[] elts = (T[])new Object[x.size()] ;
+ // Copy contents, should not create a new array because elts
+ // is created with the right size so elts == elts2
+ T[] elts2 = x.toArray(elts) ;
+ return new Tuple<>(elts2) ;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/XMLLib.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/XMLLib.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/XMLLib.java
new file mode 100644
index 0000000..e8640df
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/XMLLib.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.lib;
+
+/** Operations in someway related to XML */
+public class XMLLib
+{
+ /** Trim the XML whitespace characters strictly needed for whitespace facet collapse.
+ * This <b>not</b> full whitespace facet collapse, which also requires processing of
+ * internal spaces. Because none of the datatypes that have whitespace facet
+ * collapse and have values we extract can legally contain internal whitespace,
+ * we just need to trim the string.
+ *
+ * Java String.trim removes any characters less than 0x20.
+ */
+ static String WScollapse(String string)
+ {
+ int len = string.length();
+ if ( len == 0 )
+ return string ;
+
+ if ( (string.charAt(0) > 0x20) && (string.charAt(len-1) > 0x20) )
+ return string ;
+
+ int idx1 = 0 ;
+ for ( ; idx1 < len ; idx1++ )
+ {
+ char ch = string.charAt(idx1) ;
+ if ( ! testForWS(ch) )
+ break ;
+ }
+ int idx2 = len-1 ;
+ for ( ; idx2 > idx1 ; idx2-- )
+ {
+ char ch = string.charAt(idx2) ;
+ if ( ! testForWS(ch) )
+ break ;
+ }
+ return string.substring(idx1, idx2+1) ;
+ }
+
+ private static boolean testForWS(char ch)
+ {
+ return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t' ;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/cache/Cache0.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/cache/Cache0.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/cache/Cache0.java
new file mode 100644
index 0000000..00befa0
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/cache/Cache0.java
@@ -0,0 +1,72 @@
+/*
+ * 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.cache ;
+
+import java.util.Iterator ;
+import java.util.concurrent.Callable ;
+
+import org.apache.jena.atlas.iterator.Iter ;
+import org.apache.jena.atlas.lib.ActionKeyValue ;
+import org.apache.jena.atlas.lib.Cache ;
+
+/** A cache that keeps nothing */
+public final class Cache0<K, V> implements Cache<K, V> {
+ @Override
+ public boolean containsKey(K key) {
+ return false ;
+ }
+
+ @Override
+ public V getIfPresent(K key) {
+ return null ;
+ }
+
+ @Override
+ public V getOrFill(K key, Callable<V> callable) {
+ return null ;
+ }
+
+ @Override
+ public void put(K key, V thing) {}
+
+ @Override
+ public void remove(K key) {}
+
+ @Override
+ public Iterator<K> keys() {
+ return Iter.nullIterator() ;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return true ;
+ }
+
+ @Override
+ public void clear() {}
+
+ @Override
+ public long size() {
+ return 0 ;
+ }
+
+ @Override
+ public void setDropHandler(ActionKeyValue<K, V> dropHandler) {}
+
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/cache/Cache1.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/cache/Cache1.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/cache/Cache1.java
new file mode 100644
index 0000000..38ab5c6
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/cache/Cache1.java
@@ -0,0 +1,127 @@
+/*
+ * 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.cache;
+
+import java.util.Iterator ;
+import java.util.concurrent.Callable ;
+
+import org.apache.jena.atlas.iterator.SingletonIterator ;
+import org.apache.jena.atlas.lib.ActionKeyValue ;
+import org.apache.jena.atlas.lib.Cache ;
+import org.apache.jena.atlas.lib.Lib ;
+
+/** A one-slot cache.*/
+public class Cache1<K, V> implements Cache<K,V>
+{
+ private ActionKeyValue<K, V> dropHandler = null ;
+ private K cacheKey ;
+ private V cacheValue ;
+
+ public Cache1() { clear() ; }
+
+ @Override
+ public boolean containsKey(K key)
+ {
+ if ( cacheKey == null )
+ return false ;
+ return cacheKey.equals(key) ;
+ }
+
+ @Override
+ public V getIfPresent(K key)
+ {
+ if ( cacheKey == null ) return null ;
+ if ( cacheKey.equals(key) ) return cacheValue ;
+ return null ;
+ }
+
+ @Override
+ public V getOrFill(K key, Callable<V> callable) {
+ return CacheOps.getOrFillSync(this, key, callable) ;
+ }
+
+ @Override
+ public void clear()
+ {
+ if ( cacheKey == null )
+ return ;
+
+ K k = cacheKey ;
+ V v = cacheValue ;
+ cacheKey = null ;
+ cacheValue = null ;
+
+ notifyDrop(k, v) ;
+ }
+
+ @Override
+ public boolean isEmpty()
+ {
+ return cacheKey == null ;
+ }
+
+ @Override
+ public Iterator<K> keys()
+ {
+ return new SingletonIterator<>(cacheKey) ;
+ }
+
+ @Override
+ public void put(K key, V thing)
+ {
+ if ( Lib.equal(cacheKey, key) && Lib.equal(cacheValue, thing) )
+ // No change.
+ return ;
+
+ // Change
+ K k = cacheKey ;
+ V v = cacheValue ;
+ // Displaces any existing cached key/value pair
+ cacheKey = key ;
+ cacheValue = thing ;
+ notifyDrop(k, v) ;
+ }
+
+ @Override
+ public void remove(K key)
+ {
+ if ( cacheKey == null ) return ;
+ if ( cacheKey.equals(key) )
+ clear() ; // Will notify
+ }
+
+ @Override
+ public void setDropHandler(ActionKeyValue<K, V> dropHandler)
+ {
+ this.dropHandler = dropHandler ;
+ }
+
+ private void notifyDrop(K key, V thing)
+ {
+ if ( dropHandler != null && key != null )
+ dropHandler.apply(key, thing) ;
+ }
+
+ @Override
+ public long size()
+ {
+ return (cacheKey == null) ? 0 : 1 ;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/cache/CacheGuava.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/cache/CacheGuava.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/cache/CacheGuava.java
new file mode 100644
index 0000000..fd5959c
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/cache/CacheGuava.java
@@ -0,0 +1,119 @@
+/**
+ * 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.cache;
+
+import java.util.Iterator ;
+import java.util.concurrent.Callable ;
+import java.util.concurrent.ExecutionException ;
+
+import org.apache.jena.atlas.lib.ActionKeyValue ;
+import org.apache.jena.atlas.lib.Cache ;
+import org.apache.jena.atlas.logging.Log ;
+
+import org.apache.jena.ext.com.google.common.cache.CacheBuilder ;
+import org.apache.jena.ext.com.google.common.cache.RemovalListener ;
+import org.apache.jena.ext.com.google.common.cache.RemovalNotification ;
+
+/** Wrapper around com.google.common.cache */
+final
+public class CacheGuava<K,V> implements Cache<K, V>
+{
+ private ActionKeyValue<K, V> dropHandler = null ;
+ /*private*/ org.apache.jena.ext.com.google.common.cache.Cache<K,V> cache ;
+
+ public CacheGuava(int size)
+ {
+ RemovalListener<K,V> drop = new RemovalListener<K, V>() {
+ @Override
+ public void onRemoval(RemovalNotification<K, V> notification) {
+ if ( dropHandler != null )
+ dropHandler.apply(notification.getKey(),
+ notification.getValue()) ;
+ }
+ } ;
+ cache = CacheBuilder.newBuilder()
+ .maximumSize(size)
+ .removalListener(drop)
+ .recordStats()
+ .concurrencyLevel(8)
+ .build() ;
+ }
+
+ // Change the interface to be ...
+ @Override
+ public V getOrFill(K key, Callable<V> filler) {
+ try {
+ return cache.get(key, filler) ;
+ }
+ catch (ExecutionException e) {
+ Log.warn(CacheGuava.class, "Execution exception filling cache", e) ;
+ return null ;
+ }
+ }
+
+ @Override
+ public V getIfPresent(K key) {
+ return cache.getIfPresent(key) ;
+ }
+
+ @Override
+ public void put(K key, V thing) {
+ if ( thing == null ) {
+ cache.invalidate(key);
+ return ;
+ }
+ cache.put(key, thing) ;
+ }
+
+ @Override
+ public boolean containsKey(K key) {
+ return cache.getIfPresent(key) != null ;
+ }
+
+ @Override
+ public void remove(K key) {
+ cache.invalidate(key) ;
+ }
+
+ @Override
+ public Iterator<K> keys() {
+ return cache.asMap().keySet().iterator() ;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return cache.size() == 0 ;
+ }
+
+ @Override
+ public void clear() {
+ cache.invalidateAll() ;
+ }
+
+ @Override
+ public long size() {
+ return cache.size() ;
+ }
+
+ @Override
+ public void setDropHandler(ActionKeyValue<K, V> dropHandler) {
+ this.dropHandler = dropHandler ;
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/cache/CacheOps.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/cache/CacheOps.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/cache/CacheOps.java
new file mode 100644
index 0000000..c8560bb
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/cache/CacheOps.java
@@ -0,0 +1,50 @@
+/**
+ * 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.cache;
+
+import java.util.concurrent.Callable ;
+
+import org.apache.jena.atlas.AtlasException ;
+import org.apache.jena.atlas.lib.Cache ;
+
+/** Support operations for Cache functions */
+class CacheOps {
+
+ /** Implementation of getOrFill based on Cache.get and Cache.put */
+ public static <K,V> V getOrFill(Cache<K,V> cache, K key, Callable<V> callable) {
+ V value = cache.getIfPresent(key) ;
+ if ( value == null ) {
+ try { value = callable.call() ; }
+ catch (Exception e) {
+ throw new AtlasException("Exception on cache fill", e) ;
+ }
+ if ( value != null )
+ cache.put(key, value) ;
+ }
+ return value ;
+ }
+
+ /** Thread safe implementation of getOrFill based on Cache.get and Cache.put */
+ public static <K,V> V getOrFillSync(Cache<K,V> cache, K key, Callable<V> callable) {
+ synchronized(cache) {
+ return getOrFill(cache, key, callable) ;
+ }
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/cache/CacheSetImpl.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/cache/CacheSetImpl.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/cache/CacheSetImpl.java
new file mode 100644
index 0000000..b3bf048
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/cache/CacheSetImpl.java
@@ -0,0 +1,93 @@
+/*
+ * 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.cache ;
+
+import java.util.Iterator ;
+
+import org.apache.jena.atlas.iterator.Action ;
+import org.apache.jena.atlas.lib.ActionKeyValue ;
+import org.apache.jena.atlas.lib.Cache ;
+import org.apache.jena.atlas.lib.CacheSet ;
+
+/** Cache set */
+public class CacheSetImpl<T> implements CacheSet<T> {
+ // LinkHashSet does not have LRU support.
+ static Object theOnlyValue = new Object() ;
+ Cache<T, Object> cacheMap = null ;
+
+ public CacheSetImpl(Cache<T, Object> cache) {
+ cacheMap = cache ;
+ }
+
+ /** Callback for entries when dropped from the cache */
+ @Override
+ public void setDropHandler(Action<T> dropHandler) {
+ cacheMap.setDropHandler(new Wrapper<T>(dropHandler)) ;
+ }
+
+ // From map action to set action.
+ static class Wrapper<T> implements ActionKeyValue<T, Object> {
+ Action<T> dropHandler ;
+
+ public Wrapper(Action<T> dropHandler) {
+ this.dropHandler = dropHandler ;
+ }
+
+ @Override
+ public void apply(T key, Object value) {
+ dropHandler.apply(key) ;
+ }
+
+ }
+
+ @Override
+ public void add(T e) {
+ cacheMap.put(e, theOnlyValue) ;
+ }
+
+ @Override
+ public void clear() {
+ cacheMap.clear() ;
+ }
+
+ @Override
+ public boolean contains(T obj) {
+ return cacheMap.containsKey(obj) ;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return cacheMap.isEmpty() ;
+ }
+
+ public Iterator<T> iterator() {
+ return cacheMap.keys() ;
+ }
+
+ @Override
+ public void remove(T obj) {
+ cacheMap.remove(obj) ;
+ }
+
+ @Override
+ public long size() {
+ return cacheMap.size() ;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/cache/CacheSetSync.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/cache/CacheSetSync.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/cache/CacheSetSync.java
new file mode 100644
index 0000000..fc3a3bd
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/cache/CacheSetSync.java
@@ -0,0 +1,65 @@
+/*
+ * 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.cache ;
+
+import org.apache.jena.atlas.iterator.Action ;
+import org.apache.jena.atlas.lib.CacheSet ;
+
+public class CacheSetSync<T> implements CacheSet<T> {
+ private CacheSet<T> cache ;
+
+ public CacheSetSync(CacheSet<T> cache) {
+ this.cache = cache ;
+ }
+
+ @Override
+ synchronized public void add(T e) {
+ cache.add(e) ;
+ }
+
+ @Override
+ synchronized public void clear() {
+ cache.clear() ;
+ }
+
+ @Override
+ synchronized public boolean contains(T obj) {
+ return cache.contains(obj) ;
+ }
+
+ @Override
+ synchronized public boolean isEmpty() {
+ return cache.isEmpty() ;
+ }
+
+ @Override
+ synchronized public void remove(T obj) {
+ cache.remove(obj) ;
+ }
+
+ @Override
+ synchronized public long size() {
+ return cache.size() ;
+ }
+
+ @Override
+ synchronized public void setDropHandler(Action<T> dropHandler) {
+ cache.setDropHandler(dropHandler) ;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/cache/CacheSetWrapper.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/cache/CacheSetWrapper.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/cache/CacheSetWrapper.java
new file mode 100644
index 0000000..c11ffb0
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/cache/CacheSetWrapper.java
@@ -0,0 +1,65 @@
+/*
+ * 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.cache ;
+
+import org.apache.jena.atlas.iterator.Action ;
+import org.apache.jena.atlas.lib.CacheSet ;
+
+public class CacheSetWrapper<T> implements CacheSet<T> {
+ private CacheSet<T> cache ;
+
+ public CacheSetWrapper(CacheSet<T> cache) {
+ this.cache = cache ;
+ }
+
+ @Override
+ public void add(T e) {
+ cache.add(e) ;
+ }
+
+ @Override
+ public void clear() {
+ cache.clear() ;
+ }
+
+ @Override
+ public boolean contains(T obj) {
+ return cache.contains(obj) ;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return cache.isEmpty() ;
+ }
+
+ @Override
+ public void remove(T obj) {
+ cache.remove(obj) ;
+ }
+
+ @Override
+ public long size() {
+ return cache.size() ;
+ }
+
+ @Override
+ public void setDropHandler(Action<T> dropHandler) {
+ cache.setDropHandler(dropHandler) ;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/cache/CacheSimple.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/cache/CacheSimple.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/cache/CacheSimple.java
new file mode 100644
index 0000000..a33d8e2
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/cache/CacheSimple.java
@@ -0,0 +1,161 @@
+/*
+ * 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.cache;
+
+import java.util.Arrays ;
+import java.util.Iterator ;
+import java.util.concurrent.Callable ;
+
+import org.apache.jena.atlas.iterator.Iter ;
+import org.apache.jena.atlas.iterator.IteratorArray ;
+import org.apache.jena.atlas.lib.ActionKeyValue ;
+import org.apache.jena.atlas.lib.Cache ;
+
+
+/**
+ * A simple fixed size cache that uses the hash code to address a slot.
+ * Clash policy is to overwrite.
+ * No object creation during lookup or insert.
+ */
+
+public class CacheSimple<K,V> implements Cache<K,V>
+{
+ private final V[] values ;
+ private final K[] keys ;
+ private final int size ;
+ private int currentSize = 0 ;
+ private ActionKeyValue<K,V> dropHandler = null ;
+
+ public CacheSimple(int size)
+ {
+ @SuppressWarnings("unchecked")
+ V[] x = (V[])new Object[size] ;
+ values = x ;
+
+ @SuppressWarnings("unchecked")
+ K[] z = (K[])new Object[size] ;
+ keys = z ;
+
+ this.size = size ;
+ }
+
+
+ @Override
+ public void clear()
+ {
+ Arrays.fill(values, null) ;
+ Arrays.fill(keys, null) ;
+ // drop handler
+ currentSize = 0 ;
+ }
+
+ @Override
+ public boolean containsKey(K key)
+ {
+ return getIfPresent(key) != null ;
+ }
+
+ // Return key index : -(index+1) if the key does not match
+ private final int index(K key)
+ {
+ int x = (key.hashCode()&0x7fffffff) % size ;
+ if ( keys[x] != null && keys[x].equals(key) )
+ return x ;
+ return -x-1 ;
+ }
+
+ private final int decode(int x)
+ {
+ if ( x >= 0 ) return x ;
+ return -x-1 ;
+ }
+
+ @Override
+ public V getIfPresent(K key)
+ {
+ int x = index(key) ;
+ if ( x < 0 )
+ return null ;
+ return values[x] ;
+ }
+
+ @Override
+ public V getOrFill(K key, Callable<V> callable) {
+ return CacheOps.getOrFill(this, key, callable) ;
+ }
+
+ @Override
+ public void put(K key, V thing)
+ {
+ int x = index(key) ;
+ V old = null ;
+ if ( x < 0 )
+ // New.
+ x = decode(x) ;
+ else
+ {
+ // Drop the old K->V
+ old = values[x] ;
+ if ( dropHandler != null )
+ dropHandler.apply(keys[x], old) ;
+ currentSize-- ;
+ }
+
+ values[x] = thing ;
+ if ( thing == null )
+ //put(,null) is a remove.
+ keys[x] = null ;
+ else {
+ keys[x] = key ;
+ currentSize++ ;
+ }
+ }
+
+ @Override
+ public void remove(K key)
+ {
+ put(key, null) ;
+ }
+
+ @Override
+ public long size()
+ {
+ return currentSize ;
+ }
+
+ @Override
+ public Iterator<K> keys()
+ {
+ Iterator<K> iter = IteratorArray.create(keys) ;
+ return Iter.removeNulls(iter) ;
+ }
+
+ @Override
+ public boolean isEmpty()
+ {
+ return currentSize == 0 ;
+ }
+
+ /** Callback for entries when dropped from the cache */
+ @Override
+ public void setDropHandler(ActionKeyValue<K,V> dropHandler)
+ {
+ this.dropHandler = dropHandler ;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/cache/CacheWrapper.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/cache/CacheWrapper.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/cache/CacheWrapper.java
new file mode 100644
index 0000000..e655749
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/cache/CacheWrapper.java
@@ -0,0 +1,65 @@
+/*
+ * 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.cache;
+import java.util.Iterator ;
+import java.util.concurrent.Callable ;
+
+import org.apache.jena.atlas.lib.ActionKeyValue ;
+import org.apache.jena.atlas.lib.Cache ;
+
+
+
+public class CacheWrapper<Key,T> implements Cache<Key,T>
+{
+ protected Cache<Key,T> cache ;
+
+ public CacheWrapper(Cache<Key,T> cache) { this.cache = cache ; }
+
+ @Override
+ public void clear() { cache.clear(); }
+
+ @Override
+ public boolean containsKey(Key key) { return cache.containsKey(key) ; }
+
+ @Override
+ public T getIfPresent(Key key) { return cache.getIfPresent(key) ; }
+
+ @Override
+ public T getOrFill(Key key, Callable<T> callable) { return cache.getOrFill(key, callable) ; }
+
+ @Override
+ public boolean isEmpty() { return cache.isEmpty() ; }
+
+ @Override
+ public Iterator<Key> keys() { return cache.keys(); }
+
+ @Override
+ public void put(Key key, T thing) { cache.put(key, thing) ; }
+
+ @Override
+ public void remove(Key key) { cache.remove(key) ; }
+
+ @Override
+ public void setDropHandler(ActionKeyValue<Key, T> dropHandler)
+ { cache.setDropHandler(dropHandler) ; }
+
+ @Override
+ public long size() { return cache.size() ; }
+
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/cache/Getter.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/cache/Getter.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/cache/Getter.java
new file mode 100644
index 0000000..c9f879c
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/cache/Getter.java
@@ -0,0 +1,25 @@
+/*
+ * 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.cache;
+
+/** A get interface */
+public interface Getter<K, V>
+{
+ public V get(K key) ;
+}