//******************************************************************************
//
// File: ByteBuf.java
// Package: edu.rit.mp
// Unit: Class edu.rit.mp.ByteBuf
//
// This Java source file is copyright (C) 2007 by Alan Kaminsky. All rights
// reserved. For further information, contact the author, Alan Kaminsky, at
// ark@cs.rit.edu.
//
// This Java source file is part of the Parallel Java Library ("PJ"). PJ is free
// software; you can redistribute it and/or modify it under the terms of the GNU
// General Public License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// PJ is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
// A PARTICULAR PURPOSE. See the GNU General Public License for more details.
//
// A copy of the GNU General Public License is provided in the file gpl.txt. You
// may also obtain a copy of the GNU General Public License on the World Wide
// Web at http://www.gnu.org/licenses/gpl.html.
//
//******************************************************************************
package edu.rit.mp;
import edu.rit.mp.buf.ByteArrayBuf;
import edu.rit.mp.buf.ByteArrayBuf_1;
import edu.rit.mp.buf.ByteItemBuf;
import edu.rit.mp.buf.ByteMatrixBuf;
import edu.rit.mp.buf.ByteMatrixBuf_1;
import edu.rit.mp.buf.EmptyByteBuf;
import edu.rit.mp.buf.SharedByteBuf;
import edu.rit.mp.buf.SharedByteArrayBuf;
import edu.rit.mp.buf.SharedByteArrayBuf_1;
import edu.rit.pj.reduction.ByteOp;
import edu.rit.pj.reduction.Op;
import edu.rit.pj.reduction.SharedByte;
import edu.rit.pj.reduction.SharedByteArray;
import edu.rit.util.Arrays;
import edu.rit.util.Range;
import java.io.IOException;
import java.nio.ByteBuffer;
/**
* Class ByteBuf is the abstract base class for a buffer of byte items sent or
* received using the Message Protocol (MP). In a message, a byte item is
* represented as one byte.
*
* A buffer may be used to send one or more messages at the same time in
* multiple threads. If a buffer is being used to send a message or messages,
* the buffer must not be used to receive a message at the same time.
*
* A buffer may be used to receive one message at a time. If a buffer is being
* used to receive a message, the buffer must not be used to receive another
* message in a different thread, and the buffer must not be used to send a
* message or messages.
*
* A buffer is a conduit for retrieving and storing data in some underlying data
* structure. If the underlying data structure is multiple thread safe, then one
* thread can be retrieving or storing data via the buffer at the same time as
* other threads are accessing the data structure. If the underlying data
* structure is not multiple thread safe, then other threads must not access the
* data structure while one thread is retrieving or storing data via the buffer.
*
* To create a ByteBuf, call one of the following static factory methods:
*
* - emptyBuffer()
*
- buffer()
*
- buffer (byte)
*
- buffer (byte[])
*
- sliceBuffer (byte[], Range)
*
- sliceBuffers (byte[], Range[])
*
- buffer (byte[][])
*
- rowSliceBuffer (byte[][], Range)
*
- rowSliceBuffers (byte[][], Range[])
*
- colSliceBuffer (byte[][], Range)
*
- colSliceBuffers (byte[][], Range[])
*
- patchBuffer (byte[][], Range, Range)
*
- patchBuffers (byte[][], Range[], Range[])
*
- buffer (SharedByte)
*
- buffer (SharedByteArray)
*
- sliceBuffer (SharedByteArray, Range)
*
- sliceBuffers (SharedByteArray, Range[])
*
*
* @author Alan Kaminsky
* @version 03-May-2008
*/
public abstract class ByteBuf
extends Buf
{
// Hidden constructors.
/**
* Construct a new byte buffer.
*
* @param theLength Number of items.
*
* @exception IllegalArgumentException
* (unchecked exception) Thrown if theLength < 0.
*/
protected ByteBuf
(int theLength)
{
super (Constants.TYPE_BOOLEAN, theLength);
}
// Exported operations.
/**
* Create an empty buffer. The buffer's length is 0. The buffer's item type
* is byte.
*
* @return Empty buffer.
*/
public static ByteBuf emptyBuffer()
{
return new EmptyByteBuf();
}
/**
* Create a buffer for a byte item. The item is stored in the item
* field of the buffer.
*
* @return Buffer.
*/
public static ByteItemBuf buffer()
{
return new ByteItemBuf();
}
/**
* Create a buffer for a byte item with the given initial value. The item
* is stored in the item field of the buffer.
*
* @param item Initial value of the item field.
*
* @return Buffer.
*/
public static ByteItemBuf buffer
(byte item)
{
return new ByteItemBuf (item);
}
/**
* Create a buffer for the entire given byte array. The returned buffer
* encompasses all the elements in theArray.
*
* @param theArray Array.
*
* @return Buffer.
*
* @exception NullPointerException
* (unchecked exception) Thrown if theArray is null.
*/
public static ByteBuf buffer
(byte[] theArray)
{
if (theArray == null)
{
throw new NullPointerException
("ByteBuf.buffer(): theArray is null");
}
int nr = Arrays.length (theArray);
return new ByteArrayBuf_1 (theArray, new Range (0, nr-1));
}
/**
* Create a buffer for one slice of the given byte array. The returned
* buffer encompasses theRange of elements in theArray.
* The range's stride may be 1 or greater than 1.
*
* @param theArray Array.
* @param theRange Range of elements to include.
*
* @return Buffer.
*
* @exception NullPointerException
* (unchecked exception) Thrown if theArray is null or
* theRange is null.
* @exception IndexOutOfBoundsException
* (unchecked exception) Thrown if theArray does not include
* all the indexes in theRange.
*/
public static ByteBuf sliceBuffer
(byte[] theArray,
Range theRange)
{
if (theArray == null)
{
throw new NullPointerException
("ByteBuf.sliceBuffer(): theArray is null");
}
int nr = Arrays.length (theArray);
if (0 > theRange.lb() || theRange.ub() >= nr)
{
throw new IndexOutOfBoundsException
("ByteBuf.sliceBuffer(): theArray index range = 0.." +
(nr-1) + ", theRange = " + theRange);
}
if (theRange.stride() == 1)
{
return new ByteArrayBuf_1 (theArray, theRange);
}
else
{
return new ByteArrayBuf (theArray, theRange);
}
}
/**
* Create an array of buffers for multiple slices of the given byte array.
* The returned buffer array has the same length as theRanges. Each
* element [i] of the returned buffer array encompasses the elements
* of theArray specified by theRanges[i]. Each range's
* stride may be 1 or greater than 1.
*
* @param theArray Array.
* @param theRanges Array of ranges of elements to include.
*
* @return Array of buffers.
*
* @exception NullPointerException
* (unchecked exception) Thrown if theArray is null or
* theRanges or any element thereof is null.
* @exception IndexOutOfBoundsException
* (unchecked exception) Thrown if theArray's allocation does
* not include any element of theRanges.
*/
public static ByteBuf[] sliceBuffers
(byte[] theArray,
Range[] theRanges)
{
int n = theRanges.length;
ByteBuf[] result = new ByteBuf [n];
for (int i = 0; i < n; ++ i)
{
result[i] = sliceBuffer (theArray, theRanges[i]);
}
return result;
}
/**
* Create a buffer for the entire given byte matrix. The returned buffer
* encompasses all the rows and all the columns in theMatrix.
*
* @param theMatrix Matrix.
*
* @return Buffer.
*
* @exception NullPointerException
* (unchecked exception) Thrown if theMatrix is null.
*/
public static ByteBuf buffer
(byte[][] theMatrix)
{
if (theMatrix == null)
{
throw new NullPointerException
("ByteBuf.buffer(): theMatrix is null");
}
int nr = Arrays.rowLength (theMatrix);
int nc = Arrays.colLength (theMatrix, 0);
return new ByteMatrixBuf_1
(theMatrix, new Range (0, nr-1), new Range (0, nc-1));
}
/**
* Create a buffer for one row slice of the given byte matrix. The returned
* buffer encompasses theRowRange of rows, and all the columns, in
* theMatrix. The range's stride may be 1 or greater than 1.
*
* @param theMatrix Matrix.
* @param theRowRange Range of rows to include.
*
* @return Buffer.
*
* @exception NullPointerException
* (unchecked exception) Thrown if theMatrix is null or
* theRowRange is null.
* @exception IndexOutOfBoundsException
* (unchecked exception) Thrown if theMatrix's allocation does
* not include theRowRange.
*/
public static ByteBuf rowSliceBuffer
(byte[][] theMatrix,
Range theRowRange)
{
if (theMatrix == null)
{
throw new NullPointerException
("ByteBuf.rowSliceBuffer(): theMatrix is null");
}
int nr = Arrays.rowLength (theMatrix);
if (0 > theRowRange.lb() || theRowRange.ub() >= nr)
{
throw new IndexOutOfBoundsException
("ByteBuf.rowSliceBuffer(): theMatrix row index range = 0.." +
(nr-1) + ", theRowRange = " + theRowRange);
}
int nc = Arrays.colLength (theMatrix, theRowRange.lb());
if (theRowRange.stride() == 1)
{
return new ByteMatrixBuf_1
(theMatrix, theRowRange, new Range (0, nc-1));
}
else
{
return new ByteMatrixBuf
(theMatrix, theRowRange, new Range (0, nc-1));
}
}
/**
* Create an array of buffers for multiple row slices of the given byte
* matrix. The returned buffer array has the same length as
* theRowRanges. Each element [i] of the returned buffer
* array encompasses the rows of theMatrix specified by
* theRowRanges[i] and all the columns of theMatrix. Each
* range's stride may be 1 or greater than 1.
*
* @param theMatrix Matrix.
* @param theRowRanges Array of ranges of rows to include.
*
* @return Array of buffers.
*
* @exception NullPointerException
* (unchecked exception) Thrown if theMatrix is null or
* theRowRanges or any element thereof is null.
* @exception IndexOutOfBoundsException
* (unchecked exception) Thrown if theMatrix's allocation does
* not include any element of theRowRanges.
*/
public static ByteBuf[] rowSliceBuffers
(byte[][] theMatrix,
Range[] theRowRanges)
{
int n = theRowRanges.length;
ByteBuf[] result = new ByteBuf [n];
for (int i = 0; i < n; ++ i)
{
result[i] = rowSliceBuffer (theMatrix, theRowRanges[i]);
}
return result;
}
/**
* Create a buffer for one column slice of the given byte matrix. The
* returned buffer encompasses all the rows, and theColRange of
* columns, in theMatrix. The range's stride may be 1 or greater
* than 1.
*
* @param theMatrix Matrix.
* @param theColRange Range of columns to include.
*
* @return Buffer.
*
* @exception NullPointerException
* (unchecked exception) Thrown if theMatrix is null or
* theColRange is null.
* @exception IndexOutOfBoundsException
* (unchecked exception) Thrown if theMatrix's allocation does
* not include theColRange.
*/
public static ByteBuf colSliceBuffer
(byte[][] theMatrix,
Range theColRange)
{
if (theMatrix == null)
{
throw new NullPointerException
("ByteBuf.colSliceBuffer(): theMatrix is null");
}
int nr = Arrays.rowLength (theMatrix);
int nc = Arrays.colLength (theMatrix, 0);
if (0 > theColRange.lb() || theColRange.ub() >= nc)
{
throw new IndexOutOfBoundsException
("ByteBuf.colSliceBuffer(): theMatrix column index range = 0.."
+ (nc-1) + ", theColRange = " + theColRange);
}
if (theColRange.stride() == 1)
{
return new ByteMatrixBuf_1
(theMatrix, new Range (0, nr-1), theColRange);
}
else
{
return new ByteMatrixBuf
(theMatrix, new Range (0, nr-1), theColRange);
}
}
/**
* Create an array of buffers for multiple column slices of the given byte
* matrix. The returned buffer array has the same length as
* theColRanges. Each element [i] of the returned buffer
* array encompasses all the rows of theMatrix and the columns of
* theMatrix specified by theColRanges[i]. Each range's
* stride may be 1 or greater than 1.
*
* @param theMatrix Matrix.
* @param theColRanges Array of ranges of columns to include.
*
* @return Array of buffers.
*
* @exception NullPointerException
* (unchecked exception) Thrown if theMatrix is null or
* theColRanges or any element thereof is null.
* @exception IndexOutOfBoundsException
* (unchecked exception) Thrown if theMatrix's allocation does
* not include any element of theColRanges.
*/
public static ByteBuf[] colSliceBuffers
(byte[][] theMatrix,
Range[] theColRanges)
{
int n = theColRanges.length;
ByteBuf[] result = new ByteBuf [n];
for (int i = 0; i < n; ++ i)
{
result[i] = colSliceBuffer (theMatrix, theColRanges[i]);
}
return result;
}
/**
* Create a buffer for one patch of the given byte matrix. The returned
* buffer encompasses theRowRange of rows, and theColRange
* of columns, in theMatrix. Each range's stride may be 1 or
* greater than 1.
*
* @param theMatrix Matrix.
* @param theRowRange Range of rows to include.
* @param theColRange Range of columns to include.
*
* @return Buffer.
*
* @exception NullPointerException
* (unchecked exception) Thrown if theMatrix is null,
* theRowRange is null, or theColRange is null.
* @exception IndexOutOfBoundsException
* (unchecked exception) Thrown if theMatrix's allocation does
* not include theRowRange and theColRange.
*/
public static ByteBuf patchBuffer
(byte[][] theMatrix,
Range theRowRange,
Range theColRange)
{
if (theMatrix == null)
{
throw new NullPointerException
("ByteBuf.patchBuffer(): theMatrix is null");
}
int nr = Arrays.rowLength (theMatrix);
if (0 > theRowRange.lb() || theRowRange.ub() >= nr)
{
throw new IndexOutOfBoundsException
("ByteBuf.patchBuffer(): theMatrix row index range = 0.."
+ (nr-1) + ", theRowRange = " + theRowRange);
}
int nc = Arrays.colLength (theMatrix, theRowRange.lb());
if (0 > theColRange.lb() || theColRange.ub() >= nc)
{
throw new IndexOutOfBoundsException
("ByteBuf.patchBuffer(): theMatrix column index range = 0.."
+ (nc-1) + ", theColRange = " + theColRange);
}
if (theRowRange.stride() == 1 && theColRange.stride() == 1)
{
return new ByteMatrixBuf_1 (theMatrix, theRowRange, theColRange);
}
else
{
return new ByteMatrixBuf (theMatrix, theRowRange, theColRange);
}
}
/**
* Create an array of buffers for multiple patches of the given byte matrix.
* The length of the returned buffer array is equal to the length of
* theRowRanges times the length of theColRanges. Each
* element of the returned buffer array encompasses the rows given in one
* element of theRowRanges array, and the columns given in one
* element of theColRanges array, in all possible combinations, of
* theMatrix. Each range's stride may be 1 or greater than 1.
*
* @param theMatrix Matrix.
* @param theRowRanges Array of ranges of rows to include.
* @param theColRanges Array of ranges of columns to include.
*
* @return Array of buffers.
*
* @exception NullPointerException
* (unchecked exception) Thrown if theMatrix is null,
* theRowRanges or any element thereof is null, or
* theColRanges or any element thereof is null.
* @exception IndexOutOfBoundsException
* (unchecked exception) Thrown if theMatrix's allocation does
* not include any element of theRowRanges or
* theColRanges.
*/
public static ByteBuf[] patchBuffers
(byte[][] theMatrix,
Range[] theRowRanges,
Range[] theColRanges)
{
int m = theRowRanges.length;
int n = theColRanges.length;
ByteBuf[] result = new ByteBuf [m*n];
int k = 0;
for (int i = 0; i < m; ++ i)
{
Range rowrange = theRowRanges[i];
for (int j = 0; j < n; ++ j)
{
result[k++] =
patchBuffer (theMatrix, rowrange, theColRanges[j]);
}
}
return result;
}
/**
* Create a buffer for a shared byte item. The item is wrapped in an
* instance of class {@linkplain edu.rit.pj.reduction.SharedByte
* SharedByte}. Use the methods of the SharedByte object to access the
* actual item.
*
* @param item SharedByte object that wraps the item.
*
* @exception NullPointerException
* (unchecked exception) Thrown if item is null.
*/
public static ByteBuf buffer
(SharedByte item)
{
if (item == null)
{
throw new NullPointerException
("ByteBuf.buffer(): item is null");
}
return new SharedByteBuf (item);
}
/**
* Create a buffer for the entire given shared byte array. The returned
* buffer encompasses all the elements in theArray.
*
* @param theArray Array.
*
* @return Buffer.
*
* @exception NullPointerException
* (unchecked exception) Thrown if theArray is null.
*/
public static ByteBuf buffer
(SharedByteArray theArray)
{
if (theArray == null)
{
throw new NullPointerException
("ByteBuf.buffer(): theArray is null");
}
int nr = theArray.length();
return new SharedByteArrayBuf_1 (theArray, new Range (0, nr-1));
}
/**
* Create a buffer for one slice of the given shared byte array. The
* returned buffer encompasses theRange of elements in
* theArray. The range's stride may be 1 or greater than 1.
*
* @param theArray Array.
* @param theRange Range of elements to include.
*
* @return Buffer.
*
* @exception NullPointerException
* (unchecked exception) Thrown if theArray is null or
* theRange is null.
* @exception IndexOutOfBoundsException
* (unchecked exception) Thrown if theArray does not include
* all the indexes in theRange.
*/
public static ByteBuf sliceBuffer
(SharedByteArray theArray,
Range theRange)
{
if (theArray == null)
{
throw new NullPointerException
("ByteBuf.sliceBuffer(): theArray is null");
}
int nr = theArray.length();
if (0 > theRange.lb() || theRange.ub() >= nr)
{
throw new IndexOutOfBoundsException
("ByteBuf.sliceBuffer(): theArray index range = 0.."
+ (nr-1) + ", theRange = " + theRange);
}
if (theRange.stride() == 1)
{
return new SharedByteArrayBuf_1 (theArray, theRange);
}
else
{
return new SharedByteArrayBuf (theArray, theRange);
}
}
/**
* Create an array of buffers for multiple slices of the given shared byte
* array. The returned buffer array has the same length as
* theRanges. Each element [i] of the returned buffer array
* encompasses the elements of theArray specified by
* theRanges[i]. Each range's stride may be 1 or greater than 1.
*
* @param theArray Array.
* @param theRanges Array of ranges of elements to include.
*
* @return Array of buffers.
*
* @exception NullPointerException
* (unchecked exception) Thrown if theArray is null or
* theRanges or any element thereof is null.
* @exception IndexOutOfBoundsException
* (unchecked exception) Thrown if theArray's allocation does
* not include any element of theRanges.
*/
public static ByteBuf[] sliceBuffers
(SharedByteArray theArray,
Range[] theRanges)
{
int n = theRanges.length;
ByteBuf[] result = new ByteBuf [n];
for (int i = 0; i < n; ++ i)
{
result[i] = sliceBuffer (theArray, theRanges[i]);
}
return result;
}
/**
* Obtain the given item from this buffer.
*
* The get() method must not block the calling thread; if it does,
* all message I/O in MP will be blocked.
*
* @param i Item index in the range 0 .. length()-1.
*
* @return Item at index i.
*/
public abstract byte get
(int i);
/**
* Store the given item in this buffer.
*
* The put() method must not block the calling thread; if it does,
* all message I/O in MP will be blocked.
*
* @param i Item index in the range 0 .. length()-1.
* @param item Item to be stored at index i.
*/
public abstract void put
(int i,
byte item);
/**
* Copy items from the given buffer to this buffer. The number of items
* copied is this buffer's length or theSrc's length, whichever is
* smaller. If theSrc is this buffer, the copy() method
* does nothing.
*
* The default implementation of the copy() method calls the
* defaultCopy() method. A subclass can override the
* copy() method to use a more efficient algorithm.
*
* @param theSrc Source of items to copy into this buffer.
*
* @exception ClassCastException
* (unchecked exception) Thrown if theSrc's item data type is
* not the same as this buffer's item data type.
*/
public void copy
(Buf theSrc)
{
if (theSrc != this) defaultCopy ((ByteBuf) theSrc, this);
}
/**
* Fill this buffer with the given item. The item is assigned to
* each element in this buffer.
*
* The item must be an instance of class Byte. If the item
* is null, 0 is assigned to each element in this buffer.
*
* @param item Item.
*
* @exception ClassCastException
* (unchecked exception) Thrown if the item's data type is not
* the same as this buffer's item data type.
*/
public void fill
(Object item)
{
byte value = item == null ? (byte) 0 : ((Byte) item).byteValue();
for (int i = 0; i < myLength; ++ i)
{
put (i, value);
}
}
/**
* Create a temporary buffer with the same type of items and the same length
* as this buffer. The new buffer items are stored in a newly created array,
* separate from the storage for this buffer's items.
*/
public Buf getTemporaryBuf()
{
return buffer (new byte [myLength]);
}
// Hidden operations.
/**
* Skip as many items as possible from the given byte buffer.
*
* @param num Number of items to skip.
* @param buffer Buffer.
*
* @return Number of items actually skipped.
*/
int skipItems
(int num,
ByteBuffer buffer)
{
int n = Math.min (num, buffer.remaining());
buffer.position (buffer.position() + n);
return n;
}
/**
* Copy items from the given source buffer to the given destination buffer.
* The number of items copied is theSrc's length or
* theDst's length, whichever is smaller. Each item is copied
* individually using the get() and put() methods. It is
* assumed that theSrc is not the same as theDst.
*
* @param theSrc Source of items to copy.
* @param theDst Destination of items to copy.
*/
protected static void defaultCopy
(ByteBuf theSrc,
ByteBuf theDst)
{
int n = Math.min (theSrc.myLength, theDst.myLength);
for (int i = 0; i < n; ++ i)
{
theDst.put (i, theSrc.get (i));
}
}
}
Ads help maintain this website.