1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.util.internal;
17
18 import java.util.ArrayList;
19 import java.util.List;
20
21 import static io.netty.util.internal.ObjectUtil.checkPositive;
22 import static java.lang.Math.max;
23 import static java.lang.Math.min;
24
25
26
27
28 public final class AdaptiveCalculator {
29 private static final int INDEX_INCREMENT = 4;
30 private static final int INDEX_DECREMENT = 1;
31
32 private static final int[] SIZE_TABLE;
33
34 static {
35 List<Integer> sizeTable = new ArrayList<Integer>();
36 for (int i = 16; i < 512; i += 16) {
37 sizeTable.add(i);
38 }
39
40
41 for (int i = 512; i > 0; i <<= 1) {
42 sizeTable.add(i);
43 }
44
45 SIZE_TABLE = new int[sizeTable.size()];
46 for (int i = 0; i < SIZE_TABLE.length; i ++) {
47 SIZE_TABLE[i] = sizeTable.get(i);
48 }
49 }
50
51 private static int getSizeTableIndex(final int size) {
52 for (int low = 0, high = SIZE_TABLE.length - 1;;) {
53 if (high < low) {
54 return low;
55 }
56 if (high == low) {
57 return high;
58 }
59
60 int mid = low + high >>> 1;
61 int a = SIZE_TABLE[mid];
62 int b = SIZE_TABLE[mid + 1];
63 if (size > b) {
64 low = mid + 1;
65 } else if (size < a) {
66 high = mid - 1;
67 } else if (size == a) {
68 return mid;
69 } else {
70 return mid + 1;
71 }
72 }
73 }
74
75 private final int minIndex;
76 private final int maxIndex;
77 private final int minCapacity;
78 private final int maxCapacity;
79 private int index;
80 private int nextSize;
81 private boolean decreaseNow;
82
83 public AdaptiveCalculator(int minimum, int initial, int maximum) {
84 checkPositive(minimum, "minimum");
85 if (initial < minimum) {
86 throw new IllegalArgumentException("initial: " + initial);
87 }
88 if (maximum < initial) {
89 throw new IllegalArgumentException("maximum: " + maximum);
90 }
91
92 int minIndex = getSizeTableIndex(minimum);
93 if (SIZE_TABLE[minIndex] < minimum) {
94 this.minIndex = minIndex + 1;
95 } else {
96 this.minIndex = minIndex;
97 }
98
99 int maxIndex = getSizeTableIndex(maximum);
100 if (SIZE_TABLE[maxIndex] > maximum) {
101 this.maxIndex = maxIndex - 1;
102 } else {
103 this.maxIndex = maxIndex;
104 }
105
106 int initialIndex = getSizeTableIndex(initial);
107 if (SIZE_TABLE[initialIndex] > initial) {
108 this.index = initialIndex - 1;
109 } else {
110 this.index = initialIndex;
111 }
112 this.minCapacity = minimum;
113 this.maxCapacity = maximum;
114 nextSize = max(SIZE_TABLE[index], minCapacity);
115 }
116
117 public void record(int size) {
118 if (size <= SIZE_TABLE[max(0, index - INDEX_DECREMENT)]) {
119 if (decreaseNow) {
120 index = max(index - INDEX_DECREMENT, minIndex);
121 nextSize = max(SIZE_TABLE[index], minCapacity);
122 decreaseNow = false;
123 } else {
124 decreaseNow = true;
125 }
126 } else if (size >= nextSize) {
127 index = min(index + INDEX_INCREMENT, maxIndex);
128 nextSize = min(SIZE_TABLE[index], maxCapacity);
129 decreaseNow = false;
130 }
131 }
132
133 public int nextSize() {
134 return nextSize;
135 }
136 }