Set: Fix comparing with removed elements
This commit is contained in:
parent
dc39efd316
commit
4633bcc680
@ -69,6 +69,34 @@ package struct Bucket(T)
|
|||||||
return this.content_;
|
return this.content_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool opEquals(ref T content)
|
||||||
|
{
|
||||||
|
if (this.status == BucketStatus.used && this.content == content)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool opEquals(ref T content) const
|
||||||
|
{
|
||||||
|
if (this.status == BucketStatus.used && this.content == content)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool opEquals(ref typeof(this) that)
|
||||||
|
{
|
||||||
|
return this.content == that.content && this.status == that.status;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool opEquals(ref typeof(this) that) const
|
||||||
|
{
|
||||||
|
return this.content == that.content && this.status == that.status;
|
||||||
|
}
|
||||||
|
|
||||||
void remove()
|
void remove()
|
||||||
{
|
{
|
||||||
static if (hasElaborateDestructor!T)
|
static if (hasElaborateDestructor!T)
|
||||||
|
@ -142,10 +142,13 @@ struct Range(E)
|
|||||||
* This $(D_PSYMBOL Set) is implemented using closed hashing. Hash collisions
|
* This $(D_PSYMBOL Set) is implemented using closed hashing. Hash collisions
|
||||||
* are resolved with linear probing.
|
* are resolved with linear probing.
|
||||||
*
|
*
|
||||||
|
* Currently works only with integral types.
|
||||||
|
*
|
||||||
* Params:
|
* Params:
|
||||||
* T = Element type.
|
* T = Element type.
|
||||||
*/
|
*/
|
||||||
struct Set(T)
|
struct Set(T)
|
||||||
|
if (isIntegral!T || is(Unqual!T == bool))
|
||||||
{
|
{
|
||||||
/// The range types for $(D_PSYMBOL Set).
|
/// The range types for $(D_PSYMBOL Set).
|
||||||
alias Range = .Range!T;
|
alias Range = .Range!T;
|
||||||
@ -191,6 +194,19 @@ struct Set(T)
|
|||||||
this.data = typeof(this.data)(allocator);
|
this.data = typeof(this.data)(allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
{
|
||||||
|
auto set = Set!int(defaultAllocator);
|
||||||
|
assert(set.capacity == 0);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto set = Set!int(8);
|
||||||
|
assert(set.capacity == 13);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes this $(D_PARAM Set) from another one.
|
* Initializes this $(D_PARAM Set) from another one.
|
||||||
*
|
*
|
||||||
@ -285,6 +301,16 @@ struct Set(T)
|
|||||||
return this.data.length;
|
return this.data.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
Set!int set;
|
||||||
|
assert(set.capacity == 0);
|
||||||
|
|
||||||
|
set.insert(8);
|
||||||
|
assert(set.capacity == 3);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Iterates over the $(D_PSYMBOL Set) and counts the elements.
|
* Iterates over the $(D_PSYMBOL Set) and counts the elements.
|
||||||
*
|
*
|
||||||
@ -303,6 +329,16 @@ struct Set(T)
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
Set!int set;
|
||||||
|
assert(set.length == 0);
|
||||||
|
|
||||||
|
set.insert(8);
|
||||||
|
assert(set.length == 1);
|
||||||
|
}
|
||||||
|
|
||||||
private static const size_t[41] primes = [
|
private static const size_t[41] primes = [
|
||||||
3, 7, 13, 23, 29, 37, 53, 71, 97, 131, 163, 193, 239, 293, 389, 521,
|
3, 7, 13, 23, 29, 37, 53, 71, 97, 131, 163, 193, 239, 293, 389, 521,
|
||||||
769, 919, 1103, 1327, 1543, 2333, 3079, 4861, 6151, 12289, 24593,
|
769, 919, 1103, 1327, 1543, 2333, 3079, 4861, 6151, 12289, 24593,
|
||||||
@ -339,8 +375,8 @@ struct Set(T)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Inserts the value in an empty or deleted bucket. If the value is
|
* Inserts the value in an empty or deleted bucket. If the value is
|
||||||
* already in there, does nothing and returns true. If the hash array
|
* already in there, does nothing and returns InsertStatus.found. If the
|
||||||
* is full returns false.
|
* hash array is full returns InsertStatus.failed.
|
||||||
*/
|
*/
|
||||||
private InsertStatus insertInUnusedBucket(ref T value)
|
private InsertStatus insertInUnusedBucket(ref T value)
|
||||||
{
|
{
|
||||||
@ -348,7 +384,7 @@ struct Set(T)
|
|||||||
|
|
||||||
foreach (ref e; this.data[bucketPosition .. $])
|
foreach (ref e; this.data[bucketPosition .. $])
|
||||||
{
|
{
|
||||||
if (e.content == value) // Already in the set.
|
if (e == value) // Already in the set.
|
||||||
{
|
{
|
||||||
return InsertStatus.found;
|
return InsertStatus.found;
|
||||||
}
|
}
|
||||||
@ -391,6 +427,24 @@ struct Set(T)
|
|||||||
return status == InsertStatus.added;
|
return status == InsertStatus.added;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
Set!int set;
|
||||||
|
assert(8 !in set);
|
||||||
|
|
||||||
|
assert(set.insert(8) == 1);
|
||||||
|
assert(set.length == 1);
|
||||||
|
assert(8 in set);
|
||||||
|
|
||||||
|
assert(set.insert(8) == 0);
|
||||||
|
assert(set.length == 1);
|
||||||
|
assert(8 in set);
|
||||||
|
|
||||||
|
assert(set.remove(8));
|
||||||
|
assert(set.insert(8) == 1);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes an element.
|
* Removes an element.
|
||||||
*
|
*
|
||||||
@ -410,7 +464,7 @@ struct Set(T)
|
|||||||
auto bucketPosition = locateBucket(this.data, calculateHash(value));
|
auto bucketPosition = locateBucket(this.data, calculateHash(value));
|
||||||
foreach (ref e; this.data[bucketPosition .. $])
|
foreach (ref e; this.data[bucketPosition .. $])
|
||||||
{
|
{
|
||||||
if (e.content == value) // Found.
|
if (e == value) // Found.
|
||||||
{
|
{
|
||||||
e.remove();
|
e.remove();
|
||||||
return 1;
|
return 1;
|
||||||
@ -423,6 +477,20 @@ struct Set(T)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
Set!int set;
|
||||||
|
assert(8 !in set);
|
||||||
|
|
||||||
|
set.insert(8);
|
||||||
|
assert(8 in set);
|
||||||
|
|
||||||
|
assert(set.remove(8) == 1);
|
||||||
|
assert(set.remove(8) == 0);
|
||||||
|
assert(8 !in set);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* $(D_KEYWORD in) operator.
|
* $(D_KEYWORD in) operator.
|
||||||
*
|
*
|
||||||
@ -442,7 +510,7 @@ struct Set(T)
|
|||||||
auto bucketPosition = locateBucket(this.data, calculateHash(value));
|
auto bucketPosition = locateBucket(this.data, calculateHash(value));
|
||||||
foreach (ref e; this.data[bucketPosition .. $])
|
foreach (ref e; this.data[bucketPosition .. $])
|
||||||
{
|
{
|
||||||
if (e.content == value) // Found.
|
if (e == value) // Found.
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -465,7 +533,7 @@ struct Set(T)
|
|||||||
auto bucketPosition = locateBucket(this.data, calculateHash(value));
|
auto bucketPosition = locateBucket(this.data, calculateHash(value));
|
||||||
foreach (ref e; this.data[bucketPosition .. $])
|
foreach (ref e; this.data[bucketPosition .. $])
|
||||||
{
|
{
|
||||||
if (e.content == value) // Found.
|
if (e.status == BucketStatus.used && e.content == value) // Found.
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -477,7 +545,6 @@ struct Set(T)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
///
|
///
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
@ -565,6 +632,21 @@ struct Set(T)
|
|||||||
return typeof(return)(this.data[]);
|
return typeof(return)(this.data[]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
Set!int set;
|
||||||
|
assert(set[].empty);
|
||||||
|
|
||||||
|
set.insert(8);
|
||||||
|
assert(!set[].empty);
|
||||||
|
assert(set[].front == 8);
|
||||||
|
assert(set[].back == 8);
|
||||||
|
|
||||||
|
set.remove(8);
|
||||||
|
assert(set[].empty);
|
||||||
|
}
|
||||||
|
|
||||||
private alias DataType = Array!(Bucket!T);
|
private alias DataType = Array!(Bucket!T);
|
||||||
private DataType data;
|
private DataType data;
|
||||||
private size_t lengthIndex;
|
private size_t lengthIndex;
|
||||||
@ -618,4 +700,11 @@ private unittest
|
|||||||
|
|
||||||
static assert(!isInfinite!(Set!int.Range));
|
static assert(!isInfinite!(Set!int.Range));
|
||||||
static assert(!hasLength!(Set!int.Range));
|
static assert(!hasLength!(Set!int.Range));
|
||||||
|
|
||||||
|
static assert(is(Set!uint));
|
||||||
|
static assert(is(Set!long));
|
||||||
|
static assert(is(Set!ulong));
|
||||||
|
static assert(is(Set!short));
|
||||||
|
static assert(is(Set!ushort));
|
||||||
|
static assert(is(Set!bool));
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user