18 Commits

Author SHA1 Message Date
647cfe03c2 Update latest supported compiler 2017-03-29 17:23:10 +02:00
4cd6126d6b Fix SList documentation for insertFront and insertBefore 2017-03-29 17:22:25 +02:00
b870179a35 Move bitvector to another branch till it is finished 2017-03-29 11:17:03 +02:00
aabb4fb534 Add SList.opAssign 2017-03-29 10:35:45 +02:00
4d8b95812e Implement opAssign for the Vector 2017-03-28 20:42:42 +02:00
e921413249 Merge branch 'master' of github.com:caraus-ecms/tanya 2017-03-24 20:54:47 +01:00
49cae88645 Add insertBefore and remove to SList 2017-03-24 20:54:28 +01:00
402fdfae89 math.mp: Fix initialization issues after resizing 2017-03-23 15:36:17 +01:00
7892c1a930 Remove Init template parameter from memory.resize() 2017-03-22 08:51:00 +01:00
b90517580e Merge math.mp.Integer changes from the crypto branch 2017-03-21 19:25:12 +01:00
85380ac3fc Remove makeArray import 2017-03-19 06:54:59 +01:00
b90c56395c Remove resizeArray alias 2017-03-19 06:10:27 +01:00
d0ada39fa7 Add Mallocator as an alternative allocator 2017-03-18 08:07:01 +01:00
f4145abfd1 Add SList constructors 2017-03-09 06:07:23 +01:00
093d499729 Fix element order inserted from a range into list 2017-03-08 07:12:23 +01:00
f90a03501b Move BitVector from the crypto branch 2017-03-02 11:27:26 +01:00
c6a99b114e SList.insertFront for ranges 2017-03-01 19:23:54 +01:00
3c23aca6a6 Improve Vector module and reserve documentation 2017-02-20 12:03:49 +01:00
15 changed files with 5568 additions and 4591 deletions

View File

@ -7,7 +7,7 @@ os:
language: d
d:
- dmd-2.073.0
- dmd-2.073.2
- dmd-2.072.2
- dmd-2.071.2
- dmd-2.070.2

View File

@ -29,7 +29,7 @@ helper functions).
### Supported compilers
* dmd 2.073.0
* dmd 2.073.2
* dmd 2.072.2
* dmd 2.071.2
* dmd 2.070.2

View File

