1 /* 2 * Copyright (C) 2017 The Android Open Source Project 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 package com.android.internal.util.function.pooled; 18 19 import android.annotation.Nullable; 20 import android.os.Message; 21 import android.text.TextUtils; 22 import android.util.Log; 23 import android.util.Pools; 24 25 import com.android.internal.util.ArrayUtils; 26 import com.android.internal.util.BitUtils; 27 import com.android.internal.util.Preconditions; 28 import com.android.internal.util.function.HeptConsumer; 29 import com.android.internal.util.function.HeptFunction; 30 import com.android.internal.util.function.HeptPredicate; 31 import com.android.internal.util.function.HexConsumer; 32 import com.android.internal.util.function.HexFunction; 33 import com.android.internal.util.function.HexPredicate; 34 import com.android.internal.util.function.NonaConsumer; 35 import com.android.internal.util.function.NonaFunction; 36 import com.android.internal.util.function.NonaPredicate; 37 import com.android.internal.util.function.OctConsumer; 38 import com.android.internal.util.function.OctFunction; 39 import com.android.internal.util.function.OctPredicate; 40 import com.android.internal.util.function.QuadConsumer; 41 import com.android.internal.util.function.QuadFunction; 42 import com.android.internal.util.function.QuadPredicate; 43 import com.android.internal.util.function.QuintConsumer; 44 import com.android.internal.util.function.QuintFunction; 45 import com.android.internal.util.function.QuintPredicate; 46 import com.android.internal.util.function.TriConsumer; 47 import com.android.internal.util.function.TriFunction; 48 import com.android.internal.util.function.TriPredicate; 49 50 import java.util.Arrays; 51 import java.util.Objects; 52 import java.util.function.BiConsumer; 53 import java.util.function.BiFunction; 54 import java.util.function.BiPredicate; 55 import java.util.function.Consumer; 56 import java.util.function.Function; 57 import java.util.function.Predicate; 58 import java.util.function.Supplier; 59 60 /** 61 * @see PooledLambda 62 * @hide 63 */ 64 final class PooledLambdaImpl<R> extends OmniFunction<Object, 65 Object, Object, Object, Object, Object, Object, Object, Object, R> { 66 67 private static final boolean DEBUG = false; 68 private static final String LOG_TAG = "PooledLambdaImpl"; 69 70 private static final int MAX_ARGS = 9; 71 72 private static final int MAX_POOL_SIZE = 50; 73 74 static class Pool extends Pools.SynchronizedPool<PooledLambdaImpl> { 75 Pool(Object lock)76 public Pool(Object lock) { 77 super(MAX_POOL_SIZE, lock); 78 } 79 } 80 81 static final Pool sPool = new Pool(new Object()); 82 static final Pool sMessageCallbacksPool = new Pool(Message.sPoolSync); 83 PooledLambdaImpl()84 private PooledLambdaImpl() {} 85 86 /** 87 * The function reference to be invoked 88 * 89 * May be the return value itself in case when an immediate result constant is provided instead 90 */ 91 Object mFunc; 92 93 /** 94 * A primitive result value to be immediately returned on invocation instead of calling 95 * {@link #mFunc} 96 */ 97 long mConstValue; 98 99 /** 100 * Arguments for {@link #mFunc} 101 */ 102 @Nullable Object[] mArgs = null; 103 104 /** 105 * Flag for {@link #mFlags} 106 * 107 * Indicates whether this instance is recycled 108 */ 109 private static final int FLAG_RECYCLED = 1 << MAX_ARGS; 110 111 /** 112 * Flag for {@link #mFlags} 113 * 114 * Indicates whether this instance should be immediately recycled on invocation 115 * (as requested via {@link PooledLambda#recycleOnUse()}) or not(default) 116 */ 117 private static final int FLAG_RECYCLE_ON_USE = 1 << (MAX_ARGS + 1); 118 119 /** 120 * Flag for {@link #mFlags} 121 * 122 * Indicates that this instance was acquired from {@link #sMessageCallbacksPool} as opposed to 123 * {@link #sPool} 124 */ 125 private static final int FLAG_ACQUIRED_FROM_MESSAGE_CALLBACKS_POOL = 1 << (MAX_ARGS + 2); 126 127 /** @see #mFlags */ 128 static final int MASK_EXPOSED_AS = LambdaType.MASK << (MAX_ARGS + 3); 129 130 /** @see #mFlags */ 131 static final int MASK_FUNC_TYPE = LambdaType.MASK << 132 (MAX_ARGS + 3 + LambdaType.MASK_BIT_COUNT); 133 134 /** 135 * Bit schema: 136 * AAAAAAAAABCDEEEEEEFFFFFF 137 * 138 * Where: 139 * A - whether {@link #mArgs arg} at corresponding index was specified at 140 * {@link #acquire creation time} (0) or {@link #invoke invocation time} (1) 141 * B - {@link #FLAG_RECYCLED} 142 * C - {@link #FLAG_RECYCLE_ON_USE} 143 * D - {@link #FLAG_ACQUIRED_FROM_MESSAGE_CALLBACKS_POOL} 144 * E - {@link LambdaType} representing the type of the lambda returned to the caller from a 145 * factory method 146 * F - {@link LambdaType} of {@link #mFunc} as resolved when calling a factory method 147 */ 148 int mFlags = 0; 149 150 151 @Override recycle()152 public void recycle() { 153 if (DEBUG) Log.i(LOG_TAG, this + ".recycle()"); 154 if (!isRecycled()) doRecycle(); 155 } 156 doRecycle()157 private void doRecycle() { 158 if (DEBUG) Log.i(LOG_TAG, this + ".doRecycle()"); 159 Pool pool = (mFlags & FLAG_ACQUIRED_FROM_MESSAGE_CALLBACKS_POOL) != 0 160 ? PooledLambdaImpl.sMessageCallbacksPool 161 : PooledLambdaImpl.sPool; 162 163 mFunc = null; 164 if (mArgs != null) Arrays.fill(mArgs, null); 165 mFlags = FLAG_RECYCLED; 166 mConstValue = 0L; 167 168 pool.release(this); 169 } 170 171 @Override invoke(Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9)172 R invoke(Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, 173 Object a8, Object a9) { 174 checkNotRecycled(); 175 if (DEBUG) { 176 Log.i(LOG_TAG, this + ".invoke(" 177 + commaSeparateFirstN( 178 new Object[] { a1, a2, a3, a4, a5, a6, a7, a8, a9 }, 179 LambdaType.decodeArgCount(getFlags(MASK_EXPOSED_AS))) 180 + ")"); 181 } 182 final boolean notUsed = fillInArg(a1) && fillInArg(a2) && fillInArg(a3) && fillInArg(a4) 183 && fillInArg(a5) && fillInArg(a6) && fillInArg(a7) && fillInArg(a8) 184 && fillInArg(a9); 185 int argCount = LambdaType.decodeArgCount(getFlags(MASK_FUNC_TYPE)); 186 if (argCount != LambdaType.MASK_ARG_COUNT) { 187 for (int i = 0; i < argCount; i++) { 188 if (mArgs[i] == ArgumentPlaceholder.INSTANCE) { 189 throw new IllegalStateException("Missing argument #" + i + " among " 190 + Arrays.toString(mArgs)); 191 } 192 } 193 } 194 try { 195 return doInvoke(); 196 } finally { 197 if (isRecycleOnUse()) doRecycle(); 198 if (!isRecycled()) { 199 int argsSize = ArrayUtils.size(mArgs); 200 for (int i = 0; i < argsSize; i++) { 201 popArg(i); 202 } 203 } 204 } 205 } 206 fillInArg(Object invocationArg)207 private boolean fillInArg(Object invocationArg) { 208 int argsSize = ArrayUtils.size(mArgs); 209 for (int i = 0; i < argsSize; i++) { 210 if (mArgs[i] == ArgumentPlaceholder.INSTANCE) { 211 mArgs[i] = invocationArg; 212 mFlags |= BitUtils.bitAt(i); 213 return true; 214 } 215 } 216 if (invocationArg != null && invocationArg != ArgumentPlaceholder.INSTANCE) { 217 throw new IllegalStateException("No more arguments expected for provided arg " 218 + invocationArg + " among " + Arrays.toString(mArgs)); 219 } 220 return false; 221 } 222 checkNotRecycled()223 private void checkNotRecycled() { 224 if (isRecycled()) throw new IllegalStateException("Instance is recycled: " + this); 225 } 226 227 @SuppressWarnings("unchecked") doInvoke()228 private R doInvoke() { 229 final int funcType = getFlags(MASK_FUNC_TYPE); 230 final int argCount = LambdaType.decodeArgCount(funcType); 231 final int returnType = LambdaType.decodeReturnType(funcType); 232 233 switch (argCount) { 234 case LambdaType.MASK_ARG_COUNT: { 235 switch (returnType) { 236 case LambdaType.ReturnType.INT: return (R) (Integer) getAsInt(); 237 case LambdaType.ReturnType.LONG: return (R) (Long) getAsLong(); 238 case LambdaType.ReturnType.DOUBLE: return (R) (Double) getAsDouble(); 239 default: return (R) mFunc; 240 } 241 } 242 case 0: { 243 switch (returnType) { 244 case LambdaType.ReturnType.VOID: { 245 ((Runnable) mFunc).run(); 246 return null; 247 } 248 case LambdaType.ReturnType.BOOLEAN: 249 case LambdaType.ReturnType.OBJECT: { 250 return (R) ((Supplier) mFunc).get(); 251 } 252 } 253 } break; 254 case 1: { 255 switch (returnType) { 256 case LambdaType.ReturnType.VOID: { 257 ((Consumer) mFunc).accept(popArg(0)); 258 return null; 259 } 260 case LambdaType.ReturnType.BOOLEAN: { 261 return (R) (Object) ((Predicate) mFunc).test(popArg(0)); 262 } 263 case LambdaType.ReturnType.OBJECT: { 264 return (R) ((Function) mFunc).apply(popArg(0)); 265 } 266 } 267 } break; 268 case 2: { 269 switch (returnType) { 270 case LambdaType.ReturnType.VOID: { 271 ((BiConsumer) mFunc).accept(popArg(0), popArg(1)); 272 return null; 273 } 274 case LambdaType.ReturnType.BOOLEAN: { 275 return (R) (Object) ((BiPredicate) mFunc).test(popArg(0), popArg(1)); 276 } 277 case LambdaType.ReturnType.OBJECT: { 278 return (R) ((BiFunction) mFunc).apply(popArg(0), popArg(1)); 279 } 280 } 281 } break; 282 case 3: { 283 switch (returnType) { 284 case LambdaType.ReturnType.VOID: { 285 ((TriConsumer) mFunc).accept(popArg(0), popArg(1), popArg(2)); 286 return null; 287 } 288 case LambdaType.ReturnType.BOOLEAN: { 289 return (R) (Object) ((TriPredicate) mFunc).test( 290 popArg(0), popArg(1), popArg(2)); 291 } 292 case LambdaType.ReturnType.OBJECT: { 293 return (R) ((TriFunction) mFunc).apply(popArg(0), popArg(1), popArg(2)); 294 } 295 } 296 } break; 297 case 4: { 298 switch (returnType) { 299 case LambdaType.ReturnType.VOID: { 300 ((QuadConsumer) mFunc).accept(popArg(0), popArg(1), popArg(2), popArg(3)); 301 return null; 302 } 303 case LambdaType.ReturnType.BOOLEAN: { 304 return (R) (Object) ((QuadPredicate) mFunc).test( 305 popArg(0), popArg(1), popArg(2), popArg(3)); 306 } 307 case LambdaType.ReturnType.OBJECT: { 308 return (R) ((QuadFunction) mFunc).apply( 309 popArg(0), popArg(1), popArg(2), popArg(3)); 310 } 311 } 312 } break; 313 314 case 5: { 315 switch (returnType) { 316 case LambdaType.ReturnType.VOID: { 317 ((QuintConsumer) mFunc).accept(popArg(0), popArg(1), 318 popArg(2), popArg(3), popArg(4)); 319 return null; 320 } 321 case LambdaType.ReturnType.BOOLEAN: { 322 return (R) (Object) ((QuintPredicate) mFunc).test( 323 popArg(0), popArg(1), popArg(2), popArg(3), popArg(4)); 324 } 325 case LambdaType.ReturnType.OBJECT: { 326 return (R) ((QuintFunction) mFunc).apply( 327 popArg(0), popArg(1), popArg(2), popArg(3), popArg(4)); 328 } 329 } 330 } break; 331 332 case 6: { 333 switch (returnType) { 334 case LambdaType.ReturnType.VOID: { 335 ((HexConsumer) mFunc).accept(popArg(0), popArg(1), 336 popArg(2), popArg(3), popArg(4), popArg(5)); 337 return null; 338 } 339 case LambdaType.ReturnType.BOOLEAN: { 340 return (R) (Object) ((HexPredicate) mFunc).test(popArg(0), 341 popArg(1), popArg(2), popArg(3), popArg(4), popArg(5)); 342 } 343 case LambdaType.ReturnType.OBJECT: { 344 return (R) ((HexFunction) mFunc).apply(popArg(0), popArg(1), 345 popArg(2), popArg(3), popArg(4), popArg(5)); 346 } 347 } 348 } break; 349 350 case 7: { 351 switch (returnType) { 352 case LambdaType.ReturnType.VOID: { 353 ((HeptConsumer) mFunc).accept(popArg(0), popArg(1), 354 popArg(2), popArg(3), popArg(4), 355 popArg(5), popArg(6)); 356 return null; 357 } 358 case LambdaType.ReturnType.BOOLEAN: { 359 return (R) (Object) ((HeptPredicate) mFunc).test(popArg(0), 360 popArg(1), popArg(2), popArg(3), 361 popArg(4), popArg(5), popArg(6)); 362 } 363 case LambdaType.ReturnType.OBJECT: { 364 return (R) ((HeptFunction) mFunc).apply(popArg(0), popArg(1), 365 popArg(2), popArg(3), popArg(4), 366 popArg(5), popArg(6)); 367 } 368 } 369 } break; 370 371 case 8: { 372 switch (returnType) { 373 case LambdaType.ReturnType.VOID: { 374 ((OctConsumer) mFunc).accept(popArg(0), popArg(1), 375 popArg(2), popArg(3), popArg(4), 376 popArg(5), popArg(6), popArg(7)); 377 return null; 378 } 379 case LambdaType.ReturnType.BOOLEAN: { 380 return (R) (Object) ((OctPredicate) mFunc).test(popArg(0), 381 popArg(1), popArg(2), popArg(3), 382 popArg(4), popArg(5), popArg(6), popArg(7)); 383 } 384 case LambdaType.ReturnType.OBJECT: { 385 return (R) ((OctFunction) mFunc).apply(popArg(0), popArg(1), 386 popArg(2), popArg(3), popArg(4), 387 popArg(5), popArg(6), popArg(7)); 388 } 389 } 390 } break; 391 392 case 9: { 393 switch (returnType) { 394 case LambdaType.ReturnType.VOID: { 395 ((NonaConsumer) mFunc).accept(popArg(0), popArg(1), 396 popArg(2), popArg(3), popArg(4), popArg(5), 397 popArg(6), popArg(7), popArg(8)); 398 return null; 399 } 400 case LambdaType.ReturnType.BOOLEAN: { 401 return (R) (Object) ((NonaPredicate) mFunc).test(popArg(0), 402 popArg(1), popArg(2), popArg(3), popArg(4), 403 popArg(5), popArg(6), popArg(7), popArg(8)); 404 } 405 case LambdaType.ReturnType.OBJECT: { 406 return (R) ((NonaFunction) mFunc).apply(popArg(0), popArg(1), 407 popArg(2), popArg(3), popArg(4), popArg(5), 408 popArg(6), popArg(7), popArg(8)); 409 } 410 } 411 } break; 412 } 413 throw new IllegalStateException("Unknown function type: " + LambdaType.toString(funcType)); 414 } 415 isConstSupplier()416 private boolean isConstSupplier() { 417 return LambdaType.decodeArgCount(getFlags(MASK_FUNC_TYPE)) == LambdaType.MASK_ARG_COUNT; 418 } 419 popArg(int index)420 private Object popArg(int index) { 421 Object result = mArgs[index]; 422 if (isInvocationArgAtIndex(index)) { 423 mArgs[index] = ArgumentPlaceholder.INSTANCE; 424 mFlags &= ~BitUtils.bitAt(index); 425 } 426 return result; 427 } 428 429 @Override toString()430 public String toString() { 431 if (isRecycled()) return "<recycled PooledLambda@" + hashCodeHex(this) + ">"; 432 433 StringBuilder sb = new StringBuilder(); 434 if (isConstSupplier()) { 435 sb.append(getFuncTypeAsString()).append("(").append(doInvoke()).append(")"); 436 } else { 437 Object func = mFunc; 438 if (func instanceof PooledLambdaImpl) { 439 sb.append(func); 440 } else { 441 sb.append(getFuncTypeAsString()).append("@").append(hashCodeHex(func)); 442 } 443 sb.append("("); 444 sb.append(commaSeparateFirstN(mArgs, 445 LambdaType.decodeArgCount(getFlags(MASK_FUNC_TYPE)))); 446 sb.append(")"); 447 } 448 return sb.toString(); 449 } 450 commaSeparateFirstN(@ullable Object[] arr, int n)451 private String commaSeparateFirstN(@Nullable Object[] arr, int n) { 452 if (arr == null) return ""; 453 return TextUtils.join(",", Arrays.copyOf(arr, n)); 454 } 455 hashCodeHex(Object o)456 private static String hashCodeHex(Object o) { 457 return Integer.toHexString(Objects.hashCode(o)); 458 } 459 getFuncTypeAsString()460 private String getFuncTypeAsString() { 461 if (isRecycled()) return "<recycled>"; 462 if (isConstSupplier()) return "supplier"; 463 String name = LambdaType.toString(getFlags(MASK_EXPOSED_AS)); 464 if (name.endsWith("Consumer")) return "consumer"; 465 if (name.endsWith("Function")) return "function"; 466 if (name.endsWith("Predicate")) return "predicate"; 467 if (name.endsWith("Supplier")) return "supplier"; 468 if (name.endsWith("Runnable")) return "runnable"; 469 return name; 470 } 471 472 /** 473 * Internal non-typesafe factory method for {@link PooledLambdaImpl} 474 */ acquire(Pool pool, Object func, int fNumArgs, int numPlaceholders, int fReturnType, Object a, Object b, Object c, Object d, Object e, Object f, Object g, Object h, Object i)475 static <E extends PooledLambda> E acquire(Pool pool, Object func, 476 int fNumArgs, int numPlaceholders, int fReturnType, Object a, Object b, Object c, 477 Object d, Object e, Object f, Object g, Object h, Object i) { 478 PooledLambdaImpl r = acquire(pool); 479 if (DEBUG) { 480 Log.i(LOG_TAG, 481 "acquire(this = @" + hashCodeHex(r) 482 + ", func = " + func 483 + ", fNumArgs = " + fNumArgs 484 + ", numPlaceholders = " + numPlaceholders 485 + ", fReturnType = " + LambdaType.ReturnType.toString(fReturnType) 486 + ", a = " + a 487 + ", b = " + b 488 + ", c = " + c 489 + ", d = " + d 490 + ", e = " + e 491 + ", f = " + f 492 + ", g = " + g 493 + ", h = " + h 494 + ", i = " + i 495 + ")"); 496 } 497 r.mFunc = Preconditions.checkNotNull(func); 498 r.setFlags(MASK_FUNC_TYPE, LambdaType.encode(fNumArgs, fReturnType)); 499 r.setFlags(MASK_EXPOSED_AS, LambdaType.encode(numPlaceholders, fReturnType)); 500 if (ArrayUtils.size(r.mArgs) < fNumArgs) r.mArgs = new Object[fNumArgs]; 501 setIfInBounds(r.mArgs, 0, a); 502 setIfInBounds(r.mArgs, 1, b); 503 setIfInBounds(r.mArgs, 2, c); 504 setIfInBounds(r.mArgs, 3, d); 505 setIfInBounds(r.mArgs, 4, e); 506 setIfInBounds(r.mArgs, 5, f); 507 setIfInBounds(r.mArgs, 6, g); 508 setIfInBounds(r.mArgs, 7, h); 509 setIfInBounds(r.mArgs, 8, i); 510 return (E) r; 511 } 512 acquireConstSupplier(int type)513 static PooledLambdaImpl acquireConstSupplier(int type) { 514 PooledLambdaImpl r = acquire(PooledLambdaImpl.sPool); 515 int lambdaType = LambdaType.encode(LambdaType.MASK_ARG_COUNT, type); 516 r.setFlags(PooledLambdaImpl.MASK_FUNC_TYPE, lambdaType); 517 r.setFlags(PooledLambdaImpl.MASK_EXPOSED_AS, lambdaType); 518 return r; 519 } 520 acquire(Pool pool)521 static PooledLambdaImpl acquire(Pool pool) { 522 PooledLambdaImpl r = pool.acquire(); 523 if (r == null) r = new PooledLambdaImpl(); 524 r.mFlags &= ~FLAG_RECYCLED; 525 r.setFlags(FLAG_ACQUIRED_FROM_MESSAGE_CALLBACKS_POOL, 526 pool == sMessageCallbacksPool ? 1 : 0); 527 return r; 528 } 529 setIfInBounds(Object[] array, int i, Object a)530 private static void setIfInBounds(Object[] array, int i, Object a) { 531 if (i < ArrayUtils.size(array)) array[i] = a; 532 } 533 534 @Override 535 public OmniFunction<Object, Object, Object, Object, Object, Object, Object, Object, Object, negate()536 R> negate() { 537 throw new UnsupportedOperationException(); 538 } 539 540 @Override 541 public <V> OmniFunction<Object, Object, Object, Object, Object, Object, Object, Object, Object, andThen(Function<? super R, ? extends V> after)542 V> andThen(Function<? super R, ? extends V> after) { 543 throw new UnsupportedOperationException(); 544 } 545 546 @Override getAsDouble()547 public double getAsDouble() { 548 return Double.longBitsToDouble(mConstValue); 549 } 550 551 @Override getAsInt()552 public int getAsInt() { 553 return (int) mConstValue; 554 } 555 556 @Override getAsLong()557 public long getAsLong() { 558 return mConstValue; 559 } 560 561 @Override 562 public OmniFunction<Object, Object, Object, Object, Object, Object, Object, Object, Object, recycleOnUse()563 R> recycleOnUse() { 564 if (DEBUG) Log.i(LOG_TAG, this + ".recycleOnUse()"); 565 mFlags |= FLAG_RECYCLE_ON_USE; 566 return this; 567 } 568 isRecycled()569 private boolean isRecycled() { 570 return (mFlags & FLAG_RECYCLED) != 0; 571 } 572 isRecycleOnUse()573 private boolean isRecycleOnUse() { 574 return (mFlags & FLAG_RECYCLE_ON_USE) != 0; 575 } 576 isInvocationArgAtIndex(int argIndex)577 private boolean isInvocationArgAtIndex(int argIndex) { 578 return (mFlags & (1 << argIndex)) != 0; 579 } 580 getFlags(int mask)581 int getFlags(int mask) { 582 return unmask(mask, mFlags); 583 } 584 setFlags(int mask, int value)585 void setFlags(int mask, int value) { 586 mFlags &= ~mask; 587 mFlags |= mask(mask, value); 588 } 589 590 /** 591 * 0xFF000, 0xAB -> 0xAB000 592 */ mask(int mask, int value)593 private static int mask(int mask, int value) { 594 return (value << Integer.numberOfTrailingZeros(mask)) & mask; 595 } 596 597 /** 598 * 0xFF000, 0xAB123 -> 0xAB 599 */ unmask(int mask, int bits)600 private static int unmask(int mask, int bits) { 601 return (bits & mask) / (1 << Integer.numberOfTrailingZeros(mask)); 602 } 603 604 /** 605 * Contract for encoding a supported lambda type in {@link #MASK_BIT_COUNT} bits 606 */ 607 static class LambdaType { 608 public static final int MASK_ARG_COUNT = 0b1111; 609 public static final int MASK_RETURN_TYPE = 0b1110000; 610 public static final int MASK = MASK_ARG_COUNT | MASK_RETURN_TYPE; 611 public static final int MASK_BIT_COUNT = 7; 612 encode(int argCount, int returnType)613 static int encode(int argCount, int returnType) { 614 return mask(MASK_ARG_COUNT, argCount) | mask(MASK_RETURN_TYPE, returnType); 615 } 616 decodeArgCount(int type)617 static int decodeArgCount(int type) { 618 return type & MASK_ARG_COUNT; 619 } 620 decodeReturnType(int type)621 static int decodeReturnType(int type) { 622 return unmask(MASK_RETURN_TYPE, type); 623 } 624 toString(int type)625 static String toString(int type) { 626 int argCount = decodeArgCount(type); 627 int returnType = decodeReturnType(type); 628 if (argCount == 0) { 629 if (returnType == ReturnType.VOID) return "Runnable"; 630 if (returnType == ReturnType.OBJECT || returnType == ReturnType.BOOLEAN) { 631 return "Supplier"; 632 } 633 } 634 return argCountPrefix(argCount) + ReturnType.lambdaSuffix(returnType); 635 } 636 argCountPrefix(int argCount)637 private static String argCountPrefix(int argCount) { 638 switch (argCount) { 639 case MASK_ARG_COUNT: return ""; 640 case 0: return ""; 641 case 1: return ""; 642 case 2: return "Bi"; 643 case 3: return "Tri"; 644 case 4: return "Quad"; 645 case 5: return "Quint"; 646 case 6: return "Hex"; 647 case 7: return "Hept"; 648 case 8: return "Oct"; 649 case 9: return "Nona"; 650 default: return "" + argCount + "arg"; 651 } 652 } 653 654 static class ReturnType { 655 public static final int VOID = 1; 656 public static final int BOOLEAN = 2; 657 public static final int OBJECT = 3; 658 public static final int INT = 4; 659 public static final int LONG = 5; 660 public static final int DOUBLE = 6; 661 toString(int returnType)662 static String toString(int returnType) { 663 switch (returnType) { 664 case VOID: return "VOID"; 665 case BOOLEAN: return "BOOLEAN"; 666 case OBJECT: return "OBJECT"; 667 case INT: return "INT"; 668 case LONG: return "LONG"; 669 case DOUBLE: return "DOUBLE"; 670 default: return "" + returnType; 671 } 672 } 673 lambdaSuffix(int type)674 static String lambdaSuffix(int type) { 675 return prefix(type) + suffix(type); 676 } 677 prefix(int type)678 private static String prefix(int type) { 679 switch (type) { 680 case INT: return "Int"; 681 case LONG: return "Long"; 682 case DOUBLE: return "Double"; 683 default: return ""; 684 } 685 } 686 suffix(int type)687 private static String suffix(int type) { 688 switch (type) { 689 case VOID: return "Consumer"; 690 case BOOLEAN: return "Predicate"; 691 case OBJECT: return "Function"; 692 default: return "Supplier"; 693 } 694 } 695 } 696 } 697 } 698