Fix reallocating the vector

This commit is contained in:
Eugen Wissner 2017-01-09 17:03:09 +01:00
parent d6514cb515
commit 87b74b2542
3 changed files with 52 additions and 49 deletions

2
.gitignore vendored
View File

@ -5,4 +5,6 @@
.dub .dub
__test__*__ __test__*__
__test__*__.core __test__*__.core
/docs/ /docs/
/docs.json

View File

@ -5,8 +5,7 @@
[![Dub downloads](https://img.shields.io/dub/dt/tanya.svg)](https://code.dlang.org/packages/tanya) [![Dub downloads](https://img.shields.io/dub/dt/tanya.svg)](https://code.dlang.org/packages/tanya)
[![License](https://img.shields.io/badge/license-MPL_2.0-blue.svg)](https://raw.githubusercontent.com/caraus-ecms/tanya/master/LICENSE) [![License](https://img.shields.io/badge/license-MPL_2.0-blue.svg)](https://raw.githubusercontent.com/caraus-ecms/tanya/master/LICENSE)
Tanya is a general purpose library for D programming language that doesn't Tanya is a general purpose library for D programming language.
rely on the Garbage Collector.
Its aim is to simplify the manual memory management in D and to provide a Its aim is to simplify the manual memory management in D and to provide a
guarantee with @nogc attribute that there are no hidden allocations on the guarantee with @nogc attribute that there are no hidden allocations on the
@ -36,12 +35,12 @@ helper functions).
The library is currently under development, but some parts of it can already be The library is currently under development, but some parts of it can already be
used. used.
`network` and `async` exist for quite some time and could be better tested than
other components.
Containers were newly reworked and the API won't change significantly, but will Containers were newly reworked and the API won't change significantly, but will
be only extended. The same is true for the `memory` package. be only extended. The same is true for the `memory` package.
`network` and `async` packages should be reviewed in the future and the API may
change.
`math` package contains an arbitrary precision integer implementation that has `math` package contains an arbitrary precision integer implementation that has
a stable API (that mostly consists of operator overloads), but still needs a stable API (that mostly consists of operator overloads), but still needs
testing and work on its performance. testing and work on its performance.

View File

@ -10,9 +10,11 @@
*/ */
module tanya.container.vector; module tanya.container.vector;
import core.stdc.string; import core.checkedint;
import core.exception; import core.exception;
import core.stdc.string;
import std.algorithm.comparison; import std.algorithm.comparison;
import std.algorithm.mutation;
import std.conv; import std.conv;
import std.range.primitives; import std.range.primitives;
import std.meta; import std.meta;
@ -297,30 +299,6 @@ struct Vector(T)
assert(capacity_ == 0 || vector !is null); assert(capacity_ == 0 || vector !is null);
} }
// Reserves memory to store len objects and initializes it.
// Doesn't change the length.
private void initialize(in size_t len)
{
reserve(len);
if (capacity_ < len)
{
onOutOfMemoryError();
}
const init = typeid(T).initializer();
if (init.ptr)
{
const T* end = vector + len;
for (void* v = vector + length_; v != end; v += init.length)
{
memcpy(v, init.ptr, init.length);
}
}
else
{
memset(vector + length_, 0, (len - length_) * T.sizeof);
}
}
/** /**
* Creates a new $(D_PSYMBOL Vector). * Creates a new $(D_PSYMBOL Vector).
* *
@ -364,7 +342,8 @@ struct Vector(T)
{ {
return; return;
} }
initialize(len); reserve(len);
initializeAll(vector[0 .. len]);
capacity_ = length_ = len; capacity_ = length_ = len;
} }
@ -385,9 +364,9 @@ struct Vector(T)
{ {
return; return;
} }
initialize(len); reserve(len);
uninitializedFill(vector[0 .. len], init);
capacity_ = length_ = len; capacity_ = length_ = len;
opSliceAssign(init, 0, length_);
} }
/// Ditto. /// Ditto.
@ -503,7 +482,8 @@ struct Vector(T)
} }
else if (len > length_) else if (len > length_)
{ {
initialize(len); reserve(len);
initializeAll(vector[length_ .. len]);
} }
else else
{ {
@ -549,13 +529,41 @@ struct Vector(T)
*/ */
void reserve(in size_t size) @trusted void reserve(in size_t size) @trusted
{ {
if (capacity_ < size) if (capacity_ >= size)
{ {
void[] buf = vector[0 .. capacity_]; return;
allocator.reallocate(buf, size * T.sizeof);
vector = cast(T*) buf;
capacity_ = size;
} }
bool overflow;
immutable byteSize = mulu(size, T.sizeof, overflow);
if (overflow)
{
onOutOfMemoryErrorNoGC();
}
void[] buf = vector[0 .. capacity_];
if (!allocator.expand(buf, byteSize))
{
buf = allocator.allocate(byteSize);
if (buf is null)
{
onOutOfMemoryErrorNoGC();
}
scope (failure)
{
allocator.deallocate(buf);
}
const T* end = vector + length_;
for (T* src = vector, dest = cast(T*) buf; src != end; ++src, ++dest)
{
moveEmplace(*src, *dest);
static if (hasElaborateDestructor!T)
{
destroy(*src);
}
}
allocator.deallocate(vector[0 .. capacity_]);
vector = cast(T*) buf;
}
capacity_ = size;
} }
/// ///
@ -718,10 +726,6 @@ struct Vector(T)
if (allSatisfy!(ApplyRight!(isImplicitlyConvertible, T), R)) if (allSatisfy!(ApplyRight!(isImplicitlyConvertible, T), R))
{ {
reserve(length_ + el.length); reserve(length_ + el.length);
if (capacity_ <= length_)
{
onOutOfMemoryError();
}
foreach (i; el) foreach (i; el)
{ {
emplace(vector + length_, i); emplace(vector + length_, i);
@ -737,8 +741,10 @@ struct Vector(T)
&& isImplicitlyConvertible!(ElementType!R, T)) && isImplicitlyConvertible!(ElementType!R, T))
{ {
immutable rLen = walkLength(el); immutable rLen = walkLength(el);
immutable newLen = length_ + rLen;
initialize(length_ + rLen); reserve(newLen);
initializeAll(vector[length_ .. newLen]);
T* pos = vector + length_; T* pos = vector + length_;
foreach (e; el) foreach (e; el)
{ {
@ -1270,11 +1276,7 @@ struct Vector(T)
} }
body body
{ {
const T* end = vector + j; fill(vector[i .. j], value);
for (T* v = vector + i; v != end; ++v)
{
*v = value;
}
return opSlice(i, j); return opSlice(i, j);
} }