]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.lz4/src/net/jpountz/xxhash/XXHashFactory.java
Fixed org.simantics.lz4 to use bundle data area when running in OSGi
[simantics/platform.git] / bundles / org.simantics.lz4 / src / net / jpountz / xxhash / XXHashFactory.java
1 package net.jpountz.xxhash;
2
3 /*
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 import java.lang.reflect.Field;
18 import java.util.Random;
19
20 import net.jpountz.util.Native;
21 import net.jpountz.util.Utils;
22
23 /**
24  * Entry point to get {@link XXHash32} and {@link StreamingXXHash32} instances.
25  * <p>
26  * This class has 3 instances<ul>
27  * <li>a {@link #nativeInstance() native} instance which is a JNI binding to
28  * <a href="http://code.google.com/p/xxhash/">the original LZ4 C implementation</a>.
29  * <li>a {@link #safeInstance() safe Java} instance which is a pure Java port
30  * of the original C library,</li>
31  * <li>an {@link #unsafeInstance() unsafe Java} instance which is a Java port
32  * using the unofficial {@link sun.misc.Unsafe} API.
33  * </ul>
34  * <p>
35  * Only the {@link #safeInstance() safe instance} is guaranteed to work on your
36  * JVM, as a consequence it is advised to use the {@link #fastestInstance()} or
37  * {@link #fastestJavaInstance()} to pull a {@link XXHashFactory} instance.
38  * <p>
39  * All methods from this class are very costly, so you should get an instance
40  * once, and then reuse it whenever possible. This is typically done by storing
41  * a {@link XXHashFactory} instance in a static field.
42  */
43 public final class XXHashFactory {
44
45   private static XXHashFactory instance(String impl) {
46     try {
47       return new XXHashFactory(impl);
48     } catch (Exception e) {
49       throw new AssertionError(e);
50     }
51   }
52
53   private static XXHashFactory NATIVE_INSTANCE,
54                                JAVA_UNSAFE_INSTANCE,
55                                JAVA_SAFE_INSTANCE;
56
57   /** Return a {@link XXHashFactory} that returns {@link XXHash32} instances that
58    *  are native bindings to the original C API.
59    * <p>
60    * Please note that this instance has some traps you should be aware of:<ol>
61    * <li>Upon loading this instance, files will be written to the temporary
62    * directory of the system. Although these files are supposed to be deleted
63    * when the JVM exits, they might remain on systems that don't support
64    * removal of files being used such as Windows.
65    * <li>The instance can only be loaded once per JVM. This can be a problem
66    * if your application uses multiple class loaders (such as most servlet
67    * containers): this instance will only be available to the children of the
68    * class loader which has loaded it. As a consequence, it is advised to
69    * either not use this instance in webapps or to put this library in the lib
70    * directory of your servlet container so that it is loaded by the system
71    * class loader.
72    * </ol>
73    */
74   public static synchronized XXHashFactory nativeInstance() {
75     if (NATIVE_INSTANCE == null) {
76       NATIVE_INSTANCE = instance("JNI");
77     }
78     return NATIVE_INSTANCE;
79   }
80
81   /** Return a {@link XXHashFactory} that returns {@link XXHash32} instances that
82    *  are written with Java's official API. */
83   public static synchronized XXHashFactory safeInstance() {
84     if (JAVA_SAFE_INSTANCE == null) {
85       JAVA_SAFE_INSTANCE = instance("JavaSafe");
86     }
87     return JAVA_SAFE_INSTANCE;
88   }
89
90   /** Return a {@link XXHashFactory} that returns {@link XXHash32} instances that
91    *  may use {@link sun.misc.Unsafe} to speed up hashing. */
92   public static synchronized XXHashFactory unsafeInstance() {
93     if (JAVA_UNSAFE_INSTANCE == null) {
94       JAVA_UNSAFE_INSTANCE = instance("JavaUnsafe");
95     }
96     return JAVA_UNSAFE_INSTANCE;
97   }
98
99   /**
100    * Return the fastest available {@link XXHashFactory} instance which does not
101    * rely on JNI bindings. It first tries to load the
102    * {@link #unsafeInstance() unsafe instance}, and then the
103    * {@link #safeInstance() safe Java instance} if the JVM doesn't have a
104    * working {@link sun.misc.Unsafe}.
105    */
106   public static XXHashFactory fastestJavaInstance() {
107     if (Utils.isUnalignedAccessAllowed()) {
108       try {
109         return unsafeInstance();
110       } catch (Throwable t) {
111         return safeInstance();
112       }
113     } else {
114       return safeInstance();
115     }
116   }
117
118   /**
119    * Return the fastest available {@link XXHashFactory} instance. If the class
120    * loader is the system class loader and if the
121    * {@link #nativeInstance() native instance} loads successfully, then the
122    * {@link #nativeInstance() native instance} is returned, otherwise the
123    * {@link #fastestJavaInstance() fastest Java instance} is returned.
124    * <p>
125    * Please read {@link #nativeInstance() javadocs of nativeInstance()} before
126    * using this method.
127    */
128   public static XXHashFactory fastestInstance() {
129     if (!Native.failedToLoad()
130         && (Native.isLoaded()
131             || Native.class.getClassLoader() == ClassLoader.getSystemClassLoader())) {
132       try {
133         return nativeInstance();
134       } catch (Throwable t) {
135         return fastestJavaInstance();
136       }
137     } else {
138       return fastestJavaInstance();
139     }
140   }
141
142   @SuppressWarnings("unchecked")
143   private static <T> T classInstance(String cls) throws NoSuchFieldException, SecurityException, ClassNotFoundException, IllegalArgumentException, IllegalAccessException {
144     ClassLoader loader = XXHashFactory.class.getClassLoader();
145     loader = loader == null ? ClassLoader.getSystemClassLoader() : loader;
146     final Class<?> c = loader.loadClass(cls);
147     Field f = c.getField("INSTANCE");
148     return (T) f.get(null);
149   }
150
151   private final String impl;
152   private final XXHash32 hash32;
153   private final XXHash64 hash64;
154   private final StreamingXXHash32.Factory streamingHash32Factory;
155   private final StreamingXXHash64.Factory streamingHash64Factory;
156
157   private XXHashFactory(String impl) throws ClassNotFoundException, NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
158     this.impl = impl;
159     hash32 = classInstance("net.jpountz.xxhash.XXHash32" + impl);
160     streamingHash32Factory = classInstance("net.jpountz.xxhash.StreamingXXHash32" + impl + "$Factory");
161     hash64 = classInstance("net.jpountz.xxhash.XXHash64" + impl);
162     streamingHash64Factory = classInstance("net.jpountz.xxhash.StreamingXXHash64" + impl + "$Factory");
163
164     // make sure it can run
165     final byte[] bytes = new byte[100];
166     final Random random = new Random();
167     random.nextBytes(bytes);
168     final int seed = random.nextInt();
169
170     final int h1 = hash32.hash(bytes, 0, bytes.length, seed);
171     final StreamingXXHash32 streamingHash32 = newStreamingHash32(seed);
172     streamingHash32.update(bytes, 0, bytes.length);
173     final int h2 = streamingHash32.getValue();
174     final long h3 = hash64.hash(bytes, 0, bytes.length, seed);
175     final StreamingXXHash64 streamingHash64 = newStreamingHash64(seed);
176     streamingHash64.update(bytes, 0, bytes.length);
177     final long h4 = streamingHash64.getValue();
178     if (h1 != h2) {
179       throw new AssertionError();
180     }
181     if (h3 != h4) {
182       throw new AssertionError();
183     }
184   }
185
186   /** Return a {@link XXHash32} instance. */
187   public XXHash32 hash32() {
188     return hash32;
189   }
190
191   /** Return a {@link XXHash64} instance. */
192   public XXHash64 hash64() {
193     return hash64;
194   }
195
196   /**
197    * Return a new {@link StreamingXXHash32} instance.
198    */
199   public StreamingXXHash32 newStreamingHash32(int seed) {
200     return streamingHash32Factory.newStreamingHash(seed);
201   }
202
203   /**
204    * Return a new {@link StreamingXXHash64} instance.
205    */
206   public StreamingXXHash64 newStreamingHash64(long seed) {
207     return streamingHash64Factory.newStreamingHash(seed);
208   }
209
210   /** Prints the fastest instance. */
211   public static void main(String[] args) {
212     System.out.println("Fastest instance is " + fastestInstance());
213     System.out.println("Fastest Java instance is " + fastestJavaInstance());
214   }
215
216   @Override
217   public String toString() {
218     return getClass().getSimpleName() + ":" + impl;
219   }
220
221 }