You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by gn...@apache.org on 2018/11/07 08:41:17 UTC

[camel] 02/03: Use a really static map for static converters

This is an automated email from the ASF dual-hosted git repository.

gnodet pushed a commit to branch sandbox/camel-3.x
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 06c24320fe96ebb957f6160634b3831b09c7f198
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Wed Nov 7 09:39:15 2018 +0100

    Use a really static map for static converters
---
 .../impl/converter/BaseTypeConverterRegistry.java  | 177 +------------------
 .../org/apache/camel/impl/converter/DoubleMap.java | 190 +++++++++++++++++++++
 .../apache/camel/tools/apt/ConverterProcessor.java |  16 +-
 3 files changed, 203 insertions(+), 180 deletions(-)

diff --git a/camel-core/src/main/java/org/apache/camel/impl/converter/BaseTypeConverterRegistry.java b/camel-core/src/main/java/org/apache/camel/impl/converter/BaseTypeConverterRegistry.java
index 73f6acf..2d44c19 100644
--- a/camel-core/src/main/java/org/apache/camel/impl/converter/BaseTypeConverterRegistry.java
+++ b/camel-core/src/main/java/org/apache/camel/impl/converter/BaseTypeConverterRegistry.java
@@ -23,8 +23,6 @@ import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.LongAdder;
-import java.util.concurrent.locks.StampedLock;
-import java.util.function.Predicate;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.CamelContextAware;
@@ -51,7 +49,6 @@ import org.apache.camel.support.MessageHelper;
 import org.apache.camel.support.ServiceSupport;
 import org.apache.camel.support.TypeConverterSupport;
 import org.apache.camel.util.ObjectHelper;
