blob: e7d4bed2577502ef821cee282b63b84fdc31eeb5 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _DECAF_NIO_BUFFER_H_
#define _DECAF_NIO_BUFFER_H_
#include <decaf/lang/exceptions/IllegalArgumentException.h>
#include <decaf/nio/InvalidMarkException.h>
namespace decaf {
namespace nio {
/**
* A container for data of a specific primitive type.
*
* A buffer is a linear, finite sequence of elements of a specific primitive
* type. Aside from its content, the essential properties of a buffer are
* its capacity, limit, and position:
*
* A buffer's capacity is the number of elements it contains. The capacity of a
* buffer is never negative and never changes.
*
* A buffer's limit is the index of the first element that should not be read
* or written. A buffer's limit is never negative and is never greater than its
* capacity.
*
* A buffer's position is the index of the next element to be read or written.
* A buffer's position is never negative and is never greater than its limit.
*
* There is one subclass of this class for each non-boolean primitive type.
*
* Transferring data:
* Each subclass of this class defines two categories of get and put operations:
* * Relative operations read or write one or more elements starting at the
* current position and then increment the position by the number of
* elements transferred. If the requested transfer exceeds the limit then a
* relative get operation throws a BufferUnderflowException and a relative
* put operation throws a BufferOverflowException; in either case, no data
* is transferred.
* * Absolute operations take an explicit element index and do not affect the
* position. Absolute get and put operations throw an IndexOutOfBoundsException
* if the index argument exceeds the limit.
*
* Data may also, of course, be transferred in to or out of a buffer by the I/O
* operations of an appropriate channel, which are always relative to the current
* position.
*
* Marking and resetting:
*
* A buffer's mark is the index to which its position will be reset when the
* reset method is invoked. The mark is not always defined, but when it is
* defined it is never negative and is never greater than the position. If the
* mark is defined then it is discarded when the position or the limit is
* adjusted to a value smaller than the mark. If the mark is not defined then
* invoking the reset method causes an InvalidMarkException to be thrown.
*
* Invariants:
*
* The following invariant holds for the mark, position, limit, and capacity values:
* 0 <= mark <= position <= limit <= capacity
*
* A newly-created buffer always has a position of zero and a mark that is
* undefined. The initial limit may be zero, or it may be some other value that
* depends upon the type of the buffer and the manner in which it is constructed.
* The initial content of a buffer is, in general, undefined.
*
* Clearing, flipping, and rewinding:
*
* In addition to methods for accessing the position, limit, and capacity values
* and for marking and resetting, this class also defines the following operations
* upon buffers:
*
* clear() makes a buffer ready for a new sequence of channel-read or relative
* put operations: It sets the limit to the capacity and the position to zero.
*
* flip() makes a buffer ready for a new sequence of channel-write or relative
* get operations: It sets the limit to the current position and then sets the
* position to zero.
*
* rewind() makes a buffer ready for re-reading the data that it already
* contains: It leaves the limit unchanged and sets the position to zero.
*
* Read-only buffers:
*
* Every buffer is readable, but not every buffer is writable. The mutation
* methods of each buffer class are specified as optional operations that will
* throw a ReadOnlyBufferException when invoked upon a read-only buffer. A
* read-only buffer does not allow its content to be changed, but its mark,
* position, and limit values are mutable. Whether or not a buffer is read-only
* may be determined by invoking its isReadOnly method.
*
* Thread safety:
*
* Buffers are not safe for use by multiple concurrent threads. If a buffer is to
* be used by more than one thread then access to the buffer should be controlled
* by appropriate synchronization.
*
* Invocation chaining:
*
* Methods in this class that do not otherwise have a value to return are specified
* to return the buffer upon which they are invoked. This allows method invocations
* to be chained; for example, the sequence of statements
*
* b.flip();
* b.position(23);
* b.limit(42);
*
* can be replaced by the single, more compact statement
* b.flip().position(23).limit(42);
*/
class DECAF_API Buffer {
protected:
mutable int _position;
int _capacity;
int _limit;
int _mark;
bool _markSet;
public:
Buffer(int capactiy);
Buffer(const Buffer& other);
virtual ~Buffer() {}
public:
/**
* @return this buffer's capacity.
*/
virtual int capacity() const {
return this->_capacity;
}
/**
* @return the current position in the buffer
*/
virtual int position() const {
return this->_position;
}
/**
* Sets this buffer's position. If the mark is defined and larger than the
* new position then it is discarded.
*
* @param newPosition
* The new postion in the buffer to set.
*
* @return a reference to This buffer.
*
* @throws IllegalArgumentException if preconditions on the new pos don't hold.
*/
virtual Buffer& position(int newPosition);
/**
* @return this buffers Limit
*/
virtual int limit() const {
return this->_limit;
}
/**
* Sets this buffer's limit. If the position is larger than the new limit then
* it is set to the new limit. If the mark is defined and larger than the new
* limit then it is discarded.
*
* @param newLimit
* The new limit value; must be no larger than this buffer's capacity.
*
* @return A reference to This buffer
*
* @throws IllegalArgumentException if preconditions on the new pos don't hold.
*/
virtual Buffer& limit(int newLimit);
/**
* Sets this buffer's mark at its position.
*
* @return a reference to this buffer.
*/
virtual Buffer& mark();
/**
* Resets this buffer's position to the previously-marked position.
*
* @return a reference to this buffer.
*
* @throws InvalidMarkException - If the mark has not been set
*/
virtual Buffer& reset();
/**
* Clears this buffer. The position is set to zero, the limit is set to the
* capacity, and the mark is discarded.
*
* Invoke this method before using a sequence of channel-read or put operations
* to fill this buffer. For example:
*
* buf.clear(); // Prepare buffer for reading
* in.read(buf); // Read data
*
* This method does not actually erase the data in the buffer, but it is named
* as if it did because it will most often be used in situations in which that
* might as well be the case.
*
* @return a reference to this buffer.
*/
virtual Buffer& clear();
/**
* Flips this buffer. The limit is set to the current position and then the
* position is set to zero. If the mark is defined then it is discarded.
*
* After a sequence of channel-read or put operations, invoke this method to
* prepare for a sequence of channel-write or relative get operations. For
* example:
*
* buf.put(magic); // Prepend header
* in.read(buf); // Read data into rest of buffer
* buf.flip(); // Flip buffer
* out.write(buf); // Write header + data to channel
*
* This method is often used in conjunction with the compact method when
* transferring data from one place to another.
*
* @return a reference to this buffer.
*/
virtual Buffer& flip();
/**
* Rewinds this buffer. The position is set to zero and the mark is discarded.
*
* Invoke this method before a sequence of channel-write or get operations,
* assuming that the limit has already been set appropriately. For example:
*
* out.write(buf); // Write remaining data
* buf.rewind(); // Rewind buffer
* buf.get(array); // Copy data into array
*
* @return a reference to this buffer.
*/
virtual Buffer& rewind();
/**
* Returns the number of elements between the current position and the limit.
*
* @return The number of elements remaining in this buffer
*/
virtual int remaining() const {
return _limit - _position;
}
/**
* Tells whether there are any elements between the current position and the limit.
*
* @return true if, and only if, there is at least one element remaining in
* this buffer.
*/
virtual bool hasRemaining() const {
return remaining() != 0;
}
/**
* Tells whether or not this buffer is read-only.
*
* @return true if, and only if, this buffer is read-only.
*/
virtual bool isReadOnly() const = 0;
};
}}
#endif /*_DECAF_NIO_BUFFER_H_*/