From f1bc4dc2e202c7103e199a9331c9b0e93bd6c8ec Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Mon, 19 Dec 2016 16:33:16 +0100 Subject: [PATCH] Add length and opCmp to the Queue --- source/tanya/container/entry.d | 45 +++++ source/tanya/container/list.d | 83 +++------ source/tanya/container/package.d | 1 - source/tanya/container/queue.d | 205 +++++++++++++++++------ source/tanya/{container => crypto}/bit.d | 2 +- source/tanya/crypto/des.d | 2 +- source/tanya/crypto/package.d | 10 +- source/tanya/memory/allocator.d | 21 ++- 8 files changed, 248 insertions(+), 121 deletions(-) create mode 100644 source/tanya/container/entry.d rename source/tanya/{container => crypto}/bit.d (99%) diff --git a/source/tanya/container/entry.d b/source/tanya/container/entry.d new file mode 100644 index 0000000..ce267a0 --- /dev/null +++ b/source/tanya/container/entry.d @@ -0,0 +1,45 @@ +/* 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/. */ + +/* + * Internal package used by containers that rely on entries/nodes. + * + * 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.entry; + +version (unittest) +{ + package struct ConstEqualsStruct + { + int opEquals(typeof(this) that) const + { + return true; + } + } + + package struct MutableEqualsStruct + { + int opEquals(typeof(this) that) + { + return true; + } + } + + package struct NoEqualsStruct + { + } +} + +package struct Entry(T) +{ + /// Item content. + T content; + + /// Next item. + Entry* next; +} diff --git a/source/tanya/container/list.d b/source/tanya/container/list.d index 0ce7e4f..d0691ee 100644 --- a/source/tanya/container/list.d +++ b/source/tanya/container/list.d @@ -10,28 +10,17 @@ */ module tanya.container.list; +import tanya.container.entry; import tanya.memory; /** - * Singly linked list. + * Singly-linked list. * * Params: * T = Content type. */ -class SList(T) +struct SList(T) { - /** - * Creates a new $(D_PSYMBOL SList). - * - * Params: - * allocator = The allocator should be used for the element - * allocations. - */ - this(shared Allocator allocator = defaultAllocator) - { - this.allocator = allocator; - } - /** * Removes all elements from the list. */ @@ -41,7 +30,7 @@ class SList(T) } /** - * Remove all contents from the $(D_PSYMBOL SList). + * Removes all contents from the list. */ void clear() { @@ -54,14 +43,12 @@ class SList(T) /// unittest { - auto l = make!(SList!int)(defaultAllocator); + SList!int l; l.insertFront(8); l.insertFront(5); l.clear(); assert(l.empty); - - dispose(defaultAllocator, l); } /** @@ -83,35 +70,39 @@ class SList(T) * Params: * x = New element. */ - void insertFront(T x) + void insertFront(ref T x) { - Entry* temp = make!Entry(allocator); + auto temp = allocator.make!(Entry!T); temp.content = x; temp.next = first.next; first.next = temp; } + /// Ditto. + void insertFront(T x) + { + insertFront(x); + } + /// Ditto. alias insert = insertFront; /// unittest { - auto l = make!(SList!int)(defaultAllocator); + SList!int l; l.insertFront(8); assert(l.front == 8); l.insertFront(9); assert(l.front == 9); - - dispose(defaultAllocator, l); } /** * Returns: $(D_KEYWORD true) if the list is empty. */ - @property bool empty() inout const + @property bool empty() const { return first.next is null; } @@ -121,7 +112,7 @@ class SList(T) * * Returns: The first element. */ - T popFront() + void popFront() in { assert(!empty); @@ -129,26 +120,21 @@ class SList(T) body { auto n = first.next.next; - auto content = first.next.content; - dispose(allocator, first.next); + allocator.dispose(first.next); first.next = n; - - return content; } /// unittest { - auto l = make!(SList!int)(defaultAllocator); + SList!int l; l.insertFront(8); l.insertFront(9); assert(l.front == 9); l.popFront(); assert(l.front == 8); - - dispose(defaultAllocator, l); } /** @@ -179,7 +165,7 @@ class SList(T) /// unittest { - auto l = make!(SList!int)(defaultAllocator); + SList!int l; l.insertFront(8); l.insertFront(5); @@ -188,8 +174,6 @@ class SList(T) assert(l.removeFront(2) == 2); assert(l.removeFront(3) == 1); assert(l.removeFront(3) == 0); - - dispose(defaultAllocator, l); } /** @@ -235,7 +219,7 @@ class SList(T) /// unittest { - auto l = make!(SList!int)(defaultAllocator); + SList!int l; l.insertFront(5); l.insertFront(4); @@ -246,32 +230,18 @@ class SList(T) assert(i != 1 || e == 4); assert(i != 2 || e == 5); } - dispose(defaultAllocator, l); - } - - /** - * List entry. - */ - protected struct Entry - { - /// List item content. - T content; - - /// Next list item. - Entry* next; } /// 0th element of the list. - protected Entry first; + private Entry!T first; - /// Allocator. - protected shared Allocator allocator; + mixin DefaultAllocator; } /// unittest { - auto l = make!(SList!int)(defaultAllocator); + SList!int l; size_t i; l.insertFront(5); @@ -285,8 +255,6 @@ unittest ++i; } assert(i == 3); - - dispose(defaultAllocator, l); } private unittest @@ -294,8 +262,5 @@ private unittest interface Stuff { } - - auto l = make!(SList!Stuff)(defaultAllocator); - - dispose(defaultAllocator, l); + static assert(is(SList!Stuff)); } diff --git a/source/tanya/container/package.d b/source/tanya/container/package.d index e1a5205..eba95a7 100644 --- a/source/tanya/container/package.d +++ b/source/tanya/container/package.d @@ -10,7 +10,6 @@ */ module tanya.container; -public import tanya.container.bit; public import tanya.container.buffer; public import tanya.container.list; public import tanya.container.vector; diff --git a/source/tanya/container/queue.d b/source/tanya/container/queue.d index 960254b..6470044 100644 --- a/source/tanya/container/queue.d +++ b/source/tanya/container/queue.d @@ -6,32 +6,22 @@ * 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) + * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) */ module tanya.container.queue; +import tanya.container.entry; +import std.traits; import tanya.memory; /** - * Queue. + * FIFO queue. * * Params: * T = Content type. */ struct Queue(T) { - /** - * Creates a new $(D_PSYMBOL Queue). - * - * Params: - * allocator = The allocator should be used for the element - * allocations. - */ - this(shared Allocator allocator) - { - this.allocator = allocator; - } - /** * Removes all elements from the queue. */ @@ -54,15 +44,147 @@ struct Queue(T) /// unittest { - auto q = defaultAllocator.make!(Queue!int); + Queue!int q; assert(q.empty); q.insertBack(8); q.insertBack(9); q.clear(); assert(q.empty); + } - defaultAllocator.dispose(q); + /** + * Returns how many elements are in the queue. It iterates through the queue + * to count the elements. + * + * Returns: How many elements are in the queue. + */ + size_t length() const + { + size_t len; + for (const(Entry!T)* i = first.next; i !is null; i = i.next) + { + ++len; + } + return len; + } + + /// + unittest + { + Queue!int q; + + assert(q.length == 0); + q.insertBack(5); + assert(q.length == 1); + q.insertBack(4); + assert(q.length == 2); + q.insertBack(9); + assert(q.length == 3); + + q.popFront(); + assert(q.length == 2); + q.popFront(); + assert(q.length == 1); + q.popFront(); + assert(q.length == 0); + } + + version (D_Ddoc) + { + /** + * Compares two queues. Checks if all elements of the both queues are equal. + * + * Returns: Whether $(D_KEYWORD this) and $(D_PARAM that) are equal. + */ + int opEquals(ref typeof(this) that); + + /// Ditto. + int opEquals(typeof(this) that); + } + else static if (!hasMember!(T, "opEquals") + || (functionAttributes!(T.opEquals) & FunctionAttribute.const_)) + { + bool opEquals(in ref typeof(this) that) const + { + const(Entry!T)* i = first.next; + const(Entry!T)* j = that.first.next; + while (i !is null && j !is null) + { + if (i.content != j.content) + { + return false; + } + i = i.next; + j = j.next; + } + return i is null && j is null; + } + + /// Ditto. + bool opEquals(in typeof(this) that) const + { + return opEquals(that); + } + } + else + { + /** + * Compares two queues. Checks if all elements of the both queues are equal. + * + * Returns: How many elements are in the queue. + */ + bool opEquals(ref typeof(this) that) + { + Entry!T* i = first.next; + Entry!T* j = that.first.next; + while (i !is null && j !is null) + { + if (i.content != j.content) + { + return false; + } + i = i.next; + j = j.next; + } + return i is null && j is null; + } + + /// Ditto. + bool opEquals(typeof(this) that) + { + return opEquals(that); + } + } + + /// + unittest + { + Queue!int q1, q2; + + q1.insertBack(5); + q1.insertBack(4); + q2.insertBack(5); + assert(q1 != q2); + q2.insertBack(4); + assert(q1 == q2); + + q2.popFront(); + assert(q1 != q2); + + q1.popFront(); + assert(q1 == q2); + + q1.popFront(); + q2.popFront(); + assert(q1 == q2); + } + + private unittest + { + static assert(is(Queue!ConstEqualsStruct)); + static assert(is(Queue!MutableEqualsStruct)); + static assert(is(Queue!NoEqualsStruct)); } /** @@ -84,13 +206,9 @@ struct Queue(T) * Params: * x = New element. */ - void insertBack(T x) + void insertBack(ref T x) { - if (allocator is null) - { - allocator = defaultAllocator; - } - Entry* temp = make!Entry(allocator); + auto temp = allocator.make!(Entry!T); temp.content = x; @@ -105,27 +223,31 @@ struct Queue(T) } } + /// Ditto. + void insertBack(T x) + { + insertBack(x); + } + /// Ditto. alias insert = insertBack; /// unittest { - auto q = make!(Queue!int)(defaultAllocator); + Queue!int q; assert(q.empty); q.insertBack(8); assert(q.front == 8); q.insertBack(9); assert(q.front == 8); - - dispose(defaultAllocator, q); } /** * Returns: $(D_KEYWORD true) if the queue is empty. */ - @property bool empty() inout const pure nothrow @safe + @property bool empty() const { return first.next is null; } @@ -133,14 +255,12 @@ struct Queue(T) /// unittest { - auto q = make!(Queue!int)(defaultAllocator); + Queue!int q; int value = 7; assert(q.empty); q.insertBack(value); assert(!q.empty); - - dispose(defaultAllocator, q); } /** @@ -163,15 +283,13 @@ struct Queue(T) /// unittest { - auto q = make!(Queue!int)(defaultAllocator); + Queue!int q; q.insertBack(8); q.insertBack(9); assert(q.front == 8); q.popFront(); assert(q.front == 9); - - dispose(defaultAllocator, q); } /** @@ -215,7 +333,7 @@ struct Queue(T) /// unittest { - auto q = Queue!int(defaultAllocator); + Queue!int q; size_t j; q.insertBack(5); @@ -246,32 +364,19 @@ struct Queue(T) assert(q.empty); } - /** - * Queue entry. - */ - protected struct Entry - { - /// Queue item content. - T content; - - /// Next list item. - Entry* next; - } - /// The first element of the list. - protected Entry first; + private Entry!T first; /// The last element of the list. - protected Entry* rear; + private Entry!T* rear; - /// The allocator. - protected shared Allocator allocator; + mixin DefaultAllocator; } /// unittest { - auto q = Queue!int(defaultAllocator); + Queue!int q; q.insertBack(5); assert(!q.empty); diff --git a/source/tanya/container/bit.d b/source/tanya/crypto/bit.d similarity index 99% rename from source/tanya/container/bit.d rename to source/tanya/crypto/bit.d index 88c563f..8610577 100644 --- a/source/tanya/container/bit.d +++ b/source/tanya/crypto/bit.d @@ -8,7 +8,7 @@ * Mozilla Public License, v. 2.0). * Authors: $(LINK2 mailto:belka@caraus.de, Eugene Wissner) */ -module tanya.container.bit; +module tanya.crypto.bit; /** * Wrapper that allows bit manipulation on $(D_KEYWORD ubyte[]) array. diff --git a/source/tanya/crypto/des.d b/source/tanya/crypto/des.d index a67ba6f..8154056 100644 --- a/source/tanya/crypto/des.d +++ b/source/tanya/crypto/des.d @@ -10,7 +10,7 @@ */ module tanya.crypto.des; -import tanya.container.bit; +import tanya.crypto.bit; import tanya.crypto.symmetric; /// Initial permutation table. diff --git a/source/tanya/crypto/package.d b/source/tanya/crypto/package.d index 314d0f1..37cb3c7 100644 --- a/source/tanya/crypto/package.d +++ b/source/tanya/crypto/package.d @@ -10,9 +10,7 @@ */ module tanya.crypto; -public -{ - import tanya.crypto.des; - import tanya.crypto.mode; - import tanya.crypto.symmetric; -} +public import tanya.crypto.bit; +public import tanya.crypto.des; +public import tanya.crypto.mode; +public import tanya.crypto.symmetric; diff --git a/source/tanya/memory/allocator.d b/source/tanya/memory/allocator.d index c9b7386..4da32c8 100644 --- a/source/tanya/memory/allocator.d +++ b/source/tanya/memory/allocator.d @@ -54,15 +54,30 @@ interface Allocator /** * The mixin generates common methods for classes and structs using - * allocators. It provides a protected member and a read-only property, - * that checks if an allocator was already set and sets it to the default - * one, if not (useful for structs which don't have a default constructor). + * allocators. It provides a protected member, constructor and a read-only + * property, that checks if an allocator was already set and sets it to the + * default one, if not (useful for structs which don't have a default + * constructor). */ mixin template DefaultAllocator() { /// Allocator. protected shared Allocator allocator_; + /** + * Params: + * allocator = The allocator should be used. + */ + this(shared Allocator allocator) + in + { + assert(allocator !is null); + } + body + { + this.allocator_ = allocator; + } + /** * This property checks if the allocator was set in the constructor * and sets it to the default one, if not.