1 /***
2 * Copyright 2003-2010 Terracotta, Inc.
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 net.sf.ehcache.config;
18
19 /***
20 * Memory unit: byte-based
21 * @author Alex Snaps
22 */
23 public enum MemoryUnit {
24
25 /***
26 * BYTES
27 */
28 BYTES(0, 'b') {
29 /***
30 * {@inheritDoc}
31 */
32 public long toBytes(final long amount) { return amount; }
33 /***
34 * {@inheritDoc}
35 */
36 public long toKiloBytes(final long amount) { return safeShift(amount, KILOBYTES.offset - BYTES.offset); }
37 /***
38 * {@inheritDoc}
39 */
40 public long toMegaBytes(final long amount) { return safeShift(amount, MEGABYTES.offset - BYTES.offset); }
41 /***
42 * {@inheritDoc}
43 */
44 public long toGigaBytes(final long amount) { return safeShift(amount, GIGABYTES.offset - BYTES.offset); }
45 },
46
47 /***
48 * KILOBYTES (1024 BYTES)
49 */
50 KILOBYTES(BYTES.offset + MemoryUnit.OFFSET, 'k') {
51 /***
52 * {@inheritDoc}
53 */
54 public long toBytes(final long amount) { return safeShift(amount, BYTES.offset - KILOBYTES.offset); }
55 /***
56 * {@inheritDoc}
57 */
58 public long toKiloBytes(final long amount) { return amount; }
59 /***
60 * {@inheritDoc}
61 */
62 public long toMegaBytes(final long amount) { return safeShift(amount, MEGABYTES.offset - KILOBYTES.offset); }
63 /***
64 * {@inheritDoc}
65 */
66 public long toGigaBytes(final long amount) { return safeShift(amount, GIGABYTES.offset - KILOBYTES.offset); }
67 },
68
69 /***
70 * MEGABYTES (1024 KILOBYTES)
71 */
72 MEGABYTES(KILOBYTES.offset + MemoryUnit.OFFSET, 'm') {
73 /***
74 * {@inheritDoc}
75 */
76 public long toBytes(final long amount) { return safeShift(amount, BYTES.offset - MEGABYTES.offset); }
77 /***
78 * {@inheritDoc}
79 */
80 public long toKiloBytes(final long amount) { return safeShift(amount, KILOBYTES.offset - MEGABYTES.offset); }
81 /***
82 * {@inheritDoc}
83 */
84 public long toMegaBytes(final long amount) { return amount; }
85 /***
86 * {@inheritDoc}
87 */
88 public long toGigaBytes(final long amount) { return safeShift(amount, GIGABYTES.offset - MEGABYTES.offset); }
89 },
90
91 /***
92 * GIGABYTES (1024 MEGABYTES)
93 */
94 GIGABYTES(MEGABYTES.offset + MemoryUnit.OFFSET, 'g') {
95 /***
96 * {@inheritDoc}
97 */
98 public long toBytes(final long amount) { return safeShift(amount, BYTES.offset - GIGABYTES.offset); }
99 /***
100 * {@inheritDoc}
101 */
102 public long toKiloBytes(final long amount) { return safeShift(amount, KILOBYTES.offset - GIGABYTES.offset); }
103 /***
104 * {@inheritDoc}
105 */
106 public long toMegaBytes(final long amount) { return safeShift(amount, MEGABYTES.offset - GIGABYTES.offset); }
107 /***
108 * {@inheritDoc}
109 */
110 public long toGigaBytes(final long amount) { return amount; }
111 };
112
113 private static final int OFFSET = 10;
114
115 private final int offset;
116 private final char unit;
117
118 private MemoryUnit(final int offset, final char unit) {
119 this.offset = offset;
120 this.unit = unit;
121 }
122
123 /***
124 * Retrieves the unit character for the MemoryUnit
125 * @return the unit character
126 */
127 public char getUnit() {
128 return unit;
129 }
130
131 /***
132 * returns the amount in bytes
133 * @param amount of the unit
134 * @return value in bytes
135 */
136 public abstract long toBytes(long amount);
137 /***
138 * returns the amount in kilobytes
139 * @param amount of the unit
140 * @return value in kilobytes
141 */
142 public abstract long toKiloBytes(long amount);
143 /***
144 * returns the amount in megabytes
145 * @param amount of the unit
146 * @return value in megabytes
147 */
148 public abstract long toMegaBytes(long amount);
149 /***
150 * returns the amount in gigabytes
151 * @param amount of the unit
152 * @return value in gigabytes
153 */
154 public abstract long toGigaBytes(long amount);
155
156 /***
157 * Human readable value, with the added unit character as a suffix
158 * @param amount the amount to print
159 * @return the String representation
160 */
161 public String toString(final long amount) {
162 return amount + Character.toString(this.unit);
163 }
164
165 /***
166 * Returns the MemoryUnit instance based on provided char
167 * @param unit the unit to look for
168 * @return the MemoryUnit instance matching the unit
169 * @throws IllegalArgumentException if no matching MemoryUnit matching the char
170 */
171 public static MemoryUnit forUnit(final char unit) throws IllegalArgumentException {
172 for (MemoryUnit memoryUnit : values()) {
173 if (memoryUnit.unit == unit) {
174 return memoryUnit;
175 }
176 }
177 throw new IllegalArgumentException("'" + unit + "' suffix doesn't match any SizeUnit");
178 }
179
180 /***
181 * Parses the unit part of a String, if no unit char available, returns {@link MemoryUnit#BYTES}
182 * @param value the String representation of an amount of memory
183 * @return the MemoryUnit instance, or BYTES if none
184 */
185 public static MemoryUnit parseUnit(final String value) {
186 if (hasUnit(value)) {
187 return forUnit(Character.toLowerCase(value.charAt(value.length() - 1)));
188 }
189 return BYTES;
190 }
191
192 /***
193 * Parses the amount represented by the string, without caring for the unit
194 * @param value the String representation of an amount of memory
195 * @return the amount of mem in the unit represented by the potential unit char
196 * @throws NumberFormatException if not a number (with potential unit char stripped)
197 */
198 public static long parseAmount(final String value) throws NumberFormatException {
199 if (value == null) {
200 throw new NullPointerException("Value can't be null!");
201 }
202
203 if (value.length() == 0) {
204 throw new IllegalArgumentException("Value can't be an empty string!");
205 }
206
207 if (hasUnit(value)) {
208 return Long.parseLong(value.substring(0, value.length() - 1).trim());
209 } else {
210 return Long.parseLong(value);
211 }
212 }
213
214 /***
215 * Parses the string for its content, returning the represented value in bytes
216 * @param value the String representation of an amount of memory
217 * @return the amount of bytes represented by the string
218 * @throws NumberFormatException if not a number (with potential unit char stripped)
219 * @throws IllegalArgumentException if no matching MemoryUnit matching the char
220 */
221 public static long parseSizeInBytes(final String value) throws NumberFormatException, IllegalArgumentException {
222 if (value.length() == 0) {
223 throw new IllegalArgumentException("Value can't be an empty string!");
224 }
225
226 MemoryUnit memoryUnit = parseUnit(value);
227 return memoryUnit.toBytes(parseAmount(value));
228 }
229
230 private static boolean hasUnit(final String value) {
231 if (value.length() > 0) {
232 char potentialUnit = value.charAt(value.length() - 1);
233 return potentialUnit < '0' || potentialUnit > '9';
234 }
235 return false;
236 }
237
238 private static long safeShift(final long unit, final long shift) {
239 if (shift > 0) {
240 return unit >>> shift;
241 } else if (shift <= -1 * Long.numberOfLeadingZeros(unit)) {
242 return Long.MAX_VALUE;
243 } else {
244 return unit << -shift;
245 }
246 }
247 }