From 60e8221fc79a0329299b0cb32b787183280450b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Szathma=CC=81ry?= Date: Sun, 3 Jan 2016 22:25:53 +0100 Subject: [PATCH] eliminate Decoder.Result objects The ByteBuffer itself keeps track of the read position. --- src/main/java/com/maxmind/db/Decoder.java | 107 ++++++------------ src/main/java/com/maxmind/db/Reader.java | 4 +- src/test/java/com/maxmind/db/DecoderTest.java | 28 ++--- src/test/java/com/maxmind/db/PointerTest.java | 12 +- 4 files changed, 50 insertions(+), 101 deletions(-) diff --git a/src/main/java/com/maxmind/db/Decoder.java b/src/main/java/com/maxmind/db/Decoder.java index 34863a29..55936c66 100644 --- a/src/main/java/com/maxmind/db/Decoder.java +++ b/src/main/java/com/maxmind/db/Decoder.java @@ -58,34 +58,6 @@ public static Type fromControlByte(int b) { } } - static class Result { - private final JsonNode node; - private int offset; - - Result(JsonNode node, int offset) { - this.node = node; - this.offset = offset; - } - - JsonNode getNode() { - return this.node; - } - - int getOffset() { - return this.offset; - } - - void setOffset(int offset) { - this.offset = offset; - } - - @Override - public String toString() { - return "Result[" + offset + " " + node.getNodeType() + " " + node.asText() + "]"; - } - - } - Decoder(NodeCache cache, ByteBuffer buffer, long pointerBase) { this.cache = cache; this.pointerBase = pointerBase; @@ -95,11 +67,11 @@ public String toString() { private final NodeCache.Loader cacheLoader = new NodeCache.Loader() { @Override public JsonNode load(int key) throws IOException { - return decode(key).getNode(); + return decode(key); } }; - Result decode(int offset) throws IOException { + JsonNode decode(int offset) throws IOException { if (offset >= this.buffer.capacity()) { throw new InvalidDatabaseException( "The MaxMind DB file's data section contains bad data: " @@ -107,8 +79,11 @@ Result decode(int offset) throws IOException { } this.buffer.position(offset); + return decode(); + } + + JsonNode decode() throws IOException { int ctrlByte = 0xFF & this.buffer.get(); - offset++; Type type = Type.fromControlByte(ctrlByte); @@ -120,16 +95,17 @@ Result decode(int offset) throws IOException { int base = pointerSize == 4 ? (byte) 0 : (byte) (ctrlByte & 0x7); int packed = this.decodeInteger(base, pointerSize); long pointer = packed + this.pointerBase + POINTER_VALUE_OFFSETS[pointerSize]; - int newOffset = offset + pointerSize; // for unit testing if (this.POINTER_TEST_HACK) { - return new Result(new LongNode(pointer), newOffset); + return new LongNode(pointer); } int targetOffset = (int) pointer; + int position = buffer.position(); JsonNode node = cache.get(targetOffset, cacheLoader); - return new Result(node, newOffset); + buffer.position(position); + return node; } if (type.equals(Type.EXTENDED)) { @@ -145,7 +121,6 @@ Result decode(int offset) throws IOException { } type = Type.get(typeNum); - offset++; } int size = ctrlByte & 0x1f; @@ -162,49 +137,38 @@ Result decode(int offset) throws IOException { default: size = 65821 + (i & (0x0FFFFFFF >>> 32 - 8 * bytesToRead)); } - offset += bytesToRead; } - return this.decodeByType(type, offset, size); + return this.decodeByType(type, size); } - private Result decodeByType(Type type, int offset, int size) + private JsonNode decodeByType(Type type, int size) throws IOException { - // MAP, ARRAY, and BOOLEAN do not use newOffset as we don't read the - // next size bytes. For all other types, we do. - int newOffset = offset + size; switch (type) { case MAP: - return this.decodeMap(size, offset); + return this.decodeMap(size); case ARRAY: - return this.decodeArray(size, offset); + return this.decodeArray(size); case BOOLEAN: - return new Result(Decoder.decodeBoolean(size), offset); + return Decoder.decodeBoolean(size); case UTF8_STRING: - TextNode s = new TextNode(this.decodeString(size)); - return new Result(s, newOffset); + return new TextNode(this.decodeString(size)); case DOUBLE: - return new Result(this.decodeDouble(size), newOffset); + return this.decodeDouble(size); case FLOAT: - return new Result(this.decodeFloat(size), newOffset); + return this.decodeFloat(size); case BYTES: - BinaryNode b = new BinaryNode(this.getByteArray(size)); - return new Result(b, newOffset); + return new BinaryNode(this.getByteArray(size)); case UINT16: - IntNode i = this.decodeUint16(size); - return new Result(i, newOffset); + return this.decodeUint16(size); case UINT32: - LongNode l = this.decodeUint32(size); - return new Result(l, newOffset); + return this.decodeUint32(size); case INT32: - IntNode int32 = this.decodeInt32(size); - return new Result(int32, newOffset); + return this.decodeInt32(size); case UINT64: - BigIntegerNode bi = this.decodeBigInteger(size); - return new Result(bi, newOffset); + return this.decodeBigInteger(size); case UINT128: - BigIntegerNode uint128 = this.decodeBigInteger(size); - return new Result(uint128, newOffset); + return this.decodeBigInteger(size); default: throw new InvalidDatabaseException( "Unknown or unexpected type: " + type.name()); @@ -292,34 +256,27 @@ private static BooleanNode decodeBoolean(int size) } } - private Result decodeArray(int size, int offset) throws IOException { + private JsonNode decodeArray(int size) throws IOException { ArrayNode array = OBJECT_MAPPER.createArrayNode(); for (int i = 0; i < size; i++) { - Result r = this.decode(offset); - offset = r.getOffset(); - array.add(r.getNode()); + JsonNode r = this.decode(); + array.add(r); } - return new Result(array, offset); + return array; } - private Result decodeMap(int size, int offset) throws IOException { + private JsonNode decodeMap(int size) throws IOException { ObjectNode map = OBJECT_MAPPER.createObjectNode(); for (int i = 0; i < size; i++) { - Result keyResult = this.decode(offset); - String key = keyResult.getNode().asText(); - offset = keyResult.getOffset(); - - Result valueResult = this.decode(offset); - JsonNode value = valueResult.getNode(); - offset = valueResult.getOffset(); - + String key = this.decode().asText(); + JsonNode value = this.decode(); map.set(key, value); } - return new Result(map, offset); + return map; } private byte[] getByteArray(int length) { diff --git a/src/main/java/com/maxmind/db/Reader.java b/src/main/java/com/maxmind/db/Reader.java index 004e3268..198f0ff3 100644 --- a/src/main/java/com/maxmind/db/Reader.java +++ b/src/main/java/com/maxmind/db/Reader.java @@ -131,7 +131,7 @@ private Reader(BufferHolder bufferHolder, String name, NodeCache cache) throws I int start = this.findMetadataStart(buffer, name); Decoder metadataDecoder = new Decoder(this.cache, buffer, start); - this.metadata = new Metadata(metadataDecoder.decode(start).getNode()); + this.metadata = new Metadata(metadataDecoder.decode(start)); this.ipV4Start = this.findIpV4StartNode(buffer); } @@ -251,7 +251,7 @@ private JsonNode resolveDataPointer(ByteBuffer buffer, int pointer) // found. Decoder decoder = new Decoder(this.cache, buffer, this.metadata.getSearchTreeSize() + DATA_SECTION_SEPARATOR_SIZE); - return decoder.decode(resolved).getNode(); + return decoder.decode(resolved); } /* diff --git a/src/test/java/com/maxmind/db/DecoderTest.java b/src/test/java/com/maxmind/db/DecoderTest.java index ec8ca0c6..dc5ef462 100644 --- a/src/test/java/com/maxmind/db/DecoderTest.java +++ b/src/test/java/com/maxmind/db/DecoderTest.java @@ -430,36 +430,28 @@ private static void testTypeDecoding(Decoder.Type type, Map tests // XXX - this could be streamlined if (type.equals(Decoder.Type.BYTES)) { - assertArrayEquals(desc, (byte[]) expect, decoder.decode(0) - .getNode().binaryValue()); + assertArrayEquals(desc, (byte[]) expect, decoder.decode(0).binaryValue()); } else if (type.equals(Decoder.Type.ARRAY)) { - assertEquals(desc, expect, decoder.decode(0).getNode()); + assertEquals(desc, expect, decoder.decode(0)); } else if (type.equals(Decoder.Type.UINT16) || type.equals(Decoder.Type.INT32)) { - assertEquals(desc, expect, decoder.decode(0).getNode() - .asInt()); + assertEquals(desc, expect, decoder.decode(0).asInt()); } else if (type.equals(Decoder.Type.UINT32) || type.equals(Decoder.Type.POINTER)) { - assertEquals(desc, expect, decoder.decode(0).getNode() - .asLong()); + assertEquals(desc, expect, decoder.decode(0).asLong()); } else if (type.equals(Decoder.Type.UINT64) || type.equals(Decoder.Type.UINT128)) { - assertEquals(desc, expect, decoder.decode(0).getNode() - .bigIntegerValue()); + assertEquals(desc, expect, decoder.decode(0).bigIntegerValue()); } else if (type.equals(Decoder.Type.DOUBLE)) { - assertEquals(desc, expect, decoder.decode(0).getNode() - .asDouble()); + assertEquals(desc, expect, decoder.decode(0).asDouble()); } else if (type.equals(Decoder.Type.FLOAT)) { - assertEquals(desc, new FloatNode((Float) expect), decoder - .decode(0).getNode()); + assertEquals(desc, new FloatNode((Float) expect), decoder.decode(0)); } else if (type.equals(Decoder.Type.UTF8_STRING)) { - assertEquals(desc, expect, decoder.decode(0).getNode() - .asText()); + assertEquals(desc, expect, decoder.decode(0).asText()); } else if (type.equals(Decoder.Type.BOOLEAN)) { - assertEquals(desc, expect, decoder.decode(0).getNode() - .asBoolean()); + assertEquals(desc, expect, decoder.decode(0).asBoolean()); } else { - assertEquals(desc, expect, decoder.decode(0).getNode()); + assertEquals(desc, expect, decoder.decode(0)); } } finally { fc.close(); diff --git a/src/test/java/com/maxmind/db/PointerTest.java b/src/test/java/com/maxmind/db/PointerTest.java index 717260e4..54531987 100644 --- a/src/test/java/com/maxmind/db/PointerTest.java +++ b/src/test/java/com/maxmind/db/PointerTest.java @@ -23,26 +23,26 @@ public void testWithPointers() throws IOException { ObjectNode map = om.createObjectNode(); map.put("long_key", "long_value1"); - assertEquals(map, decoder.decode(0).getNode()); + assertEquals(map, decoder.decode(0)); map = om.createObjectNode(); map.put("long_key", "long_value2"); - assertEquals(map, decoder.decode(22).getNode()); + assertEquals(map, decoder.decode(22)); map = om.createObjectNode(); map.put("long_key2", "long_value1"); - assertEquals(map, decoder.decode(37).getNode()); + assertEquals(map, decoder.decode(37)); map = om.createObjectNode(); map.put("long_key2", "long_value2"); - assertEquals(map, decoder.decode(50).getNode()); + assertEquals(map, decoder.decode(50)); map = om.createObjectNode(); map.put("long_key", "long_value1"); - assertEquals(map, decoder.decode(55).getNode()); + assertEquals(map, decoder.decode(55)); map = om.createObjectNode(); map.put("long_key2", "long_value2"); - assertEquals(map, decoder.decode(57).getNode()); + assertEquals(map, decoder.decode(57)); } }