EMMA Coverage Report (generated Sun Mar 01 22:06:14 CET 2015)
[all classes][org.h2.mvstore]

COVERAGE SUMMARY FOR SOURCE FILE [DataUtils.java]

nameclass, %method, %block, %line, %
DataUtils.java100% (2/2)87%  (41/47)87%  (1192/1377)86%  (248/287)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class DataUtils$MapEntry100% (1/1)75%  (3/4)83%  (15/18)86%  (6/7)
setValue (Object): Object 0%   (0/1)0%   (0/3)0%   (0/1)
DataUtils$MapEntry (Object, Object): void 100% (1/1)100% (9/9)100% (4/4)
getKey (): Object 100% (1/1)100% (3/3)100% (1/1)
getValue (): Object 100% (1/1)100% (3/3)100% (1/1)
     
class DataUtils100% (1/1)88%  (38/43)87%  (1177/1359)86%  (242/280)
DataUtils (): void 0%   (0/1)0%   (0/3)0%   (0/2)
ensureCapacity (ByteBuffer, int): ByteBuffer 0%   (0/1)0%   (0/12)0%   (0/4)
grow (ByteBuffer, int): ByteBuffer 0%   (0/1)0%   (0/30)0%   (0/7)
newConcurrentModificationException (String): ConcurrentModificationException 0%   (0/1)0%   (0/9)0%   (0/1)
writeStringData (ByteBuffer, String, int): ByteBuffer 0%   (0/1)0%   (0/73)0%   (0/12)
parseHexInt (String): int 100% (1/1)25%  (5/20)33%  (1/3)
newBytes (int): byte [] 100% (1/1)27%  (7/26)43%  (3/7)
readHexLong (Map, String, long): long 100% (1/1)56%  (19/34)75%  (6/8)
getErrorCode (String): int 100% (1/1)89%  (25/28)71%  (5/7)
readFully (FileChannel, long, ByteBuffer): void 100% (1/1)95%  (59/62)86%  (12/14)
<static initializer> 100% (1/1)100% (10/10)100% (3/3)
appendMap (StringBuilder, HashMap): StringBuilder 100% (1/1)100% (25/25)100% (6/6)
appendMap (StringBuilder, String, Object): void 100% (1/1)100% (81/81)100% (18/18)
checkArgument (boolean, String, Object []): void 100% (1/1)100% (7/7)100% (3/3)
copyExcept (Object, Object, int, int): void 100% (1/1)100% (26/26)100% (5/5)
copyWithGap (Object, Object, int, int): void 100% (1/1)100% (22/22)100% (5/5)
encodeLength (int): int 100% (1/1)100% (36/36)100% (11/11)
formatMessage (int, String, Object []): String 100% (1/1)100% (69/69)100% (8/8)
getCheckValue (int): short 100% (1/1)100% (7/7)100% (1/1)
getFletcher32 (byte [], int): int 100% (1/1)100% (107/107)100% (15/15)
getPageChunkId (long): int 100% (1/1)100% (5/5)100% (1/1)
getPageMaxLength (long): int 100% (1/1)100% (24/24)100% (4/4)
getPageOffset (long): int 100% (1/1)100% (5/5)100% (1/1)
getPagePos (int, int, int, int): long 100% (1/1)100% (27/27)100% (5/5)
getPageType (long): int 100% (1/1)100% (5/5)100% (1/1)
getVarIntLen (int): int 100% (1/1)100% (26/26)100% (9/9)
getVarLongLen (long): int 100% (1/1)100% (14/14)100% (5/5)
initCause (Exception, Object []): Exception 100% (1/1)100% (21/21)100% (6/6)
newIllegalArgumentException (String, Object []): IllegalArgumentException 100% (1/1)100% (11/11)100% (1/1)
newIllegalStateException (int, String, Object []): IllegalStateException 100% (1/1)100% (11/11)100% (1/1)
newUnsupportedOperationException (String): UnsupportedOperationException 100% (1/1)100% (9/9)100% (1/1)
parseHexLong (String): long 100% (1/1)100% (39/39)100% (5/5)
parseMap (String): HashMap 100% (1/1)100% (107/107)100% (27/27)
readHexInt (HashMap, String, int): int 100% (1/1)100% (36/36)100% (8/8)
readString (ByteBuffer, int): String 100% (1/1)100% (68/68)100% (9/9)
readVarInt (ByteBuffer): int 100% (1/1)100% (11/11)100% (4/4)
readVarIntRest (ByteBuffer, int): int 100% (1/1)100% (68/68)100% (14/14)
readVarLong (ByteBuffer): long 100% (1/1)100% (40/40)100% (10/10)
writeFully (FileChannel, long, ByteBuffer): void 100% (1/1)100% (45/45)100% (8/8)
writeVarInt (ByteBuffer, int): void 100% (1/1)100% (24/24)100% (5/5)
writeVarInt (OutputStream, int): void 100% (1/1)100% (22/22)100% (5/5)
writeVarLong (ByteBuffer, long): void 100% (1/1)100% (28/28)100% (5/5)
writeVarLong (OutputStream, long): void 100% (1/1)100% (26/26)100% (5/5)

