Interface DataBuffer

All Known Subinterfaces:
DataBitBuffer, DataByteBuffer, DataCharBuffer, DataDoubleBuffer, DataFloatBuffer, DataIntBuffer, DataLongBuffer, DataObjectBuffer<E>, DataShortBuffer

public interface DataBuffer

Data buffer: an interface allowing to read and write blocks from / to some linear data storage, containing a sequence of elements of any Java type, with maximal performance. It is the recommended basic way for block accessing AlgART arrays.

Theoretically, this technology can be used for accessing any types of data storages: java.nio.* buffers, RandomAccessFile, etc. But the main application area of data buffers is accessing AlgART arrays — the only storage variant, for which this package offers a ready implementation. Below we shall suppose that data buffers are used for accessing AlgART arrays.

AlgART arrays support block read / write methods (Array.getData(long, Object), UpdatableArray.setData(long, Object) and similar), that read / write some data block, specified by it's position and size, into / from usual Java array. However, such access way may be not most efficient. For example, if an AlgART array implements DirectAccessible interface, i.e. is backed by an accessible Java array, then reading the fragment of this array into a separate Java array (Array.getData method) is not a good idea: it's much more rational to work with the backing Java array directly. If an AlgART array is a constant array, then reading data by Array.getData(long, Object) method may be performed only once: the loaded data will be always the same.

Unlike the block read / write methods, the data buffer provides the most efficient and convenient read / write block access to any kinds of AlgART arrays.

The scheme of usage is alike file mapping by java.nio.channels.FileChannel class, with some little differences.

The model of data buffers is the following. Every data buffer is associated with a single AlgART array and consists of:

  1. A reference to the data array: a usual Java array, returned by data() method. This array contains all elements of some "mapped" region of the AlgART array. The mapped region usually corresponds not to entire Java array, but only to its fragment (see actual region in the section C below). The type of elements of the Java array is the same as the type of AlgART array elements (Array.elementType()), excepting the only case of bit arrays. For bit arrays, the elements are packed into long[] array (64 bits per every long), as specified in PackedBitArrays class.
     
  2. The capacity: maximal possible number of actual elements in the data buffer, or, in other words, the maximal possible number of elements in a mapped region. This value can be got by capacity() method. Please note that the data array may contain more than capacity elements; but the length of its actual region (toIndex-fromIndex) never exceeds capacity.
     
  3. The actual region fromIndex..toIndex in the data array: the elements of the AlgART array are always placed at the positions fromIndex..toIndex-1 in this Java array. The region boundaries can be got by fromIndex() and toIndex() methods. The number of actual elements is count=toIndex-fromIndex and can be also got by count() method.
     
  4. Current mapping position in the AlgART array. The actual region in the Java array corresponds to the region of the same size in the AlgART array, starting from current mapping position: position..position+count-1. This value can be got by position() method.
     
  5. The access mode, describing possible access ways to the data: see DataBuffer.AccessMode.

Please note that all integer values, described above — capacity, fromIndex, toIndex, count, position — are long, not int values. The reason is that data buffers for bit arrays are packed into long[] arrays and, so, can contain 231 or more bits. In any case, all describied integer characteristics cannot be greater than 237-1 for bit arrays and cannot be greater than Integer.MAX_VALUE==231-1 for all other element types.

There are additional methods from(), to(), cnt(), that return the results of full methods fromIndex(), toIndex(), count(), cast to int type. If the precise long values cannot be cast to int, because they are greater than Integer.MAX_VALUE, these methods throw DataBufferIndexOverflowException. You may use these methods to simplify your code, if the element type is not bit.

