Add code
This commit is contained in:
641
source/tanya/container/buffer.d
Normal file
641
source/tanya/container/buffer.d
Normal file
@ -0,0 +1,641 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* Copyright: Eugene Wissner 2016.
|
||||
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
||||
* Mozilla Public License, v. 2.0).
|
||||
* Authors: $(LINK2 mailto:belka@caraus.de, Eugene Wissner)
|
||||
*/
|
||||
module tanya.container.buffer;
|
||||
|
||||
import tanya.memory;
|
||||
|
||||
@nogc:
|
||||
|
||||
version (unittest)
|
||||
{
|
||||
private int fillBuffer(void* buffer,
|
||||
in size_t size,
|
||||
int start = 0,
|
||||
int end = 10)
|
||||
in
|
||||
{
|
||||
assert(start < end);
|
||||
}
|
||||
body
|
||||
{
|
||||
ubyte[] buf = cast(ubyte[]) buffer[0..size];
|
||||
auto numberRead = end - start;
|
||||
|
||||
for (ubyte i; i < numberRead; ++i)
|
||||
{
|
||||
buf[i] = cast(ubyte) (start + i);
|
||||
}
|
||||
return numberRead;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface for implemeting input/output buffers.
|
||||
*/
|
||||
interface Buffer
|
||||
{
|
||||
@nogc:
|
||||
/**
|
||||
* Returns: The size of the internal buffer.
|
||||
*/
|
||||
@property size_t capacity() const @safe pure nothrow;
|
||||
|
||||
/**
|
||||
* Returns: Data size.
|
||||
*/
|
||||
@property size_t length() const @safe pure nothrow;
|
||||
|
||||
/**
|
||||
* Returns: Available space.
|
||||
*/
|
||||
@property size_t free() const @safe pure nothrow;
|
||||
|
||||
/**
|
||||
* Appends some data to the buffer.
|
||||
*
|
||||
* Params:
|
||||
* buffer = Buffer chunk got with $(D_PSYMBOL buffer).
|
||||
*/
|
||||
Buffer opOpAssign(string op)(void[] buffer)
|
||||
if (op == "~");
|
||||
}
|
||||
|
||||
/**
|
||||
* Buffer that can be used with C functions accepting void pointer and
|
||||
* returning the number of the read bytes.
|
||||
*/
|
||||
class ReadBuffer : Buffer
|
||||
{
|
||||
@nogc:
|
||||
/// Internal buffer.
|
||||
protected ubyte[] _buffer;
|
||||
|
||||
/// Filled buffer length.
|
||||
protected size_t _length;
|
||||
|
||||
/// Available space.
|
||||
protected immutable size_t minAvailable;
|
||||
|
||||
/// Size by which the buffer will grow.
|
||||
protected immutable size_t blockSize;
|
||||
|
||||
private Allocator allocator;
|
||||
|
||||
invariant
|
||||
{
|
||||
assert(_length <= _buffer.length);
|
||||
assert(blockSize > 0);
|
||||
assert(minAvailable > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Params:
|
||||
* size = Initial buffer size and the size by which the buffer
|
||||
* will grow.
|
||||
* minAvailable = minimal size should be always available to fill.
|
||||
* So it will reallocate if $(D_INLINECODE
|
||||
* $(D_PSYMBOL free) < $(D_PARAM minAvailable)
|
||||
* ).
|
||||
*/
|
||||
this(size_t size = 8192,
|
||||
size_t minAvailable = 1024,
|
||||
Allocator allocator = defaultAllocator)
|
||||
{
|
||||
this.allocator = allocator;
|
||||
this.minAvailable = minAvailable;
|
||||
this.blockSize = size;
|
||||
resizeArray!ubyte(this.allocator, _buffer, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deallocates the internal buffer.
|
||||
*/
|
||||
~this()
|
||||
{
|
||||
finalize(allocator, _buffer);
|
||||
}
|
||||
|
||||
///
|
||||
unittest
|
||||
{
|
||||
auto b = make!ReadBuffer(defaultAllocator);
|
||||
assert(b.capacity == 8192);
|
||||
assert(b.length == 0);
|
||||
|
||||
finalize(defaultAllocator, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns: The size of the internal buffer.
|
||||
*/
|
||||
@property size_t capacity() const @safe pure nothrow
|
||||
{
|
||||
return _buffer.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns: Data size.
|
||||
*/
|
||||
@property size_t length() const @safe pure nothrow
|
||||
{
|
||||
return _length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns: Available space.
|
||||
*/
|
||||
@property size_t free() const @safe pure nothrow
|
||||
{
|
||||
return capacity - length;
|
||||
}
|
||||
|
||||
///
|
||||
unittest
|
||||
{
|
||||
auto b = make!ReadBuffer(defaultAllocator);
|
||||
size_t numberRead;
|
||||
void* buf;
|
||||
|
||||
// Fills the buffer with values 0..10
|
||||
assert(b.free == b.blockSize);
|
||||
buf = b.buffer;
|
||||
numberRead = fillBuffer(buf, b.free, 0, 10);
|
||||
b ~= buf[0..numberRead];
|
||||
assert(b.free == b.blockSize - numberRead);
|
||||
b[];
|
||||
assert(b.free == b.blockSize);
|
||||
|
||||
finalize(defaultAllocator, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a pointer to a chunk of the internal buffer. You can pass it to
|
||||
* a function that requires such a buffer.
|
||||
*
|
||||
* Set the buffer again after reading something into it. Append
|
||||
* $(D_KEYWORD ~=) a slice from the beginning of the buffer you got and
|
||||
* till the number of the read bytes. The data will be appended to the
|
||||
* existing buffer.
|
||||
*
|
||||
* Returns: A chunk of available buffer.
|
||||
*/
|
||||
@property void* buffer()
|
||||
{
|
||||
if (capacity - length < minAvailable)
|
||||
{
|
||||
resizeArray!ubyte(this.allocator, _buffer, capacity + blockSize);
|
||||
}
|
||||
return _buffer[_length..$].ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends some data to the buffer. Use only the buffer you got
|
||||
* with $(D_PSYMBOL buffer)!
|
||||
*
|
||||
* Params:
|
||||
* buffer = Buffer chunk got with $(D_PSYMBOL buffer).
|
||||
*/
|
||||
ReadBuffer opOpAssign(string op)(void[] buffer)
|
||||
if (op == "~")
|
||||
{
|
||||
_length += buffer.length;
|
||||
return this;
|
||||
}
|
||||
|
||||
///
|
||||
unittest
|
||||
{
|
||||
auto b = make!ReadBuffer(defaultAllocator);
|
||||
size_t numberRead;
|
||||
void* buf;
|
||||
ubyte[] result;
|
||||
|
||||
// Fills the buffer with values 0..10
|
||||
buf = b.buffer;
|
||||
numberRead = fillBuffer(buf, b.free, 0, 10);
|
||||
b ~= buf[0..numberRead];
|
||||
|
||||
result = b[];
|
||||
assert(result[0] == 0);
|
||||
assert(result[1] == 1);
|
||||
assert(result[9] == 9);
|
||||
|
||||
// It shouldn't overwrite, but append another 5 bytes to the buffer
|
||||
buf = b.buffer;
|
||||
numberRead = fillBuffer(buf, b.free, 0, 10);
|
||||
b ~= buf[0..numberRead];
|
||||
|
||||
buf = b.buffer;
|
||||
numberRead = fillBuffer(buf, b.free, 20, 25);
|
||||
b ~= buf[0..numberRead];
|
||||
|
||||
result = b[];
|
||||
assert(result[0] == 0);
|
||||
assert(result[1] == 1);
|
||||
assert(result[9] == 9);
|
||||
assert(result[10] == 20);
|
||||
assert(result[14] == 24);
|
||||
|
||||
finalize(defaultAllocator, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the buffer. The buffer is cleared after that. So you can get it
|
||||
* only one time.
|
||||
*
|
||||
* Returns: The buffer as array.
|
||||
*/
|
||||
@property ubyte[] opIndex()
|
||||
{
|
||||
auto ret = _buffer[0.._length];
|
||||
_length = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
///
|
||||
unittest
|
||||
{
|
||||
auto b = make!ReadBuffer(defaultAllocator);
|
||||
size_t numberRead;
|
||||
void* buf;
|
||||
ubyte[] result;
|
||||
|
||||
// Fills the buffer with values 0..10
|
||||
buf = b.buffer;
|
||||
numberRead = fillBuffer(buf, b.free, 0, 10);
|
||||
b ~= buf[0..numberRead];
|
||||
|
||||
assert(b.length == 10);
|
||||
result = b[];
|
||||
assert(result[0] == 0);
|
||||
assert(result[9] == 9);
|
||||
assert(b.length == 0);
|
||||
|
||||
finalize(defaultAllocator, b);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Circular, self-expanding buffer that can be used with C functions accepting
|
||||
* void pointer and returning the number of the read bytes.
|
||||
*
|
||||
* The buffer is optimized for situations where you read all the data from it
|
||||
* at once (without writing to it occasionally). It can become ineffective if
|
||||
* you permanently keep some data in the buffer and alternate writing and
|
||||
* reading, because it may allocate and move elements.
|
||||
*/
|
||||
class WriteBuffer : Buffer
|
||||
{
|
||||
@nogc:
|
||||
/// Internal buffer.
|
||||
protected ubyte[] _buffer;
|
||||
|
||||
/// Buffer start position.
|
||||
protected size_t start;
|
||||
|
||||
/// Buffer ring area size. After this position begins buffer overflow area.
|
||||
protected size_t ring;
|
||||
|
||||
/// Size by which the buffer will grow.
|
||||
protected immutable size_t blockSize;
|
||||
|
||||
/// The position of the free area in the buffer.
|
||||
protected size_t position;
|
||||
|
||||
private Allocator allocator;
|
||||
|
||||
invariant
|
||||
{
|
||||
assert(blockSize > 0);
|
||||
// position can refer to an element outside the buffer if the buffer is full.
|
||||
assert(position <= _buffer.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Params:
|
||||
* size = Initial buffer size and the size by which the buffer
|
||||
* will grow.
|
||||
*/
|
||||
this(size_t size = 8192,
|
||||
Allocator allocator = defaultAllocator)
|
||||
{
|
||||
this.allocator = allocator;
|
||||
blockSize = size;
|
||||
ring = size - 1;
|
||||
resizeArray!ubyte(this.allocator, _buffer, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deallocates the internal buffer.
|
||||
*/
|
||||
~this()
|
||||
{
|
||||
finalize(allocator, _buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns: The size of the internal buffer.
|
||||
*/
|
||||
@property size_t capacity() const @safe pure nothrow
|
||||
{
|
||||
return _buffer.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Note that $(D_PSYMBOL length) doesn't return the real length of the data,
|
||||
* but only the array length that will be returned with $(D_PSYMBOL buffer)
|
||||
* next time. Be sure to call $(D_PSYMBOL buffer) and set $(D_PSYMBOL written)
|
||||
* until $(D_PSYMBOL length) returns 0.
|
||||
*
|
||||
* Returns: Data size.
|
||||
*/
|
||||
@property size_t length() const @safe pure nothrow
|
||||
{
|
||||
if (position > ring || position < start) // Buffer overflowed
|
||||
{
|
||||
return ring - start + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return position - start;
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
unittest
|
||||
{
|
||||
auto b = make!WriteBuffer(defaultAllocator, 4);
|
||||
ubyte[3] buf = [48, 23, 255];
|
||||
|
||||
b ~= buf;
|
||||
assert(b.length == 3);
|
||||
b.written = 2;
|
||||
assert(b.length == 1);
|
||||
|
||||
b ~= buf;
|
||||
assert(b.length == 2);
|
||||
b.written = 2;
|
||||
assert(b.length == 2);
|
||||
|
||||
b ~= buf;
|
||||
assert(b.length == 5);
|
||||
b.written = b.length;
|
||||
assert(b.length == 0);
|
||||
|
||||
finalize(defaultAllocator, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns: Available space.
|
||||
*/
|
||||
@property size_t free() const @safe pure nothrow
|
||||
{
|
||||
return capacity - length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends data to the buffer.
|
||||
*
|
||||
* Params:
|
||||
* buffer = Buffer chunk got with $(D_PSYMBOL buffer).
|
||||
*/
|
||||
WriteBuffer opOpAssign(string op)(ubyte[] buffer)
|
||||
if (op == "~")
|
||||
{
|
||||
size_t end, start;
|
||||
|
||||
if (position >= this.start && position <= ring)
|
||||
{
|
||||
auto afterRing = ring + 1;
|
||||
|
||||
end = position + buffer.length;
|
||||
if (end > afterRing)
|
||||
{
|
||||
end = afterRing;
|
||||
}
|
||||
start = end - position;
|
||||
_buffer[position..end] = buffer[0..start];
|
||||
if (end == afterRing)
|
||||
{
|
||||
position = this.start == 0 ? afterRing : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
position = end;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we have some free space at the beginning
|
||||
if (start < buffer.length && position < this.start)
|
||||
{
|
||||
end = position + buffer.length - start;
|
||||
if (end > this.start)
|
||||
{
|
||||
end = this.start;
|
||||
}
|
||||
auto areaEnd = end - position + start;
|
||||
_buffer[position..end] = buffer[start..areaEnd];
|
||||
position = end == this.start ? ring + 1 : end - position;
|
||||
start = areaEnd;
|
||||
}
|
||||
|
||||
// And if we still haven't found any place, save the rest in the overflow area
|
||||
if (start < buffer.length)
|
||||
{
|
||||
end = position + buffer.length - start;
|
||||
if (end > capacity)
|
||||
{
|
||||
auto newSize = end / blockSize * blockSize + blockSize;
|
||||
|
||||
resizeArray!ubyte(this.allocator, _buffer, newSize);
|
||||
}
|
||||
_buffer[position..end] = buffer[start..$];
|
||||
position = end;
|
||||
if (this.start == 0)
|
||||
{
|
||||
ring = capacity - 1;
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
///
|
||||
unittest
|
||||
{
|
||||
auto b = make!WriteBuffer(defaultAllocator, 4);
|
||||
ubyte[3] buf = [48, 23, 255];
|
||||
|
||||
b ~= buf;
|
||||
assert(b.capacity == 4);
|
||||
assert(b._buffer[0] == 48 && b._buffer[1] == 23 && b._buffer[2] == 255);
|
||||
|
||||
b.written = 2;
|
||||
b ~= buf;
|
||||
assert(b.capacity == 4);
|
||||
assert(b._buffer[0] == 23 && b._buffer[1] == 255
|
||||
&& b._buffer[2] == 255 && b._buffer[3] == 48);
|
||||
|
||||
b.written = 2;
|
||||
b ~= buf;
|
||||
assert(b.capacity == 8);
|
||||
assert(b._buffer[0] == 23 && b._buffer[1] == 255
|
||||
&& b._buffer[2] == 48 && b._buffer[3] == 23 && b._buffer[4] == 255);
|
||||
|
||||
finalize(defaultAllocator, b);
|
||||
|
||||
b = make!WriteBuffer(defaultAllocator, 2);
|
||||
|
||||
b ~= buf;
|
||||
assert(b.start == 0);
|
||||
assert(b.capacity == 4);
|
||||
assert(b.ring == 3);
|
||||
assert(b.position == 3);
|
||||
|
||||
finalize(defaultAllocator, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets how many bytes were written. It will shrink the buffer
|
||||
* appropriately. Always set this property after calling
|
||||
* $(D_PSYMBOL buffer).
|
||||
*
|
||||
* Params:
|
||||
* length = Length of the written data.
|
||||
*/
|
||||
@property void written(size_t length) @safe pure nothrow
|
||||
in
|
||||
{
|
||||
assert(length <= this.length);
|
||||
}
|
||||
body
|
||||
{
|
||||
auto afterRing = ring + 1;
|
||||
auto oldStart = start;
|
||||
|
||||
if (length <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else if (position <= afterRing)
|
||||
{
|
||||
start += length;
|
||||
if (start > 0 && position == afterRing)
|
||||
{
|
||||
position = oldStart;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto overflow = position - afterRing;
|
||||
|
||||
if (overflow > length) {
|
||||
_buffer[start.. start + length] = _buffer[afterRing.. afterRing + length];
|
||||
_buffer[afterRing.. afterRing + length] = _buffer[afterRing + length ..position];
|
||||
position -= length;
|
||||
}
|
||||
else if (overflow == length)
|
||||
{
|
||||
_buffer[start.. start + overflow] = _buffer[afterRing..position];
|
||||
position -= overflow;
|
||||
}
|
||||
else
|
||||
{
|
||||
_buffer[start.. start + overflow] = _buffer[afterRing..position];
|
||||
position = overflow;
|
||||
}
|
||||
start += length;
|
||||
|
||||
if (start == position)
|
||||
{
|
||||
if (position != afterRing)
|
||||
{
|
||||
position = 0;
|
||||
}
|
||||
start = 0;
|
||||
ring = capacity - 1;
|
||||
}
|
||||
}
|
||||
if (start > ring)
|
||||
{
|
||||
start = 0;
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
unittest
|
||||
{
|
||||
auto b = make!WriteBuffer(defaultAllocator);
|
||||
ubyte[6] buf = [23, 23, 255, 128, 127, 9];
|
||||
|
||||
b ~= buf;
|
||||
assert(b.length == 6);
|
||||
b.written = 2;
|
||||
assert(b.length == 4);
|
||||
b.written = 4;
|
||||
assert(b.length == 0);
|
||||
|
||||
finalize(defaultAllocator, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a pointer to a buffer chunk with data. You can pass it to
|
||||
* a function that requires such a buffer.
|
||||
*
|
||||
* After calling it, set $(D_PSYMBOL written) to the length could be
|
||||
* written.
|
||||
*
|
||||
* $(D_PSYMBOL buffer) may return only part of the data. You may need
|
||||
* to call it (and set $(D_PSYMBOL written) several times until
|
||||
* $(D_PSYMBOL length) is 0. If all the data can be written,
|
||||
* maximally 3 calls are required.
|
||||
*
|
||||
* Returns: A chunk of data buffer.
|
||||
*/
|
||||
@property void* buffer() @safe pure nothrow
|
||||
{
|
||||
if (position > ring || position < start) // Buffer overflowed
|
||||
{
|
||||
return _buffer[start.. ring + 1].ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
return _buffer[start..position].ptr;
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
unittest
|
||||
{
|
||||
auto b = make!WriteBuffer(defaultAllocator, 6);
|
||||
ubyte[6] buf = [23, 23, 255, 128, 127, 9];
|
||||
void* returnedBuf;
|
||||
|
||||
b ~= buf;
|
||||
returnedBuf = b.buffer;
|
||||
assert(returnedBuf[0..b.length] == buf[0..6]);
|
||||
b.written = 2;
|
||||
|
||||
returnedBuf = b.buffer;
|
||||
assert(returnedBuf[0..b.length] == buf[2..6]);
|
||||
|
||||
b ~= buf;
|
||||
returnedBuf = b.buffer;
|
||||
assert(returnedBuf[0..b.length] == buf[2..6]);
|
||||
b.written = b.length;
|
||||
|
||||
returnedBuf = b.buffer;
|
||||
assert(returnedBuf[0..b.length] == buf[0..6]);
|
||||
b.written = b.length;
|
||||
|
||||
finalize(defaultAllocator, b);
|
||||
}
|
||||
}
|
405
source/tanya/container/list.d
Normal file
405
source/tanya/container/list.d
Normal file
@ -0,0 +1,405 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* Copyright: Eugene Wissner 2016.
|
||||
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
||||
* Mozilla Public License, v. 2.0).
|
||||
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
||||
*/
|
||||
module tanya.container.list;
|
||||
|
||||
import tanya.memory;
|
||||
|
||||
/**
|
||||
* Singly linked list.
|
||||
*
|
||||
* Params:
|
||||
* T = Content type.
|
||||
*/
|
||||
class SList(T)
|
||||
{
|
||||
@nogc:
|
||||
/**
|
||||
* Creates a new $(D_PSYMBOL SList).
|
||||
*
|
||||
* Params:
|
||||
* allocator = The allocator should be used for the element
|
||||
* allocations.
|
||||
*/
|
||||
this(Allocator allocator = defaultAllocator)
|
||||
{
|
||||
this.allocator = allocator;
|
||||
reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all elements from the list.
|
||||
*/
|
||||
~this()
|
||||
{
|
||||
while (!empty)
|
||||
{
|
||||
static if (isFinalizable!T)
|
||||
{
|
||||
finalize(allocator, front);
|
||||
}
|
||||
popFront();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns: First element.
|
||||
*/
|
||||
@property ref T front()
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
}
|
||||
body
|
||||
{
|
||||
return first.next.content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a new element at the beginning.
|
||||
*
|
||||
* Params:
|
||||
* x = New element.
|
||||
*/
|
||||
@property void front(T x)
|
||||
{
|
||||
Entry* temp = make!Entry(allocator);
|
||||
|
||||
temp.content = x;
|
||||
temp.next = first.next;
|
||||
first.next = temp;
|
||||
}
|
||||
|
||||
///
|
||||
unittest
|
||||
{
|
||||
auto l = make!(SList!int)(defaultAllocator);
|
||||
int[2] values = [8, 9];
|
||||
|
||||
l.front = values[0];
|
||||
assert(l.front == values[0]);
|
||||
l.front = values[1];
|
||||
assert(l.front == values[1]);
|
||||
|
||||
finalize(defaultAllocator, l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a new element at the beginning.
|
||||
*
|
||||
* Params:
|
||||
* x = New element.
|
||||
*
|
||||
* Returns: $(D_KEYWORD this).
|
||||
*/
|
||||
typeof(this) opOpAssign(string Op)(ref T x)
|
||||
if (Op == "~")
|
||||
{
|
||||
front = x;
|
||||
return this;
|
||||
}
|
||||
|
||||
///
|
||||
unittest
|
||||
{
|
||||
auto l = make!(SList!int)(defaultAllocator);
|
||||
int value = 5;
|
||||
|
||||
assert(l.empty);
|
||||
|
||||
l ~= value;
|
||||
|
||||
assert(l.front == value);
|
||||
assert(!l.empty);
|
||||
|
||||
finalize(defaultAllocator, l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns: $(D_KEYWORD true) if the list is empty.
|
||||
*/
|
||||
@property bool empty() const @safe pure nothrow
|
||||
{
|
||||
return first.next is null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first element and moves to the next one.
|
||||
*
|
||||
* Returns: The first element.
|
||||
*/
|
||||
T popFront()
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
}
|
||||
body
|
||||
{
|
||||
auto n = first.next.next;
|
||||
auto content = first.next.content;
|
||||
|
||||
finalize(allocator, first.next);
|
||||
first.next = n;
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
///
|
||||
unittest
|
||||
{
|
||||
auto l = make!(SList!int)(defaultAllocator);
|
||||
int[2] values = [8, 9];
|
||||
|
||||
l.front = values[0];
|
||||
l.front = values[1];
|
||||
assert(l.front == values[1]);
|
||||
l.popFront();
|
||||
assert(l.front == values[0]);
|
||||
|
||||
finalize(defaultAllocator, l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current item from the list and removes from the list.
|
||||
*
|
||||
* Params:
|
||||
* x = The item should be removed.
|
||||
*
|
||||
* Returns: Removed item.
|
||||
*/
|
||||
T remove()
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
}
|
||||
body
|
||||
{
|
||||
auto temp = position.next.next;
|
||||
auto content = position.next.content;
|
||||
|
||||
finalize(allocator, position.next);
|
||||
position.next = temp;
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
///
|
||||
unittest
|
||||
{
|
||||
auto l = make!(SList!int)(defaultAllocator);
|
||||
int[3] values = [8, 5, 4];
|
||||
|
||||
l.front = values[0];
|
||||
l.front = values[1];
|
||||
assert(l.remove() == 5);
|
||||
l.front = values[2];
|
||||
assert(l.remove() == 4);
|
||||
assert(l.remove() == 8);
|
||||
assert(l.empty);
|
||||
|
||||
finalize(defaultAllocator, l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the current position.
|
||||
*
|
||||
* Returns: $(D_KEYWORD this).
|
||||
*/
|
||||
typeof(this) reset()
|
||||
{
|
||||
position = &first;
|
||||
return this;
|
||||
}
|
||||
|
||||
///
|
||||
unittest
|
||||
{
|
||||
auto l = make!(SList!int)(defaultAllocator);
|
||||
int[2] values = [8, 5];
|
||||
|
||||
l.current = values[0];
|
||||
l.current = values[1];
|
||||
assert(l.current == 5);
|
||||
l.advance();
|
||||
assert(l.current == 8);
|
||||
l.reset();
|
||||
assert(l.current == 5);
|
||||
|
||||
finalize(defaultAllocator, l);
|
||||
}
|
||||
|
||||
/**
|
||||
* $(D_KEYWORD foreach) iteration.
|
||||
*
|
||||
* Params:
|
||||
* dg = $(D_KEYWORD foreach) body.
|
||||
*/
|
||||
int opApply(int delegate(ref size_t i, ref T) @nogc dg)
|
||||
{
|
||||
int result;
|
||||
size_t i;
|
||||
|
||||
for (position = first.next; position; position = position.next, ++i)
|
||||
{
|
||||
result = dg(i, position.content);
|
||||
|
||||
if (result != 0)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
reset();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
///
|
||||
unittest
|
||||
{
|
||||
auto l = make!(SList!int)(defaultAllocator);
|
||||
int[3] values = [5, 4, 9];
|
||||
|
||||
l.front = values[0];
|
||||
l.front = values[1];
|
||||
l.front = values[2];
|
||||
foreach (i, e; l)
|
||||
{
|
||||
assert(i != 0 || e == values[2]);
|
||||
assert(i != 1 || e == values[1]);
|
||||
assert(i != 2 || e == values[0]);
|
||||
}
|
||||
|
||||
finalize(defaultAllocator, l);
|
||||
}
|
||||
|
||||
/// Ditto.
|
||||
int opApply(int delegate(ref T) @nogc dg)
|
||||
{
|
||||
int result;
|
||||
|
||||
for (position = first.next; position; position = position.next)
|
||||
{
|
||||
result = dg(position.content);
|
||||
|
||||
if (result != 0)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
reset();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
///
|
||||
unittest
|
||||
{
|
||||
auto l = make!(SList!int)(defaultAllocator);
|
||||
int[3] values = [5, 4, 9];
|
||||
size_t i;
|
||||
|
||||
l.front = values[0];
|
||||
l.front = values[1];
|
||||
l.front = values[2];
|
||||
foreach (e; l)
|
||||
{
|
||||
assert(i != 0 || e == values[2]);
|
||||
assert(i != 1 || e == values[1]);
|
||||
assert(i != 2 || e == values[0]);
|
||||
++i;
|
||||
}
|
||||
|
||||
finalize(defaultAllocator, l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns: $(D_KEYWORD true) if the current position is the end position.
|
||||
*/
|
||||
@property bool end() const
|
||||
{
|
||||
return empty || position.next.next is null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves to the next element and returns it.
|
||||
*
|
||||
* Returns: The element on the next position.
|
||||
*/
|
||||
T advance()
|
||||
in
|
||||
{
|
||||
assert(!end);
|
||||
}
|
||||
body
|
||||
{
|
||||
position = position.next;
|
||||
return position.content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns: Element on the current position.
|
||||
*/
|
||||
@property ref T current()
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
}
|
||||
body
|
||||
{
|
||||
return position.next.content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a new element at the current position.
|
||||
*
|
||||
* Params:
|
||||
* x = New element.
|
||||
*/
|
||||
@property void current(T x)
|
||||
{
|
||||
Entry* temp = make!Entry(allocator);
|
||||
|
||||
temp.content = x;
|
||||
temp.next = position.next;
|
||||
position.next = temp;
|
||||
}
|
||||
|
||||
/**
|
||||
* List entry.
|
||||
*/
|
||||
protected struct Entry
|
||||
{
|
||||
/// List item content.
|
||||
T content;
|
||||
|
||||
/// Next list item.
|
||||
Entry* next;
|
||||
}
|
||||
|
||||
/// 0th element of the list.
|
||||
protected Entry first;
|
||||
|
||||
/// Current position in the list.
|
||||
protected Entry* position;
|
||||
|
||||
private Allocator allocator;
|
||||
}
|
||||
|
||||
interface Stuff
|
||||
{
|
||||
}
|
||||
|
||||
///
|
||||
unittest
|
||||
{
|
||||
auto l = make!(SList!Stuff)(defaultAllocator);
|
||||
|
||||
finalize(defaultAllocator, l);
|
||||
}
|
16
source/tanya/container/package.d
Normal file
16
source/tanya/container/package.d
Normal file
@ -0,0 +1,16 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* Copyright: Eugene Wissner 2016.
|
||||
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
||||
* Mozilla Public License, v. 2.0).
|
||||
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
||||
*/
|
||||
module tanya.container;
|
||||
|
||||
public import tanya.container.buffer;
|
||||
public import tanya.container.list;
|
||||
public import tanya.container.vector;
|
||||
public import tanya.container.queue;
|
219
source/tanya/container/queue.d
Normal file
219
source/tanya/container/queue.d
Normal file
@ -0,0 +1,219 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* Copyright: Eugene Wissner 2016.
|
||||
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
||||
* Mozilla Public License, v. 2.0).
|
||||
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
||||
*/
|
||||
module tanya.container.queue;
|
||||
|
||||
import tanya.memory;
|
||||
|
||||
/**
|
||||
* Queue.
|
||||
*
|
||||
* Params:
|
||||
* T = Content type.
|
||||
*/
|
||||
class Queue(T)
|
||||
{
|
||||
@nogc:
|
||||
/**
|
||||
* Creates a new $(D_PSYMBOL Queue).
|
||||
*
|
||||
* Params:
|
||||
* allocator = The allocator should be used for the element
|
||||
* allocations.
|
||||
*/
|
||||
this(Allocator allocator = defaultAllocator)
|
||||
{
|
||||
this.allocator = allocator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all elements from the queue.
|
||||
*/
|
||||
~this()
|
||||
{
|
||||
foreach (e; this)
|
||||
{
|
||||
static if (isFinalizable!T)
|
||||
{
|
||||
finalize(allocator, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns: First element.
|
||||
*/
|
||||
@property ref T front()
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
}
|
||||
body
|
||||
{
|
||||
return first.next.content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a new element.
|
||||
*
|
||||
* Params:
|
||||
* x = New element.
|
||||
*
|
||||
* Returns: $(D_KEYWORD this).
|
||||
*/
|
||||
typeof(this) insertBack(T x)
|
||||
{
|
||||
Entry* temp = make!Entry(allocator);
|
||||
|
||||
temp.content = x;
|
||||
|
||||
if (empty)
|
||||
{
|
||||
first.next = rear = temp;
|
||||
}
|
||||
else
|
||||
{
|
||||
rear.next = temp;
|
||||
rear = rear.next;
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
alias insert = insertBack;
|
||||
|
||||
///
|
||||
unittest
|
||||
{
|
||||
auto q = make!(Queue!int)(defaultAllocator);
|
||||
int[2] values = [8, 9];
|
||||
|
||||
q.insertBack(values[0]);
|
||||
assert(q.front is values[0]);
|
||||
q.insertBack(values[1]);
|
||||
assert(q.front is values[0]);
|
||||
|
||||
finalize(defaultAllocator, q);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a new element.
|
||||
*
|
||||
* Params:
|
||||
* x = New element.
|
||||
*
|
||||
* Returns: $(D_KEYWORD this).
|
||||
*/
|
||||
typeof(this) opOpAssign(string Op)(ref T x)
|
||||
if (Op == "~")
|
||||
{
|
||||
return insertBack(x);
|
||||
}
|
||||
|
||||
///
|
||||
unittest
|
||||
{
|
||||
auto q = make!(Queue!int)(defaultAllocator);
|
||||
int value = 5;
|
||||
|
||||
assert(q.empty);
|
||||
|
||||
q ~= value;
|
||||
|
||||
assert(q.front == value);
|
||||
assert(!q.empty);
|
||||
|
||||
finalize(defaultAllocator, q);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns: $(D_KEYWORD true) if the queue is empty.
|
||||
*/
|
||||
@property bool empty() const @safe pure nothrow
|
||||
{
|
||||
return first.next is null;
|
||||
}
|
||||
|
||||
///
|
||||
unittest
|
||||
{
|
||||
auto q = make!(Queue!int)(defaultAllocator);
|
||||
int value = 7;
|
||||
|
||||
assert(q.empty);
|
||||
q.insertBack(value);
|
||||
assert(!q.empty);
|
||||
|
||||
finalize(defaultAllocator, q);
|
||||
}
|
||||
|
||||
/**
|
||||
* Move position to the next element.
|
||||
*
|
||||
* Returns: $(D_KEYWORD this).
|
||||
*/
|
||||
typeof(this) popFront()
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
}
|
||||
body
|
||||
{
|
||||
auto n = first.next.next;
|
||||
|
||||
finalize(allocator, first.next);
|
||||
first.next = n;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
///
|
||||
unittest
|
||||
{
|
||||
auto q = make!(Queue!int)(defaultAllocator);
|
||||
int[2] values = [8, 9];
|
||||
|
||||
q.insertBack(values[0]);
|
||||
q.insertBack(values[1]);
|
||||
assert(q.front is values[0]);
|
||||
q.popFront();
|
||||
assert(q.front is values[1]);
|
||||
|
||||
finalize(defaultAllocator, q);
|
||||
}
|
||||
|
||||
/**
|
||||
* Queue entry.
|
||||
*/
|
||||
protected struct Entry
|
||||
{
|
||||
/// Queue item content.
|
||||
T content;
|
||||
|
||||
/// Next list item.
|
||||
Entry* next;
|
||||
}
|
||||
|
||||
/// The first element of the list.
|
||||
protected Entry first;
|
||||
|
||||
/// The last element of the list.
|
||||
protected Entry* rear;
|
||||
|
||||
private Allocator allocator;
|
||||
}
|
||||
|
||||
///
|
||||
unittest
|
||||
{
|
||||
auto q = make!(Queue!int)(defaultAllocator);
|
||||
|
||||
finalize(defaultAllocator, q);
|
||||
}
|
420
source/tanya/container/vector.d
Normal file
420
source/tanya/container/vector.d
Normal file
@ -0,0 +1,420 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* Copyright: Eugene Wissner 2016.
|
||||
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
||||
* Mozilla Public License, v. 2.0).
|
||||
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
||||
*/
|
||||
module tanya.container.vector;
|
||||
|
||||
import tanya.memory;
|
||||
|
||||
@nogc:
|
||||
|
||||
/**
|
||||
* One dimensional array. It allocates automatically if needed.
|
||||
*
|
||||
* If you assign a value:
|
||||
* ---
|
||||
* auto v = make!(Vector!int)(defaultAllocator);
|
||||
* int value = 5;
|
||||
*
|
||||
* v[1000] = value;
|
||||
*
|
||||
* finalize(defaultAllocator, v);
|
||||
* ---
|
||||
* it will allocate not only for one, but for 1000 elements. So this
|
||||
* implementation is more suitable for sequential data with random access.
|
||||
*
|
||||
* Params:
|
||||
* T = Content type.
|
||||
*/
|
||||
class Vector(T)
|
||||
{
|
||||
@nogc:
|
||||
/**
|
||||
* Creates a new $(D_PSYMBOL Vector).
|
||||
*
|
||||
* Params:
|
||||
* length = Initial length.
|
||||
* allocator = The allocator should be used for the element
|
||||
* allocations.
|
||||
*/
|
||||
this(size_t length, Allocator allocator = defaultAllocator)
|
||||
{
|
||||
this.allocator = allocator;
|
||||
vector = makeArray!T(allocator, length);
|
||||
}
|
||||
|
||||
/// Ditto.
|
||||
this(Allocator allocator = defaultAllocator)
|
||||
{
|
||||
this(0, allocator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all elements from the vector.
|
||||
*/
|
||||
~this()
|
||||
{
|
||||
finalize(allocator, vector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns: Vector length.
|
||||
*/
|
||||
@property size_t length() const
|
||||
{
|
||||
return vector.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expans/shrinks the vector.
|
||||
*
|
||||
* Params:
|
||||
* length = New length.
|
||||
*/
|
||||
@property void length(size_t length)
|
||||
{
|
||||
resizeArray!T(allocator, vector, length);
|
||||
}
|
||||
|
||||
///
|
||||
unittest
|
||||
{
|
||||
auto v = make!(Vector!int)(defaultAllocator);
|
||||
|
||||
v.length = 5;
|
||||
assert(v.length == 5);
|
||||
|
||||
// TODO
|
||||
v.length = 7;
|
||||
assert(v.length == 7);
|
||||
|
||||
v.length = 0;
|
||||
assert(v.length == 0);
|
||||
|
||||
finalize(defaultAllocator, v);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns: $(D_KEYWORD true) if the vector is empty.
|
||||
*/
|
||||
@property bool empty() const
|
||||
{
|
||||
return length == 0;
|
||||
}
|
||||
|
||||
static if (isFinalizable!T)
|
||||
{
|
||||
/**
|
||||
* Removes an elements from the vector.
|
||||
*
|
||||
* Params:
|
||||
* pos = Element index.
|
||||
*/
|
||||
void remove(size_t pos)
|
||||
{
|
||||
auto el = vector[pos];
|
||||
finalize(allocator, el);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns a value. Allocates if needed.
|
||||
*
|
||||
* Params:
|
||||
* value = Value.
|
||||
*
|
||||
* Returns: Assigned value.
|
||||
*/
|
||||
T opIndexAssign(T value, size_t pos)
|
||||
{
|
||||
if (pos >= length)
|
||||
{
|
||||
resizeArray!T(allocator, vector, pos + 1);
|
||||
}
|
||||
return vector[pos] = value;
|
||||
}
|
||||
|
||||
///
|
||||
unittest
|
||||
{
|
||||
auto v = make!(Vector!int)(defaultAllocator);
|
||||
int[2] values = [5, 15];
|
||||
|
||||
assert(v.length == 0);
|
||||
v[1] = values[0];
|
||||
assert(v.length == 2);
|
||||
v[3] = values[0];
|
||||
assert(v.length == 4);
|
||||
v[4] = values[1];
|
||||
assert(v.length == 5);
|
||||
|
||||
finalize(defaultAllocator, v);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns: The value on index $(D_PARAM pos).
|
||||
*/
|
||||
ref T opIndex(in size_t pos)
|
||||
in
|
||||
{
|
||||
assert(length > pos);
|
||||
}
|
||||
body
|
||||
{
|
||||
return vector[pos];
|
||||
}
|
||||
|
||||
///
|
||||
unittest
|
||||
{
|
||||
auto v = make!(Vector!int)(defaultAllocator);
|
||||
int[2] values = [5, 15];
|
||||
|
||||
v[1] = values[0];
|
||||
assert(v[1] is values[0]);
|
||||
v[3] = values[0];
|
||||
assert(v[3] is values[0]);
|
||||
v[4] = values[1];
|
||||
assert(v[4] is values[1]);
|
||||
v[0] = values[1];
|
||||
assert(v[0] is values[1]);
|
||||
|
||||
finalize(defaultAllocator, v);
|
||||
}
|
||||
|
||||
/**
|
||||
* $(D_KEYWORD foreach) iteration.
|
||||
*
|
||||
* Params:
|
||||
* dg = $(D_KEYWORD foreach) body.
|
||||
*/
|
||||
int opApply(int delegate(ref T) @nogc dg)
|
||||
{
|
||||
int result;
|
||||
|
||||
foreach (e; vector)
|
||||
{
|
||||
result = dg(e);
|
||||
|
||||
if (result != 0)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Ditto.
|
||||
int opApply(int delegate(ref size_t i, ref T) @nogc dg)
|
||||
{
|
||||
int result;
|
||||
|
||||
foreach (i, e; vector)
|
||||
{
|
||||
result = dg(i, e);
|
||||
|
||||
if (result != 0)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
///
|
||||
unittest
|
||||
{
|
||||
auto v = make!(Vector!int)(defaultAllocator, 1);
|
||||
int[3] values = [5, 15, 8];
|
||||
|
||||
v[0] = values[0];
|
||||
v[1] = values[1];
|
||||
v[2] = values[2];
|
||||
|
||||
int i;
|
||||
foreach (e; v)
|
||||
{
|
||||
assert(i != 0 || e is values[0]);
|
||||
assert(i != 1 || e is values[1]);
|
||||
assert(i != 2 || e is values[2]);
|
||||
++i;
|
||||
}
|
||||
|
||||
foreach (j, e; v)
|
||||
{
|
||||
assert(j != 0 || e is values[0]);
|
||||
assert(j != 1 || e is values[1]);
|
||||
assert(j != 2 || e is values[2]);
|
||||
}
|
||||
|
||||
finalize(defaultAllocator, v);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the first element. Allocates if the vector is empty.
|
||||
*
|
||||
* Params:
|
||||
* x = New element.
|
||||
*/
|
||||
@property void front(ref T x)
|
||||
{
|
||||
this[0] = x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns: The first element.
|
||||
*/
|
||||
@property ref inout(T) front() inout
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
}
|
||||
body
|
||||
{
|
||||
return vector[0];
|
||||
}
|
||||
|
||||
///
|
||||
unittest
|
||||
{
|
||||
auto v = make!(Vector!int)(defaultAllocator, 1);
|
||||
int[2] values = [5, 15];
|
||||
|
||||
v.front = values[0];
|
||||
assert(v.front == 5);
|
||||
|
||||
v.front = values[1];
|
||||
assert(v.front == 15);
|
||||
|
||||
finalize(defaultAllocator, v);
|
||||
}
|
||||
|
||||
/**
|
||||
* Move position to the next element.
|
||||
*
|
||||
* Returns: $(D_KEYWORD this).
|
||||
*/
|
||||
typeof(this) popFront()
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
}
|
||||
body
|
||||
{
|
||||
vector[0 .. $ - 1] = vector[1..$];
|
||||
resizeArray(allocator, vector, length - 1);
|
||||
return this;
|
||||
}
|
||||
|
||||
///
|
||||
unittest
|
||||
{
|
||||
auto v = make!(Vector!int)(defaultAllocator, 1);
|
||||
int[2] values = [5, 15];
|
||||
|
||||
v[0] = values[0];
|
||||
v[1] = values[1];
|
||||
assert(v.front is values[0]);
|
||||
assert(v.length == 2);
|
||||
v.popFront();
|
||||
assert(v.front is values[1]);
|
||||
assert(v.length == 1);
|
||||
v.popFront();
|
||||
assert(v.empty);
|
||||
|
||||
finalize(defaultAllocator, v);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the last element. Allocates if the vector is empty.
|
||||
*
|
||||
* Params:
|
||||
* x = New element.
|
||||
*/
|
||||
@property void back(ref T x)
|
||||
{
|
||||
vector[empty ? 0 : $ - 1] = x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns: The last element.
|
||||
*/
|
||||
@property ref inout(T) back() inout
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
}
|
||||
body
|
||||
{
|
||||
return vector[$ - 1];
|
||||
}
|
||||
|
||||
///
|
||||
unittest
|
||||
{
|
||||
auto v = make!(Vector!int)(defaultAllocator, 1);
|
||||
int[2] values = [5, 15];
|
||||
|
||||
v.back = values[0];
|
||||
assert(v.back == 5);
|
||||
|
||||
v.back = values[1];
|
||||
assert(v.back == 15);
|
||||
|
||||
finalize(defaultAllocator, v);
|
||||
}
|
||||
|
||||
/**
|
||||
* Move position to the previous element.
|
||||
*
|
||||
* Returns: $(D_KEYWORD this).
|
||||
*/
|
||||
typeof(this) popBack()
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
}
|
||||
body
|
||||
{
|
||||
resizeArray(allocator, vector, length - 1);
|
||||
return this;
|
||||
}
|
||||
|
||||
///
|
||||
unittest
|
||||
{
|
||||
auto v = make!(Vector!int)(defaultAllocator, 1);
|
||||
int[2] values = [5, 15];
|
||||
|
||||
v[0] = values[0];
|
||||
v[1] = values[1];
|
||||
assert(v.back is values[1]);
|
||||
assert(v.length == 2);
|
||||
v.popBack();
|
||||
assert(v.back is values[0]);
|
||||
assert(v.length == 1);
|
||||
v.popBack();
|
||||
assert(v.empty);
|
||||
|
||||
finalize(defaultAllocator, v);
|
||||
}
|
||||
|
||||
/// Container.
|
||||
protected T[] vector;
|
||||
|
||||
private Allocator allocator;
|
||||
}
|
||||
|
||||
///
|
||||
unittest
|
||||
{
|
||||
auto v = make!(Vector!int)(defaultAllocator);
|
||||
|
||||
finalize(defaultAllocator, v);
|
||||
}
|
Reference in New Issue
Block a user