diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 092a3a54..d011b46b 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -47,7 +47,7 @@ jobs:
- name: build with maven
run: |
mvn -q -N "io.takari:maven:${{env.IO_TAKARI_MAVEN_WRAPPER_VERSION}}:wrapper" "-Dmaven=${{env.MAVEN_VERSION}}"
- ./mvnw -B -ntp formatter:validate verify --file pom.xml "-Djava11.home=${{env.JAVA_HOME_11_X64}}"
+ ./mvnw -B -ntp formatter:validate verify --file pom.xml "-Dexpected-cpu=x64" "-Djava11.home=${{env.JAVA_HOME_11_X64}}"
quality:
needs: [ build ]
diff --git a/cpu/pom.xml b/cpu/pom.xml
index 8dadcccb..651eb81e 100644
--- a/cpu/pom.xml
+++ b/cpu/pom.xml
@@ -12,12 +12,32 @@
SmallRye Common: CPU
+
+
+
+
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ test
+
+
+
io.github.dmlloyd.module-info
module-info
+
+ maven-surefire-plugin
+
+
+ ${expected-cpu}
+
+
+
diff --git a/cpu/src/main/java/io/smallrye/common/cpu/CPU.java b/cpu/src/main/java/io/smallrye/common/cpu/CPU.java
new file mode 100644
index 00000000..050f16c9
--- /dev/null
+++ b/cpu/src/main/java/io/smallrye/common/cpu/CPU.java
@@ -0,0 +1,192 @@
+package io.smallrye.common.cpu;
+
+import java.nio.ByteOrder;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import sun.misc.Unsafe;
+
+/**
+ * Enumerated type for CPU types.
+ */
+// We should try to support (at least) all of the CPU types defined in jdk.internal.util.Architecture
+public enum CPU {
+
+ // IMPORTANT: Only add new CPU types to the end of the list to preserve ordinal sequence.
+ /**
+ * An unknown 32-bit little-endian CPU.
+ */
+ unknown32(4, ByteOrder.LITTLE_ENDIAN, Set.of(), true),
+ /**
+ * An unknown 32-bit big-endian CPU.
+ */
+ unknown32be(4, ByteOrder.BIG_ENDIAN, Set.of(), true),
+ /**
+ * An unknown 64-bit little-endian CPU.
+ */
+ unknown64(8, ByteOrder.LITTLE_ENDIAN, Set.of("unknown"), true),
+ /**
+ * An unknown 64-bit big-endian CPU.
+ */
+ unknown64be(8, ByteOrder.BIG_ENDIAN, Set.of(), true),
+
+ x64(8, ByteOrder.LITTLE_ENDIAN, Set.of("x86_64", "amd64"), false),
+ x86(4, ByteOrder.LITTLE_ENDIAN, Set.of("i386", "i486", "i586", "i686"), false),
+
+ aarch64(8, ByteOrder.LITTLE_ENDIAN, Set.of("arm64"), false),
+ arm(4, ByteOrder.LITTLE_ENDIAN, Set.of("armv7", "armv7hl", "aarch32"), false),
+
+ riscv(8, ByteOrder.LITTLE_ENDIAN, Set.of("riscv64"), false),
+
+ ppc32(4, ByteOrder.BIG_ENDIAN, Set.of("ppc32be"), false),
+ ppc32le(4, ByteOrder.LITTLE_ENDIAN, Set.of(), false),
+ ppc(8, ByteOrder.BIG_ENDIAN, Set.of("ppc64", "ppcbe", "ppc64be"), false),
+ ppcle(8, ByteOrder.LITTLE_ENDIAN, Set.of("ppc64le"), false),
+
+ wasm32(4, ByteOrder.LITTLE_ENDIAN, Set.of("wasm"), false),
+
+ // todo: s390
+
+ mips(4, ByteOrder.BIG_ENDIAN, Set.of("mips32, mipsbe, mips32be"), false),
+ mipsel(4, ByteOrder.LITTLE_ENDIAN, Set.of("mips32el"), false),
+ mips64(4, ByteOrder.BIG_ENDIAN, Set.of("mips64be"), false),
+ mips64el(4, ByteOrder.LITTLE_ENDIAN, Set.of(), false),
+ ;
+
+ /**
+ * All of the possible CPU values, in order.
+ */
+ public static final List values = List.of(values());
+
+ private static final CPU hostCpu;
+
+ // a "map" which is sorted by name, ignoring case
+ private static final List> index = values.stream()
+ .flatMap(cpu -> Stream.concat(Stream.of(cpu.name()), cpu.aliases().stream()).map(v -> Map.entry(v, cpu)))
+ .sorted(Map.Entry.comparingByKey(String::compareToIgnoreCase))
+ .collect(Collectors.toUnmodifiableList());
+
+ private final int pointerSizeBytes;
+ private final ByteOrder nativeByteOrder;
+ private final Set aliases;
+ private final boolean unknown;
+
+ CPU(final int pointerSizeBytes, final ByteOrder nativeByteOrder, final Set aliases, final boolean unknown) {
+ this.pointerSizeBytes = pointerSizeBytes;
+ this.nativeByteOrder = nativeByteOrder;
+ this.aliases = aliases;
+ this.unknown = unknown;
+ }
+
+ /**
+ * {@return this CPU's pointer size, in bytes}
+ */
+ public int pointerSizeBytes() {
+ return pointerSizeBytes;
+ }
+
+ /**
+ * {@return this CPU's pointer size, in bits}
+ */
+ public int pointerSizeBits() {
+ return pointerSizeBytes << 3;
+ }
+
+ /**
+ * {@return this CPU's native byte order}
+ */
+ public ByteOrder nativeByteOrder() {
+ return nativeByteOrder;
+ }
+
+ /**
+ * {@return other names that this CPU is known by}
+ */
+ public Set aliases() {
+ return aliases;
+ }
+
+ /**
+ * {@return true
if this CPU is unknown}
+ */
+ public boolean isUnknown() {
+ return unknown;
+ }
+
+ /**
+ * {@return the CPU for the given name}
+ * Names are compared case-insensitively.
+ *
+ * @throws NoSuchElementException if no such CPU is found
+ */
+ public static CPU forName(String name) throws NoSuchElementException {
+ CPU cpu = forNameOrNull(name);
+ if (cpu == null) {
+ throw new NoSuchElementException();
+ }
+ return cpu;
+ }
+
+ /**
+ * {@return the CPU for the given name or null
if it is not found}
+ * Names are compared case-insensitively.
+ */
+ public static CPU forNameOrNull(String name) throws NoSuchElementException {
+ Comparator cmp = String::compareToIgnoreCase;
+
+ int low = 0;
+ int high = index.size() - 1;
+
+ while (low <= high) {
+ int mid = (low + high) >>> 1;
+ Map.Entry entry = index.get(mid);
+ int res = cmp.compare(entry.getKey(), name);
+
+ if (res < 0) {
+ low = mid + 1;
+ } else if (res > 0) {
+ high = mid - 1;
+ } else {
+ return entry.getValue();
+ }
+ }
+ return null;
+ }
+
+ /**
+ * {@return the optional CPU for the given name}
+ * Names are compared case-insensitively.
+ */
+ public static Optional forNameOpt(String name) throws NoSuchElementException {
+ return Optional.ofNullable(forNameOrNull(name));
+ }
+
+ /**
+ * {@return the host CPU type}
+ */
+ public static CPU host() {
+ return hostCpu;
+ }
+
+ static {
+ hostCpu = forNameOpt(System.getProperty("os.arch", "???")).map(CPU::check).orElseThrow();
+ }
+
+ private static CPU check(CPU cpu) {
+ ByteOrder no = ByteOrder.nativeOrder();
+ // todo: in 22+, bytes = (int) ValueLayout.ADDRESS.byteSize();
+ int bytes = Unsafe.ADDRESS_SIZE;
+ if (cpu.pointerSizeBytes() == bytes && cpu.nativeByteOrder() == no) {
+ // OK
+ return cpu;
+ }
+ // CPU is unknown or doesn't match observed host characteristics
+ return no == ByteOrder.BIG_ENDIAN ? bytes == 4 ? unknown32be : unknown64be : bytes == 4 ? unknown32 : unknown64;
+ }
+}
diff --git a/cpu/src/test/java/io/smallrye/common/cpu/CPUTests.java b/cpu/src/test/java/io/smallrye/common/cpu/CPUTests.java
new file mode 100644
index 00000000..3ca8d65f
--- /dev/null
+++ b/cpu/src/test/java/io/smallrye/common/cpu/CPUTests.java
@@ -0,0 +1,18 @@
+package io.smallrye.common.cpu;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Assumptions;
+import org.junit.jupiter.api.Test;
+
+/**
+ *
+ */
+public final class CPUTests {
+
+ @Test
+ public void testCpu() {
+ String expectedCpuName = System.getProperty("expected-cpu");
+ Assumptions.assumeTrue(expectedCpuName != null && !expectedCpuName.isEmpty());
+ Assertions.assertEquals(CPU.host().name(), expectedCpuName);
+ }
+}