The scheme of using data buffers is the following.

  1. First, you must create the data buffer (an object implementing this interface), that will correspond to an AlgART array (or maybe for another kind of storage). For AlgART arrays, you may use Array.buffer(DataBuffer.AccessMode mode, long capacity) method. At this stage, you specify the access mode and desired capacity. You also may use one of overloaded simplified variants of this method, allowing to choose its arguments automatically, for example, Array.buffer().
     
    Note: the newly created data buffer, unlike java.nio.MappedByteBuffer, contains no elements! Now count is zero, the value fromIndex=toIndex is unspecified, mapping position is zero.
     
    Note also: the creation of the new buffer is supposed to be very quick operation. In particular, all necessary memory and other "heavy" resources are allocated later, usually while the first mapping at the step 2.
     
  2. Then you call map(long position) method of the created data buffer for any desired mapping position in the AlgART array. After this call, the mapping position becomes equal to the passed passition, and the number of actual elements count (=toIndex-fromIndex) becomes equal to min(capacity,length-position), where length is the length of the AlgART array (Array.length()) and capacity is the buffer capacity specified while its creation at the step 1.
     
    If you don't need access all capacity elements (for example, the capacity, specified while buffer creation, is 32 KB, but you need to read 100 elements only), you may use map(long position, long maxCount) method: it may work faster.
     
    Please compare: java.nio.MappedByteBuffer instance is always mapped to the fixed file position, but an instance of this data buffer may be (and usually should be) remapped to another positions of AlgART array by its map(long position) or map(long position, long maxCount) methods.
     
  3. Now you may access the data elements via the Java array, the reference to which is returned by data() method. The actual elements will be placed in this Java array at indexes fromIndex..toIndex-1. For bits arrays, it means the indexes in terms of PackedBitArrays class; so, these elements may be get and set via getBit(src,index) and setBit(dest,index,value) methods of that class, where fromIndex<=index<toIndex. For other element types, the actual elements may be accessed via Java operator data[index], fromIndex<=index<toIndex, where elementType[] data is the result of data() method.
     
    Note: you may change elements of the returned Java array, but these changes may reflect or not reflect in the original data storage (in particular, the AlgART array). It depends on the nature of this storage. For example, if it is backed by an accessible Java array, the changes will probably be reflected in the storage immediately; if it is a large array backed by a disk file, the changes are stored in a local buffer only. See the step 4.
     
    Note also: for bit arrays, you must modify bits in the packed Java array only by methods of PackedBitArrays class or by fully equivalent code, containing the same synchronization while changing not all bits in some packed long element. Without synchronization, some elements can be written incorrectly while multithreading using. See comments to PackedBitArrays class for more details.
     
    Note also: the reference, returned by data() method, may change after any call of map method. You should get this reference again after every its call.
     
  4. If you need to write the changed data into the AlgART array, you must call force() method after changing them. If not all elements in the actual region were really changed, you may use force(long fromIndex, long toIndex) method: it may work faster.
     
  5. You may repeat steps 2-4 many times to access different mapping positions in the same AlgART array. It usually will not lead to allocating new memory and will be performed quickly. To map the next region of the AlgART array, you may use mapNext() method. If the AlgART array is exhausted, the buffer becomes empty, that may be checked by hasData() method.

Direct and indirect data buffers

The data buffers, provided by this package for AlgART arrays, are divided into 2 groups.

The first group is direct buffers. They provide maximally efficient access to AlgART arrays. Such kind of buffers is returned by Array.buffer method, implemented in this package, if and only if the following conditions are fulfilled:

Direct buffers do not allocate any memory and work with maximal possible speed. For these buffers, the data() method returns a reference to the internal Java array where the elements are stored. All map and mapNext methods work very quickly: they just correct the fromIndex and toIndex offsets. Any changes, made in the data() array, immediately reflect in the original data storage; the force() method, in READ_WRITE access mode, does nothing.

The second group is indirect buffers. These buffers are usually not so efficient as direct ones, because every mapping / writing data requires copying a Java array from / to an AlgART array. The Array.buffer method, implemented in this package, returns an indirect buffer if one of the conditions listed above is not fulfilled, in particular, if the AlgART array is created by the buffer memory model or the large memory model, if it is immutable (and, so, direct access could violate immutability) or it is copy-on-next-write (and, so, an attempt of direct access could lead to cloning all internal storage).

