@Override
  public void addRange(
      AttributeStreamBase src, int start, int count, boolean bForward, int stride) {
    if (m_bReadonly) throw new GeometryException("invalid_call");

    if (!bForward && (stride < 1 || count % stride != 0)) throw new IllegalArgumentException();

    int oldSize = m_size;
    int newSize = oldSize + count;
    resize(newSize);

    if (bForward) {
      System.arraycopy(((AttributeStreamOfDbl) src).m_buffer, start, m_buffer, oldSize, count);
    } else {
      int n = count;

      for (int i = 0; i < count; i += stride) {
        n -= stride;

        for (int s = 0; s < stride; s++) {
          m_buffer[oldSize + i + s] = ((AttributeStreamOfInt32) src).m_buffer[start + n + s];
        }
      }
    }
  }
  // Removes the element from the array in constant time.
  // It moves the last element of the array to the index and decrements the
  // array size by 1.
  void popElement(int index) {
    assert (index >= 0 && index < m_size);
    if (index < m_size - 1) {
      m_buffer[index] = m_buffer[m_size - 1];
    }

    resize(m_size - 1);
  }
  @Override
  public void writeRange(
      int startElement,
      int count,
      AttributeStreamBase _src,
      int srcStart,
      boolean bForward,
      int stride) {
    if (startElement < 0 || count < 0 || srcStart < 0) throw new IllegalArgumentException();

    if (!bForward && (stride <= 0 || (count % stride != 0))) throw new IllegalArgumentException();

    AttributeStreamOfInt32 src = (AttributeStreamOfInt32) _src; // the input
    // type must
    // match

    if (src.size() < (int) (srcStart + count)) throw new IllegalArgumentException();

    if (count == 0) return;

    if (size() < count + startElement) resize(count + startElement);

    if (_src == (AttributeStreamBase) this) {
      _selfWriteRangeImpl(startElement, count, srcStart, bForward, stride);
      return;
    }

    if (bForward) {
      System.arraycopy(src.m_buffer, srcStart, m_buffer, startElement, count);
      // int j = startElement;
      // int offset = srcStart;
      // for (int i = 0; i < count; i++)
      // {
      // m_buffer[j] = src.m_buffer[offset];
      // j++;
      // offset++;
      // }
    } else {
      int j = startElement;
      int offset = srcStart + count - stride;
      if (stride == 1) {
        for (int i = 0; i < count; i++) {
          m_buffer[j] = src.m_buffer[offset];
          j++;
          offset--;
        }
      } else {
        for (int i = 0, n = count / stride; i < n; i++) {
          for (int k = 0; k < stride; k++) m_buffer[j + k] = src.m_buffer[offset + k];

          j += stride;
          offset -= stride;
        }
      }
    }
  }
  @Override
  public void resizePreserveCapacity(int newSize) // java only method
      {
    if (m_buffer == null || newSize > m_buffer.length) resize(newSize);
    if (m_bLockedInSize)
      throw new GeometryException(
          "invalid call. Attribute Stream is locked and cannot be resized.");

    m_size = newSize;
  }
  @Override
  public void writeRange(
      int startElement, int count, ByteBuffer src, int offsetBytes, boolean bForward) {
    if (startElement < 0 || count < 0 || offsetBytes < 0) throw new IllegalArgumentException();

    final int elmSize = NumberUtils.sizeOf((double) 0);
    if (src.capacity() < (int) (offsetBytes + elmSize * count))
      throw new IllegalArgumentException();

    if (count == 0) return;

    if (size() < count + startElement) resize(count + startElement);

    int j = startElement;
    if (!bForward) j += count - 1;

    final int dj = bForward ? 1 : -1;

    int offset = offsetBytes;
    for (int i = 0; i < count; i++, offset += elmSize) {
      m_buffer[j] = src.getInt(offset);
      j += dj;
    }
  }
 public void removeLast() {
   resize(m_size - 1);
 }
 /**
  * Adds a new value at the end of the stream.
  *
  * @param offset is the element number in the stream.
  * @param value is the value to write.
  */
 public void add(int v) {
   resize(m_size + 1);
   m_buffer[m_size - 1] = v;
 }