-import org.apache.camel.util.function.TriConsumer;
 
 /**
  * Base implementation of a type converter registry used for
@@ -499,7 +496,7 @@ public abstract class BaseTypeConverterRegistry extends ServiceSupport implement
 
                 // lets try classes derived from this toType
                 TypeConverter converter = typeMappings.getFirst(
-                        to -> toType.isAssignableFrom(to),
+                        toType::isAssignableFrom,
                         // skip Object based we do them last
                         from -> !from.equals(Object.class) && from.isAssignableFrom(fromType));
                 if (converter != null) {
@@ -529,8 +526,7 @@ public abstract class BaseTypeConverterRegistry extends ServiceSupport implement
      */
     public void loadCoreTypeConverters() throws Exception {
         // load all the type converters from camel-core
-        CoreStaticTypeConverterLoader core = new CoreStaticTypeConverterLoader();
-        core.load(this);
+        CoreStaticTypeConverterLoader.INSTANCE.load(this);
     }
 
     /**
@@ -702,173 +698,4 @@ public abstract class BaseTypeConverterRegistry extends ServiceSupport implement
         }
     }
 
-    @SuppressWarnings("unchecked")
-    protected static class DoubleMap<K1, K2, V> {
-
-        static class Entry {
-            Object k1;
-            Object k2;
-            Object v;
-            Entry next;
-        }
-
-        private Entry[] table;
-        private int mask;
-
-        public DoubleMap(int size) {
-            table = new Entry[closedTableSize(size)];
-            mask = table.length - 1;
-        }
-
-        public V get(K1 k1, K2 k2) {
-            Entry[] table = this.table;
-            int mask = this.mask;
-            int index = smear(k1.hashCode() * 31 + k2.hashCode()) & mask;
-            for (Entry entry = table[index]; entry != null; entry = entry.next) {
-                if (k1 == entry.k1 && k2 == entry.k2) {
-                    return (V) entry.v;
-                }
-            }
-            return null;
-        }
-
-        public void forEach(TriConsumer<K1, K2, V> consumer) {
-            Entry[] table = this.table;
-            for (Entry entry : table) {
-                while (entry != null) {
-                    consumer.accept((K1) entry.k1, (K2) entry.k2, (V) entry.v);
-                    entry = entry.next;
-                }
-            }
-        }
-
-        public boolean containsKey(K1 k1, K2 k2) {
-            Entry[] table = this.table;
-            int mask = this.mask;
-            int index = smear(k1.hashCode() * 31 + k2.hashCode()) & mask;
-            for (Entry entry = table[index]; entry != null; entry = entry.next) {
-                if (k1 == entry.k1 && k2 == entry.k2) {
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        public synchronized void put(K1 k1, K2 k2, V v) {
-            Entry[] table = this.table;
-            int size = size() + 1;
-            int realSize = closedTableSize(size);
-            if (realSize <= table.length) {
-                realSize = table.length;
-                int index = smear(k1.hashCode() * 31 + k2.hashCode()) & (realSize - 1);
-                for (Entry oldEntry = table[index]; oldEntry != null; oldEntry = oldEntry.next) {
-                    if (oldEntry.k1 == k1 && oldEntry.k2 == k2) {
-                        oldEntry.v = v;
-                        return;
-                    }
-                }
-                Entry entry = new Entry();
-                entry.k1 = k1;
-                entry.k2 = k2;
-                entry.v = v;
-                entry.next = table[index];
-                table[index] = entry;
-            } else {
-                Entry[] newT = new Entry[realSize];
-                int index = smear(k1.hashCode() * 31 + k2.hashCode()) & (realSize - 1);
-                Entry entry = new Entry();
-                newT[index] = entry;
-                entry.k1 = k1;
-                entry.k2 = k2;
-                entry.v = v;
-                for (Entry oldEntry : table) {
-                    while (oldEntry != null) {
-                        if (k1 != oldEntry.k1 || k2 != oldEntry.k2) {
-                            index = smear(oldEntry.k1.hashCode() * 31 + oldEntry.k2.hashCode()) & (realSize - 1);
-                            Entry newEntry = new Entry();
-                            newEntry.k1 = oldEntry.k1;
-                            newEntry.k2 = oldEntry.k2;
-                            newEntry.v = oldEntry.v;
-                            newEntry.next = newT[index];
-                            newT[index] = newEntry;
-                        }
-                        oldEntry = oldEntry.next;
-                    }
-                }
-                this.table = newT;
-                this.mask = realSize - 1;
-            }
-        }
-
-        public synchronized boolean remove(K1 k1, K2 k2) {
-            Entry[] table = this.table;
-            int mask = this.mask;
-            int index = smear(k1.hashCode() * 31 + k2.hashCode()) & mask;
-            Entry prevEntry = null;
-            for (Entry oldEntry = table[index]; oldEntry != null; prevEntry = oldEntry, oldEntry = oldEntry.next) {
-                if (oldEntry.k1 == k1 && oldEntry.k2 == k2) {
-                    if (prevEntry == null) {
-                        table[index] = oldEntry.next;
-                    } else {
-                        prevEntry.next = oldEntry.next;
-                    }
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        public V getFirst(Predicate<K1> p1, Predicate<K2> p2) {
-            for (Entry entry : table) {
-                while (entry != null) {
-                    if (p1.test((K1) entry.k1) && p2.test((K2) entry.k2)) {
-                        return (V) entry.v;
-                    }
-                    entry = entry.next;
-                }
-            }
-            return null;
-        }
-
-        public int size() {
-            Entry[] table = this.table;
-            int n = 0;
-            if (table != null) {
-                for (Entry e : table) {
-                    for (Entry c = e; c != null; c = c.next) {
-                        n++;
-                    }
-                }
-            }
-            return n;
-        }
-
-        public synchronized void clear() {
-            this.table = new Entry[table.length];
-        }
-
-        private static final double MAX_LOAD_FACTOR = 1.2;
-        private static final int MAX_TABLE_SIZE = 32768;
-        private static final int C1 = 0xcc9e2d51;
-        private static final int C2 = 0x1b873593;
-
-        static int smear(int hashCode) {
-            return C2 * Integer.rotateLeft(hashCode * C1, 15);
-        }
-
-        static int closedTableSize(int expectedEntries) {
-            // Get the recommended table size.
-            // Round down to the nearest power of 2.
-            expectedEntries = Math.max(expectedEntries, 2);
-            int tableSize = Integer.highestOneBit(expectedEntries);
-            // Check to make sure that we will not exceed the maximum load factor.
-            if (expectedEntries > (int) (MAX_LOAD_FACTOR * tableSize)) {
-                tableSize <<= 1;
-                return (tableSize > 0) ? tableSize : MAX_TABLE_SIZE;
-            }
-            return tableSize;
-        }
-
-    }
-
 }
diff --git a/camel-core/src/main/java/org/apache/camel/impl/converter/DoubleMap.java b/camel-core/src/main/java/org/apache/camel/impl/converter/DoubleMap.java
new file mode 100644
index 0000000..b297bcd
--- /dev/null
+++ b/camel-core/src/main/java/org/apache/camel/impl/converter/DoubleMap.java
@@ -0,0 +1,190 @@
+/**
+ * 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.camel.impl.converter;
+
+import java.util.function.Predicate;
+
+import org.apache.camel.util.function.TriConsumer;
+
+@SuppressWarnings("unchecked")
+public class DoubleMap<K1, K2, V> {
+
+    static class Entry {
+        Object k1;
+        Object k2;
+        Object v;
+        Entry next;
+    }
+
+    private Entry[] table;
+    private int mask;
+
+    public DoubleMap(int size) {
+        table = new Entry[closedTableSize(size)];
+        mask = table.length - 1;
+    }
+
+    public V get(K1 k1, K2 k2) {
+        Entry[] table = this.table;
+        int mask = this.mask;
+        int index = smear(k1.hashCode() * 31 + k2.hashCode()) & mask;
+        for (Entry entry = table[index]; entry != null; entry = entry.next) {
+            if (k1 == entry.k1 && k2 == entry.k2) {
+                return (V) entry.v;
+            }
+        }
+        return null;
+    }
+
+    public void forEach(TriConsumer<K1, K2, V> consumer) {
+        Entry[] table = this.table;
+        for (Entry entry : table) {
+            while (entry != null) {
+                consumer.accept((K1) entry.k1, (K2) entry.k2, (V) entry.v);
+                entry = entry.next;
+            }
+        }
+    }
+
+    public boolean containsKey(K1 k1, K2 k2) {
+        Entry[] table = this.table;
+        int mask = this.mask;
+        int index = smear(k1.hashCode() * 31 + k2.hashCode()) & mask;
+        for (Entry entry = table[index]; entry != null; entry = entry.next) {
+            if (k1 == entry.k1 && k2 == entry.k2) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public synchronized void put(K1 k1, K2 k2, V v) {
+        Entry[] table = this.table;
+        int size = size() + 1;
+        int realSize = closedTableSize(size);
+        if (realSize <= table.length) {
+            realSize = table.length;
+            int index = smear(k1.hashCode() * 31 + k2.hashCode()) & (realSize - 1);
+            for (Entry oldEntry = table[index]; oldEntry != null; oldEntry = oldEntry.next) {
+                if (oldEntry.k1 == k1 && oldEntry.k2 == k2) {
+                    oldEntry.v = v;
+                    return;
+                }
+            }
+            Entry entry = new Entry();
+            entry.k1 = k1;
+            entry.k2 = k2;
+            entry.v = v;
+            entry.next = table[index];
+            table[index] = entry;
+        } else {
+            Entry[] newT = new Entry[realSize];
+            int index = smear(k1.hashCode() * 31 + k2.hashCode()) & (realSize - 1);
+            Entry entry = new Entry();
+            newT[index] = entry;
+            entry.k1 = k1;
+            entry.k2 = k2;
+            entry.v = v;
+            for (Entry oldEntry : table) {
+                while (oldEntry != null) {
+                    if (k1 != oldEntry.k1 || k2 != oldEntry.k2) {
+                        index = smear(oldEntry.k1.hashCode() * 31 + oldEntry.k2.hashCode()) & (realSize - 1);
+                        Entry newEntry = new Entry();
+                        newEntry.k1 = oldEntry.k1;
+                        newEntry.k2 = oldEntry.k2;
+                        newEntry.v = oldEntry.v;
+                        newEntry.next = newT[index];
+                        newT[index] = newEntry;
+                    }
+                    oldEntry = oldEntry.next;
+                }
+            }
+            this.table = newT;
+            this.mask = realSize - 1;
+        }
+    }
+
+    public synchronized boolean remove(K1 k1, K2 k2) {
+        Entry[] table = this.table;
+        int mask = this.mask;
+        int index = smear(k1.hashCode() * 31 + k2.hashCode()) & mask;
+        Entry prevEntry = null;
+        for (Entry oldEntry = table[index]; oldEntry != null; prevEntry = oldEntry, oldEntry = oldEntry.next) {
+            if (oldEntry.k1 == k1 && oldEntry.k2 == k2) {
+                if (prevEntry == null) {
+                    table[index] = oldEntry.next;
+                } else {
+                    prevEntry.next = oldEntry.next;
+                }
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public V getFirst(Predicate<K1> p1, Predicate<K2> p2) {
+        for (Entry entry : table) {
+            while (entry != null) {
+                if (p1.test((K1) entry.k1) && p2.test((K2) entry.k2)) {
+                    return (V) entry.v;
+                }
+                entry = entry.next;
+            }
+        }
+        return null;
+    }
+
+    public int size() {
+        Entry[] table = this.table;
+        int n = 0;
+        if (table != null) {
+            for (Entry e : table) {
+                for (Entry c = e; c != null; c = c.next) {
+                    n++;
+                }
+            }
+        }
+        return n;
+    }
+
+    public synchronized void clear() {
+        this.table = new Entry[table.length];
+    }
+
+    private static final double MAX_LOAD_FACTOR = 1.2;
+    private static final int MAX_TABLE_SIZE = 32768;
+    private static final int C1 = 0xcc9e2d51;
+    private static final int C2 = 0x1b873593;
+
+    static int smear(int hashCode) {
+        return C2 * Integer.rotateLeft(hashCode * C1, 15);
+    }
+
+    static int closedTableSize(int expectedEntries) {
+        // Get the recommended table size.
+        // Round down to the nearest power of 2.
+        expectedEntries = Math.max(expectedEntries, 2);
+        int tableSize = Integer.highestOneBit(expectedEntries);
+        // Check to make sure that we will not exceed the maximum load factor.
+        if (expectedEntries > (int) (MAX_LOAD_FACTOR * tableSize)) {
+            tableSize <<= 1;
+            return (tableSize > 0) ? tableSize : MAX_TABLE_SIZE;
+        }
+        return tableSize;
+    }
+
+}
diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/ConverterProcessor.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/ConverterProcessor.java
index 1757f21..bf19948 100644
--- a/tooling/apt/src/main/java/org/apache/camel/tools/apt/ConverterProcessor.java
+++ b/tooling/apt/src/main/java/org/apache/camel/tools/apt/ConverterProcessor.java
@@ -118,6 +118,8 @@ public class ConverterProcessor extends AbstractProcessor {
                 writer.append("@SuppressWarnings(\"unchecked\")\n");
                 writer.append("public class ").append(c).append(" implements TypeConverterLoader {\n");
                 writer.append("\n");
+                writer.append("    public static final CoreStaticTypeConverterLoader INSTANCE = new CoreStaticTypeConverterLoader();\n");
+                writer.append("\n");
                 writer.append("    static abstract class SimpleTypeConverter extends TypeConverterSupport {\n");
                 writer.append("        private final boolean allowNull;\n");
                 writer.append("\n");
@@ -143,8 +145,9 @@ public class ConverterProcessor extends AbstractProcessor {
                 writer.append("        protected abstract Object doConvert(Exchange exchange, Object value) throws Exception;\n");
                 writer.append("    };\n");
                 writer.append("\n");
-                writer.append("    @Override\n");
-                writer.append("    public void load(TypeConverterRegistry registry) throws TypeConverterLoaderException {\n");
+                writer.append("    private DoubleMap<Class<?>, Class<?>, SimpleTypeConverter> converters = new DoubleMap<>(256);\n");
+                writer.append("\n");
+                writer.append("    private ").append(c).append("() {\n");
 
                 for (Map.Entry<String, Map<TypeMirror, ExecutableElement>> to : converters.entrySet()) {
                     for (Map.Entry<TypeMirror, ExecutableElement> from : to.getValue().entrySet()) {
@@ -162,7 +165,7 @@ public class ConverterProcessor extends AbstractProcessor {
                                 }
                             }
                         }
-                        writer.append("        registry.addTypeConverter(").append(to.getKey()).append(".class").append(", ")
+                        writer.append("        converters.put(").append(to.getKey()).append(".class").append(", ")
                                 .append(toString(from.getKey())).append(".class, new SimpleTypeConverter(")
                                 .append(Boolean.toString(allowNull)).append(") {\n");
                         writer.append("            @Override\n");
@@ -172,7 +175,11 @@ public class ConverterProcessor extends AbstractProcessor {
                         writer.append("        });\n");
                     }
                 }
-
+                writer.append("    }\n");
+                writer.append("\n");
+                writer.append("    @Override\n");
+                writer.append("    public void load(TypeConverterRegistry registry) throws TypeConverterLoaderException {\n");
+                writer.append("        converters.forEach((k, v, c) -> registry.addTypeConverter(k, v, c));\n");
                 for (ExecutableElement ee : fallbackConverters) {
                     boolean allowNull = false;
                     boolean canPromote = false;
@@ -209,7 +216,6 @@ public class ConverterProcessor extends AbstractProcessor {
                     writer.append("            }\n");
                     writer.append("        }, ").append(Boolean.toString(canPromote)).append(");\n");
                 }
-                writer.append("\n");
                 writer.append("    }\n");
                 writer.append("\n");