The indirect buffer automatically allocates a Java array allowing to store capacity elements. (The memory is allocated not while the buffer creation, but while the first further mapping attempt.) This array will is returned by data() method. The map(long), map(long, long) and mapNext() methods load data into this Java array by Array.getData(long, Object, int, int) or, for bit arrays, BitArray.getBits(long, long[], long, long) method. (The map(long, boolean), map(long, long, boolean) and mapNext(boolean) methods allows to skip loading data by specifying the argument readData=false, if you really don't need the current data.) The force() method, in READ_WRITE access mode, writes data back to the AlgART array by UpdatableArray.setData(long, Object, int, int) or, for bit arrays, UpdatableBitArray.setBits(long, long[], long, long) method. The changes, made in the data() array, do not reflect in the original AlgART array until the force() call. Please note that the fromIndex offset is usually little, but not necessarily zero: little non-zero offset may optimize copying data due to better alignment.

For constant arrays, created by Arrays.nBitCopies(long, boolean), Arrays.nCharCopies(long, char), Arrays.nByteCopies(long, byte), Arrays.nShortCopies(long, short), Arrays.nIntCopies(long, int), Arrays.nLongCopies(long, long), Arrays.nFloatCopies(long, float), Arrays.nDoubleCopies(long, double), Arrays.nObjectCopies(long, T) methods, the returned data buffer is also indirect, but works quickly: the sequential calls of all map and mapNext methods do nothing, because the elements in data() array are always the same.

For custom arrays, created by you (via custom memory model implemented by you, or via direct implementing Array interface with its subinterfaces), the Array.buffer method may return direct or indirect buffers: it depends on your implementation. If you extend the skeletal AbstractArray class, please see comments to AbstractArray.buffer(net.algart.arrays.DataBuffer.AccessMode, long) method.

You may determine, whether the buffer is direct or indirect, via isDirect() method.

Invariants of the data buffers

For any kind of the data buffer, there are the following guarantees:

  • the mapped position is always inside the range 0 <= position <= length, where length is the total number of elements in the data storage (Array.length() in a case of AlgART arrays);
     
  • the mapped position is 0 if the buffer is newly created and map / mapNext methods were never called yet;
     
  • for bit arrays 0 < capacity < 237, for all other element types 0 < capacity < 231;
     
  • for bit arrays 0 <= fromIndex <= toIndex <= 64*bufferDataLength, for all other element types 0 <= fromIndex <= toIndex <= bufferDataLength, where bufferDataLength is the length of data array returned by data() method.
     
  • count = toIndex - fromIndex =...

Specific subinterfaces

The data() method, declared in this interface, returns Object (the only existing superclass for all Java arrays), that is not too convenient. But there are subinterfaces DataBitBuffer, DataCharBuffer, DataByteBuffer, DataShortBuffer, DataIntBuffer, DataLongBuffer, DataFloatBuffer, DataDoubleBuffer, DataObjectBuffer, where this method is overridden and returns corresponding type of Java array: long[] (packed bit array), char[], byte[], short[], etc. The basic Array.buffer(net.algart.arrays.DataBuffer.AccessMode, long) method (as well as its overloaded simplified versions) is overridden in specific AlgART arrays (BitArray, CharArray, etc.) and returns one of the listed subinterfaces.

Sequential mapping all AlgART array

This interface has no methods allowing to get the reference to the underlying AlgART array or get its length. But you may check, whether all elements of the AlgART array were already mapped by sequential calls of mapNext() method, by hasData() method (which is equivalent to "count()>0" check). If mapNext() is called when mapping position + count() = length, then new mapping position becomes equal to length and, so, the buffer size count() becomes zero. But please remember that hasData() returns false also before the first mapping of a newly created data buffer.

Usage examples

Below is a typical usage example:

 ByteArray a = ...; // some byte AlgART array
 for (DataByteBuffer buf = a.buffer().map(0); buf.hasData(); buf.mapNext()) {
     byte[] data = buf.data();
     for (int k = buf.from(); k < buf.to(); k++) {
         // ... (analyzing and/or replacing data[k])
     }
     buf.force(); // necessary only if data were modified
 }
 

There is an equivalent form of this loop, little more complex, but easily generalized for the case of another accessing order:

 ByteArray a = ...; // some byte AlgART array
 DataByteBuffer buf = a.buffer();
 for (long p = 0, n = a.length(); p < n; p += buf.count()) {
     buf.map(p);
     byte[] data = buf.data();
     for (int k = buf.from(); k < buf.to(); k++) {
         // ... (analyzing and/or replacing data[k])
     }
     buf.force(); // necessary only if data were modified
 }
 

A usage example for bits:

 BitArray a = ...; // some bit AlgART array
 for (DataBitBuffer buf = a.buffer().map(0); buf.hasData(); buf.mapNext()) {
     long[] data = buf.data();
     for (long k = buf.fromIndex(); k < buf.toIndex(); k++) {
         boolean b = PackedBitArrays.getBit(data, k);
         // it is the element a.getBit(position()+k)
         // processing this bit...
         // then, if necessary:
         PackedBitArrays.setBit(data, k, someNewValue);
     }
     buf.force(); // necessary only if data were modified
 }
 

Performance problem connected with a lot of data buffers

There is a problem connected with creating and using a lot of indirect data buffers (thousands and tens of thousands). In this situation, every data buffer allocates its own Java array for storing data, that cannot be shared with other data buffers. Allocating thousands of Java array, where every array occupies tens of kilobytes or more (typical capacity for data buffers), may require much time and create great workload for the garbage collector. As a result, it may lead to reducing overall performance. (Of course, the direct buffers do not lead to such a problem.)

The same problem occurs with usual Java arrays, used for temporary buffers instead of this class. But JArrayPool class offers a solution for this problem for Java arrays. So, if allocation of the data buffer may really create the described performance problem, you should check the newly created buffer, is it direct, and, if not, ignore it and use standard Java arrays with help of JArrayPool.

Additional notes

The data buffers are allowed not to implement hashCode and equals method. Usually, the default implementation of these methods from Object class are used.

The data buffers are not thread-safe, but are thread-compatible and can be synchronized manually (together with AlgART arrays accessed via the buffers) if multithread access is necessary.

Author:
Daniel Alievsky
  • Nested Class Summary

    Nested Classes
    Modifier and Type
    Interface
    Description
    static enum 
    Access mode, describing access to data buffers.
  • Method Summary

    Modifier and Type
    Method
    Description
    long
    Returns the capacity of this data buffer.
    int
    cnt()
    Returns (int)count(), if count()<=Integer.MAX_VALUE, or throws DataBufferIndexOverflowException in other case.
    long
    Returns the number of elements in the current actual region.
    Returns the Java array which contains the mapped region of the data.
    Writes all elements in the actual region of the data() Java array (from fromIndex(), inclusive, to toIndex(), exclusive) back to the underlying data storage (usually AlgART array).
    force(long fromIndex, long toIndex)
    Writes all elements in the specified region of the data() Java array (from the passed fromIndex, inclusive, to the passed toIndex, exclusive) back to the underlying data storage (usually AlgART array).
    int
    Returns (int)fromIndex(), if fromIndex()<=Integer.MAX_VALUE, or throws DataBufferIndexOverflowException in other case.
    long
    Returns the low boundary (inclusive) of the current actual region.
    boolean
    Returns true if and only if count()>0.
    boolean
    Returns true if this buffer is direct.
    map(long position)
    Maps this data buffer to the specified position of the underlying data storage (usually AlgART array) for accessing first capacity() elements starting from this position.
    map(long position, boolean readData)
    An analog of map(long) with the only exception, that when readData=false, reading data from the data storage is not guaranteed.
    map(long position, long maxCount)
    map(long position, long maxCount, boolean readData)
    Maps this data buffer to the specified position of the underlying data storage (usually AlgART array) for accessing first min(maxCount,capacity()) elements starting from this position.
    Maps the next region in the underlying data storage (usually AlgART array).
    mapNext(boolean readData)
    An analog of mapNext() with the only exception, that when readData=false, reading data from the data storage is not guaranteed.
     
    long
    Returns the current mapping position.
    int
    to()
    Returns (int)toIndex(), if toIndex()<=Integer.MAX_VALUE, or throws DataBufferIndexOverflowException in other case.
    long
    Returns the high boundary (exclusive) of the current actual region.
  • Method Details

    • mode

    • data

      Object data()
      Returns the Java array which contains the mapped region of the data. The actual data elements are placed at the positions fromIndex()..toIndex()-1. For bit elements, returned Java array is a packed long[] array, and the positions in this array should be considered in terms of PackedBitArrays class.

      The length of the returned array is always enough to fit the fromIndex()..toIndex()-1 positions range in it.

      Note: this method returns null if map / mapNext methods were never called for this buffer yet, that is, if it is newly created.

      Warning: the reference, returned by this method, may change after any call of map or mapNext methods.

      Returns:
      the Java array which contains the mapped region of the data.
    • map

      DataBuffer map(long position)
      Maps this data buffer to the specified position of the underlying data storage (usually AlgART array) for accessing first capacity() elements starting from this position. The fragment of the data storage will be loaded and accessible in the data() Java array at the positions fromIndex()..toIndex()-1. Equivalent to map(position(),capacity(),true).

      The passed argument must be in range 0..length, where length is the total number of elements in the underlying data storage (for an AlgART array, its Array.length()). The number of actually mapped elements (count()) will be equal to min(capacity(),length-position).

      Parameters:
      position - new mapping position.
      Returns:
      a reference to this data buffer.
      Throws:
      IndexOutOfBoundsException - if the specified position is out of range 0..length.
      See Also:
    • map

      DataBuffer map(long position, boolean readData)
      An analog of map(long) with the only exception, that when readData=false, reading data from the data storage is not guaranteed. (When readData=true, there is no difference with map(long) method.) Equivalent to map(position(),capacity(),readData). The mode readData=false can be useful for optimization in DataBuffer.AccessMode.READ_WRITE mode, if you are sure that you will fully rewrite all mapped elements and, so, want to save time by avoiding useless reading them.
      Parameters:
      position - new mapping position.
      readData - if true, all mapped elements will be really loaded from the data storage; if false, there is no such a guarantee.
      Returns:
      a reference to this data buffer.
      Throws:
      IndexOutOfBoundsException - if the specified position is out of range 0..length.
      See Also:
    • mapNext

      DataBuffer mapNext()
      Maps the next region in the underlying data storage (usually AlgART array). Equivalent to map(position() + count()). In particular, if the buffer is newly created and map(long) and mapNext() were never called yet, this method is equivalent to map(0).

      The following loop allows to sequentially map all elements of the underlying data storage:

       for (buf.map(0); buf.hasData(); buf.mapNext()) {
           // ... (processing elements of buf.data())
       }
       
      Returns:
      a reference to this data buffer.
      See Also:
    • mapNext

      DataBuffer mapNext(boolean readData)
      An analog of mapNext() with the only exception, that when readData=false, reading data from the data storage is not guaranteed. (When readData=true, there is no difference with mapNext() method.) Equivalent to map(position() + count(), readData). The mode readData=false can be useful for optimization in DataBuffer.AccessMode.READ_WRITE mode, if you are sure that you will fully rewrite all mapped elements and, so, want to save time by avoiding useless reading them.
      Parameters:
      readData - if true, all mapped elements will be really loaded from the data storage; if false, there is no such a guarantee.
      Returns:
      a reference to this data buffer.
      See Also:
    • map

      DataBuffer map(long position, long maxCount)
      Parameters:
      position - new mapping position.
      maxCount - this method does not guarantee that the elements after #position+maxCount-1 will be loaded into the buffer.
      Returns:
      a reference to this data buffer.
      Throws:
      IndexOutOfBoundsException - if the specified position is out of range 0..length.
      IllegalArgumentException - if the specified maxCount is negative.
      See Also:
    • map

      DataBuffer map(long position, long maxCount, boolean readData)
      Maps this data buffer to the specified position of the underlying data storage (usually AlgART array) for accessing first min(maxCount,capacity()) elements starting from this position. If readData=true, the fragment of the data storage will be loaded and accessible in the data() Java array at the positions fromIndex()..toIndex()-1. If readData=false, the behaviour is the same with the exception of reading data from the data storage is not guaranteed. This mode can be useful for optimization in DataBuffer.AccessMode.READ_WRITE mode, if you are sure that you will fully rewrite all mapped elements and, so, want to save time by avoiding useless reading them.

      The passed position must be in range 0..length, where length is the total number of elements in the underlying data storage (for an AlgART array, its Array.length()). The number of actually mapped elements (count()) will be equal to min(maxCount,capacity(),length-position).

      This method should be used instead of the full map(position) version, if you need to access a less number of elements than the full buffer capacity or if you are going to fully rewrite all mapped elements.

      Parameters:
      position - new mapping position.
      maxCount - this method does not guarantee that the elements after #position+maxCount-1 will be loaded into the buffer.
      readData - if true, all mapped elements will be really loaded from the data storage; if false, there is no such a guarantee.
      Returns:
      a reference to this data buffer.
      Throws:
      IndexOutOfBoundsException - if the specified position is out of range 0..length.
      IllegalArgumentException - if the specified maxCount is negative.
      See Also:
    • force

      DataBuffer force()
      Writes all elements in the actual region of the data() Java array (from fromIndex(), inclusive, to toIndex(), exclusive) back to the underlying data storage (usually AlgART array). May do nothing if the changes in this Java array reflect in the storage immediately (for example, for direct buffers).

      This method must be called to ensure that all changes, performed in the mapped data elements, will be reflected in the original data storage.

      This method must not be called in the READ access mode. This method does nothing in the PRIVATE access mode.

      Returns:
      a reference to this data buffer.
      Throws:
      IllegalStateException - if the access mode is READ.
      See Also:
    • force

      DataBuffer force(long fromIndex, long toIndex)
      Writes all elements in the specified region of the data() Java array (from the passed fromIndex, inclusive, to the passed toIndex, exclusive) back to the underlying data storage (usually AlgART array). May do nothing if the changes in this Java array reflect in the storage immediately (for example, for direct buffers).

      This method may be called instead of the full force() version, if you changed only part of mapped elements (for example, only one or several elements). In this case, this method may work faster. The force() method is equivalent to the call force(fromIndex(), toIndex()).

      This method must not be called in the READ access mode. This method does nothing in the PRIVATE access mode.

      Parameters:
      fromIndex - low boundary (inclusive) of the written region.
      toIndex - high boundary (inclusive) of the written region.
      Returns:
      a reference to this data buffer.
      Throws:
      IllegalStateException - if the access mode is READ.
      IllegalArgumentException - if fromIndex>toIndex or if the passed region is not a fragment of full actual region fromIndex()..toIndex()-1.
      See Also:
    • position

      long position()
      Returns the current mapping position. Cannot be negative.
      Returns:
      the current mapping position.
    • capacity

      long capacity()
      Returns the capacity of this data buffer. Cannot be negative.
      Returns:
      the capacity of this data buffer.
    • fromIndex

      long fromIndex()
      Returns the low boundary (inclusive) of the current actual region. Cannot be negative.
      Returns:
      the low boundary (inclusive) of the current actual region.
    • toIndex

      long toIndex()
      Returns the high boundary (exclusive) of the current actual region. Cannot be negative.
      Returns:
      the high boundary (exclusive) of the current actual region.
    • count

      long count()
      Returns the number of elements in the current actual region. Equivalent to toIndex()-fromIndex(). Cannot be negative.
      Returns:
      the number of elements in the current actual region.
    • hasData

      boolean hasData()
      Returns true if and only if count()>0.

      After a call of map(long) or mapNext(), this method may be used to check that the current mapping position is equal to the length of the underlying data storage. For sequential calls of mapNext(), this method returns false when all elements from the data storage have been already mapped.

      Returns:
      true if this buffer is non-empty.
    • isDirect

      boolean isDirect()
      Returns true if this buffer is direct.

      For buffers, created by this package, the "direct" term is quite specified: please see "Direct and indirect data buffers" section above.

      For any kind of buffer, "direct" term means that all map and mapNext methods, force() and force(long, long) methods, probably, work very quickly, and the changes in the data() array, probably, reflect in the original data storage immediately.

      Returns:
      true if this buffer is direct.
    • from

      int from()
      Returns (int)fromIndex(), if fromIndex()<=Integer.MAX_VALUE, or throws DataBufferIndexOverflowException in other case. May be used if you are sure that this buffer is not a bit buffer, or if you are sure that the AlgART array, processed by this buffer, is not longer than Integer.MAX_VALUE elements.
      Returns:
      (int)fromIndex().
      Throws:
      DataBufferIndexOverflowException - if fromIndex()>Integer.MAX_VALUE.
    • to

      int to()
      Returns (int)toIndex(), if toIndex()<=Integer.MAX_VALUE, or throws DataBufferIndexOverflowException in other case. May be used if you are sure that this buffer is not a bit buffer, or if you are sure that the AlgART array, processed by this buffer, is not longer than Integer.MAX_VALUE elements.
      Returns:
      (int)toIndex().
      Throws:
      DataBufferIndexOverflowException - if toIndex()>Integer.MAX_VALUE.
    • cnt

      int cnt()
      Returns (int)count(), if count()<=Integer.MAX_VALUE, or throws DataBufferIndexOverflowException in other case. May be used if you are sure that this buffer is not a bit buffer, or if you are sure that the AlgART array, processed by this buffer, is not longer than Integer.MAX_VALUE elements.
      Returns:
      (int)count().
      Throws:
      DataBufferIndexOverflowException - if count()>Integer.MAX_VALUE.