1/*
2 * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
3 * and the EPL 1.0 (http://h2database.com/html/license.html).
4 * Initial Developer: H2 Group
5 */
6package org.h2.mvstore;
7 
8import java.io.EOFException;
9import java.io.IOException;
10import java.io.OutputStream;
11import java.nio.ByteBuffer;
12import java.nio.channels.FileChannel;
13import java.nio.charset.Charset;
14import java.text.MessageFormat;
15import java.util.ArrayList;
16import java.util.Collections;
17import java.util.ConcurrentModificationException;
18import java.util.HashMap;
19import java.util.Map;
20 
21import org.h2.engine.Constants;
22import org.h2.util.New;
23 
24/**
25 * Utility methods
26 */
27public class DataUtils {
28 
29    /**
30     * An error occurred while reading from the file.
31     */
32    public static final int ERROR_READING_FAILED = 1;
33 
34    /**
35     * An error occurred when trying to write to the file.
36     */
37    public static final int ERROR_WRITING_FAILED = 2;
38 
39    /**
40     * An internal error occurred. This could be a bug, or a memory corruption
41     * (for example caused by out of memory).
42     */
43    public static final int ERROR_INTERNAL = 3;
44 
45    /**
46     * The object is already closed.
47     */
48    public static final int ERROR_CLOSED = 4;
49 
50    /**
51     * The file format is not supported.
52     */
53    public static final int ERROR_UNSUPPORTED_FORMAT = 5;
54 
55    /**
56     * The file is corrupt or (for encrypted files) the encryption key is wrong.
57     */
58    public static final int ERROR_FILE_CORRUPT = 6;
59 
60    /**
61     * The file is locked.
62     */
63    public static final int ERROR_FILE_LOCKED = 7;
64 
65    /**
66     * An error occurred when serializing or de-serializing.
67     */
68    public static final int ERROR_SERIALIZATION = 8;
69 
70    /**
71     * The application was trying to read data from a chunk that is no longer
72     * available.
73     */
74    public static final int ERROR_CHUNK_NOT_FOUND = 9;
75 
76    /**
77     * The block in the stream store was not found.
78     */
79    public static final int ERROR_BLOCK_NOT_FOUND = 50;
80 
81    /**
82     * The transaction store is corrupt.
83     */
84    public static final int ERROR_TRANSACTION_CORRUPT = 100;
85 
86    /**
87     * An entry is still locked by another transaction.
88     */
89    public static final int ERROR_TRANSACTION_LOCKED = 101;
90 
91    /**
92     * There are too many open transactions.
93     */
94    public static final int ERROR_TOO_MANY_OPEN_TRANSACTIONS = 102;
95 
96    /**
97     * The transaction store is in an illegal state (for example, not yet
98     * initialized).
99     */
100    public static final int ERROR_TRANSACTION_ILLEGAL_STATE = 103;
101 
102    /**
103     * The type for leaf page.
104     */
105    public static final int PAGE_TYPE_LEAF = 0;
106 
107    /**
108     * The type for node page.
109     */
110    public static final int PAGE_TYPE_NODE = 1;
111 
112    /**
113     * The bit mask for compressed pages (compression level fast).
114     */
115    public static final int PAGE_COMPRESSED = 2;
116 
117    /**
118     * The bit mask for compressed pages (compression level high).
119     */
120    public static final int PAGE_COMPRESSED_HIGH = 2 + 4;
121 
122    /**
123     * The maximum length of a variable size int.
124     */
125    public static final int MAX_VAR_INT_LEN = 5;
126 
127    /**
128     * The maximum length of a variable size long.
129     */
130    public static final int MAX_VAR_LONG_LEN = 10;
131 
132    /**
133     * The maximum integer that needs less space when using variable size
134     * encoding (only 3 bytes instead of 4).
135     */
136    public static final int COMPRESSED_VAR_INT_MAX = 0x1fffff;
137 
138    /**
139     * The maximum long that needs less space when using variable size
140     * encoding (only 7 bytes instead of 8).
141     */
142    public static final long COMPRESSED_VAR_LONG_MAX = 0x1ffffffffffffL;
143 
144    /**
145     * The estimated number of bytes used per page object.
146     */
147    public static final int PAGE_MEMORY = 128;
148 
149    /**
150     * The estimated number of bytes used per child entry.
151     */
152    public static final int PAGE_MEMORY_CHILD = 16;
153 
154    /**
155     * The marker size of a very large page.
156     */
157    public static final int PAGE_LARGE = 2 * 1024 * 1024;
158 
159    /**
160     * The UTF-8 character encoding format.
161     */
162    public static final Charset UTF8 = Charset.forName("UTF-8");
163 
164    /**
165     * The ISO Latin character encoding format.
166     */
167    public static final Charset LATIN = Charset.forName("ISO-8859-1");
168 
169    /**
170     * An 0-size byte array.
171     */
172    private static final byte[] EMPTY_BYTES = {};
173 
174    /**
175     * The maximum byte to grow a buffer at a time.
176     */
177    private static final int MAX_GROW = 16 * 1024 * 1024;
178 
179    /**
180     * Get the length of the variable size int.
181     *
182     * @param x the value
183     * @return the length in bytes
184     */
185    public static int getVarIntLen(int x) {
186        if ((x & (-1 << 7)) == 0) {
187            return 1;
188        } else if ((x & (-1 << 14)) == 0) {
189            return 2;
190        } else if ((x & (-1 << 21)) == 0) {
191            return 3;
192        } else if ((x & (-1 << 28)) == 0) {
193            return 4;
194        }
195        return 5;
196    }
197 
198    /**
199     * Get the length of the variable size long.
200     *
201     * @param x the value
202     * @return the length in bytes
203     */
204    public static int getVarLongLen(long x) {
205        int i = 1;
206        while (true) {
207            x >>>= 7;
208            if (x == 0) {
209                return i;
210            }
211            i++;
212        }
213    }
214 
215    /**
216     * Read a variable size int.
217     *
218     * @param buff the source buffer
219     * @return the value
220     */
221    public static int readVarInt(ByteBuffer buff) {
222        int b = buff.get();
223        if (b >= 0) {
224            return b;
225        }
226        // a separate function so that this one can be inlined
227        return readVarIntRest(buff, b);
228    }
229 
230    private static int readVarIntRest(ByteBuffer buff, int b) {
231        int x = b & 0x7f;
232        b = buff.get();
233        if (b >= 0) {
234            return x | (b << 7);
235        }
236        x |= (b & 0x7f) << 7;
237        b = buff.get();
238        if (b >= 0) {
239            return x | (b << 14);
240        }
241        x |= (b & 0x7f) << 14;
242        b = buff.get();
243        if (b >= 0) {
244            return x | b << 21;
245        }
246        x |= ((b & 0x7f) << 21) | (buff.get() << 28);
247        return x;
248    }
249 
250    /**
251     * Read a variable size long.
252     *
253     * @param buff the source buffer
254     * @return the value
255     */
256    public static long readVarLong(ByteBuffer buff) {
257        long x = buff.get();
258        if (x >= 0) {
259            return x;
260        }
261        x &= 0x7f;
262        for (int s = 7; s < 64; s += 7) {
263            long b = buff.get();
264            x |= (b & 0x7f) << s;
265            if (b >= 0) {
266                break;
267            }
268        }
269        return x;
270    }
271 
272    /**
273     * Write a variable size int.
274     *
275     * @param out the output stream
276     * @param x the value
277     */
278    public static void writeVarInt(OutputStream out, int x) throws IOException {
279        while ((x & ~0x7f) != 0) {
280            out.write((byte) (0x80 | (x & 0x7f)));
281            x >>>= 7;
282        }
283        out.write((byte) x);
284    }
285 
286    /**
287     * Write a variable size int.
288     *
289     * @param buff the source buffer
290     * @param x the value
291     */
292    public static void writeVarInt(ByteBuffer buff, int x) {
293        while ((x & ~0x7f) != 0) {
294            buff.put((byte) (0x80 | (x & 0x7f)));
295            x >>>= 7;
296        }
297        buff.put((byte) x);
298    }
299 
300    /**
301     * Write characters from a string (without the length).
302     *
303     * @param buff the target buffer
304     * @param s the string
305     * @param len the number of characters
306     * @return the byte buffer
307     */
308    public static ByteBuffer writeStringData(ByteBuffer buff,
309            String s, int len) {
310        buff = DataUtils.ensureCapacity(buff, 3 * len);
311        for (int i = 0; i < len; i++) {
312            int c = s.charAt(i);
313            if (c < 0x80) {
314                buff.put((byte) c);
315            } else if (c >= 0x800) {
316                buff.put((byte) (0xe0 | (c >> 12)));
317                buff.put((byte) (((c >> 6) & 0x3f)));
318                buff.put((byte) (c & 0x3f));
319            } else {
320                buff.put((byte) (0xc0 | (c >> 6)));
321                buff.put((byte) (c & 0x3f));
322            }
323        }
324        return buff;
325    }
326 
327    /**
328     * Read a string.
329     *
330     * @param buff the source buffer
331     * @param len the number of characters
332     * @return the value
333     */
334    public static String readString(ByteBuffer buff, int len) {
335        char[] chars = new char[len];
336        for (int i = 0; i < len; i++) {
337            int x = buff.get() & 0xff;
338            if (x < 0x80) {
339                chars[i] = (char) x;
340            } else if (x >= 0xe0) {
341                chars[i] = (char) (((x & 0xf) << 12)
342                        + ((buff.get() & 0x3f) << 6) + (buff.get() & 0x3f));
343            } else {
344                chars[i] = (char) (((x & 0x1f) << 6) + (buff.get() & 0x3f));
345            }
346        }
347        return new String(chars);
348    }
349 
350    /**
351     * Write a variable size long.
352     *
353     * @param buff the target buffer
354     * @param x the value
355     */
356    public static void writeVarLong(ByteBuffer buff, long x) {
357        while ((x & ~0x7f) != 0) {
358            buff.put((byte) (0x80 | (x & 0x7f)));
359            x >>>= 7;
360        }
361        buff.put((byte) x);
362    }
363 
364    /**
365     * Write a variable size long.
366     *
367     * @param out the output stream
368     * @param x the value
369     */
370    public static void writeVarLong(OutputStream out, long x)
371            throws IOException {
372        while ((x & ~0x7f) != 0) {
373            out.write((byte) (0x80 | (x & 0x7f)));
374            x >>>= 7;
375        }
376        out.write((byte) x);
377    }
378 
379    /**
380     * Copy the elements of an array, with a gap.
381     *
382     * @param src the source array
383     * @param dst the target array
384     * @param oldSize the size of the old array
385     * @param gapIndex the index of the gap
386     */
387    public static void copyWithGap(Object src, Object dst, int oldSize,
388            int gapIndex) {
389        if (gapIndex > 0) {
390            System.arraycopy(src, 0, dst, 0, gapIndex);
391        }
392        if (gapIndex < oldSize) {
393            System.arraycopy(src, gapIndex, dst, gapIndex + 1, oldSize
394                    - gapIndex);
395        }
396    }
397 
398    /**
399     * Copy the elements of an array, and remove one element.
400     *
401     * @param src the source array
402     * @param dst the target array
403     * @param oldSize the size of the old array
404     * @param removeIndex the index of the entry to remove
405     */
406    public static void copyExcept(Object src, Object dst, int oldSize,
407            int removeIndex) {
408        if (removeIndex > 0 && oldSize > 0) {
409            System.arraycopy(src, 0, dst, 0, removeIndex);
410        }
411        if (removeIndex < oldSize) {
412            System.arraycopy(src, removeIndex + 1, dst, removeIndex, oldSize
413                    - removeIndex - 1);
414        }
415    }
416 
417    /**
418     * Read from a file channel until the buffer is full.
419     * The buffer is rewind after reading.
420     *
421     * @param file the file channel
422     * @param pos the absolute position within the file
423     * @param dst the byte buffer
424     * @throws IllegalStateException if some data could not be read
425     */
426    public static void readFully(FileChannel file, long pos, ByteBuffer dst) {
427        try {
428            do {
429                int len = file.read(dst, pos);
430                if (len < 0) {
431                    throw new EOFException();
432                }
433                pos += len;
434            } while (dst.remaining() > 0);
435            dst.rewind();
436        } catch (IOException e) {
437            long size;
438            try {
439                size = file.size();
440            } catch (IOException e2) {
441                size = -1;
442            }
443            throw newIllegalStateException(
444                    ERROR_READING_FAILED,
445                    "Reading from {0} failed; file length {1} " +
446                    "read length {2} at {3}",
447                    file, size, dst.remaining(), pos, e);
448        }
449    }
450 
451    /**
452     * Write to a file channel.
453     *
454     * @param file the file channel
455     * @param pos the absolute position within the file
456     * @param src the source buffer
457     */
458    public static void writeFully(FileChannel file, long pos, ByteBuffer src) {
459        try {
460            int off = 0;
461            do {
462                int len = file.write(src, pos + off);
463                off += len;
464            } while (src.remaining() > 0);
465        } catch (IOException e) {
466            throw newIllegalStateException(
467                    ERROR_WRITING_FAILED,
468                    "Writing to {0} failed; length {1} at {2}",
469                    file, src.remaining(), pos, e);
470        }
471    }
472 
473    /**
474     * Convert the length to a length code 0..31. 31 means more than 1 MB.
475     *
476     * @param len the length
477     * @return the length code
478     */
479    public static int encodeLength(int len) {
480        if (len <= 32) {
481            return 0;
482        }
483        int code = Integer.numberOfLeadingZeros(len);
484        int remaining = len << (code + 1);
485        code += code;
486        if ((remaining & (1 << 31)) != 0) {
487            code--;
488        }
489        if ((remaining << 1) != 0) {
490            code--;
491        }
492        code = Math.min(31, 52 - code);
493        // alternative code (slower):
494        // int x = len;
495        // int shift = 0;
496        // while (x > 3) {
497        //    shift++;
498        //    x = (x >>> 1) + (x & 1);
499        // }
500        // shift = Math.max(0,  shift - 4);
501        // int code = (shift << 1) + (x & 1);
502        // code = Math.min(31, code);
503        return code;
504    }
505 
506    /**
507     * Get the chunk id from the position.
508     *
509     * @param pos the position
510     * @return the chunk id
511     */
512    public static int getPageChunkId(long pos) {
513        return (int) (pos >>> 38);
514    }
515 
516    /**
517     * Get the maximum length for the given code.
518     * For the code 31, PAGE_LARGE is returned.
519     *
520     * @param pos the position
521     * @return the maximum length
522     */
523    public static int getPageMaxLength(long pos) {
524        int code = (int) ((pos >> 1) & 31);
525        if (code == 31) {
526            return PAGE_LARGE;
527        }
528        return (2 + (code & 1)) << ((code >> 1) + 4);
529    }
530 
531    /**
532     * Get the offset from the position.
533     *
534     * @param pos the position
535     * @return the offset
536     */
537    public static int getPageOffset(long pos) {
538        return (int) (pos >> 6);
539    }
540 
541    /**
542     * Get the page type from the position.
543     *
544     * @param pos the position
545     * @return the page type (PAGE_TYPE_NODE or PAGE_TYPE_LEAF)
546     */
547    public static int getPageType(long pos) {
548        return ((int) pos) & 1;
549    }
550 
551    /**
552     * Get the position of this page. The following information is encoded in
553     * the position: the chunk id, the offset, the maximum length, and the type
554     * (node or leaf).
555     *
556     * @param chunkId the chunk id
557     * @param offset the offset
558     * @param length the length
559     * @param type the page type (1 for node, 0 for leaf)
560     * @return the position
561     */
562    public static long getPagePos(int chunkId, int offset,
563            int length, int type) {
564        long pos = (long) chunkId << 38;
565        pos |= (long) offset << 6;
566        pos |= encodeLength(length) << 1;
567        pos |= type;
568        return pos;
569    }
570 
571    /**
572     * Calculate a check value for the given integer. A check value is mean to
573     * verify the data is consistent with a high probability, but not meant to
574     * protect against media failure or deliberate changes.
575     *
576     * @param x the value
577     * @return the check value
578     */
579    public static short getCheckValue(int x) {
580        return (short) ((x >> 16) ^ x);
581    }
582 
583    /**
584     * Append a map to the string builder, sorted by key.
585     *
586     * @param buff the target buffer
587     * @param map the map
588     * @return the string builder
589     */
590    public static StringBuilder appendMap(StringBuilder buff,
591            HashMap<String, ?> map) {
592        ArrayList<String> list = New.arrayList(map.keySet());
593        Collections.sort(list);
594        for (String k : list) {
595            appendMap(buff, k, map.get(k));
596        }
597        return buff;
598    }
599 
600    /**
601     * Append a key-value pair to the string builder. Keys may not contain a
602     * colon. Values that contain a comma or a double quote are enclosed in
603     * double quotes, with special characters escaped using a backslash.
604     *
605     * @param buff the target buffer
606     * @param key the key
607     * @param value the value
608     */
609    public static void appendMap(StringBuilder buff, String key, Object value) {
610        if (buff.length() > 0) {
611            buff.append(',');
612        }
613        buff.append(key).append(':');
614        String v;
615        if (value instanceof Long) {
616            v = Long.toHexString((Long) value);
617        } else if (value instanceof Integer) {
618            v = Integer.toHexString((Integer) value);
619        } else {
620            v = value.toString();
621        }
622        if (v.indexOf(',') < 0 && v.indexOf('\"') < 0) {
623            buff.append(v);
624        } else {
625            buff.append('\"');
626            for (int i = 0, size = v.length(); i < size; i++) {
627                char c = v.charAt(i);
628                if (c == '\"') {
629                    buff.append('\\');
630                }
631                buff.append(c);
632            }
633            buff.append('\"');
634        }
635    }
636 
637    /**
638     * Parse a key-value pair list.
639     *
640     * @param s the list
641     * @return the map
642     * @throws IllegalStateException if parsing failed
643     */
644    public static HashMap<String, String> parseMap(String s) {
645        HashMap<String, String> map = New.hashMap();
646        for (int i = 0, size = s.length(); i < size;) {
647            int startKey = i;
648            i = s.indexOf(':', i);
649            if (i < 0) {
650                throw DataUtils.newIllegalStateException(
651                        DataUtils.ERROR_FILE_CORRUPT, "Not a map: {0}", s);
652            }
653            String key = s.substring(startKey, i++);
654            StringBuilder buff = new StringBuilder();
655            while (i < size) {
656                char c = s.charAt(i++);
657                if (c == ',') {
658                    break;
659                } else if (c == '\"') {
660                    while (i < size) {
661                        c = s.charAt(i++);
662                        if (c == '\\') {
663                            if (i == size) {
664                                throw DataUtils.newIllegalStateException(
665                                        DataUtils.ERROR_FILE_CORRUPT,
666                                        "Not a map: {0}", s);
667                            }
668                            c = s.charAt(i++);
669                        } else if (c == '\"') {
670                            break;
671                        }
672                        buff.append(c);
673                    }
674                } else {
675                    buff.append(c);
676                }
677            }
678            map.put(key, buff.toString());
679        }
680        return map;
681    }
682 
683    /**
684     * Calculate the Fletcher32 checksum.
685     *
686     * @param bytes the bytes
687     * @param length the message length (if odd, 0 is appended)
688     * @return the checksum
689     */
690    public static int getFletcher32(byte[] bytes, int length) {
691        int s1 = 0xffff, s2 = 0xffff;
692        int i = 0, evenLength = length / 2 * 2;
693        while (i < evenLength) {
694            // reduce after 360 words (each word is two bytes)
695            for (int end = Math.min(i + 720, evenLength); i < end;) {
696                int x = ((bytes[i++] & 0xff) << 8) | (bytes[i++] & 0xff);
697                s2 += s1 += x;
698            }
699            s1 = (s1 & 0xffff) + (s1 >>> 16);
700            s2 = (s2 & 0xffff) + (s2 >>> 16);
701        }
702        if (i < length) {
703            // odd length: append 0
704            int x = (bytes[i] & 0xff) << 8;
705            s2 += s1 += x;
706        }
707        s1 = (s1 & 0xffff) + (s1 >>> 16);
708        s2 = (s2 & 0xffff) + (s2 >>> 16);
709        return (s2 << 16) | s1;
710    }
711 
712    /**
713     * Throw an IllegalArgumentException if the argument is invalid.
714     *
715     * @param test true if the argument is valid
716     * @param message the message
717     * @param arguments the arguments
718     * @throws IllegalArgumentException if the argument is invalid
719     */
720    public static void checkArgument(boolean test, String message,
721            Object... arguments) {
722        if (!test) {
723            throw newIllegalArgumentException(message, arguments);
724        }
725    }
726 
727    /**
728     * Create a new IllegalArgumentException.
729     *
730     * @param message the message
731     * @param arguments the arguments
732     * @return the exception
733     */
734    public static IllegalArgumentException newIllegalArgumentException(
735            String message, Object... arguments) {
736        return initCause(new IllegalArgumentException(
737                formatMessage(0, message, arguments)),
738                arguments);
739    }
740 
741    /**
742     * Create a new UnsupportedOperationException.
743     *
744     * @param message the message
745     * @return the exception
746     */
747    public static UnsupportedOperationException
748            newUnsupportedOperationException(String message) {
749        return new UnsupportedOperationException(formatMessage(0, message));
750    }
751 
752    /**
753     * Create a new ConcurrentModificationException.
754     *
755     * @param message the message
756     * @return the exception
757     */
758    public static ConcurrentModificationException
759            newConcurrentModificationException(String message) {
760        return new ConcurrentModificationException(formatMessage(0, message));
761    }
762 
763    /**
764     * Create a new IllegalStateException.
765     *
766     * @param errorCode the error code
767     * @param message the message
768     * @param arguments the arguments
769     * @return the exception
770     */
771    public static IllegalStateException newIllegalStateException(
772            int errorCode, String message, Object... arguments) {
773        return initCause(new IllegalStateException(
774                formatMessage(errorCode, message, arguments)),
775                arguments);
776    }
777 
778    private static <T extends Exception> T initCause(T e, Object... arguments) {
779        int size = arguments.length;
780        if (size > 0) {
781            Object o = arguments[size - 1];
782            if (o instanceof Exception) {
783                e.initCause((Exception) o);
784            }
785        }
786        return e;
787    }
788 
789    /**
790     * Format an error message.
791     *
792     * @param errorCode the error code
793     * @param message the message
794     * @param arguments the arguments
795     * @return the formatted message
796     */
797    public static String formatMessage(int errorCode, String message,
798            Object... arguments) {
799        // convert arguments to strings, to avoid locale specific formatting
800        for (int i = 0; i < arguments.length; i++) {
801            Object a = arguments[i];
802            if (!(a instanceof Exception)) {
803                String s = a == null ? "null" : a.toString();
804                if (s.length() > 1000) {
805                    s = s.substring(0, 1000) + "...";
806                }
807                arguments[i] = s;
808            }
809        }
810        return MessageFormat.format(message, arguments) +
811                " [" + Constants.VERSION_MAJOR + "." +
812                Constants.VERSION_MINOR + "." + Constants.BUILD_ID +
813                "/" + errorCode + "]";
814    }
815 
816    /**
817     * Get the error code from an exception message.
818     *
819     * @param m the message
820     * @return the error code, or 0 if none
821     */
822    public static int getErrorCode(String m) {
823        if (m != null && m.endsWith("]")) {
824            int dash = m.lastIndexOf('/');
825            if (dash >= 0) {
826                String s = m.substring(dash + 1, m.length() - 1);
827                try {
828                    return Integer.parseInt(s);
829                } catch (NumberFormatException e) {
830                    // no error code
831                }
832            }
833        }
834        return 0;
835    }
836 
837    /**
838     * Create an array of bytes with the given size. If this is not possible
839     * because not enough memory is available, an OutOfMemoryError with the
840     * requested size in the message is thrown.
841     * <p>
842     * This method should be used if the size of the array is user defined, or
843     * stored in a file, so wrong size data can be distinguished from regular
844     * out-of-memory.
845     *
846     * @param len the number of bytes requested
847     * @return the byte array
848     * @throws OutOfMemoryError if the allocation was too large
849     */
850    public static byte[] newBytes(int len) {
851        if (len == 0) {
852            return EMPTY_BYTES;
853        }
854        try {
855            return new byte[len];
856        } catch (OutOfMemoryError e) {
857            Error e2 = new OutOfMemoryError("Requested memory: " + len);
858            e2.initCause(e);
859            throw e2;
860        }
861    }
862 
863    /**
864     * Ensure the byte buffer has the given capacity, plus 1 KB. If not, a new,
865     * larger byte buffer is created and the data is copied.
866     *
867     * @param buff the byte buffer
868     * @param len the minimum remaining capacity
869     * @return the byte buffer (possibly a new one)
870     */
871    public static ByteBuffer ensureCapacity(ByteBuffer buff, int len) {
872        len += 1024;
873        if (buff.remaining() > len) {
874            return buff;
875        }
876        return grow(buff, len);
877    }
878 
879    private static ByteBuffer grow(ByteBuffer buff, int len) {
880        len = buff.remaining() + len;
881        int capacity = buff.capacity();
882        len = Math.max(len, Math.min(capacity + MAX_GROW, capacity * 2));
883        ByteBuffer temp = ByteBuffer.allocate(len);
884        buff.flip();
885        temp.put(buff);
886        return temp;
887    }
888 
889    /**
890     * Read a hex long value from a map.
891     *
892     * @param map the map
893     * @param key the key
894     * @param defaultValue if the value is null
895     * @return the parsed value
896     * @throws IllegalStateException if parsing fails
897     */
898    public static long readHexLong(Map<String, ? extends Object> map,
899            String key, long defaultValue) {
900        Object v = map.get(key);
901        if (v == null) {
902            return defaultValue;
903        } else if (v instanceof Long) {
904            return (Long) v;
905        }
906        try {
907            return parseHexLong((String) v);
908        } catch (NumberFormatException e) {
909            throw newIllegalStateException(ERROR_FILE_CORRUPT,
910                    "Error parsing the value {0}", v, e);
911        }
912    }
913 
914    /**
915     * Parse an unsigned, hex long.
916     *
917     * @param x the string
918     * @return the parsed value
919     * @throws IllegalStateException if parsing fails
920     */
921    public static long parseHexLong(String x) {
922        try {
923            if (x.length() == 16) {
924                // avoid problems with overflow
925                // in Java 8, this special case is not needed
926                return (Long.parseLong(x.substring(0, 8), 16) << 32) |
927                        Long.parseLong(x.substring(8, 16), 16);
928            }
929            return Long.parseLong(x, 16);
930        } catch (NumberFormatException e) {
931            throw newIllegalStateException(ERROR_FILE_CORRUPT,
932                    "Error parsing the value {0}", x, e);
933        }
934    }
935 
936    /**
937     * Parse an unsigned, hex long.
938     *
939     * @param x the string
940     * @return the parsed value
941     * @throws IllegalStateException if parsing fails
942     */
943    public static int parseHexInt(String x) {
944        try {
945            // avoid problems with overflow
946            // in Java 8, we can use Integer.parseLong(x, 16);
947            return (int) Long.parseLong(x, 16);
948        } catch (NumberFormatException e) {
949            throw newIllegalStateException(ERROR_FILE_CORRUPT,
950                    "Error parsing the value {0}", x, e);
951        }
952    }
953 
954    /**
955     * Read a hex int value from a map.
956     *
957     * @param map the map
958     * @param key the key
959     * @param defaultValue if the value is null
960     * @return the parsed value
961     * @throws IllegalStateException if parsing fails
962     */
963    public static int readHexInt(HashMap<String, ? extends Object> map,
964            String key, int defaultValue) {
965        Object v = map.get(key);
966        if (v == null) {
967            return defaultValue;
968        } else if (v instanceof Integer) {
969            return (Integer) v;
970        }
971        try {
972            // support unsigned hex value
973            return (int) Long.parseLong((String) v, 16);
974        } catch (NumberFormatException e) {
975            throw newIllegalStateException(ERROR_FILE_CORRUPT,
976                    "Error parsing the value {0}", v, e);
977        }
978    }
979 
980    /**
981     * An entry of a map.
982     *
983     * @param <K> the key type
984     * @param <V> the value type
985     */
986    public static class MapEntry<K, V> implements Map.Entry<K, V> {
987 
988        private final K key;
989        private V value;
990 
991        public MapEntry(K key, V value) {
992            this.key = key;
993            this.value = value;
994        }
995 
996        @Override
997        public K getKey() {
998            return key;
999        }
1000 
1001        @Override
1002        public V getValue() {
1003            return value;
1004        }
1005 
1006        @Override
1007        public V setValue(V value) {
1008            throw DataUtils.newUnsupportedOperationException(
1009                    "Updating the value is not supported");
1010        }
1011 
1012    }
1013 
1014}

[all classes][org.h2.mvstore]
EMMA 2.0.5312 (C) Vladimir Roubtsov