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");