Compare commits
18 Commits
Author | SHA1 | Date | |
---|---|---|---|
647cfe03c2 | |||
4cd6126d6b | |||
b870179a35 | |||
aabb4fb534 | |||
4d8b95812e | |||
e921413249 | |||
49cae88645 | |||
402fdfae89 | |||
7892c1a930 | |||
b90517580e | |||
85380ac3fc | |||
b90c56395c | |||
d0ada39fa7 | |||
f4145abfd1 | |||
093d499729 | |||
f90a03501b | |||
c6a99b114e | |||
3c23aca6a6 |
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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).
|
||||
|
@ -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).
|
||||
|
@ -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
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
185
source/tanya/memory/mallocator.d
Normal file
185
source/tanya/memory/mallocator.d
Normal 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_;
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
Reference in New Issue
Block a user