ceddaea0e004afc5dcd6dc4add70ebd7e320dc47
1 /*******************************************************************************.
2 * Copyright (c) 2011, 2014 Ericsson, Ecole Polytechnique de Montreal and others
4 * All rights reserved. This program and the accompanying materials are made
5 * available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * Matthew Khouzam - Initial Design and implementation + overhaul
11 * Francis Giraldeau - Initial API and implementation
12 * Philippe Proulx - Some refinement and optimization
13 * Etienne Bergeron <Etienne.Bergeron@gmail.com> - fix zero size read + cleanup
14 *******************************************************************************/
16 package org
.eclipse
.tracecompass
.ctf
.core
.event
.io
;
18 import static org
.eclipse
.tracecompass
.common
.core
.NonNullUtils
.checkNotNull
;
20 import java
.nio
.BufferUnderflowException
;
21 import java
.nio
.ByteBuffer
;
22 import java
.nio
.ByteOrder
;
24 import org
.eclipse
.jdt
.annotation
.NonNull
;
25 import org
.eclipse
.tracecompass
.ctf
.core
.trace
.CTFReaderException
;
28 * <b><u>BitBuffer</u></b>
30 * A bitwise buffer capable of accessing fields with bit offsets.
34 public final class BitBuffer
{
36 // ------------------------------------------------------------------------
38 // ------------------------------------------------------------------------
40 /* default bit width */
41 private static final int BIT_CHAR
= Byte
.SIZE
; // yum
42 private static final int BYTE_MASK
= (1 << BIT_CHAR
) - 1;
43 private static final int BIT_SHORT
= Short
.SIZE
;
44 private static final int SHORT_MASK
= (1 << BIT_SHORT
) - 1;
45 private static final int BIT_INT
= Integer
.SIZE
;
46 private static final long INT_MASK
= (1L << BIT_INT
) - 1;
47 private static final int BIT_LONG
= Long
.SIZE
;
49 // ------------------------------------------------------------------------
51 // ------------------------------------------------------------------------
53 private final @NonNull ByteBuffer fBuffer
;
54 private final long fBitCapacity
;
57 * Bit-buffer's position, maximum value = Integer.MAX_VALUE * 8
59 private long fPosition
;
60 private ByteOrder fByteOrder
;
62 // ------------------------------------------------------------------------
64 // ------------------------------------------------------------------------
66 * Default constructor, makes a big-endian buffer
69 this(checkNotNull(ByteBuffer
.allocateDirect(0)), ByteOrder
.BIG_ENDIAN
);
73 * Constructor, makes a big-endian buffer
76 * the bytebuffer to read
78 public BitBuffer(@NonNull ByteBuffer buf
) {
79 this(buf
, ByteOrder
.BIG_ENDIAN
);
83 * Constructor that is fully parameterizable
88 * the byte order (big-endian, little-endian, network?)
90 public BitBuffer(@NonNull ByteBuffer buf
, ByteOrder order
) {
94 fBitCapacity
= (long) fBuffer
.capacity() * BIT_CHAR
;
97 private void resetPosition() {
101 // ------------------------------------------------------------------------
102 // 'Get' operations on buffer
103 // ------------------------------------------------------------------------
106 * Relative <i>get</i> method for reading 32-bit integer.
108 * Reads next four bytes from the current bit position according to current
111 * @return The int value (signed) read from the buffer
112 * @throws CTFReaderException
113 * An error occurred reading the long. This exception can be
114 * raised if the buffer tries to read out of bounds
116 public int getInt() throws CTFReaderException
{
117 return getInt(BIT_INT
, true);
121 * Relative <i>get</i> method for reading 64-bit integer.
123 * Reads next eight bytes from the current bit position according to current
126 * @return The long value (signed) read from the buffer
127 * @throws CTFReaderException
128 * An error occurred reading the long. This exception can be
129 * raised if the buffer tries to read out of bounds
132 public long getLong() throws CTFReaderException
{
133 return get(BIT_LONG
, true);
137 * Relative <i>get</i> method for reading long of <i>length</i> bits.
139 * Reads <i>length</i> bits starting at the current position. The result is
140 * signed extended if <i>signed</i> is true. The current position is
141 * increased of <i>length</i> bits.
144 * The length in bits of this integer
146 * The sign extended flag
147 * @return The long value read from the buffer
148 * @throws CTFReaderException
149 * An error occurred reading the data. If more than 64 bits at a
150 * time are read, or the buffer is read beyond its end, this
151 * exception will be raised.
154 public long get(int length
, boolean signed
) throws CTFReaderException
{
155 if (length
> BIT_LONG
) {
156 throw new CTFReaderException("Cannot read a long longer than 64 bits. Rquested: " + length
); //$NON-NLS-1$
158 if (length
> BIT_INT
) {
159 final int highShift
= length
- BIT_INT
;
161 long b
= getInt(highShift
, false);
163 /* Cast the signed-extended int into a unsigned int. */
165 b
&= (1L << highShift
) - 1L;
167 retVal
= (fByteOrder
== ByteOrder
.BIG_ENDIAN
) ?
((a
<< highShift
) | b
) : ((b
<< BIT_INT
) | a
);
170 int signExtendBits
= BIT_LONG
- length
;
171 retVal
= (retVal
<< signExtendBits
) >> signExtendBits
;
175 long retVal
= getInt(length
, signed
);
176 return (signed ? retVal
: (retVal
& INT_MASK
));
180 * Relative bulk <i>get</i> method.
183 * This method transfers <strong>bytes</strong> from this buffer into the
184 * given destination array. This method currently only supports reads
185 * aligned to 8 bytes. It is up to the developer to shift the bits in
186 * post-processing to do unaligned reads.
189 * the bytes to write to
190 * @throws BufferUnderflowException
191 * - If there are fewer than length bytes remaining in this
195 public void get(@NonNull byte[] dst
) {
196 fBuffer
.position((int) (fPosition
/ BIT_CHAR
));
198 fPosition
+= dst
.length
* BIT_CHAR
;
202 * Relative <i>get</i> method for reading integer of <i>length</i> bits.
204 * Reads <i>length</i> bits starting at the current position. The result is
205 * signed extended if <i>signed</i> is true. The current position is
206 * increased of <i>length</i> bits.
209 * The length in bits of this integer
211 * The sign extended flag
212 * @return The int value read from the buffer
213 * @throws CTFReaderException
214 * An error occurred reading the data. When the buffer is read
215 * beyond its end, this exception will be raised.
217 private int getInt(int length
, boolean signed
) throws CTFReaderException
{
219 /* Nothing to read. */
224 /* Validate that the buffer has enough bits. */
225 if (!canRead(length
)) {
226 throw new CTFReaderException("Cannot read the integer, " + //$NON-NLS-1$
227 "the buffer does not have enough remaining space. " + //$NON-NLS-1$
228 "Requested:" + length
); //$NON-NLS-1$
231 /* Get the value from the byte buffer. */
233 boolean gotIt
= false;
236 * Try a fast read when the position is byte-aligned by using
237 * java.nio.ByteBuffer's native methods
240 * A faster alignment detection as the compiler cannot guaranty that pos
241 * is always positive.
243 if ((fPosition
& (BitBuffer
.BIT_CHAR
- 1)) == 0) {
245 case BitBuffer
.BIT_CHAR
:
247 val
= fBuffer
.get((int) (fPosition
/ BIT_CHAR
));
249 val
= val
& BYTE_MASK
;
254 case BitBuffer
.BIT_SHORT
:
256 val
= fBuffer
.getShort((int) (fPosition
/ BIT_CHAR
));
258 val
= val
& SHORT_MASK
;
263 case BitBuffer
.BIT_INT
:
265 val
= fBuffer
.getInt((int) (fPosition
/ BIT_CHAR
));
274 /* When not byte-aligned, fall-back to a general decoder. */
276 // Nothing read yet: use longer methods
277 if (fByteOrder
== ByteOrder
.LITTLE_ENDIAN
) {
278 val
= getIntLE(fPosition
, length
, signed
);
280 val
= getIntBE(fPosition
, length
, signed
);
288 private int getIntBE(long index
, int length
, boolean signed
) {
289 if ((length
<= 0) || (length
> BIT_INT
)) {
290 throw new IllegalArgumentException("Length must be between 1-32 bits"); //$NON-NLS-1$
292 long end
= index
+ length
;
293 int startByte
= (int) (index
/ BIT_CHAR
);
294 int endByte
= (int) ((end
+ (BIT_CHAR
- 1)) / BIT_CHAR
);
295 int currByte
, lshift
, cshift
, mask
, cmask
, cache
;
298 currByte
= startByte
;
299 cache
= fBuffer
.get(currByte
) & BYTE_MASK
;
300 boolean isNeg
= (cache
& (1 << (BIT_CHAR
- (index
% BIT_CHAR
) - 1))) != 0;
301 if (signed
&& isNeg
) {
304 if (startByte
== (endByte
- 1)) {
305 cmask
= cache
>>> ((BIT_CHAR
- (end
% BIT_CHAR
)) % BIT_CHAR
);
306 if (((length
) % BIT_CHAR
) > 0) {
307 mask
= ~
((~
0) << length
);
314 cshift
= (int) (index
% BIT_CHAR
);
316 mask
= ~
((~
0) << (BIT_CHAR
- cshift
));
317 cmask
= cache
& mask
;
318 lshift
= BIT_CHAR
- cshift
;
323 for (; currByte
< (endByte
- 1); currByte
++) {
325 value
|= fBuffer
.get(currByte
) & BYTE_MASK
;
327 lshift
= (int) (end
% BIT_CHAR
);
329 mask
= ~
((~
0) << lshift
);
330 cmask
= fBuffer
.get(currByte
) & BYTE_MASK
;
331 cmask
>>>= BIT_CHAR
- lshift
;
337 value
|= fBuffer
.get(currByte
) & BYTE_MASK
;
342 private int getIntLE(long index
, int length
, boolean signed
) {
343 if ((length
<= 0) || (length
> BIT_INT
)) {
344 throw new IllegalArgumentException("Length must be between 1-32 bits"); //$NON-NLS-1$
346 long end
= index
+ length
;
347 int startByte
= (int) (index
/ BIT_CHAR
);
348 int endByte
= (int) ((end
+ (BIT_CHAR
- 1)) / BIT_CHAR
);
349 int currByte
, lshift
, cshift
, mask
, cmask
, cache
, mod
;
352 currByte
= endByte
- 1;
353 cache
= fBuffer
.get(currByte
) & BYTE_MASK
;
354 mod
= (int) (end
% BIT_CHAR
);
355 lshift
= (mod
> 0) ? mod
: BIT_CHAR
;
356 boolean isNeg
= (cache
& (1 << (lshift
- 1))) != 0;
357 if (signed
&& isNeg
) {
360 if (startByte
== (endByte
- 1)) {
361 cmask
= cache
>>> (index
% BIT_CHAR
);
362 if (((length
) % BIT_CHAR
) > 0) {
363 mask
= ~
((~
0) << length
);
370 cshift
= (int) (end
% BIT_CHAR
);
372 mask
= ~
((~
0) << cshift
);
373 cmask
= cache
& mask
;
378 for (; currByte
>= (startByte
+ 1); currByte
--) {
380 value
|= fBuffer
.get(currByte
) & BYTE_MASK
;
382 lshift
= (int) (index
% BIT_CHAR
);
384 mask
= ~
((~
0) << (BIT_CHAR
- lshift
));
385 cmask
= fBuffer
.get(currByte
) & BYTE_MASK
;
388 value
<<= (BIT_CHAR
- lshift
);
392 value
|= fBuffer
.get(currByte
) & BYTE_MASK
;
397 // ------------------------------------------------------------------------
398 // 'Put' operations on buffer
399 // ------------------------------------------------------------------------
402 * Relative <i>put</i> method to write signed 32-bit integer.
404 * Write four bytes starting from current bit position in the buffer
405 * according to the current byte order. The current position is increased of
406 * <i>length</i> bits.
409 * The int value to write
410 * @throws CTFReaderException
411 * An error occurred writing the data. If the buffer is written
412 * beyond its end, this exception will be raised.
414 public void putInt(int value
) throws CTFReaderException
{
415 putInt(BIT_INT
, value
);
419 * Relative <i>put</i> method to write <i>length</i> bits integer.
421 * Writes <i>length</i> lower-order bits from the provided <i>value</i>,
422 * starting from current bit position in the buffer. Sequential bytes are
423 * written according to the current byte order. The sign bit is carried to
424 * the MSB if signed is true. The sign bit is included in <i>length</i>. The
425 * current position is increased of <i>length</i>.
428 * The number of bits to write
431 * @throws CTFReaderException
432 * An error occurred writing the data. If the buffer is written
433 * beyond its end, this exception will be raised.
435 public void putInt(int length
, int value
) throws CTFReaderException
{
436 final long curPos
= fPosition
;
438 if (!canRead(length
)) {
439 throw new CTFReaderException("Cannot write to bitbuffer, " //$NON-NLS-1$
440 + "insufficient space. Requested: " + length
); //$NON-NLS-1$
445 if (fByteOrder
== ByteOrder
.LITTLE_ENDIAN
) {
446 putIntLE(curPos
, length
, value
);
448 putIntBE(curPos
, length
, value
);
453 private void putIntBE(long index
, int length
, int value
) {
454 if ((length
<= 0) || (length
> BIT_INT
)) {
455 throw new IllegalArgumentException("Length must be between 1-32 bits"); //$NON-NLS-1$
457 long end
= index
+ length
;
458 int startByte
= (int) (index
/ BIT_CHAR
);
459 int endByte
= (int) ((end
+ (BIT_CHAR
- 1)) / BIT_CHAR
);
460 int currByte
, lshift
, cshift
, mask
, cmask
;
461 int correctedValue
= value
;
464 * mask v high bits. Works for unsigned and two complement signed
465 * numbers which value do not overflow on length bits.
468 if (length
< BIT_INT
) {
469 correctedValue
&= ~
(~
0 << length
);
473 if (startByte
== (endByte
- 1)) {
474 lshift
= (int) ((BIT_CHAR
- (end
% BIT_CHAR
)) % BIT_CHAR
);
475 mask
= ~
((~
0) << lshift
);
476 if ((index
% BIT_CHAR
) > 0) {
477 mask
|= (~
(0)) << (BIT_CHAR
- (index
% BIT_CHAR
));
479 cmask
= correctedValue
<< lshift
;
481 * low bits are cleared because of left-shift and high bits are
485 int b
= fBuffer
.get(startByte
) & BYTE_MASK
;
486 fBuffer
.put(startByte
, (byte) ((b
& mask
) | cmask
));
490 /* head byte contains MSB */
491 currByte
= endByte
- 1;
492 cshift
= (int) (end
% BIT_CHAR
);
494 lshift
= BIT_CHAR
- cshift
;
495 mask
= ~
((~
0) << lshift
);
496 cmask
= correctedValue
<< lshift
;
498 int b
= fBuffer
.get(currByte
) & BYTE_MASK
;
499 fBuffer
.put(currByte
, (byte) ((b
& mask
) | cmask
));
500 correctedValue
>>>= cshift
;
505 for (; currByte
>= (startByte
+ 1); currByte
--) {
506 fBuffer
.put(currByte
, (byte) correctedValue
);
507 correctedValue
>>>= BIT_CHAR
;
509 /* end byte contains LSB */
510 if ((index
% BIT_CHAR
) > 0) {
511 mask
= (~
0) << (BIT_CHAR
- (index
% BIT_CHAR
));
512 cmask
= correctedValue
& ~mask
;
513 int b
= fBuffer
.get(currByte
) & BYTE_MASK
;
514 fBuffer
.put(currByte
, (byte) ((b
& mask
) | cmask
));
516 fBuffer
.put(currByte
, (byte) correctedValue
);
520 private void putIntLE(long index
, int length
, int value
) {
521 if ((length
<= 0) || (length
> BIT_INT
)) {
522 throw new IllegalArgumentException("Length must be between 1-32 bits"); //$NON-NLS-1$
524 long end
= index
+ length
;
525 int startByte
= (int) (index
/ BIT_CHAR
);
526 int endByte
= (int) ((end
+ (BIT_CHAR
- 1)) / BIT_CHAR
);
527 int currByte
, lshift
, cshift
, mask
, cmask
;
528 int correctedValue
= value
;
531 * mask v high bits. Works for unsigned and two complement signed
532 * numbers which value do not overflow on length bits.
535 if (length
< BIT_INT
) {
536 correctedValue
&= ~
(~
0 << length
);
540 if (startByte
== (endByte
- 1)) {
541 lshift
= (int) (index
% BIT_CHAR
);
542 mask
= ~
((~
0) << lshift
);
543 if ((end
% BIT_CHAR
) > 0) {
544 mask
|= (~
(0)) << (end
% BIT_CHAR
);
546 cmask
= correctedValue
<< lshift
;
548 * low bits are cleared because of left-shift and high bits are
552 int b
= fBuffer
.get(startByte
) & BYTE_MASK
;
553 fBuffer
.put(startByte
, (byte) ((b
& mask
) | cmask
));
558 currByte
= startByte
;
559 cshift
= (int) (index
% BIT_CHAR
);
561 mask
= ~
((~
0) << cshift
);
562 cmask
= correctedValue
<< cshift
;
564 int b
= fBuffer
.get(currByte
) & BYTE_MASK
;
565 fBuffer
.put(currByte
, (byte) ((b
& mask
) | cmask
));
566 correctedValue
>>>= BIT_CHAR
- cshift
;
571 for (; currByte
< (endByte
- 1); currByte
++) {
572 fBuffer
.put(currByte
, (byte) correctedValue
);
573 correctedValue
>>>= BIT_CHAR
;
576 if ((end
% BIT_CHAR
) > 0) {
577 mask
= (~
0) << (end
% BIT_CHAR
);
578 cmask
= correctedValue
& ~mask
;
579 int b
= fBuffer
.get(currByte
) & BYTE_MASK
;
580 fBuffer
.put(currByte
, (byte) ((b
& mask
) | cmask
));
582 fBuffer
.put(currByte
, (byte) correctedValue
);
586 // ------------------------------------------------------------------------
587 // Buffer attributes handling
588 // ------------------------------------------------------------------------
591 * Can this buffer be read for thus amount of bits?
594 * the length in bits to read
595 * @return does the buffer have enough room to read the next "length"
597 public boolean canRead(int length
) {
598 return ((fPosition
+ length
) <= fBitCapacity
);
602 * Sets the order of the buffer.
605 * The order of the buffer.
607 public void setByteOrder(ByteOrder order
) {
609 fBuffer
.order(order
);
613 * Sets the order of the buffer.
615 * @return The order of the buffer.
617 public ByteOrder
getByteOrder() {
622 * Sets the position in the buffer.
625 * The new position of the buffer.
626 * @throws CTFReaderException
627 * Thrown on out of bounds exceptions
630 public void position(long newPosition
) throws CTFReaderException
{
632 if (newPosition
> fBitCapacity
) {
633 throw new CTFReaderException("Out of bounds exception on a position move, attempting to access position: " + newPosition
); //$NON-NLS-1$
635 fPosition
= newPosition
;
640 * Sets the position in the buffer.
642 * @return order The position of the buffer.
645 public long position() {
650 * Sets the byte buffer
656 public void setByteBuffer(ByteBuffer buf
) {
658 * to avoid "The method setByteBuffer(ByteBuffer) from the type
659 * BitBuffer can be declared as static"
661 long data
= fPosition
;
663 throw new UnsupportedOperationException("Bytebuffers are now final"); //$NON-NLS-1$
668 * Gets the byte buffer
670 * @return The byte buffer
672 public ByteBuffer
getByteBuffer() {
677 * Resets the bitbuffer.
679 public void clear() {
This page took 0.048362 seconds and 5 git commands to generate.