@ -3,6 +3,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* Linked list.
*
* Copyright: Eugene Wissner 2016-2017.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
* Mozilla Public License, v. 2.0).
@ -11,21 +13,29 @@
module tanya.container.list;
import std.algorithm.comparison;
import std.algorithm.mutation;
import std.algorithm.searching;
import std.range.primitives;
import std.traits;
import tanya.container.entry;
import tanya.memory;
private struct Range(E)
if (__traits(isSame, TemplateOf!E, SEntry))
private struct Range(Entry)
if (__traits(isSame, TemplateOf!Entry, SEntry))
{
private alias T = typeof(E.content);
private alias E = CopyConstness!(Entry, Entry*);
private E* head;
private this(E* head)
invariant
{
this.head = head;
assert(head !is null);
}
private this(ref E head) @trusted
{
this.head = &head;
}
@property Range save()
@ -40,7 +50,7 @@ private struct Range(E)
@property bool empty() const
{
return head is null;
return *head is null;
}
@property ref inout(T) front() inout
@ -50,27 +60,27 @@ private struct Range(E)
}
body
{
return head.content;
return (*head).content;
}
void popFront()
void popFront() @trusted
in
{
assert(!empty);
}
body
{
head = head.next;
head = &(*head).next;
}
Range opIndex()
{
return typeof(return)(head);
return typeof(return)(*head);
}
Range!(const E) opIndex() const
Range!(const Entry) opIndex() const
{
return typeof(return)(head);
return typeof(return)(*head);
}
}
@ -87,6 +97,162 @@ struct SList(T)
// 0th element of the list.
private Entry* head;
/**
* Creates a new $(D_PSYMBOL SList) with the elements from a static array.
*
* Params:
* R = Static array size.
* init = Values to initialize the list with.
* allocator = Allocator.
*/
this(size_t R)(T[R] init, shared Allocator allocator = defaultAllocator)
{
this(allocator);
insertFront(init[]);
}
///
@safe @nogc unittest
{
auto l = SList!int([5, 8, 15]);
assert(l.front == 5);
}
/**
* Creates a new $(D_PSYMBOL SList) with the elements from an input range.
*
* Params:
* R = Type of the initial range.
* init = Values to initialize the list with.
* allocator = Allocator.
*/
this(R)(R init, shared Allocator allocator = defaultAllocator)
if (!isInfinite!R
&& isInputRange!R
&& isImplicitlyConvertible!(ElementType!R, T))
{
this(allocator);
insertFront(init);
}
/**
* Creates a new $(D_PSYMBOL SList).
*
* Params:
* len = Initial length of the list.
* init = Initial value to fill the list with.
* allocator = Allocator.
*/
this(const size_t len, T init, shared Allocator allocator = defaultAllocator) @trusted
{
this(allocator);
Entry* next;
foreach (i; 0 .. len)
{
if (next is null)
{
next = allocator.make!Entry(init);
head = next;
}
else
{
next.next = allocator.make!Entry(init);
next = next.next;
}
}
}
///
@safe @nogc unittest
{
auto l = SList!int(2, 3);
assert(l.length == 2);
assert(l.front == 3);
}
/// Ditto.
this(const size_t len, shared Allocator allocator = defaultAllocator)
{
this(len, T.init, allocator);
}
///
@safe @nogc unittest
{
auto l = SList!int(2);
assert(l.length == 2);
assert(l.front == 0);
}
/// Ditto.
this(shared Allocator allocator)
in
{
assert(allocator !is null);
}
body
{
this.allocator_ = allocator;
}
/**
* Initializes this list from another one.
*
* If $(D_PARAM init) is passed by value, it won't be copied, but moved.
* If the allocator of ($D_PARAM init) matches $(D_PARAM allocator),
* $(D_KEYWORD this) will just take the ownership over $(D_PARAM init)'s
* storage, otherwise, the storage will be allocated with
* $(D_PARAM allocator) and all elements will be moved;
* $(D_PARAM init) will be destroyed at the end.
*
* If $(D_PARAM init) is passed by reference, it will be copied.
*
* Params:
* init = Source list.
* allocator = Allocator.
*/
this(ref SList init, shared Allocator allocator = defaultAllocator)
{
this(init[], allocator);
}
/// Ditto.
this(SList init, shared Allocator allocator = defaultAllocator) @trusted
{
this(allocator);
if (allocator is init.allocator)
{
head = init.head;
init.head = null;
}
else
{
Entry* next;
for (auto current = init.head; current !is null; current = current.next)
{
if (head is null)
{
head = allocator.make!Entry(move(current.content));
next = head;
}
else
{
next.next = allocator.make!Entry(move(current.content));
next = next.next;
}
}
}
}
///
@safe @nogc unittest
{
auto l1 = SList!int([5, 1, 234]);
auto l2 = SList!int(l1);
assert(l1 == l2);
}
/**
* Removes all elements from the list.
*/
@ -95,6 +261,24 @@ struct SList(T)
clear();
}
/**
* Copies the list.
*/
this(this)
{
auto list = typeof(this)(this[], this.allocator);
this.head = list.head;
list.head = null;
}
///
@safe @nogc unittest
{
auto l1 = SList!int([5, 1, 234]);
auto l2 = l1;
assert(l1 == l2);
}
/**
* Removes all contents from the list.
*/
@ -107,12 +291,11 @@ struct SList(T)
}
///
unittest
@safe @nogc unittest
{
SList!int l;
SList!int l = SList!int([8, 5]);
l.insertFront(8);
l.insertFront(5);
assert(!l.empty);
l.clear();
assert(l.empty);
}
@ -130,39 +313,211 @@ struct SList(T)
return head.content;
}
private size_t moveEntry(R)(ref Entry* head, ref R el) @trusted
if (isImplicitlyConvertible!(R, T))
{
auto temp = cast(Entry*) allocator.allocate(Entry.sizeof);
el.moveEmplace(temp.content);
temp.next = head;
head = temp;
return 1;
}
/**
* Inserts a new element at the beginning.
*
* Params:
* x = New element.
* R = Type of the inserted value(s).
* el = New element(s).
*
* Returns: The number of elements inserted.
*/
void insertFront(ref T x)
size_t insertFront(R)(R el)
if (isImplicitlyConvertible!(R, T))
{
auto temp = allocator.make!Entry;
temp.content = x;
temp.next = head;
head = temp;
return moveEntry(head, el);
}
/// Ditto.
void insertFront(T x)
size_t insertFront(R)(R el) @trusted
if (!isInfinite!R
&& isInputRange!R
&& isImplicitlyConvertible!(ElementType!R, T))
{
insertFront(x);
size_t retLength;
Entry* next, newHead;
if (!el.empty)
{
next = allocator.make!Entry(el.front);
newHead = next;
el.popFront();
retLength = 1;
}
foreach (ref e; el)
{
next.next = allocator.make!Entry(e);
next = next.next;
++retLength;
}
if (newHead !is null)
{
next.next = head;
head = newHead;
}
return retLength;
}
/// Ditto.
size_t insertFront(size_t R)(T[R] el)
{
return insertFront!(T[])(el[]);
}
/// Ditto.
size_t insertFront(ref T el) @trusted
{
head = allocator.make!Entry(el, head);
return 1;
}
/// Ditto.
alias insert = insertFront;
///
unittest
@safe @nogc unittest
{
SList!int l;
SList!int l1;
l.insertFront(8);
assert(l.front == 8);
l.insertFront(9);
assert(l.front == 9);
assert(l1.insertFront(8) == 1);
assert(l1.front == 8);
assert(l1.insertFront(9) == 1);
assert(l1.front == 9);
SList!int l2;
assert(l2.insertFront([25, 30, 15]) == 3);
assert(l2.front == 25);
l2.insertFront(l1[]);
assert(l2.length == 5);
assert(l2.front == 9);
}
version (assert)
{
private bool checkRangeBelonging(ref Range!Entry r) const
{
const(Entry*)* pos;
for (pos = &head; pos != r.head && *pos !is null; pos = &(*pos).next)
{
}
return pos == r.head;
}
}
/**
* Inserts new elements before $(D_PARAM r).
*
* Params:
* R = Type of the inserted value(s).
* r = Range extracted from this list.
* el = New element(s).
*
* Returns: The number of elements inserted.
*
* Precondition: $(D_PARAM r) is extracted from this list.
*/
size_t insertBefore(R)(Range!Entry r, R el)
if (isImplicitlyConvertible!(R, T))
in
{
assert(checkRangeBelonging(r));
}
body
{
return moveEntry(*r.head, el);
}
///
@safe @nogc unittest
{
auto l1 = SList!int([234, 5, 1]);
auto l2 = SList!int([5, 1]);
l2.insertBefore(l2[], 234);
assert(l1 == l2);
}
/// Ditto.
size_t insertBefore(R)(Range!Entry r, R el)
if (!isInfinite!R
&& isInputRange!R
&& isImplicitlyConvertible!(ElementType!R, T))
in
{
assert(checkRangeBelonging(r));
}
body
{
size_t inserted;
foreach (e; el)
{
inserted += insertBefore(r, e);
r.popFront();
}
return inserted;
}
///
@safe @nogc unittest
{
auto l1 = SList!int([5, 234, 30, 1]);
auto l2 = SList!int([5, 1]);
auto l3 = SList!int([234, 30]);
auto r = l2[];
r.popFront();
l2.insertBefore(r, l3[]);
assert(l1 == l2);
}
/// Ditto.
size_t insertBefore(Range!Entry r, ref T el) @trusted
in
{
assert(checkRangeBelonging(r));
}
body
{
*r.head = allocator.make!Entry(el, *r.head);
return 1;
}
///
@safe @nogc unittest
{
auto l1 = SList!int([234, 5, 1]);
auto l2 = SList!int([5, 1]);
int var = 234;
l2.insertBefore(l2[], var);
assert(l1 == l2);
}
/**
* Inserts elements from a static array before $(D_PARAM r).
*
* Params:
* R = Static array size.
* r = Range extracted from this list.
* el = New elements.
*
* Returns: The number of elements inserted.
*
* Precondition: $(D_PARAM r) is extracted from this list.
*/
size_t insertBefore(size_t R)(Range!Entry r, T[R] el)
{
return insertFront!(T[])(el[]);
}
/**
@ -170,11 +525,11 @@ struct SList(T)
*/
@property size_t length() const
{
return count(opIndex());
return count(this[]);
}
///
unittest
@safe @nogc unittest
{
SList!int l;
@ -196,19 +551,13 @@ struct SList(T)
* Returns: $(D_KEYWORD true) if the lists are equal, $(D_KEYWORD false)
* otherwise.
*/
bool opEquals()(auto ref typeof(this) that) @trusted
bool opEquals()(auto ref typeof(this) that) inout
{
return equal(opIndex(), that[]);
}
/// Ditto.
bool opEquals()(in auto ref typeof(this) that) const @trusted
{
return equal(opIndex(), that[]);
return equal(this[], that[]);
}
///
unittest
@safe @nogc unittest
{
SList!int l1, l2;
@ -253,14 +602,14 @@ struct SList(T)
}
body
{
auto n = head.next;
auto n = this.head.next;
allocator.dispose(head);
head = n;
this.allocator.dispose(this.head);
this.head = n;
}
///
unittest
@safe @nogc unittest
{
SList!int l;
@ -285,7 +634,7 @@ struct SList(T)
*
* Returns: The number of elements removed.
*/
size_t removeFront(in size_t howMany)
size_t removeFront(const size_t howMany)
out (removed)
{
assert(removed <= howMany);
@ -300,23 +649,54 @@ struct SList(T)
return i;
}
/// Ditto.
alias remove = removeFront;
///
unittest
@safe @nogc unittest
{
SList!int l;
SList!int l = SList!int([8, 5, 4]);
l.insertFront(8);
l.insertFront(5);
l.insertFront(4);
assert(l.removeFront(0) == 0);
assert(l.removeFront(2) == 2);
assert(l.removeFront(3) == 1);
assert(l.removeFront(3) == 0);
}
/**
* Removes $(D_PARAM r) from the list.
*
* Params:
* r = The range to remove.
*
* Returns: An empty range.
*
* Precondition: $(D_PARAM r) is extracted from this list.
*/
Range!Entry remove(Range!Entry r)
in
{
assert(checkRangeBelonging(r));
}
body
{
typeof(this) outOfScopeList;
outOfScopeList.head = *r.head;
*r.head = null;
return r;
}
///
@safe @nogc unittest
{
auto l1 = SList!int([5, 234, 30, 1]);
auto l2 = SList!int([5]);
auto r = l1[];
r.popFront();
assert(l1.remove(r).empty);
assert(l1 == l2);
}
/**
* $(D_KEYWORD foreach) iteration.
*
@ -360,7 +740,7 @@ struct SList(T)
}
///
unittest
@nogc unittest
{
SList!int l;
@ -375,21 +755,121 @@ struct SList(T)
}
}
/**
* Returns: Range that iterates over all elements of the container, in
* forward order.
*/
Range!Entry opIndex()
{
return typeof(return)(head);
}
/// Ditto.
Range!(const Entry) opIndex() const
{
return typeof(return)(head);
}
/**
* Assigns another list.
*
* If $(D_PARAM that) is passed by value, it won't be copied, but moved.
* This list will take the ownership over $(D_PARAM that)'s storage and
* the allocator.
*
* If $(D_PARAM that) is passed by reference, it will be copied.
*
* Params:
* R = Content type.
* that = The value should be assigned.
*
* Returns: $(D_KEYWORD this).
*/
ref typeof(this) opAssign(R)(const ref R that)
if (is(Unqual!R == SList))
{
return this = that[];
}
/// Ditto.
ref typeof(this) opAssign(R)(const ref R that)
if (is(Unqual!R == SList))
{
swap(this.head, that.head);
swap(this.allocator_, that.allocator_);
}
/**
* Assigns an input range.
*
* Params:
* R = Type of the initial range.
* that = Values to initialize the list with.
*
* Returns: $(D_KEYWORD this).
*/
ref typeof(this) opAssign(R)(R that) @trusted
if (!isInfinite!R
&& isInputRange!R
&& isImplicitlyConvertible!(ElementType!R, T))
{
Entry** next = &head;
foreach (ref e; that)
{
if (*next is null)
{
*next = allocator.make!Entry(e);
}
else
{
(*next).content = e;
}
next = &(*next).next;
}
remove(Range!Entry(*next));
return this;
}
///
@safe @nogc unittest
{
auto l1 = SList!int([5, 4, 9]);
auto l2 = SList!int([9, 4]);
l1 = l2[];
assert(l1 == l2);
}
/**
* Assigns a static array.
*
* Params:
* R = Static array size.
* that = Values to initialize the vector with.
*
* Returns: $(D_KEYWORD this).
*/
ref typeof(this) opAssign(size_t R)(T[R] that)
{
return opAssign!(T[])(that[]);
}
///
@safe @nogc unittest
{
auto l1 = SList!int([5, 4, 9]);
auto l2 = SList!int([9, 4]);
l1 = [9, 4];
assert(l1 == l2);
}
mixin DefaultAllocator;
}
///
unittest
@nogc unittest
{
SList!int l;
size_t i;
@ -407,7 +887,7 @@ unittest
assert(i == 3);
}
unittest
@safe @nogc private unittest
{
interface Stuff
{

View File

@ -3,6 +3,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* Abstract data types whose instances are collections of other objects.
*
* Copyright: Eugene Wissner 2016-2017.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
* Mozilla Public License, v. 2.0).

View File

@ -3,6 +3,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* FIFO queue.
*
* Copyright: Eugene Wissner 2016-2017.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
* Mozilla Public License, v. 2.0).

View File

@ -3,6 +3,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* Single-dimensioned array.
*
* Copyright: Eugene Wissner 2016-2017.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
* Mozilla Public License, v. 2.0).
@ -93,7 +95,7 @@ private struct Range(E)
--end;
}
ref inout(E) opIndex(in size_t i) inout @trusted
ref inout(E) opIndex(const size_t i) inout @trusted
in
{
assert(i < length);
@ -113,7 +115,7 @@ private struct Range(E)
return typeof(return)(begin, end);
}
Range opSlice(in size_t i, in size_t j) @trusted
Range opSlice(const size_t i, const size_t j) @trusted
in
{
assert(i <= j);
@ -124,7 +126,7 @@ private struct Range(E)
return typeof(return)(begin + i, begin + j);
}
Range!(const E) opSlice(in size_t i, in size_t j) const @trusted
Range!(const E) opSlice(const size_t i, const size_t j) const @trusted
in
{
assert(i <= j);
@ -160,13 +162,11 @@ struct Vector(T)
}
/**
* Creates a new $(D_PSYMBOL Vector) with the elements from another input
* range or a static array $(D_PARAM init).
* Creates a new $(D_PSYMBOL Vector) with the elements from a static array.
*
* Params:
* R = Type of the initial range or size of the static array.
* init = Values to initialize the array with.
* to generate a list.
* R = Static array size.
* init = Values to initialize the vector with.
* allocator = Allocator.
*/
this(size_t R)(T[R] init, shared Allocator allocator = defaultAllocator)
@ -175,7 +175,14 @@ struct Vector(T)
insertBack!(T[])(init[]);
}
/// Ditto.
/**
* Creates a new $(D_PSYMBOL Vector) with the elements from an input range.
*
* Params:
* R = Type of the initial range.
* init = Values to initialize the vector with.
* allocator = Allocator.
*/
this(R)(R init, shared Allocator allocator = defaultAllocator)
if (!isInfinite!R
&& isInputRange!R
@ -188,7 +195,7 @@ struct Vector(T)
/**
* Initializes this vector from another one.
*
* If $(D_PARAM init) is passed by value, it won't be copied, but moved
* If $(D_PARAM init) is passed by value, it won't be copied, but moved.
* If the allocator of ($D_PARAM init) matches $(D_PARAM allocator),
* $(D_KEYWORD this) will just take the ownership over $(D_PARAM init)'s
* storage, otherwise, the storage will be allocated with
@ -202,7 +209,7 @@ struct Vector(T)
* init = Source vector.
* allocator = Allocator.
*/
this(R)(ref R init, shared Allocator allocator = defaultAllocator)
this(R)(const ref R init, shared Allocator allocator = defaultAllocator)
if (is(Unqual!R == Vector))
{
this(allocator);
@ -236,7 +243,7 @@ struct Vector(T)
}
///
unittest
@trusted @nogc unittest
{
auto v1 = Vector!int([1, 2, 3]);
auto v2 = Vector!int(v1);
@ -249,7 +256,7 @@ struct Vector(T)
assert(v3.capacity == 3);
}
unittest // const constructor tests
private @trusted @nogc unittest // const constructor tests
{
auto v1 = const Vector!int([1, 2, 3]);
auto v2 = Vector!int(v1);
@ -262,19 +269,6 @@ struct Vector(T)
assert(v3.capacity == 3);
}
/**
* Creates a new $(D_PSYMBOL Vector).
*
* Params:
* len = Initial length of the vector.
* allocator = Allocator.
*/
this(in size_t len, shared Allocator allocator = defaultAllocator)
{
this(allocator);
length = len;
}
/**
* Creates a new $(D_PSYMBOL Vector).
*
@ -283,7 +277,7 @@ struct Vector(T)
* init = Initial value to fill the vector with.
* allocator = Allocator.
*/
this(in size_t len, T init, shared Allocator allocator = defaultAllocator) @trusted
this(const size_t len, T init, shared Allocator allocator = defaultAllocator) @trusted
{
this(allocator);
reserve(len);
@ -291,6 +285,13 @@ struct Vector(T)
length_ = len;
}
/// Ditto.
this(const size_t len, shared Allocator allocator = defaultAllocator)
{
this(allocator);
length = len;
}
/// Ditto.
this(shared Allocator allocator)
in
@ -372,6 +373,13 @@ struct Vector(T)
return capacity_;
}
///
@safe @nogc unittest
{
auto v = Vector!int(4);
assert(v.capacity == 4);
}
/**
* Returns: Vector length.
*/
@ -392,7 +400,7 @@ struct Vector(T)
* Params:
* len = New length.
*/
@property void length(in size_t len) @trusted
@property void length(const size_t len) @trusted
{
if (len == length)
{
@ -442,10 +450,14 @@ struct Vector(T)
/**
* Reserves space for $(D_PARAM size) elements.
*
* If $(D_PARAM size) is less than or equal to the $(D_PSYMBOL capacity), the
* function call does not cause a reallocation and the vector capacity is not
* affected.
*
* Params:
* size = Desired size.
*/
void reserve(in size_t size) @trusted
void reserve(const size_t size) @trusted
{
if (capacity_ >= size)
{
@ -483,7 +495,7 @@ struct Vector(T)
}
///
unittest
@nogc @safe unittest
{
Vector!int v;
assert(v.capacity == 0);
@ -503,7 +515,7 @@ struct Vector(T)
* Params:
* size = Desired size.
*/
void shrink(in size_t size) @trusted
void shrink(const size_t size) @trusted
{
if (capacity_ <= size)
{
@ -518,7 +530,7 @@ struct Vector(T)
}
///
unittest
@nogc @safe unittest
{
Vector!int v;
assert(v.capacity == 0);
@ -529,14 +541,6 @@ struct Vector(T)
v.insertBack(3);
assert(v.capacity == 5);
assert(v.length == 2);
v.shrink(4);
assert(v.capacity == 4);
assert(v.length == 2);
v.shrink(1);
assert(v.capacity == 2);
assert(v.length == 2);
}
/**
@ -576,7 +580,7 @@ struct Vector(T)
*
* Returns: The number of elements removed
*/
size_t removeBack(in size_t howMany)
size_t removeBack(const size_t howMany)
out (removed)
{
assert(removed <= howMany);
@ -940,7 +944,7 @@ struct Vector(T)
*
* Precondition: $(D_INLINECODE length > pos)
*/
ref T opIndexAssign(ref T value, in size_t pos)
ref T opIndexAssign(ref T value, const size_t pos)
{
return opIndex(pos) = value;
}
@ -953,7 +957,7 @@ struct Vector(T)
}
/// Ditto.
T opIndexAssign(T value, in size_t pos)
T opIndexAssign(T value, const size_t pos)
{
return opIndexAssign(value, pos);
}
@ -1018,7 +1022,7 @@ struct Vector(T)
*
* Precondition: $(D_INLINECODE length > pos)
*/
ref inout(T) opIndex(in size_t pos) inout @trusted
ref inout(T) opIndex(const size_t pos) inout @trusted
in
{
assert(length > pos);
@ -1071,7 +1075,7 @@ struct Vector(T)
}
/// Ditto.
bool opEquals()(in auto ref typeof(this) that) const @trusted
bool opEquals()(const auto ref typeof(this) that) const @trusted
{
return equal(vector[0 .. length_], that.vector[0 .. that.length_]);
}
@ -1296,7 +1300,7 @@ struct Vector(T)
*
* Precondition: $(D_INLINECODE i <= j && j <= length)
*/
Range!T opSlice(in size_t i, in size_t j) @trusted
Range!T opSlice(const size_t i, const size_t j) @trusted
in
{
assert(i <= j);
@ -1308,7 +1312,7 @@ struct Vector(T)
}
/// Ditto.
Range!(const T) opSlice(in size_t i, in size_t j) const @trusted
Range!(const T) opSlice(const size_t i, const size_t j) const @trusted
in
{
assert(i <= j);
@ -1378,7 +1382,7 @@ struct Vector(T)
* Precondition: $(D_INLINECODE i <= j && j <= length
* && value.length == j - i)
*/
Range!T opSliceAssign(R)(R value, in size_t i, in size_t j) @trusted
Range!T opSliceAssign(R)(R value, const size_t i, const size_t j) @trusted
if (!isInfinite!R
&& isInputRange!R
&& isImplicitlyConvertible!(ElementType!R, T))
@ -1395,13 +1399,13 @@ struct Vector(T)
}
/// Ditto.
Range!T opSliceAssign(size_t R)(T[R] value, in size_t i, in size_t j)
Range!T opSliceAssign(size_t R)(T[R] value, const size_t i, const size_t j)
{
return opSliceAssign!(T[])(value[], i, j);
}
/// Ditto.
Range!T opSliceAssign(ref T value, in size_t i, in size_t j) @trusted
Range!T opSliceAssign(ref T value, const size_t i, const size_t j) @trusted
in
{
assert(i <= j);
@ -1414,7 +1418,7 @@ struct Vector(T)
}
/// Ditto.
Range!T opSliceAssign(T value, in size_t i, in size_t j)
Range!T opSliceAssign(T value, const size_t i, const size_t j)
{
return opSliceAssign(value, i, j);
}
@ -1469,6 +1473,106 @@ struct Vector(T)
assert(data.length == 1);
}
/**
* Assigns another vector.
*
* If $(D_PARAM that) is passed by value, it won't be copied, but moved.
* This vector will take the ownership over $(D_PARAM that)'s storage and
* the allocator.
*
* If $(D_PARAM that) is passed by reference, it will be copied.
*
* Params:
* R = Content type.
* that = The value should be assigned.
*
* Returns: $(D_KEYWORD this).
*/
ref typeof(this) opAssign(R)(const ref R that)
if (is(Unqual!R == Vector))
{
return this = that[];
}
/// Ditto.
ref typeof(this) opAssign(R)(R that) @trusted
if (is(R == Vector))
{
swap(this.vector, that.vector);
swap(this.length_, that.length_);
swap(this.capacity_, that.capacity_);
swap(this.allocator_, that.allocator_);
return this;
}
/**
* Assigns a range to the vector.
*
* Params:
* R = Content type.
* that = The value should be assigned.
*
* Returns: $(D_KEYWORD this).
*/
ref typeof(this) opAssign(R)(R that)
if (!isInfinite!R
&& isInputRange!R
&& isImplicitlyConvertible!(ElementType!R, T))
{
this.length = 0;
insertBack(that);
return this;
}
///
@safe @nogc unittest
{
auto v1 = const Vector!int([5, 15, 8]);
Vector!int v2;
v2 = v1;
assert(v1 == v2);
}
///
@safe @nogc unittest
{
auto v1 = const Vector!int([5, 15, 8]);
Vector!int v2;
v2 = v1[0 .. 2];
assert(equal(v1[0 .. 2], v2[]));
}
// Move assignment.
private @safe @nogc unittest
{
Vector!int v1;
v1 = Vector!int([5, 15, 8]);
}
/**
* Assigns a static array.
*
* Params:
* R = Static array size.
* that = Values to initialize the vector with.
*
* Returns: $(D_KEYWORD this).
*/
ref typeof(this) opAssign(size_t R)(T[R] that)
{
return opAssign!(T[])(that[]);
}
///
@safe @nogc unittest
{
auto v1 = Vector!int([5, 15, 8]);
Vector!int v2;
v2 = [5, 15, 8];
assert(v1 == v2);
}
mixin DefaultAllocator;
}
@ -1549,7 +1653,7 @@ unittest
}
struct ConstEqualsStruct
{
int opEquals(in typeof(this) that) const @nogc
int opEquals(const typeof(this) that) const @nogc
{
return true;
}

File diff suppressed because it is too large Load Diff

View File

@ -3,10 +3,10 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* Copyright: Eugene Wissner 2016.
* Copyright: Eugene Wissner 2016-2017.
* 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.math;
@ -79,7 +79,7 @@ body
}
/// Ditto.
I pow(I)(in auto ref I x, in auto ref I y, in auto ref I z)
I pow(I)(const auto ref I x, const auto ref I y, const auto ref I z)
if (is(I == Integer))
in
{
@ -88,8 +88,8 @@ in
body
{
size_t i = y.length;
auto tmp2 = Integer(x.allocator), tmp1 = Integer(x, x.allocator);
Integer result = Integer(x.allocator);
auto tmp1 = Integer(x, x.allocator);
auto result = Integer(x.allocator);
if (x.length == 0 && i != 0)
{
@ -109,7 +109,7 @@ body
result *= tmp1;
result %= z;
}
tmp2 = tmp1;
auto tmp2 = tmp1;
tmp1 *= tmp2;
tmp1 %= z;
}
@ -134,15 +134,15 @@ pure nothrow @safe @nogc unittest
///
unittest
{
assert(cast(long) pow(Integer(3), Integer(5), Integer(7)) == 5);
assert(cast(long) pow(Integer(2), Integer(2), Integer(1)) == 0);
assert(cast(long) pow(Integer(3), Integer(3), Integer(3)) == 0);
assert(cast(long) pow(Integer(7), Integer(4), Integer(2)) == 1);
assert(cast(long) pow(Integer(53), Integer(0), Integer(2)) == 1);
assert(cast(long) pow(Integer(53), Integer(1), Integer(3)) == 2);
assert(cast(long) pow(Integer(53), Integer(2), Integer(5)) == 4);
assert(cast(long) pow(Integer(0), Integer(0), Integer(5)) == 1);
assert(cast(long) pow(Integer(0), Integer(5), Integer(5)) == 0);
assert(pow(Integer(3), Integer(5), Integer(7)) == 5);
assert(pow(Integer(2), Integer(2), Integer(1)) == 0);
assert(pow(Integer(3), Integer(3), Integer(3)) == 0);
assert(pow(Integer(7), Integer(4), Integer(2)) == 1);
assert(pow(Integer(53), Integer(0), Integer(2)) == 1);
assert(pow(Integer(53), Integer(1), Integer(3)) == 2);
assert(pow(Integer(53), Integer(2), Integer(5)) == 4);
assert(pow(Integer(0), Integer(0), Integer(5)) == 1);
assert(pow(Integer(0), Integer(5), Integer(5)) == 0);
}
/**
@ -170,3 +170,31 @@ unittest
known.each!((ref x) => assert(isPseudoprime(x)));
}
/**
* Params:
* I = Value type.
* x = Value.
*
* Returns: The absolute value of a number.
*/
I abs(I : Integer)(const auto ref I x)
{
auto result = Integer(x, x.allocator);
result.sign = Sign.positive;
return result;
}
/// Ditto.
I abs(I : Integer)(I x)
{
x.sign = Sign.positive;
return x;
}
/// Ditto.
I abs(I)(const I x)
if (isIntegral!I)
{
return x >= 0 ? x : -x;
}

View File

@ -8,7 +8,7 @@
* 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.math.random;
@ -156,7 +156,7 @@ version (linux)
*
* output = entropy.random;
*
* defaultAllocator.finalize(entropy);
* defaultAllocator.dispose(entropy);
* ---
*/
class Entropy
@ -185,7 +185,7 @@ class Entropy
}
body
{
allocator.resizeArray(sources, maxSources);
allocator.resize(sources, maxSources);
version (linux)
{

View File

@ -0,0 +1,185 @@
/* 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 2017.
* 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.memory.mallocator;
import core.stdc.stdlib;
import std.algorithm.comparison;
import tanya.memory.allocator;
/**
* Wrapper for malloc/realloc/free from the C standard library.
*/
final class Mallocator : Allocator
{
/**
* Allocates $(D_PARAM size) bytes of memory.
*
* Params:
* size = Amount of memory to allocate.
*
* Returns: The pointer to the new allocated memory.
*/
void[] allocate(in size_t size) shared nothrow @nogc
{
if (!size)
{
return null;
}
auto p = malloc(size + psize);
return p is null ? null : p[psize .. psize + size];
}
///
@nogc nothrow unittest
{
auto p = Mallocator.instance.allocate(20);
assert(p.length == 20);
Mallocator.instance.deallocate(p);
}
/**
* Deallocates a memory block.
*
* Params:
* p = A pointer to the memory block to be freed.
*
* Returns: Whether the deallocation was successful.
*/
bool deallocate(void[] p) shared nothrow @nogc
{
if (p !is null)
{
free(p.ptr - psize);
}
return true;
}
///
@nogc nothrow unittest
{
void[] p;
assert(Mallocator.instance.deallocate(p));
p = Mallocator.instance.allocate(10);
assert(Mallocator.instance.deallocate(p));
}
/**
* Reallocating in place isn't supported.
*
* Params:
* p = A pointer to the memory block.
* size = Size of the reallocated block.
*
* Returns: $(D_KEYWORD false).
*/
bool reallocateInPlace(ref void[] p, const size_t size) shared nothrow @nogc
{
return false;
}
/**
* Increases or decreases the size of a memory block.
*
* Params:
* p = A pointer to the memory block.
* size = Size of the reallocated block.
*
* Returns: Whether the reallocation was successful.
*/
bool reallocate(ref void[] p, const size_t size) shared nothrow @nogc
{
if (size == 0)
{
if (deallocate(p))
{
p = null;
return true;
}
}
else if (p is null)
{
p = allocate(size);
return p is null ? false : true;
}
else
{
auto r = realloc(p.ptr - psize, size + psize);
if (r !is null)
{
p = r[psize .. psize + size];
return true;
}
}
return false;
}
///
@nogc nothrow unittest
{
void[] p;
assert(Mallocator.instance.reallocate(p, 20));
assert(p.length == 20);
assert(Mallocator.instance.reallocate(p, 30));
assert(p.length == 30);
assert(Mallocator.instance.reallocate(p, 10));
assert(p.length == 10);
assert(Mallocator.instance.reallocate(p, 0));
assert(p is null);
}
/**
* Returns: The alignment offered.
*/
@property uint alignment() shared const pure nothrow @safe @nogc
{
return cast(uint) max(double.alignof, real.alignof);
}
/**
* Static allocator instance and initializer.
*
* Returns: The global $(D_PSYMBOL Allocator) instance.
*/
static @property ref shared(Mallocator) instance() @nogc nothrow
{
if (instance_ is null)
{
immutable size = __traits(classInstanceSize, Mallocator) + psize;
void* p = malloc(size);
if (p !is null)
{
p[psize .. size] = typeid(Mallocator).initializer[];
instance_ = cast(shared Mallocator) p[psize .. size].ptr;
}
}
return instance_;
}
///
@nogc nothrow unittest
{
assert(instance is instance);
}
private enum psize = 8;
private shared static Mallocator instance_;
}

View File

@ -11,7 +11,7 @@
module tanya.memory;
import core.exception;
public import std.experimental.allocator : make, makeArray;
public import std.experimental.allocator : make;
import std.traits;
public import tanya.memory.allocator;
@ -29,6 +29,8 @@ mixin template DefaultAllocator()
/**
* Params:
* allocator = The allocator should be used.
*
* Precondition: $(D_INLINECODE allocator_ !is null)
*/
this(shared Allocator allocator)
in
@ -46,7 +48,7 @@ mixin template DefaultAllocator()
*
* Returns: Used allocator.
*
* Postcondition: $(D_INLINECODE allocator_ !is null)
* Postcondition: $(D_INLINECODE allocator !is null)
*/
protected @property shared(Allocator) allocator() nothrow @safe @nogc
out (allocator)
@ -85,8 +87,8 @@ shared Allocator allocator;
shared static this() nothrow @trusted @nogc
{
import tanya.memory.mmappool;
allocator = MmapPool.instance;
import tanya.memory.mallocator;
allocator = Mallocator.instance;
}
@property ref shared(Allocator) defaultAllocator() nothrow @safe @nogc
@ -135,79 +137,68 @@ template stateSize(T)
*
* Returns: Aligned size.
*/
size_t alignedSize(in size_t size, in size_t alignment = 8) pure nothrow @safe @nogc
size_t alignedSize(const size_t size, const size_t alignment = 8)
pure nothrow @safe @nogc
{
return (size - 1) / alignment * alignment + alignment;
}
/**
* Internal function used to create, resize or destroy a dynamic array. It
* throws $(D_PSYMBOL OutOfMemoryError) if $(D_PARAM Throws) is set. The new
* allocated part of the array is initialized only if $(D_PARAM Init)
* is set. This function can be trusted only in the data structures that
* can ensure that the array is allocated/rellocated/deallocated with the
* same allocator.
* may throw $(D_PSYMBOL OutOfMemoryError). The new
* allocated part of the array isn't initialized. This function can be trusted
* only in the data structures that can ensure that the array is
* allocated/rellocated/deallocated with the same allocator.
*
* Params:
* T = Element type of the array being created.
* Init = If should be initialized.
* Throws = If $(D_PSYMBOL OutOfMemoryError) should be throwsn.
* allocator = The allocator used for getting memory.
* array = A reference to the array being changed.
* length = New array length.
*
* Returns: $(D_KEYWORD true) upon success, $(D_KEYWORD false) if memory could
* not be reallocated. In the latter
* Returns: $(D_PARAM array).
*/
package(tanya) bool resize(T,
bool Init = true,
bool Throws = true)
(shared Allocator allocator,
ref T[] array,
in size_t length) @trusted
package(tanya) T[] resize(T)(shared Allocator allocator,
auto ref T[] array,
const size_t length) @trusted
{
void[] buf = array;
static if (Init)
if (length == 0)
{
immutable oldLength = array.length;
if (allocator.deallocate(array))
{
return null;
}
else
{
onOutOfMemoryErrorNoGC();
}
}
void[] buf = array;
if (!allocator.reallocate(buf, length * T.sizeof))
{
static if (Throws)
{
onOutOfMemoryError;
}
return false;
onOutOfMemoryErrorNoGC();
}
// Casting from void[] is unsafe, but we know we cast to the original type.
array = cast(T[]) buf;
static if (Init)
{
if (oldLength < length)
{
array[oldLength .. $] = T.init;
}
}
return true;
return array;
}
package(tanya) alias resizeArray = resize;
///
unittest
private unittest
{
int[] p;
defaultAllocator.resizeArray(p, 20);
p = defaultAllocator.resize(p, 20);
assert(p.length == 20);
defaultAllocator.resizeArray(p, 30);
p = defaultAllocator.resize(p, 30);
assert(p.length == 30);
defaultAllocator.resizeArray(p, 10);
p = defaultAllocator.resize(p, 10);
assert(p.length == 10);
defaultAllocator.resizeArray(p, 0);
p = defaultAllocator.resize(p, 0);
assert(p is null);
}

View File

@ -3,10 +3,10 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* Copyright: Eugene Wissner 2016.
* Copyright: Eugene Wissner 2016-2017.
* 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.memory.types;