Make containers work with non-copyable elements
It is the first step. The containers can be at least created with non-copyable structs without compilation errors now. Fix #69.
This commit is contained in:
parent
884dc30953
commit
49d7452b33
@ -22,6 +22,7 @@ import tanya.memory;
|
|||||||
import tanya.meta.trait;
|
import tanya.meta.trait;
|
||||||
import tanya.meta.transform;
|
import tanya.meta.transform;
|
||||||
import tanya.range;
|
import tanya.range;
|
||||||
|
version (unittest) import tanya.test.stub;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Random-access range for the $(D_PSYMBOL Array).
|
* Random-access range for the $(D_PSYMBOL Array).
|
||||||
@ -293,7 +294,9 @@ struct Array(T)
|
|||||||
* init = Initial value to fill the array with.
|
* init = Initial value to fill the array with.
|
||||||
* allocator = Allocator.
|
* allocator = Allocator.
|
||||||
*/
|
*/
|
||||||
this(size_t len, T init, shared Allocator allocator = defaultAllocator)
|
this()(size_t len,
|
||||||
|
auto ref T init,
|
||||||
|
shared Allocator allocator = defaultAllocator)
|
||||||
{
|
{
|
||||||
this(allocator);
|
this(allocator);
|
||||||
reserve(len);
|
reserve(len);
|
||||||
@ -348,15 +351,19 @@ struct Array(T)
|
|||||||
(() @trusted => allocator.deallocate(slice(capacity)))();
|
(() @trusted => allocator.deallocate(slice(capacity)))();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static if (isCopyable!T)
|
||||||
* Copies the array.
|
|
||||||
*/
|
|
||||||
this(this)
|
|
||||||
{
|
{
|
||||||
auto buf = slice(this.length);
|
this(this)
|
||||||
this.length_ = capacity_ = 0;
|
{
|
||||||
this.data = null;
|
auto buf = slice(this.length);
|
||||||
insertBack(buf);
|
this.length_ = capacity_ = 0;
|
||||||
|
this.data = null;
|
||||||
|
insertBack(buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
@disable this(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1027,7 +1034,7 @@ struct Array(T)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
Range opIndexAssign(Range value)
|
Range opIndexAssign()(Range value)
|
||||||
{
|
{
|
||||||
return opSliceAssign(value, 0, length);
|
return opSliceAssign(value, 0, length);
|
||||||
}
|
}
|
||||||
@ -1321,7 +1328,7 @@ struct Array(T)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
Range opSliceAssign(Range value, size_t i, size_t j) @trusted
|
Range opSliceAssign()(Range value, size_t i, size_t j) @trusted
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(i <= j);
|
assert(i <= j);
|
||||||
@ -1575,15 +1582,10 @@ struct Array(T)
|
|||||||
assert(v7[].equal(v8[]));
|
assert(v7[].equal(v8[]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Destructor can destroy empty arrays
|
||||||
@nogc nothrow pure @safe unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
static struct SWithDtor
|
auto v = Array!WithDtor();
|
||||||
{
|
|
||||||
~this() @nogc nothrow pure @safe
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
auto v = Array!SWithDtor(); // Destructor can destroy empty arrays.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@nogc nothrow pure @safe unittest
|
@nogc nothrow pure @safe unittest
|
||||||
@ -1594,7 +1596,6 @@ struct Array(T)
|
|||||||
A a1, a2;
|
A a1, a2;
|
||||||
auto v1 = Array!A([a1, a2]);
|
auto v1 = Array!A([a1, a2]);
|
||||||
|
|
||||||
// Issue 232: https://issues.caraus.io/issues/232.
|
|
||||||
static assert(is(Array!(A*)));
|
static assert(is(Array!(A*)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1679,3 +1680,9 @@ struct Array(T)
|
|||||||
}
|
}
|
||||||
func(array);
|
func(array);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Can have non-copyable elements
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
static assert(is(Array!NonCopyable));
|
||||||
|
}
|
||||||
|
@ -20,6 +20,7 @@ import tanya.memory.allocator;
|
|||||||
import tanya.meta.trait;
|
import tanya.meta.trait;
|
||||||
import tanya.meta.transform;
|
import tanya.meta.transform;
|
||||||
import tanya.typecons;
|
import tanya.typecons;
|
||||||
|
version (unittest) import tanya.test.stub;
|
||||||
|
|
||||||
package struct SEntry(T)
|
package struct SEntry(T)
|
||||||
{
|
{
|
||||||
@ -59,12 +60,12 @@ package struct Bucket(K, V = void)
|
|||||||
}
|
}
|
||||||
BucketStatus status = BucketStatus.empty;
|
BucketStatus status = BucketStatus.empty;
|
||||||
|
|
||||||
this(ref K key)
|
this()(ref K key)
|
||||||
{
|
{
|
||||||
this.key = key;
|
this.key = key;
|
||||||
}
|
}
|
||||||
|
|
||||||
@property void key(ref K key)
|
@property void key()(ref K key)
|
||||||
{
|
{
|
||||||
this.key() = key;
|
this.key() = key;
|
||||||
this.status = BucketStatus.used;
|
this.status = BucketStatus.used;
|
||||||
@ -170,7 +171,7 @@ package struct HashArray(alias hasher, K, V = void)
|
|||||||
.swap(this.length, data.length);
|
.swap(this.length, data.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
void opAssign(ref typeof(this) that)
|
void opAssign()(ref typeof(this) that)
|
||||||
{
|
{
|
||||||
this.array = that.array;
|
this.array = that.array;
|
||||||
this.lengthIndex = that.lengthIndex;
|
this.lengthIndex = that.lengthIndex;
|
||||||
@ -326,3 +327,13 @@ package struct HashArray(alias hasher, K, V = void)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Can be constructed with non-copyable key/values
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
static assert(is(Bucket!NonCopyable));
|
||||||
|
static assert(is(Bucket!(NonCopyable, NonCopyable)));
|
||||||
|
|
||||||
|
static assert(is(HashArray!((ref NonCopyable) => 0U, NonCopyable)));
|
||||||
|
static assert(is(HashArray!((ref NonCopyable) => 0U, NonCopyable, NonCopyable)));
|
||||||
|
}
|
||||||
|
@ -22,6 +22,7 @@ import tanya.memory;
|
|||||||
import tanya.meta.trait;
|
import tanya.meta.trait;
|
||||||
import tanya.meta.transform;
|
import tanya.meta.transform;
|
||||||
import tanya.range.primitive;
|
import tanya.range.primitive;
|
||||||
|
version (unittest) import tanya.test.stub;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bidirectional range whose element type is a tuple of a key and the
|
* Bidirectional range whose element type is a tuple of a key and the
|
||||||
@ -68,7 +69,7 @@ struct Range(T)
|
|||||||
return this.dataRange.empty();
|
return this.dataRange.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@property void popFront()
|
void popFront()
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(!empty);
|
assert(!empty);
|
||||||
@ -87,7 +88,7 @@ struct Range(T)
|
|||||||
while (!empty && dataRange.front.status != BucketStatus.used);
|
while (!empty && dataRange.front.status != BucketStatus.used);
|
||||||
}
|
}
|
||||||
|
|
||||||
@property void popBack()
|
void popBack()
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(!empty);
|
assert(!empty);
|
||||||
@ -759,7 +760,7 @@ if (isHashFunction!(hasher, Key))
|
|||||||
*
|
*
|
||||||
* Returns: The number of the inserted elements with a unique key.
|
* Returns: The number of the inserted elements with a unique key.
|
||||||
*/
|
*/
|
||||||
size_t insert(ref KeyValue keyValue)
|
size_t insert()(ref KeyValue keyValue)
|
||||||
{
|
{
|
||||||
auto e = ((ref v) @trusted => &this.data.insert(v))(keyValue.key);
|
auto e = ((ref v) @trusted => &this.data.insert(v))(keyValue.key);
|
||||||
size_t inserted;
|
size_t inserted;
|
||||||
@ -773,7 +774,7 @@ if (isHashFunction!(hasher, Key))
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
size_t insert(KeyValue keyValue)
|
size_t insert()(KeyValue keyValue)
|
||||||
{
|
{
|
||||||
auto e = ((ref v) @trusted => &this.data.insert(v))(keyValue.key);
|
auto e = ((ref v) @trusted => &this.data.insert(v))(keyValue.key);
|
||||||
size_t inserted;
|
size_t inserted;
|
||||||
@ -1197,3 +1198,16 @@ if (isHashFunction!(hasher, Key))
|
|||||||
static assert(is(typeof("asdf" in HashTable!(String, int)())));
|
static assert(is(typeof("asdf" in HashTable!(String, int)())));
|
||||||
static assert(is(typeof(HashTable!(String, int)()["asdf"])));
|
static assert(is(typeof(HashTable!(String, int)()["asdf"])));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Can have non-copyable keys and elements
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
@NonCopyable @Hashable
|
||||||
|
static struct S
|
||||||
|
{
|
||||||
|
mixin StructStub;
|
||||||
|
}
|
||||||
|
static assert(is(HashTable!(S, int)));
|
||||||
|
static assert(is(HashTable!(int, S)));
|
||||||
|
static assert(is(HashTable!(S, S)));
|
||||||
|
}
|
||||||
|
@ -23,6 +23,7 @@ import tanya.meta.trait;
|
|||||||
import tanya.meta.transform;
|
import tanya.meta.transform;
|
||||||
import tanya.range.array;
|
import tanya.range.array;
|
||||||
import tanya.range.primitive;
|
import tanya.range.primitive;
|
||||||
|
version (unittest) import tanya.test.stub;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Forward range for the $(D_PSYMBOL SList).
|
* Forward range for the $(D_PSYMBOL SList).
|
||||||
@ -155,8 +156,9 @@ struct SList(T)
|
|||||||
* init = Initial value to fill the list with.
|
* init = Initial value to fill the list with.
|
||||||
* allocator = Allocator.
|
* allocator = Allocator.
|
||||||
*/
|
*/
|
||||||
this(size_t len, T init, shared Allocator allocator = defaultAllocator)
|
this()(size_t len,
|
||||||
@trusted
|
auto ref T init,
|
||||||
|
shared Allocator allocator = defaultAllocator)
|
||||||
{
|
{
|
||||||
this(allocator);
|
this(allocator);
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
@ -182,7 +184,18 @@ struct SList(T)
|
|||||||
/// ditto
|
/// ditto
|
||||||
this(size_t len, shared Allocator allocator = defaultAllocator)
|
this(size_t len, shared Allocator allocator = defaultAllocator)
|
||||||
{
|
{
|
||||||
this(len, T.init, allocator);
|
this(allocator);
|
||||||
|
if (len == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Entry* next = this.head = allocator.make!Entry();
|
||||||
|
foreach (i; 1 .. len)
|
||||||
|
{
|
||||||
|
next.next = allocator.make!Entry();
|
||||||
|
next = next.next;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@ -271,14 +284,18 @@ struct SList(T)
|
|||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static if (isCopyable!T)
|
||||||
* Copies the list.
|
|
||||||
*/
|
|
||||||
this(this)
|
|
||||||
{
|
{
|
||||||
auto list = typeof(this)(this[], this.allocator);
|
this(this)
|
||||||
this.head = list.head;
|
{
|
||||||
list.head = null;
|
auto list = typeof(this)(this[], this.allocator);
|
||||||
|
this.head = list.head;
|
||||||
|
list.head = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
@disable this(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@ -512,7 +529,7 @@ struct SList(T)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
size_t insertBefore(Range r, ref T el) @trusted
|
size_t insertBefore()(Range r, ref T el) @trusted
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(checkRangeBelonging(r));
|
assert(checkRangeBelonging(r));
|
||||||
@ -1120,8 +1137,9 @@ struct DList(T)
|
|||||||
* init = Initial value to fill the list with.
|
* init = Initial value to fill the list with.
|
||||||
* allocator = Allocator.
|
* allocator = Allocator.
|
||||||
*/
|
*/
|
||||||
this(size_t len, T init, shared Allocator allocator = defaultAllocator)
|
this()(size_t len,
|
||||||
@trusted
|
auto ref T init,
|
||||||
|
shared Allocator allocator = defaultAllocator)
|
||||||
{
|
{
|
||||||
this(allocator);
|
this(allocator);
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
@ -1150,7 +1168,20 @@ struct DList(T)
|
|||||||
/// ditto
|
/// ditto
|
||||||
this(size_t len, shared Allocator allocator = defaultAllocator)
|
this(size_t len, shared Allocator allocator = defaultAllocator)
|
||||||
{
|
{
|
||||||
this(len, T.init, allocator);
|
this(allocator);
|
||||||
|
if (len == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Entry* next = this.head = allocator.make!Entry();
|
||||||
|
foreach (i; 1 .. len)
|
||||||
|
{
|
||||||
|
next.next = allocator.make!Entry();
|
||||||
|
next.next.prev = next;
|
||||||
|
next = next.next;
|
||||||
|
}
|
||||||
|
this.tail = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@ -1242,15 +1273,19 @@ struct DList(T)
|
|||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static if (isCopyable!T)
|
||||||
* Copies the list.
|
|
||||||
*/
|
|
||||||
this(this)
|
|
||||||
{
|
{
|
||||||
auto list = typeof(this)(this[], this.allocator);
|
this(this)
|
||||||
this.head = list.head;
|
{
|
||||||
this.tail = list.tail;
|
auto list = typeof(this)(this[], this.allocator);
|
||||||
list.head = list .tail = null;
|
this.head = list.head;
|
||||||
|
this.tail = list.tail;
|
||||||
|
list.head = list .tail = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
@disable this(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@ -1641,7 +1676,7 @@ struct DList(T)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
size_t insertBefore(Range r, ref T el) @trusted
|
size_t insertBefore()(Range r, ref T el) @trusted
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(checkRangeBelonging(r));
|
assert(checkRangeBelonging(r));
|
||||||
@ -1758,7 +1793,7 @@ struct DList(T)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
size_t insertAfter(Range r, ref T el) @trusted
|
size_t insertAfter()(Range r, ref T el) @trusted
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(checkRangeBelonging(r));
|
assert(checkRangeBelonging(r));
|
||||||
@ -2355,3 +2390,10 @@ struct DList(T)
|
|||||||
assert(!l1.remove(r).empty);
|
assert(!l1.remove(r).empty);
|
||||||
assert(l1 == l2);
|
assert(l1 == l2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Can have non-copyable elements
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
static assert(is(SList!NonCopyable));
|
||||||
|
static assert(is(DList!NonCopyable));
|
||||||
|
}
|
||||||
|
@ -22,6 +22,7 @@ import tanya.memory;
|
|||||||
import tanya.meta.trait;
|
import tanya.meta.trait;
|
||||||
import tanya.meta.transform;
|
import tanya.meta.transform;
|
||||||
import tanya.range.primitive;
|
import tanya.range.primitive;
|
||||||
|
version (unittest) import tanya.test.stub;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bidirectional range that iterates over the $(D_PSYMBOL Set)'s values.
|
* Bidirectional range that iterates over the $(D_PSYMBOL Set)'s values.
|
||||||
@ -67,7 +68,7 @@ struct Range(T)
|
|||||||
return this.dataRange.empty();
|
return this.dataRange.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@property void popFront()
|
void popFront()
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(!empty);
|
assert(!empty);
|
||||||
@ -86,7 +87,7 @@ struct Range(T)
|
|||||||
while (!empty && dataRange.front.status != BucketStatus.used);
|
while (!empty && dataRange.front.status != BucketStatus.used);
|
||||||
}
|
}
|
||||||
|
|
||||||
@property void popBack()
|
void popBack()
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(!empty);
|
assert(!empty);
|
||||||
@ -459,7 +460,7 @@ if (isHashFunction!(hasher, T))
|
|||||||
*
|
*
|
||||||
* Returns: Amount of new elements inserted.
|
* Returns: Amount of new elements inserted.
|
||||||
*/
|
*/
|
||||||
size_t insert(ref T value)
|
size_t insert()(ref T value)
|
||||||
{
|
{
|
||||||
auto e = ((ref v) @trusted => &this.data.insert(v))(value);
|
auto e = ((ref v) @trusted => &this.data.insert(v))(value);
|
||||||
if (e.status != BucketStatus.used)
|
if (e.status != BucketStatus.used)
|
||||||
@ -470,7 +471,7 @@ if (isHashFunction!(hasher, T))
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t insert(T value)
|
size_t insert()(T value)
|
||||||
{
|
{
|
||||||
auto e = ((ref v) @trusted => &this.data.insert(v))(value);
|
auto e = ((ref v) @trusted => &this.data.insert(v))(value);
|
||||||
if (e.status != BucketStatus.used)
|
if (e.status != BucketStatus.used)
|
||||||
@ -773,3 +774,14 @@ if (isHashFunction!(hasher, T))
|
|||||||
{
|
{
|
||||||
static assert(is(Set!(int, (const ref x) => cast(size_t) x)));
|
static assert(is(Set!(int, (const ref x) => cast(size_t) x)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Can have non-copyable elements
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
@NonCopyable @Hashable
|
||||||
|
static struct S
|
||||||
|
{
|
||||||
|
mixin StructStub;
|
||||||
|
}
|
||||||
|
static assert(is(Set!S));
|
||||||
|
}
|
||||||
|
@ -16,6 +16,7 @@ module tanya.hash.lookup;
|
|||||||
|
|
||||||
import tanya.meta.trait;
|
import tanya.meta.trait;
|
||||||
import tanya.range.primitive;
|
import tanya.range.primitive;
|
||||||
|
version (unittest) import tanya.test.stub;
|
||||||
|
|
||||||
private struct FNV
|
private struct FNV
|
||||||
{
|
{
|
||||||
@ -146,14 +147,6 @@ version (unittest)
|
|||||||
~ r10!x ~ r10!x ~ r10!x ~ r10!x ~ r10!x;
|
~ r10!x ~ r10!x ~ r10!x ~ r10!x ~ r10!x;
|
||||||
enum string r500(string x) = r100!x ~ r100!x ~ r100!x ~ r100!x ~ r100!x;
|
enum string r500(string x) = r100!x ~ r100!x ~ r100!x ~ r100!x ~ r100!x;
|
||||||
|
|
||||||
private static struct ToHash
|
|
||||||
{
|
|
||||||
size_t toHash() const @nogc nothrow pure @safe
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static struct HashRange
|
private static struct HashRange
|
||||||
{
|
{
|
||||||
string fo = "fo";
|
string fo = "fo";
|
||||||
@ -178,9 +171,9 @@ version (unittest)
|
|||||||
{
|
{
|
||||||
bool empty_;
|
bool empty_;
|
||||||
|
|
||||||
@property ToHash front() const @nogc nothrow pure @safe
|
@property Hashable front() const @nogc nothrow pure @safe
|
||||||
{
|
{
|
||||||
return ToHash();
|
return Hashable();
|
||||||
}
|
}
|
||||||
|
|
||||||
void popFront() @nogc nothrow pure @safe
|
void popFront() @nogc nothrow pure @safe
|
||||||
@ -199,7 +192,7 @@ version (unittest)
|
|||||||
@nogc nothrow pure @safe unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
assert(hash(null) == 0);
|
assert(hash(null) == 0);
|
||||||
assert(hash(ToHash()) == 0U);
|
assert(hash(Hashable()) == 0U);
|
||||||
assert(hash('a') == 'a');
|
assert(hash('a') == 'a');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ struct WithLvalueElements
|
|||||||
mixin template InputRangeStub(E = int)
|
mixin template InputRangeStub(E = int)
|
||||||
{
|
{
|
||||||
import tanya.meta.metafunction : Alias;
|
import tanya.meta.metafunction : Alias;
|
||||||
import tanya.meta.trait : getUDAs, hasUDA;
|
import tanya.meta.trait : evalUDA, getUDAs, hasUDA;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Aliases for the attribute lookups to access them faster
|
* Aliases for the attribute lookups to access them faster
|
||||||
@ -279,6 +279,9 @@ mixin template RandomAccessRangeStub(E = int)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Struct with a disabled postblit constructor.
|
* Struct with a disabled postblit constructor.
|
||||||
|
*
|
||||||
|
* $(D_PSYMBOL NonCopyable) can be used as an attribute for
|
||||||
|
* $(D_PSYMBOL StructStub) or as a standalone type.
|
||||||
*/
|
*/
|
||||||
struct NonCopyable
|
struct NonCopyable
|
||||||
{
|
{
|
||||||
@ -288,10 +291,14 @@ struct NonCopyable
|
|||||||
/**
|
/**
|
||||||
* Struct with an elaborate destructor.
|
* Struct with an elaborate destructor.
|
||||||
*
|
*
|
||||||
* The constructor of $(D_PSYMBOL WithDtor) accepts an additional `counter`
|
* $(D_PSYMBOL WithDtor) can be used as an attribute for
|
||||||
* argument, which is incremented by the destructor. $(D_PSYMBOL WithDtor)
|
* $(D_PSYMBOL StructStub) or as a standalone type.
|
||||||
* stores a pointer to the passed variable, so the variable can be
|
*
|
||||||
* investigated after the struct isn't available anymore.
|
* When used as a standalone object the constructor of $(D_PSYMBOL WithDtor)
|
||||||
|
* accepts an additional `counter` argument, which is incremented by the
|
||||||
|
* destructor. $(D_PSYMBOL WithDtor) stores a pointer to the passed variable,
|
||||||
|
* so the variable can be investigated after the struct isn't available
|
||||||
|
* anymore.
|
||||||
*/
|
*/
|
||||||
struct WithDtor
|
struct WithDtor
|
||||||
{
|
{
|
||||||
@ -310,3 +317,57 @@ struct WithDtor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Struct supporting hashing.
|
||||||
|
*
|
||||||
|
* $(D_PSYMBOL Hashable) can be used as an attribute for
|
||||||
|
* $(D_PSYMBOL StructStub) or as a standalone type.
|
||||||
|
*
|
||||||
|
* The constructor accepts an additional parameter, which is returned by the
|
||||||
|
* `toHash()`-function. `0U` is returned if no hash value is given.
|
||||||
|
*/
|
||||||
|
struct Hashable
|
||||||
|
{
|
||||||
|
size_t hash;
|
||||||
|
|
||||||
|
size_t toHash() const @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
return this.hash;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a $(D_KEYWORD struct) with common functionality.
|
||||||
|
*
|
||||||
|
* To specify the needed functionality use user-defined attributes on the
|
||||||
|
* $(D_KEYWORD struct) $(D_PSYMBOL StructStub) is mixed in.
|
||||||
|
*
|
||||||
|
* Supported attributes are: $(D_PSYMBOL NonCopyable), $(D_PSYMBOL Hashable),
|
||||||
|
* $(D_PSYMBOL WithDtor).
|
||||||
|
*/
|
||||||
|
mixin template StructStub()
|
||||||
|
{
|
||||||
|
import tanya.meta.trait : evalUDA, getUDAs, hasUDA;
|
||||||
|
|
||||||
|
static if (hasUDA!(typeof(this), NonCopyable))
|
||||||
|
{
|
||||||
|
@disable this(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private alias Hashable = getUDAs!(typeof(this), .Hashable);
|
||||||
|
static if (Hashable.length > 0)
|
||||||
|
{
|
||||||
|
size_t toHash() const @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
return evalUDA!(Hashable[0]).hash;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static if (hasUDA!(typeof(this), WithDtor))
|
||||||
|
{
|
||||||
|
~this() @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -503,30 +503,16 @@ struct Option(T)
|
|||||||
// Returns default value
|
// Returns default value
|
||||||
@nogc nothrow pure @safe unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
{
|
int i = 5;
|
||||||
int i = 5;
|
assert(((ref e) => e)(Option!int().or(i)) == 5);
|
||||||
assert(((ref e) => e)(Option!int().or(i)) == 5);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implements toHash() for nothing
|
// Implements toHash() for nothing
|
||||||
@nogc nothrow pure @safe unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
static struct ToHash
|
alias OptionT = Option!Hashable;
|
||||||
{
|
assert(OptionT().toHash() == 0U);
|
||||||
size_t toHash() const @nogc nothrow pure @safe
|
assert(OptionT(Hashable(1U)).toHash() == 1U);
|
||||||
{
|
|
||||||
return 1U;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{
|
|
||||||
Option!ToHash toHash;
|
|
||||||
assert(toHash.toHash() == 0U);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
auto toHash = Option!ToHash(ToHash());
|
|
||||||
assert(toHash.toHash() == 1U);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user