001: /*-
002: * See the file LICENSE for redistribution information.
003: *
004: * Copyright (c) 2000,2008 Oracle. All rights reserved.
005: *
006: * $Id: TupleOutput.java,v 1.28.2.2 2008/01/07 15:14:06 cwl Exp $
007: */
008:
009: package com.sleepycat.bind.tuple;
010:
011: import java.math.BigInteger;
012:
013: import com.sleepycat.util.FastOutputStream;
014: import com.sleepycat.util.PackedInteger;
015: import com.sleepycat.util.UtfOps;
016:
017: /**
018: * An <code>OutputStream</code> with <code>DataOutput</code>-like methods for
019: * writing tuple fields. It is used by <code>TupleBinding</code>.
020: *
021: * <p>This class has many methods that have the same signatures as methods in
022: * the {@link java.io.DataOutput} interface. The reason this class does not
023: * implement {@link java.io.DataOutput} is because it would break the interface
024: * contract for those methods because of data format differences.</p>
025: *
026: * <p>Signed numbers are stored in the buffer in MSB (most significant byte
027: * first) order with their sign bit (high-order bit) inverted to cause negative
028: * numbers to be sorted first when comparing values as unsigned byte arrays,
029: * as done in a database. Unsigned numbers, including characters, are stored
030: * in MSB order with no change to their sign bit. BigInteger values are stored
031: * with a preceding length having the same sign as the value.</p>
032: *
033: * <p>Strings and character arrays are stored either as a fixed length array of
034: * unicode characters, where the length must be known by the application, or as
035: * a null-terminated UTF byte array.</p>
036: * <ul>
037: * <li>Null strings are UTF encoded as { 0xFF }, which is not allowed in a
038: * standard UTF encoding. This allows null strings, as distinct from empty or
039: * zero length strings, to be represented in a tuple. Using the default
040: * comparator, null strings will be ordered last.</li>
041: * <li>Zero (0x0000) character values are UTF encoded as non-zero values, and
042: * therefore embedded zeros in the string are supported. The sequence { 0xC0,
043: * 0x80 } is used to encode a zero character. This UTF encoding is the same
044: * one used by native Java UTF libraries. However, this encoding of zero does
045: * impact the lexicographical ordering, and zeros will not be sorted first (the
046: * natural order) or last. For all character values other than zero, the
047: * default UTF byte ordering is the same as the Unicode lexicographical
048: * character ordering.</li>
049: * </ul>
050: *
051: * <p>Floats and doubles are stored using two different representations: sorted
052: * representation and integer-bit (IEEE 754) representation. If you use
053: * negative floating point numbers in a key, you should use sorted
054: * representation; alternatively you may use integer-bit representation but you
055: * will need to implement and configure a custom comparator to get correct
056: * numeric ordering for negative numbers.</p>
057: *
058: * <p>To use sorted representation use this set of methods:</p>
059: * <ul>
060: * <li>{@link TupleOutput#writeSortedFloat}</li>
061: * <li>{@link TupleInput#readSortedFloat}</li>
062: * <li>{@link TupleOutput#writeSortedDouble}</li>
063: * <li>{@link TupleInput#readSortedDouble}</li>
064: * </ul>
065: *
066: * <p>To use integer-bit representation use this set of methods:</p>
067: * <ul>
068: * <li>{@link TupleOutput#writeFloat}</li>
069: * <li>{@link TupleInput#readFloat}</li>
070: * <li>{@link TupleOutput#writeDouble}</li>
071: * <li>{@link TupleInput#readDouble}</li>
072: * </ul>
073: *
074: * @author Mark Hayes
075: */
076: public class TupleOutput extends FastOutputStream {
077:
078: /**
079: * We represent a null string as a single FF UTF character, which cannot
080: * occur in a UTF encoded string.
081: */
082: static final int NULL_STRING_UTF_VALUE = ((byte) 0xFF);
083:
084: /**
085: * Creates a tuple output object for writing a byte array of tuple data.
086: */
087: public TupleOutput() {
088:
089: super ();
090: }
091:
092: /**
093: * Creates a tuple output object for writing a byte array of tuple data,
094: * using a given buffer. A new buffer will be allocated only if the number
095: * of bytes needed is greater than the length of this buffer. A reference
096: * to the byte array will be kept by this object and therefore the byte
097: * array should not be modified while this object is in use.
098: *
099: * @param buffer is the byte array to use as the buffer.
100: */
101: public TupleOutput(byte[] buffer) {
102:
103: super (buffer);
104: }
105:
106: // --- begin DataOutput compatible methods ---
107:
108: /**
109: * Writes the specified bytes to the buffer, converting each character to
110: * an unsigned byte value.
111: * Writes values that can be read using {@link TupleInput#readBytes}.
112: * Only characters with values below 0x100 may be written using this
113: * method, since the high-order 8 bits of all characters are discarded.
114: *
115: * @param val is the string containing the values to be written.
116: *
117: * @return this tuple output object.
118: *
119: * @throws NullPointerException if the val parameter is null.
120: */
121: public final TupleOutput writeBytes(String val) {
122:
123: writeBytes(val.toCharArray());
124: return this ;
125: }
126:
127: /**
128: * Writes the specified characters to the buffer, converting each character
129: * to a two byte unsigned value.
130: * Writes values that can be read using {@link TupleInput#readChars}.
131: *
132: * @param val is the string containing the characters to be written.
133: *
134: * @return this tuple output object.
135: *
136: * @throws NullPointerException if the val parameter is null.
137: */
138: public final TupleOutput writeChars(String val) {
139:
140: writeChars(val.toCharArray());
141: return this ;
142: }
143:
144: /**
145: * Writes the specified characters to the buffer, converting each character
146: * to UTF format, and adding a null terminator byte.
147: * Note that zero (0x0000) character values are encoded as non-zero values
148: * and a null String parameter is encoded as 0xFF.
149: * Writes values that can be read using {@link TupleInput#readString()}.
150: *
151: * @param val is the string containing the characters to be written.
152: *
153: * @return this tuple output object.
154: */
155: public final TupleOutput writeString(String val) {
156:
157: if (val != null) {
158: writeString(val.toCharArray());
159: } else {
160: writeFast(NULL_STRING_UTF_VALUE);
161: }
162: writeFast(0);
163: return this ;
164: }
165:
166: /**
167: * Writes a char (two byte) unsigned value to the buffer.
168: * Writes values that can be read using {@link TupleInput#readChar}.
169: *
170: * @param val is the value to write to the buffer.
171: *
172: * @return this tuple output object.
173: */
174: public final TupleOutput writeChar(int val) {
175:
176: writeFast((byte) (val >>> 8));
177: writeFast((byte) val);
178: return this ;
179: }
180:
181: /**
182: * Writes a boolean (one byte) unsigned value to the buffer, writing one
183: * if the value is true and zero if it is false.
184: * Writes values that can be read using {@link TupleInput#readBoolean}.
185: *
186: * @param val is the value to write to the buffer.
187: *
188: * @return this tuple output object.
189: */
190: public final TupleOutput writeBoolean(boolean val) {
191:
192: writeFast(val ? (byte) 1 : (byte) 0);
193: return this ;
194: }
195:
196: /**
197: * Writes an signed byte (one byte) value to the buffer.
198: * Writes values that can be read using {@link TupleInput#readByte}.
199: *
200: * @param val is the value to write to the buffer.
201: *
202: * @return this tuple output object.
203: */
204: public final TupleOutput writeByte(int val) {
205:
206: writeUnsignedByte(val ^ 0x80);
207: return this ;
208: }
209:
210: /**
211: * Writes an signed short (two byte) value to the buffer.
212: * Writes values that can be read using {@link TupleInput#readShort}.
213: *
214: * @param val is the value to write to the buffer.
215: *
216: * @return this tuple output object.
217: */
218: public final TupleOutput writeShort(int val) {
219:
220: writeUnsignedShort(val ^ 0x8000);
221: return this ;
222: }
223:
224: /**
225: * Writes an signed int (four byte) value to the buffer.
226: * Writes values that can be read using {@link TupleInput#readInt}.
227: *
228: * @param val is the value to write to the buffer.
229: *
230: * @return this tuple output object.
231: */
232: public final TupleOutput writeInt(int val) {
233:
234: writeUnsignedInt(val ^ 0x80000000);
235: return this ;
236: }
237:
238: /**
239: * Writes an signed long (eight byte) value to the buffer.
240: * Writes values that can be read using {@link TupleInput#readLong}.
241: *
242: * @param val is the value to write to the buffer.
243: *
244: * @return this tuple output object.
245: */
246: public final TupleOutput writeLong(long val) {
247:
248: writeUnsignedLong(val ^ 0x8000000000000000L);
249: return this ;
250: }
251:
252: /**
253: * Writes an signed float (four byte) value to the buffer.
254: * Writes values that can be read using {@link TupleInput#readFloat}.
255: * <code>Float.floatToIntBits</code> is used to convert the signed float
256: * value.
257: *
258: * <p><em>Note:</em> This method produces byte array values that by default
259: * (without a custom comparator) do <em>not</em> sort correctly for
260: * negative values. Only non-negative values are sorted correctly by
261: * default. To sort all values correctly by default, use {@link
262: * #writeSortedFloat}.</p>
263: *
264: * @param val is the value to write to the buffer.
265: *
266: * @return this tuple output object.
267: */
268: public final TupleOutput writeFloat(float val) {
269:
270: writeUnsignedInt(Float.floatToIntBits(val));
271: return this ;
272: }
273:
274: /**
275: * Writes an signed double (eight byte) value to the buffer.
276: * Writes values that can be read using {@link TupleInput#readDouble}.
277: * <code>Double.doubleToLongBits</code> is used to convert the signed
278: * double value.
279: *
280: * <p><em>Note:</em> This method produces byte array values that by default
281: * (without a custom comparator) do <em>not</em> sort correctly for
282: * negative values. Only non-negative values are sorted correctly by
283: * default. To sort all values correctly by default, use {@link
284: * #writeSortedDouble}.</p>
285: *
286: * @param val is the value to write to the buffer.
287: *
288: * @return this tuple output object.
289: */
290: public final TupleOutput writeDouble(double val) {
291:
292: writeUnsignedLong(Double.doubleToLongBits(val));
293: return this ;
294: }
295:
296: /**
297: * Writes a signed float (four byte) value to the buffer, with support for
298: * correct default sorting of all values.
299: * Writes values that can be read using {@link TupleInput#readSortedFloat}.
300: *
301: * <p><code>Float.floatToIntBits</code> and the following bit manipulations
302: * are used to convert the signed float value to a representation that is
303: * sorted correctly by default.</p>
304: * <pre>
305: * int intVal = Float.floatToIntBits(val);
306: * intVal ^= (intVal < 0) ? 0xffffffff : 0x80000000;
307: * </pre>
308: *
309: * @param val is the value to write to the buffer.
310: *
311: * @return this tuple output object.
312: */
313: public final TupleOutput writeSortedFloat(float val) {
314:
315: int intVal = Float.floatToIntBits(val);
316: intVal ^= (intVal < 0) ? 0xffffffff : 0x80000000;
317: writeUnsignedInt(intVal);
318: return this ;
319: }
320:
321: /**
322: * Writes a signed double (eight byte) value to the buffer, with support
323: * for correct default sorting of all values.
324: * Writes values that can be read using {@link TupleInput#readSortedDouble}.
325: *
326: * <p><code>Float.doubleToLongBits</code> and the following bit
327: * manipulations are used to convert the signed double value to a
328: * representation that is sorted correctly by default.</p>
329: * <pre>
330: * long longVal = Double.doubleToLongBits(val);
331: * longVal ^= (longVal < 0) ? 0xffffffffffffffffL : 0x8000000000000000L;
332: * </pre>
333: *
334: * @param val is the value to write to the buffer.
335: *
336: * @return this tuple output object.
337: */
338: public final TupleOutput writeSortedDouble(double val) {
339:
340: long longVal = Double.doubleToLongBits(val);
341: longVal ^= (longVal < 0) ? 0xffffffffffffffffL
342: : 0x8000000000000000L;
343: writeUnsignedLong(longVal);
344: return this ;
345: }
346:
347: // --- end DataOutput compatible methods ---
348:
349: /**
350: * Writes the specified bytes to the buffer, converting each character to
351: * an unsigned byte value.
352: * Writes values that can be read using {@link TupleInput#readBytes}.
353: * Only characters with values below 0x100 may be written using this
354: * method, since the high-order 8 bits of all characters are discarded.
355: *
356: * @param chars is the array of values to be written.
357: *
358: * @return this tuple output object.
359: *
360: * @throws NullPointerException if the chars parameter is null.
361: */
362: public final TupleOutput writeBytes(char[] chars) {
363:
364: for (int i = 0; i < chars.length; i++) {
365: writeFast((byte) chars[i]);
366: }
367: return this ;
368: }
369:
370: /**
371: * Writes the specified characters to the buffer, converting each character
372: * to a two byte unsigned value.
373: * Writes values that can be read using {@link TupleInput#readChars}.
374: *
375: * @param chars is the array of characters to be written.
376: *
377: * @return this tuple output object.
378: *
379: * @throws NullPointerException if the chars parameter is null.
380: */
381: public final TupleOutput writeChars(char[] chars) {
382:
383: for (int i = 0; i < chars.length; i++) {
384: writeFast((byte) (chars[i] >>> 8));
385: writeFast((byte) chars[i]);
386: }
387: return this ;
388: }
389:
390: /**
391: * Writes the specified characters to the buffer, converting each character
392: * to UTF format.
393: * Note that zero (0x0000) character values are encoded as non-zero values.
394: * Writes values that can be read using {@link TupleInput#readString(int)}
395: * or {@link TupleInput#readString(char[])}.
396: *
397: * @param chars is the array of characters to be written.
398: *
399: * @return this tuple output object.
400: *
401: * @throws NullPointerException if the chars parameter is null.
402: */
403: public final TupleOutput writeString(char[] chars) {
404:
405: if (chars.length == 0)
406: return this ;
407:
408: int utfLength = UtfOps.getByteLength(chars);
409:
410: makeSpace(utfLength);
411: UtfOps.charsToBytes(chars, 0, getBufferBytes(),
412: getBufferLength(), chars.length);
413: addSize(utfLength);
414: return this ;
415: }
416:
417: /**
418: * Writes an unsigned byte (one byte) value to the buffer.
419: * Writes values that can be read using {@link
420: * TupleInput#readUnsignedByte}.
421: *
422: * @param val is the value to write to the buffer.
423: *
424: * @return this tuple output object.
425: */
426: public final TupleOutput writeUnsignedByte(int val) {
427:
428: writeFast(val);
429: return this ;
430: }
431:
432: /**
433: * Writes an unsigned short (two byte) value to the buffer.
434: * Writes values that can be read using {@link
435: * TupleInput#readUnsignedShort}.
436: *
437: * @param val is the value to write to the buffer.
438: *
439: * @return this tuple output object.
440: */
441: public final TupleOutput writeUnsignedShort(int val) {
442:
443: writeFast((byte) (val >>> 8));
444: writeFast((byte) val);
445: return this ;
446: }
447:
448: /**
449: * Writes an unsigned int (four byte) value to the buffer.
450: * Writes values that can be read using {@link
451: * TupleInput#readUnsignedInt}.
452: *
453: * @param val is the value to write to the buffer.
454: *
455: * @return this tuple output object.
456: */
457: public final TupleOutput writeUnsignedInt(long val) {
458:
459: writeFast((byte) (val >>> 24));
460: writeFast((byte) (val >>> 16));
461: writeFast((byte) (val >>> 8));
462: writeFast((byte) val);
463: return this ;
464: }
465:
466: /**
467: * This method is private since an unsigned long cannot be treated as
468: * such in Java, nor converted to a BigInteger of the same value.
469: */
470: private final TupleOutput writeUnsignedLong(long val) {
471:
472: writeFast((byte) (val >>> 56));
473: writeFast((byte) (val >>> 48));
474: writeFast((byte) (val >>> 40));
475: writeFast((byte) (val >>> 32));
476: writeFast((byte) (val >>> 24));
477: writeFast((byte) (val >>> 16));
478: writeFast((byte) (val >>> 8));
479: writeFast((byte) val);
480: return this ;
481: }
482:
483: /**
484: * Writes a packed integer. Note that packed integers are not appropriate
485: * for sorted values (keys) unless a custom comparator is used.
486: *
487: * @see PackedInteger
488: */
489: public final void writePackedInt(int val) {
490:
491: makeSpace(PackedInteger.MAX_LENGTH);
492:
493: int oldLen = getBufferLength();
494: int newLen = PackedInteger.writeInt(getBufferBytes(), oldLen,
495: val);
496:
497: addSize(newLen - oldLen);
498: }
499:
500: /**
501: * Writes a {@code BigInteger}. Supported {@code BigInteger} values are
502: * limited to those with a byte array ({@link BigInteger#toByteArray})
503: * representation with a size of 0x7fff bytes or less. The maximum {@code
504: * BigInteger} value is (2<sup>0x3fff7</sup> - 1) and the minimum value is
505: * (-2<sup>0x3fff7</sup>).
506: *
507: * <p>The byte format for a {@code BigInteger} value is:</p>
508: * <ul>
509: * <li>Byte 0 and 1: The length of the following bytes, negated if the
510: * {@code BigInteger} value is negative, and written as a sorted value as
511: * if {@link #writeShort} were called.</li>
512: * <li>Byte 2: The first byte of the {@link BigInteger#toByteArray} array,
513: * written as a sorted value as if {@link #writeByte} were called.</li>
514: * <li>Byte 3 to N: The second and remaining bytes, if any, of the {@link
515: * BigInteger#toByteArray} array, written without modification.</li>
516: * </ul>
517: * <p>This format provides correct default sorting when the default
518: * byte-by-byte comparison is used.</p>
519: *
520: * @throws NullPointerException if val is null.
521: *
522: * @throws IllegalArgumentException if the byte array representation of val
523: * is larger than 0x7fff bytes.
524: */
525: public final TupleOutput writeBigInteger(BigInteger val) {
526: byte[] a = val.toByteArray();
527: if (a.length > Short.MAX_VALUE) {
528: throw new IllegalArgumentException(
529: "BigInteger byte array is larger than 0x7fff bytes");
530: }
531: int firstByte = a[0];
532: writeShort((firstByte < 0) ? (-a.length) : a.length);
533: writeByte(firstByte);
534: writeFast(a, 1, a.length - 1);
535: return this ;
536: }
537:
538: /**
539: * Returns the byte length of a given {@code BigInteger} value.
540: *
541: * @see TupleOutput#writeBigInteger
542: */
543: public static int getBigIntegerByteLength(BigInteger val) {
544: return 2 /* length bytes */+ (val.bitLength() + 1 /* sign bit */+ 7 /* round up */) / 8;
545: }
546: }
|