Mercurial > jhg
comparison src/com/tmate/hgkit/ll/Nodeid.java @ 24:d4fdd1845b3f
Nodeid with array of exactly 20 bytes
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Thu, 06 Jan 2011 04:42:15 +0100 |
parents | 603806cd2dc6 |
children | b2251b7a9823 |
comparison
equal
deleted
inserted
replaced
23:6f9aca1a97be | 24:d4fdd1845b3f |
---|---|
1 /* | 1 /* |
2 * Copyright (c) 2010, 2011 Artem Tikhomirov | 2 * Copyright (c) 2010, 2011 Artem Tikhomirov |
3 */ | 3 */ |
4 package com.tmate.hgkit.ll; | 4 package com.tmate.hgkit.ll; |
5 | |
6 import java.util.Arrays; | |
5 | 7 |
6 | 8 |
7 | 9 |
8 /** | 10 /** |
9 * Whether to store fixed size array (20 bytes) - ease of manipulation (e.g. hashcode/equals), or | 11 * Whether to store fixed size array (20 bytes) - ease of manipulation (e.g. hashcode/equals), or |
11 * Fixed size array looks most appealing to me now - I doubt one can save any significant amount of memory. | 13 * Fixed size array looks most appealing to me now - I doubt one can save any significant amount of memory. |
12 * There'd always 20 non-zero bytes, the difference is only for any extra bytes one may pass to constructor | 14 * There'd always 20 non-zero bytes, the difference is only for any extra bytes one may pass to constructor |
13 * @author artem | 15 * @author artem |
14 * | 16 * |
15 */ | 17 */ |
16 public final class Nodeid implements Comparable<Nodeid> { | 18 public final class Nodeid { |
17 | 19 |
18 public static int NULLREV = -1; | 20 public static int NULLREV = -1; |
19 private final byte[] binaryData; | 21 private final byte[] binaryData; |
20 | 22 |
23 /** | |
24 * @param binaryRepresentation - byte[20], kept by reference. Use {@link #clone()} if original array may get changed. | |
25 */ | |
21 public Nodeid(byte[] binaryRepresentation) { | 26 public Nodeid(byte[] binaryRepresentation) { |
22 // 5 int fields => 32 bytes | 27 // 5 int fields => 32 bytes |
23 // byte[20] => 48 bytes | 28 // byte[20] => 48 bytes |
29 if (binaryRepresentation == null || binaryRepresentation.length != 20) { | |
30 throw new IllegalArgumentException(); | |
31 } | |
24 this.binaryData = binaryRepresentation; | 32 this.binaryData = binaryRepresentation; |
25 } | 33 } |
26 | 34 |
27 // instead of hashCode/equals | 35 @Override |
28 public int compareTo(Nodeid o) { | 36 public int hashCode() { |
29 return equals(this.binaryData, o.binaryData) ? 0 : -1; | 37 // TODO consider own impl, especially if byte[] get replaced with 5 ints |
38 return Arrays.hashCode(binaryData); | |
39 } | |
40 | |
41 @Override | |
42 public boolean equals(Object o) { | |
43 if (o instanceof Nodeid) { | |
44 return Arrays.equals(this.binaryData, ((Nodeid) o).binaryData); | |
45 } | |
46 return false; | |
30 } | 47 } |
31 | 48 |
32 public boolean equalsTo(byte[] buf) { | 49 public boolean equalsTo(byte[] buf) { |
33 return equals(this.binaryData, buf); | 50 return Arrays.equals(this.binaryData, buf); |
34 } | 51 } |
35 | 52 |
36 private static boolean equals(byte[] a1, byte[] a2) { | |
37 if (a1 == null || a1.length < 20 || a2 == null || a2.length < 20) { | |
38 throw new IllegalArgumentException(); | |
39 } | |
40 // assume significant bits are at the end of the array | |
41 final int s1 = a1.length - 20, s2 = a2.length - 20; | |
42 for (int i = 0; i < 20; i++) { | |
43 if (a1[s1+i] != a2[s2+i]) { | |
44 return false; | |
45 } | |
46 } | |
47 return true; | |
48 } | |
49 | |
50 @Override | 53 @Override |
51 public String toString() { | 54 public String toString() { |
52 return new DigestHelper().toHexString(binaryData, 0, binaryData.length); | 55 return new DigestHelper().toHexString(binaryData, 0, binaryData.length); |
53 } | 56 } |
54 | 57 |
55 // binascii.unhexlify() | 58 // binascii.unhexlify() |
56 public static Nodeid fromAscii(byte[] asciiRepresentation, int offset, int length) { | 59 public static Nodeid fromAscii(byte[] asciiRepresentation, int offset, int length) { |
57 assert length % 2 == 0; // Python's binascii.hexlify convert each byte into 2 digits | 60 if (length != 40) { |
58 byte[] data = new byte[length >>> 1]; // XXX use known size instead? nodeid is always 20 bytes | 61 throw new IllegalArgumentException(); |
62 } | |
63 byte[] data = new byte[20]; | |
59 for (int i = 0, j = offset; i < data.length; i++) { | 64 for (int i = 0, j = offset; i < data.length; i++) { |
60 int hiNibble = Character.digit(asciiRepresentation[j++], 16); | 65 int hiNibble = Character.digit(asciiRepresentation[j++], 16); |
61 int lowNibble = Character.digit(asciiRepresentation[j++], 16); | 66 int lowNibble = Character.digit(asciiRepresentation[j++], 16); |
62 data[i] = (byte) (((hiNibble << 4) | lowNibble) & 0xFF); | 67 data[i] = (byte) (((hiNibble << 4) | lowNibble) & 0xFF); |
63 } | 68 } |