1+ package org .lmdbjava ;
2+
3+ import java .text .DecimalFormat ;
4+ import java .text .NumberFormat ;
5+
6+ /**
7+ * A {@code BinaryByteUnit} represents power-of-two byte sizes at a given unit of granularity and
8+ * provides utility methods to convert across units. A {@code BinaryByteUnit} does not maintain
9+ * byte size information, but only helps organize and use byte size representations that may be
10+ * maintained separately across various contexts.
11+ *
12+ * @author Jake Wharton
13+ */
14+ public enum ByteUnit {
15+
16+ /** Byte unit representing one byte. */
17+ BYTES {
18+ @ Override public long convert (long sourceCount , ByteUnit sourceUnit ) {
19+ return sourceUnit .toBytes (sourceCount );
20+ }
21+
22+ @ Override public long toBytes (long count ) {
23+ return count ;
24+ }
25+
26+ @ Override public long toKibibytes (long count ) {
27+ return count / (KB / B );
28+ }
29+
30+ @ Override public long toMebibytes (long count ) {
31+ return count / (MB / B );
32+ }
33+
34+ @ Override public long toGibibytes (long count ) {
35+ return count / (GB / B );
36+ }
37+
38+ @ Override public long toTebibytes (long count ) {
39+ return count / (TB / B );
40+ }
41+
42+ @ Override public long toPebibytes (long count ) {
43+ return count / (PB / B );
44+ }
45+ },
46+
47+ /** A byte unit representing 1024 bytes. */
48+ KIBIBYTES {
49+ @ Override public long convert (long sourceCount , ByteUnit sourceUnit ) {
50+ return sourceUnit .toKibibytes (sourceCount );
51+ }
52+
53+ @ Override public long toBytes (long count ) {
54+ return multiply (count , KB / B , MAX / (KB / B ));
55+ }
56+
57+ @ Override public long toKibibytes (long count ) {
58+ return count ;
59+ }
60+
61+ @ Override public long toMebibytes (long count ) {
62+ return count / (MB / KB );
63+ }
64+
65+ @ Override public long toGibibytes (long count ) {
66+ return count / (GB / KB );
67+ }
68+
69+ @ Override public long toTebibytes (long count ) {
70+ return count / (TB / KB );
71+ }
72+
73+ @ Override public long toPebibytes (long count ) {
74+ return count / (PB / KB );
75+ }
76+ },
77+
78+ /** A byte unit representing 1024 kibibytes. */
79+ MEBIBYTES {
80+ @ Override public long convert (long sourceCount , ByteUnit sourceUnit ) {
81+ return sourceUnit .toMebibytes (sourceCount );
82+ }
83+
84+ @ Override public long toBytes (long count ) {
85+ return multiply (count , MB / B , MAX / (MB / B ));
86+ }
87+
88+ @ Override public long toKibibytes (long count ) {
89+ return multiply (count , MB / KB , MAX / (MB / KB ));
90+ }
91+
92+ @ Override public long toMebibytes (long count ) {
93+ return count ;
94+ }
95+
96+ @ Override public long toGibibytes (long count ) {
97+ return count / (GB / MB );
98+ }
99+
100+ @ Override public long toTebibytes (long count ) {
101+ return count / (TB / MB );
102+ }
103+
104+ @ Override public long toPebibytes (long count ) {
105+ return count / (PB / MB );
106+ }
107+ },
108+
109+ /** A byte unit representing 1024 mebibytes. */
110+ GIBIBYTES {
111+ @ Override public long convert (long sourceCount , ByteUnit sourceUnit ) {
112+ return sourceUnit .toGibibytes (sourceCount );
113+ }
114+
115+ @ Override public long toBytes (long count ) {
116+ return multiply (count , GB / B , MAX / (GB / B ));
117+ }
118+
119+ @ Override public long toKibibytes (long count ) {
120+ return multiply (count , GB / KB , MAX / (GB / KB ));
121+ }
122+
123+ @ Override public long toMebibytes (long count ) {
124+ return multiply (count , GB / MB , MAX / (GB / MB ));
125+ }
126+
127+ @ Override public long toGibibytes (long count ) {
128+ return count ;
129+ }
130+
131+ @ Override public long toTebibytes (long count ) {
132+ return count / (TB / GB );
133+ }
134+
135+ @ Override public long toPebibytes (long count ) {
136+ return count / (PB / GB );
137+ }
138+ },
139+
140+ /** A byte unit representing 1024 gibibytes. */
141+ TEBIBYTES {
142+ @ Override public long convert (long sourceCount , ByteUnit sourceUnit ) {
143+ return sourceUnit .toTebibytes (sourceCount );
144+ }
145+
146+ @ Override public long toBytes (long count ) {
147+ return multiply (count , TB / B , MAX / (TB / B ));
148+ }
149+
150+ @ Override public long toKibibytes (long count ) {
151+ return multiply (count , TB / KB , MAX / (TB / KB ));
152+ }
153+
154+ @ Override public long toMebibytes (long count ) {
155+ return multiply (count , TB / MB , MAX / (TB / MB ));
156+ }
157+
158+ @ Override public long toGibibytes (long count ) {
159+ return multiply (count , TB / GB , MAX / (TB / GB ));
160+ }
161+
162+ @ Override public long toTebibytes (long count ) {
163+ return count ;
164+ }
165+
166+ @ Override public long toPebibytes (long count ) {
167+ return count / (PB / TB );
168+ }
169+ },
170+
171+ /** A byte unit representing 1024 tebibytes. */
172+ PEBIBYTES {
173+ @ Override public long convert (long sourceCount , ByteUnit sourceUnit ) {
174+ return sourceUnit .toPebibytes (sourceCount );
175+ }
176+
177+ @ Override public long toBytes (long count ) {
178+ return multiply (count , PB / B , MAX / (PB / B ));
179+ }
180+
181+ @ Override public long toKibibytes (long count ) {
182+ return multiply (count , PB / KB , MAX / (PB / KB ));
183+ }
184+
185+ @ Override public long toMebibytes (long count ) {
186+ return multiply (count , PB / MB , MAX / (PB / MB ));
187+ }
188+
189+ @ Override public long toGibibytes (long count ) {
190+ return multiply (count , PB / GB , MAX / (PB / GB ));
191+ }
192+
193+ @ Override public long toTebibytes (long count ) {
194+ return multiply (count , PB / TB , MAX / (PB / TB ));
195+ }
196+
197+ @ Override public long toPebibytes (long count ) {
198+ return count ;
199+ }
200+ };
201+
202+ private static final long B = 1L ;
203+ private static final long KB = B * 1024L ;
204+ private static final long MB = KB * 1024L ;
205+ private static final long GB = MB * 1024L ;
206+ private static final long TB = GB * 1024L ;
207+ private static final long PB = TB * 1024L ;
208+
209+ private static final long MAX = Long .MAX_VALUE ;
210+
211+ /**
212+ * Converts the given size in the given unit to bytes. Conversions with arguments that would
213+ * numerically overflow saturate to {@code Long.MIN_VALUE} if negative or {@code Long.MAX_VALUE}
214+ * if positive.
215+ *
216+ * @param count the bit count
217+ * @return the converted count, or {@code Long.MIN_VALUE} if conversion would negatively
218+ * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
219+ */
220+ public long toBytes (long count ) { throw new AbstractMethodError (); }
221+
222+ /**
223+ * Converts the given size in the given unit to this unit. Conversions from finer to coarser
224+ * granularities truncate, so lose precision. For example, converting from {@code 999} bytes to
225+ * kibibytes results in {@code 0}. Conversions from coarser to finer granularities with arguments
226+ * that would numerically overflow saturate to {@code Long.MIN_VALUE} if negative or
227+ * {@code Long.MAX_VALUE} if positive.
228+ * <p>
229+ * For example, to convert 10 kilobytes to bytes, use:
230+ * {@code ByteUnit.KIBIBYTES.convert(10, ByteUnit.BYTES)}
231+ *
232+ * @param sourceCount the size in the given {@code sourceUnit}.
233+ * @param sourceUnit the unit of the {@code sourceCount} argument.
234+ * @return the converted size in this unit, or {@code Long.MIN_VALUE} if conversion would
235+ * negatively overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
236+ */
237+ public long convert (long sourceCount , ByteUnit sourceUnit ) {
238+ throw new AbstractMethodError ();
239+ }
240+
241+ /**
242+ * Equivalent to {@link #convert(long, ByteUnit) KIBIBYTES.convert(count, this)}.
243+ * @param count the bit count
244+ * @return the converted count, or {@code Long.MIN_VALUE} if conversion would negatively
245+ * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
246+ */
247+ public long toKibibytes (long count ) {
248+ throw new AbstractMethodError ();
249+ }
250+
251+ /**
252+ * Equivalent to {@link #convert(long, ByteUnit) MEBIBYTES.convert(count, this)}.
253+ * @param count the bit count
254+ * @return the converted count, or {@code Long.MIN_VALUE} if conversion would negatively
255+ * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
256+ */
257+ public long toMebibytes (long count ) {
258+ throw new AbstractMethodError ();
259+ }
260+
261+ /**
262+ * Equivalent to {@link #convert(long, ByteUnit) GIBIBYTES.convert(count, this)}.
263+ * @param count the bit count
264+ * @return the converted count, or {@code Long.MIN_VALUE} if conversion would negatively
265+ * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
266+ */
267+ public long toGibibytes (long count ) {
268+ throw new AbstractMethodError ();
269+ }
270+
271+ /**
272+ * Equivalent to {@link #convert(long, ByteUnit) TEBIBYTES.convert(count, this)}.
273+ * @param count the bit count
274+ * @return the converted count, or {@code Long.MIN_VALUE} if conversion would negatively
275+ * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
276+ */
277+ public long toTebibytes (long count ) {
278+ throw new AbstractMethodError ();
279+ }
280+
281+ /**
282+ * Equivalent to {@link #convert(long, ByteUnit) PEBIBYTES.convert(count, this)}.
283+ * @param count the bit count
284+ * @return the converted count, or {@code Long.MIN_VALUE} if conversion would negatively
285+ * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
286+ */
287+ public long toPebibytes (long count ) {
288+ throw new AbstractMethodError ();
289+ }
290+
291+ private static final String [] UNITS = { "B" , "KiB" , "MiB" , "GiB" , "TiB" , "PiB" };
292+
293+ /**
294+ * Return {@code bytes} as human-readable size string (e.g., "1.2 GiB". This will use a default
295+ * {@link DecimalFormat} instance for formatting the number.
296+ */
297+ public static String format (long bytes ) {
298+ return format (bytes , new DecimalFormat (DEFAULT_FORMAT_PATTERN ));
299+ }
300+
301+ /**
302+ * Return {@code bytes} as human-readable size string (e.g., "1.2 GiB". This will use a
303+ * {@link DecimalFormat} instance with {@code pattern} for formatting the number.
304+ */
305+ public static String format (long bytes , String pattern ) {
306+ return format (bytes , new DecimalFormat (pattern ));
307+ }
308+
309+ /**
310+ * Return {@code bytes} as human-readable size string (e.g., "1.2 GiB". This will use {@code
311+ * format} for formatting the number.
312+ */
313+ public static String format (long bytes , NumberFormat format ) {
314+ if (bytes < 0 ) {
315+ throw new IllegalArgumentException ("bytes < 0: " + bytes );
316+ }
317+
318+ int unitIndex = 0 ;
319+ double count = bytes ;
320+ while (count >= 1024d && unitIndex < UNITS .length - 1 ) {
321+ count /= 1024d ;
322+ unitIndex += 1 ;
323+ }
324+ return format .format (count ) + ' ' + UNITS [unitIndex ];
325+ }
326+
327+ static final String DEFAULT_FORMAT_PATTERN = "#,##0.#" ;
328+
329+ /** Multiply {@code size} by {@code factor} accounting for overflow. */
330+ private static long multiply (long size , long factor , long over ) {
331+ if (size > over ) {
332+ return Long .MAX_VALUE ;
333+ }
334+ if (size < -over ) {
335+ return Long .MIN_VALUE ;
336+ }
337+ return size * factor ;
338+ }
339+ }
0 commit comments