-
Notifications
You must be signed in to change notification settings - Fork 155
/
Intrinsics.java
174 lines (159 loc) · 6.01 KB
/
Intrinsics.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
/*
* HPPC
*
* Copyright (C) 2010-2022 Carrot Search s.c.
* All rights reserved.
*
* Refer to the full license file "LICENSE.txt":
* https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt
*/
package com.carrotsearch.hppc;
import java.util.Objects;
/**
* Intrinsic methods that are fully functional for the source templates (generic) and are replaced
* with low-level corresponding equivalents for the generated primitive types.
*
* <p>Whenever there is a generic type on a static method it can be used to parameterize the given
* method based on the actual template type. Most intrinsics can guess their generic template
* parameter (for example if the template has only one replaceable type), but sometimes it may be
* necessary to provide the template type directly.
*
* <p><b>This class should not appear in the final distribution (all methods are replaced in
* templates.</b> Use forbidden-apis checker to make sure this is the case.
*/
public final class Intrinsics {
/**
* Anything that implements value-equality function as replaced by the {@link #equals} intrinsic.
*
* <p>Not a public interface because we want the implementing methods to be effectively protected,
* but used for API consistency in templates.
*/
public interface EqualityFunction {
boolean equals(Object v1, Object v2);
}
/**
* Anything that distributes keys by their hash value.
*
* <p>Not a public interface because we want the implementing methods to be effectively protected,
* but used for API consistency in templates. *
*/
public interface KeyHasher<T> {
int hashKey(T key);
}
/** Everything static. */
private Intrinsics() {}
/**
* Returns <code>true</code> if the provided value is an "empty key" marker. For generic types the
* empty key is <code>null</code>, for any other type it is an equivalent of zero.
*
* <p>Testing for zeros should be compiled into fast machine code.
*/
public static <T> boolean isEmpty(Object value) {
return value == null;
}
/** Returns the default "empty key" (<code>null</code> or <code>0</code> for primitive types). */
public static <T> T empty() {
return (T) null;
}
/**
* A template cast to the given type T. With type erasure it should work internally just fine and
* it simplifies code. The cast will be erased for primitive types.
*/
@SuppressWarnings("unchecked")
public static <T> T cast(Object value) {
return (T) value;
}
/** Creates an array for the given template type. */
@SuppressWarnings("unchecked")
public static <T> T[] newArray(int arraySize) {
return (T[]) new Object[arraySize];
}
/**
* Compare two keys for equivalence.
*
* <p>Generic types are compared using the delegate function.
*
* <p>Primitive types are compared using <code>==</code>, except for floating-point types where
* they're compared by their actual representation bits as returned from {@link
* Double#doubleToLongBits(double)} and {@link Float#floatToIntBits(float)}.
*/
public static <T> boolean equals(EqualityFunction delegate, Object e1, Object e2) {
return delegate.equals(e1, e2);
}
/**
* Compare two keys for equivalence.
*
* <p>Generic types are compared for null-equivalence or using {@link Object#equals(Object)}.
*
* <p>Primitive types are compared using <code>==</code>, except for floating-point types where
* they're compared by their actual representation bits as returned from {@link
* Double#doubleToLongBits(double)} and {@link Float#floatToIntBits(float)}.
*/
public static <T> boolean equals(Object e1, Object e2) {
return Objects.equals(e1, e2);
}
/**
* An intrinsic that is replaced with plain addition of arguments for primitive template types.
* Invalid for non-number generic types.
*/
@SuppressWarnings("unchecked")
public static <T> T add(T op1, T op2) {
if (op1.getClass() != op2.getClass()) {
throw new RuntimeException("Arguments of different classes: " + op1 + " " + op2);
}
if (Byte.class.isInstance(op1)) {
return (T) (Byte) (byte) (((Byte) op1).byteValue() + ((Byte) op2).byteValue());
}
if (Short.class.isInstance(op1)) {
return (T) (Short) (short) (((Short) op1).shortValue() + ((Short) op2).shortValue());
}
if (Character.class.isInstance(op1)) {
return (T) (Character) (char) (((Character) op1).charValue() + ((Character) op2).charValue());
}
if (Integer.class.isInstance(op1)) {
return (T) (Integer) (((Integer) op1).intValue() + ((Integer) op2).intValue());
}
if (Float.class.isInstance(op1)) {
return (T) (Float) (((Float) op1).floatValue() + ((Float) op2).floatValue());
}
if (Long.class.isInstance(op1)) {
return (T) (Long) (((Long) op1).longValue() + ((Long) op2).longValue());
}
if (Double.class.isInstance(op1)) {
return (T) (Double) (((Double) op1).doubleValue() + ((Double) op2).doubleValue());
}
throw new UnsupportedOperationException("Invalid for arbitrary types: " + op1 + " " + op2);
}
/**
* Returns the numerical value for the argument if it is a primitive template type. This intrinsic
* method always returns a {@code double} result for direct calls, but the template preprocessor
* will replace this method invocation with the exact type equal to the template type. So a call
* to:
*
* <pre>
* {@code Intrinsics.<KType>numeric(key)}
* </pre>
*
* with template type {@code KType} equal to {@code int} will return the raw key value (without
* any type conversion):
*
* <pre>
* {@code (key))
* </pre>
*
* <p>This intrinsic is used to apply arithmetic operations on keys. It is invalid for generic
* types.
*/
public static <T> double numeric(T e) {
if (e instanceof Byte
| e instanceof Character
| e instanceof Short
| e instanceof Integer
| e instanceof Float
| e instanceof Long
| e instanceof Double) {
return (double) e;
}
throw new UnsupportedOperationException("Invalid for generic type: " + e);
}
}