You are viewing a plain text version of this content. The canonical link for it is here.
Posted to java-commits@lucene.apache.org by mi...@apache.org on 2009/03/18 22:35:51 UTC
svn commit: r755742 - in /lucene/java/trunk: CHANGES.txt
src/java/org/apache/lucene/util/IndexableBinaryStringTools.java
src/test/org/apache/lucene/util/TestIndexableBinaryStringTools.java
Author: mikemccand
Date: Wed Mar 18 21:35:51 2009
New Revision: 755742
URL: http://svn.apache.org/viewvc?rev=755742&view=rev
Log:
LUCENE-1434: add IndexableBinaryStringTools
Added:
lucene/java/trunk/src/java/org/apache/lucene/util/IndexableBinaryStringTools.java (with props)
lucene/java/trunk/src/test/org/apache/lucene/util/TestIndexableBinaryStringTools.java (with props)
Modified:
lucene/java/trunk/CHANGES.txt
Modified: lucene/java/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/java/trunk/CHANGES.txt?rev=755742&r1=755741&r2=755742&view=diff
==============================================================================
--- lucene/java/trunk/CHANGES.txt (original)
+++ lucene/java/trunk/CHANGES.txt Wed Mar 18 21:35:51 2009
@@ -178,6 +178,11 @@
resources with the original reader. (Torin Danil via Mike
McCandless)
+17. LUCENE-1434: Added org.apache.lucene.util.IndexableBinaryStringTools,
+ to encode byte[] as String values that are valid terms, and
+ maintain sort order of the original byte[] when the bytes are
+ interpreted as unsigned. (Steven Rowe via Mike McCandless)
+
Optimizations
1. LUCENE-1427: Fixed QueryWrapperFilter to not waste time computing
Added: lucene/java/trunk/src/java/org/apache/lucene/util/IndexableBinaryStringTools.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/java/org/apache/lucene/util/IndexableBinaryStringTools.java?rev=755742&view=auto
==============================================================================
--- lucene/java/trunk/src/java/org/apache/lucene/util/IndexableBinaryStringTools.java (added)
+++ lucene/java/trunk/src/java/org/apache/lucene/util/IndexableBinaryStringTools.java Wed Mar 18 21:35:51 2009
@@ -0,0 +1,315 @@
+package org.apache.lucene.util;
+
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.nio.CharBuffer;
+import java.nio.ByteBuffer;
+
+/**
+ * Provides support for converting byte sequences to Strings and back again.
+ * The resulting Strings preserve the original byte sequences' sort order.
+ *
+ * The Strings are constructed using a Base 8000h encoding of the original
+ * binary data - each char of an encoded String represents a 15-bit chunk
+ * from the byte sequence. Base 8000h was chosen because it allows for all
+ * lower 15 bits of char to be used without restriction; the surrogate range
+ * [U+D8000-U+DFFF] does not represent valid chars, and would require
+ * complicated handling to avoid them and allow use of char's high bit.
+ *
+ * Although unset bits are used as padding in the final char, the original
+ * byte sequence could contain trailing bytes with no set bits (null bytes):
+ * padding is indistinguishable from valid information. To overcome this
+ * problem, a char is appended, indicating the number of encoded bytes in the
+ * final content char.
+ *
+ * This class's operations are defined over CharBuffers and ByteBuffers, to
+ * allow for wrapped arrays to be reused, reducing memory allocation costs for
+ * repeated operations. Note that this class calls array() and arrayOffset()
+ * on the CharBuffers and ByteBuffers it uses, so only wrapped arrays may be
+ * used. This class interprets the arrayOffset() and limit() values returned by
+ * its input buffers as beginning and end+1 positions on the wrapped array,
+ * resprectively; similarly, on the output buffer, arrayOffset() is the first
+ * position written to, and limit() is set to one past the final output array
+ * position.
+ */
+public class IndexableBinaryStringTools {
+
+ private static final CodingCase[] CODING_CASES = {
+ // CodingCase(int initialShift, int finalShift)
+ new CodingCase( 7, 1 ),
+ // CodingCase(int initialShift, int middleShift, int finalShift)
+ new CodingCase(14, 6, 2),
+ new CodingCase(13, 5, 3),
+ new CodingCase(12, 4, 4),
+ new CodingCase(11, 3, 5),
+ new CodingCase(10, 2, 6),
+ new CodingCase( 9, 1, 7),
+ new CodingCase( 8, 0 )
+ };
+
+ // Export only static methods
+ private IndexableBinaryStringTools() {}
+
+ /**
+ * Returns the number of chars required to encode the given byte sequence.
+ *
+ * @param original The byte sequence to be encoded. Must be backed by an array.
+ * @return The number of chars required to encode the given byte sequence
+ * @throws IllegalArgumentException If the given ByteBuffer is not backed by an array
+ */
+ public static int getEncodedLength(ByteBuffer original)
+ throws IllegalArgumentException {
+ if (original.hasArray()) {
+ // Use long for intermediaries to protect against overflow
+ long length = (long)(original.limit() - original.arrayOffset());
+ return (int)((length * 8L + 14L) / 15L) + 1;
+ } else {
+ throw new IllegalArgumentException("original argument must have a backing array");
+ }
+ }
+
+ /**
+ * Returns the number of bytes required to decode the given char sequence.
+ *
+ * @param encoded The char sequence to be encoded. Must be backed by an array.
+ * @return The number of bytes required to decode the given char sequence
+ * @throws IllegalArgumentException If the given CharBuffer is not backed by an array
+ */
+ public static int getDecodedLength(CharBuffer encoded)
+ throws IllegalArgumentException {
+ if (encoded.hasArray()) {
+ int numChars = encoded.limit() - encoded.arrayOffset() - 1;
+ if (numChars <= 0) {
+ return 0;
+ } else {
+ int numFullBytesInFinalChar = encoded.charAt(encoded.limit() - 1);
+ int numEncodedChars = numChars - 1;
+ return (numEncodedChars * 15 + 7) / 8 + numFullBytesInFinalChar;
+ }
+ } else {
+ throw new IllegalArgumentException("encoded argument must have a backing array");
+ }
+ }
+
+ /**
+ * Encodes the input byte sequence into the output char sequence. Before
+ * calling this method, ensure that the output CharBuffer has sufficient
+ * capacity by calling {@link #getEncodedLength(java.nio.ByteBuffer)}.
+ *
+ * @param input The byte sequence to encode
+ * @param output Where the char sequence encoding result will go. The limit
+ * is set to one past the position of the final char.
+ * @throws IllegalArgumentException If either the input or the output buffer
+ * is not backed by an array
+ */
+ public static void encode(ByteBuffer input, CharBuffer output) {
+ if (input.hasArray() && output.hasArray()) {
+ byte[] inputArray = input.array();
+ int inputOffset = input.arrayOffset();
+ int inputLength = input.limit() - inputOffset;
+ char[] outputArray = output.array();
+ int outputOffset = output.arrayOffset();
+ int outputLength = getEncodedLength(input);
+ output.limit(outputOffset + outputLength); // Set output final pos + 1
+ output.position(0);
+ if (inputLength > 0) {
+ int inputByteNum = inputOffset;
+ int caseNum = 0;
+ int outputCharNum = outputOffset;
+ CodingCase codingCase;
+ for ( ; inputByteNum + CODING_CASES[caseNum].numBytes <= inputLength ;
+ ++outputCharNum ) {
+ codingCase = CODING_CASES[caseNum];
+ if (2 == codingCase.numBytes) {
+ outputArray[outputCharNum]
+ = (char)(((inputArray[inputByteNum] & 0xFF) << codingCase.initialShift)
+ + (((inputArray[inputByteNum + 1] & 0xFF) >>> codingCase.finalShift)
+ & codingCase.finalMask)
+ & (short)0x7FFF);
+ } else { // numBytes is 3
+ outputArray[outputCharNum]
+ = (char)(((inputArray[inputByteNum] & 0xFF) << codingCase.initialShift)
+ + ((inputArray[inputByteNum + 1] & 0xFF) << codingCase.middleShift)
+ + (((inputArray[inputByteNum + 2] & 0xFF) >>> codingCase.finalShift)
+ & codingCase.finalMask)
+ & (short)0x7FFF);
+ }
+ inputByteNum += codingCase.advanceBytes;
+ if (++caseNum == CODING_CASES.length) {
+ caseNum = 0;
+ }
+ }
+ // Produce final char (if any) and trailing count chars.
+ codingCase = CODING_CASES[caseNum];
+
+ if (inputByteNum + 1 < inputLength) { // codingCase.numBytes must be 3
+ outputArray[outputCharNum++]
+ = (char)((((inputArray[inputByteNum] & 0xFF) << codingCase.initialShift)
+ + ((inputArray[inputByteNum + 1] & 0xFF) << codingCase.middleShift))
+ & (short)0x7FFF);
+ // Add trailing char containing the number of full bytes in final char
+ outputArray[outputCharNum++] = (char)1;
+ } else if (inputByteNum < inputLength) {
+ outputArray[outputCharNum++]
+ = (char)(((inputArray[inputByteNum] & 0xFF) << codingCase.initialShift)
+ & (short)0x7FFF);
+ // Add trailing char containing the number of full bytes in final char
+ outputArray[outputCharNum++] = caseNum == 0 ? (char)1 : (char)0;
+ } else { // No left over bits - last char is completely filled.
+ // Add trailing char containing the number of full bytes in final char
+ outputArray[outputCharNum++] = (char)1;
+ }
+ }
+ } else {
+ throw new IllegalArgumentException("Arguments must have backing arrays");
+ }
+ }
+
+ /**
+ * Decodes the input char sequence into the output byte sequence. Before
+ * calling this method, ensure that the output ByteBuffer has sufficient
+ * capacity by calling {@link #getDecodedLength(java.nio.CharBuffer)}.
+ *
+ * @param input The char sequence to decode
+ * @param output Where the byte sequence decoding result will go. The limit
+ * is set to one past the position of the final char.
+ * @throws IllegalArgumentException If either the input or the output buffer
+ * is not backed by an array
+ */
+ public static void decode(CharBuffer input, ByteBuffer output) {
+ if (input.hasArray() && output.hasArray()) {
+ int numInputChars = input.limit() - input.arrayOffset() - 1;
+ int numOutputBytes = getDecodedLength(input);
+ output.limit(numOutputBytes + output.arrayOffset()); // Set output final pos + 1
+ output.position(0);
+ byte[] outputArray = output.array();
+ char[] inputArray = input.array();
+ if (numOutputBytes > 0) {
+ int caseNum = 0;
+ int outputByteNum = output.arrayOffset();
+ int inputCharNum = input.arrayOffset();
+ short inputChar;
+ CodingCase codingCase;
+ for ( ; inputCharNum < numInputChars - 1 ; ++inputCharNum) {
+ codingCase = CODING_CASES[caseNum];
+ inputChar = (short)inputArray[inputCharNum];
+ if (2 == codingCase.numBytes) {
+ if (0 == caseNum) {
+ outputArray[outputByteNum] = (byte)(inputChar >>> codingCase.initialShift);
+ } else {
+ outputArray[outputByteNum] += (byte)(inputChar >>> codingCase.initialShift);
+ }
+ outputArray[outputByteNum + 1] = (byte)((inputChar & codingCase.finalMask)
+ << codingCase.finalShift);
+ } else { // numBytes is 3
+ outputArray[outputByteNum] += (byte)(inputChar >>> codingCase.initialShift);
+ outputArray[outputByteNum + 1] = (byte)((inputChar & codingCase.middleMask)
+ >>> codingCase.middleShift);
+ outputArray[outputByteNum + 2] = (byte)((inputChar & codingCase.finalMask)
+ << codingCase.finalShift);
+ }
+ outputByteNum += codingCase.advanceBytes;
+ if (++caseNum == CODING_CASES.length) {
+ caseNum = 0;
+ }
+ }
+ // Handle final char
+ inputChar = (short)inputArray[inputCharNum];
+ codingCase = CODING_CASES[caseNum];
+ if (0 == caseNum) {
+ outputArray[outputByteNum] = 0;
+ }
+ outputArray[outputByteNum] += (byte)(inputChar >>> codingCase.initialShift);
+ int bytesLeft = numOutputBytes - outputByteNum;
+ if (bytesLeft > 1) {
+ if (2 == codingCase.numBytes) {
+ outputArray[outputByteNum + 1] = (byte)((inputChar & codingCase.finalMask)
+ >>> codingCase.finalShift);
+ } else { // numBytes is 3
+ outputArray[outputByteNum + 1] = (byte)((inputChar & codingCase.middleMask)
+ >>> codingCase.middleShift);
+ if (bytesLeft > 2) {
+ outputArray[outputByteNum + 2] = (byte)((inputChar & codingCase.finalMask)
+ << codingCase.finalShift);
+ }
+ }
+ }
+ }
+ } else {
+ throw new IllegalArgumentException("Arguments must have backing arrays");
+ }
+ }
+
+ /**
+ * Decodes the given char sequence, which must have been encoded by
+ * {@link #encode(java.nio.ByteBuffer)} or
+ * {@link #encode(java.nio.ByteBuffer, java.nio.CharBuffer)}.
+ *
+ * @param input The char sequence to decode
+ * @return A byte sequence containing the decoding result. The limit
+ * is set to one past the position of the final char.
+ * @throws IllegalArgumentException If the input buffer is not backed by an
+ * array
+ */
+ public static ByteBuffer decode(CharBuffer input) {
+ byte[] outputArray = new byte[getDecodedLength(input)];
+ ByteBuffer output = ByteBuffer.wrap(outputArray);
+ decode(input, output);
+ return output;
+ }
+
+ /**
+ * Encodes the input byte sequence.
+ *
+ * @param input The byte sequence to encode
+ * @return A char sequence containing the encoding result. The limit is set
+ * to one past the position of the final char.
+ * @throws IllegalArgumentException If the input buffer is not backed by an
+ * array
+ */
+ public static CharBuffer encode(ByteBuffer input) {
+ char[] outputArray = new char[getEncodedLength(input)];
+ CharBuffer output = CharBuffer.wrap(outputArray);
+ encode(input, output);
+ return output;
+ }
+
+ static class CodingCase {
+ int numBytes, initialShift, middleShift, finalShift, advanceBytes = 2;
+ short middleMask, finalMask;
+
+ CodingCase(int initialShift, int middleShift, int finalShift) {
+ this.numBytes = 3;
+ this.initialShift = initialShift;
+ this.middleShift = middleShift;
+ this.finalShift = finalShift;
+ this.finalMask = (short)((short)0xFF >>> finalShift);
+ this.middleMask = (short)((short)0xFF << middleShift);
+ }
+
+ CodingCase(int initialShift, int finalShift) {
+ this.numBytes = 2;
+ this.initialShift = initialShift;
+ this.finalShift = finalShift;
+ this.finalMask = (short)((short)0xFF >>> finalShift);
+ if (finalShift != 0) {
+ advanceBytes = 1;
+ }
+ }
+ }
+}
Propchange: lucene/java/trunk/src/java/org/apache/lucene/util/IndexableBinaryStringTools.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: lucene/java/trunk/src/test/org/apache/lucene/util/TestIndexableBinaryStringTools.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/test/org/apache/lucene/util/TestIndexableBinaryStringTools.java?rev=755742&view=auto
==============================================================================
--- lucene/java/trunk/src/test/org/apache/lucene/util/TestIndexableBinaryStringTools.java (added)
+++ lucene/java/trunk/src/test/org/apache/lucene/util/TestIndexableBinaryStringTools.java Wed Mar 18 21:35:51 2009
@@ -0,0 +1,187 @@
+package org.apache.lucene.util;
+
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.util.Random;
+import java.nio.CharBuffer;
+import java.nio.ByteBuffer;
+
+public class TestIndexableBinaryStringTools extends LuceneTestCase {
+ private static final int NUM_RANDOM_TESTS = 20000;
+ private static final int MAX_RANDOM_BINARY_LENGTH = 300;
+
+ public void testSingleBinaryRoundTrip() {
+ byte[] binary = new byte[]
+ { (byte)0x23, (byte)0x98, (byte)0x13, (byte)0xE4, (byte)0x76, (byte)0x41,
+ (byte)0xB2, (byte)0xC9, (byte)0x7F, (byte)0x0A, (byte)0xA6, (byte)0xD8 };
+
+ ByteBuffer binaryBuf = ByteBuffer.wrap(binary);
+ CharBuffer encoded = IndexableBinaryStringTools.encode(binaryBuf);
+ ByteBuffer decoded = IndexableBinaryStringTools.decode(encoded);
+ assertEquals("Round trip decode/decode returned different results:"
+ + System.getProperty("line.separator")
+ + "original: " + binaryDump(binaryBuf)
+ + System.getProperty("line.separator")
+ + " encoded: " + charArrayDump(encoded)
+ + System.getProperty("line.separator")
+ + " decoded: " + binaryDump(decoded),
+ binaryBuf, decoded);
+ }
+
+ public void testEncodedSortability() {
+ Random random = newRandom();
+ byte[] originalArray1 = new byte[MAX_RANDOM_BINARY_LENGTH];
+ ByteBuffer originalBuf1 = ByteBuffer.wrap(originalArray1);
+ char[] originalString1 = new char[MAX_RANDOM_BINARY_LENGTH];
+ CharBuffer originalStringBuf1 = CharBuffer.wrap(originalString1);
+ char[] encoded1 = new char[IndexableBinaryStringTools.getEncodedLength(originalBuf1)];
+ CharBuffer encodedBuf1 = CharBuffer.wrap(encoded1);
+ byte[] original2 = new byte[MAX_RANDOM_BINARY_LENGTH];
+ ByteBuffer originalBuf2 = ByteBuffer.wrap(original2);
+ char[] originalString2 = new char[MAX_RANDOM_BINARY_LENGTH];
+ CharBuffer originalStringBuf2 = CharBuffer.wrap(originalString2);
+ char[] encoded2 = new char[IndexableBinaryStringTools.getEncodedLength(originalBuf2)];
+ CharBuffer encodedBuf2 = CharBuffer.wrap(encoded2);
+ for (int testNum = 0 ; testNum < NUM_RANDOM_TESTS ; ++testNum) {
+ int numBytes1 = random.nextInt(MAX_RANDOM_BINARY_LENGTH - 1) + 1; // Min == 1
+ originalBuf1.limit(numBytes1);
+ originalStringBuf1.limit(numBytes1);
+
+ for (int byteNum = 0 ; byteNum < numBytes1 ; ++byteNum) {
+ int randomInt = random.nextInt(0x100);
+ originalArray1[byteNum] = (byte) randomInt;
+ originalString1[byteNum] = (char)randomInt;
+ }
+
+ int numBytes2 = random.nextInt(MAX_RANDOM_BINARY_LENGTH - 1) + 1; // Min == 1
+ originalBuf2.limit(numBytes2);
+ originalStringBuf2.limit(numBytes2);
+ for (int byteNum = 0 ; byteNum < numBytes2 ; ++byteNum) {
+ int randomInt = random.nextInt(0x100);
+ original2[byteNum] = (byte)randomInt;
+ originalString2[byteNum] = (char)randomInt;
+ }
+ int originalComparison = originalStringBuf1.compareTo(originalStringBuf2);
+ originalComparison = originalComparison < 0 ? -1 : originalComparison > 0 ? 1 : 0;
+
+ IndexableBinaryStringTools.encode(originalBuf1, encodedBuf1);
+ IndexableBinaryStringTools.encode(originalBuf2, encodedBuf2);
+
+ int encodedComparison = encodedBuf1.compareTo(encodedBuf2);
+ encodedComparison = encodedComparison < 0 ? -1 : encodedComparison > 0 ? 1 : 0;
+
+ assertEquals("Test #" + (testNum + 1)
+ + ": Original bytes and encoded chars compare differently:"
+ + System.getProperty("line.separator")
+ + " binary 1: " + binaryDump(originalBuf1)
+ + System.getProperty("line.separator")
+ + " binary 2: " + binaryDump(originalBuf2)
+ + System.getProperty("line.separator")
+ + "encoded 1: " + charArrayDump(encodedBuf1)
+ + System.getProperty("line.separator")
+ + "encoded 2: " + charArrayDump(encodedBuf2)
+ + System.getProperty("line.separator"),
+ originalComparison, encodedComparison);
+ }
+ }
+
+ public void testEmptyInput() {
+ byte[] binary = new byte[0];
+ CharBuffer encoded = IndexableBinaryStringTools.encode(ByteBuffer.wrap(binary));
+ ByteBuffer decoded = IndexableBinaryStringTools.decode(encoded);
+ assertNotNull("decode() returned null", decoded);
+ assertEquals("decoded empty input was not empty", decoded.limit(), 0);
+ }
+
+ public void testAllNullInput() {
+ byte[] binary = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+ ByteBuffer binaryBuf = ByteBuffer.wrap(binary);
+ CharBuffer encoded = IndexableBinaryStringTools.encode(binaryBuf);
+ assertNotNull("encode() returned null", encoded);
+ ByteBuffer decodedBuf = IndexableBinaryStringTools.decode(encoded);
+ assertNotNull("decode() returned null", decodedBuf);
+ assertEquals("Round trip decode/decode returned different results:"
+ + System.getProperty("line.separator")
+ + " original: " + binaryDump(binaryBuf)
+ + System.getProperty("line.separator")
+ + "decodedBuf: " + binaryDump(decodedBuf),
+ binaryBuf, decodedBuf);
+ }
+
+ public void testRandomBinaryRoundTrip() {
+ Random random = newRandom();
+ byte[] binary = new byte[MAX_RANDOM_BINARY_LENGTH];
+ ByteBuffer binaryBuf = ByteBuffer.wrap(binary);
+ char[] encoded = new char[IndexableBinaryStringTools.getEncodedLength(binaryBuf)];
+ CharBuffer encodedBuf = CharBuffer.wrap(encoded);
+ byte[] decoded = new byte[MAX_RANDOM_BINARY_LENGTH];
+ ByteBuffer decodedBuf = ByteBuffer.wrap(decoded);
+ for (int testNum = 0 ; testNum < NUM_RANDOM_TESTS ; ++testNum) {
+ int numBytes = random.nextInt(MAX_RANDOM_BINARY_LENGTH - 1) + 1 ; // Min == 1
+ binaryBuf.limit(numBytes);
+ for (int byteNum = 0 ; byteNum < numBytes ; ++byteNum) {
+ binary[byteNum] = (byte)random.nextInt(0x100);
+ }
+ IndexableBinaryStringTools.encode(binaryBuf, encodedBuf);
+ IndexableBinaryStringTools.decode(encodedBuf, decodedBuf);
+ assertEquals("Test #" + (testNum + 1)
+ + ": Round trip decode/decode returned different results:"
+ + System.getProperty("line.separator")
+ + " original: " + binaryDump(binaryBuf)
+ + System.getProperty("line.separator")
+ + "encodedBuf: " + charArrayDump(encodedBuf)
+ + System.getProperty("line.separator")
+ + "decodedBuf: " + binaryDump(decodedBuf),
+ binaryBuf, decodedBuf);
+ }
+ }
+
+ public String binaryDump(ByteBuffer binaryBuf) {
+ StringBuffer buf = new StringBuffer();
+ int numBytes = binaryBuf.limit() - binaryBuf.arrayOffset();
+ byte[] binary = binaryBuf.array();
+ for (int byteNum = 0 ; byteNum < numBytes ; ++byteNum) {
+ String hex = Integer.toHexString((int)binary[byteNum] & 0xFF);
+ if (hex.length() == 1) {
+ buf.append('0');
+ }
+ buf.append(hex.toUpperCase());
+ if (byteNum < numBytes - 1) {
+ buf.append(' ');
+ }
+ }
+ return buf.toString();
+ }
+
+ public String charArrayDump(CharBuffer charBuf) {
+ StringBuffer buf = new StringBuffer();
+ int numBytes = charBuf.limit() - charBuf.arrayOffset();
+ char[] charArray = charBuf.array();
+ for (int charNum = 0 ; charNum < numBytes ; ++charNum) {
+ String hex = Integer.toHexString((int)charArray[charNum]);
+ for (int digit = 0 ; digit < 4 - hex.length() ; ++digit) {
+ buf.append('0');
+ }
+ buf.append(hex.toUpperCase());
+ if (charNum < numBytes - 1) {
+ buf.append(' ');
+ }
+ }
+ return buf.toString();
+ }
+}
Propchange: lucene/java/trunk/src/test/org/apache/lucene/util/TestIndexableBinaryStringTools.java
------------------------------------------------------------------------------
svn:eol-style = native