From 87b74b2542131c5a7749e1a174d776aed2e7ddeb Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Mon, 9 Jan 2017 17:03:09 +0100 Subject: [PATCH] Fix reallocating the vector --- .gitignore | 2 + README.md | 9 ++-- source/tanya/container/vector.d | 90 +++++++++++++++++---------------- 3 files changed, 52 insertions(+), 49 deletions(-) diff --git a/.gitignore b/.gitignore index 44d9c69..1b841d8 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,6 @@ .dub __test__*__ __test__*__.core + /docs/ +/docs.json diff --git a/README.md b/README.md index 0666b27..77703f7 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,7 @@ [![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) -Tanya is a general purpose library for D programming language that doesn't -rely on the Garbage Collector. +Tanya is a general purpose library for D programming language. 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 @@ -36,12 +35,12 @@ helper functions). The library is currently under development, but some parts of it can already be 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 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 a stable API (that mostly consists of operator overloads), but still needs testing and work on its performance. diff --git a/source/tanya/container/vector.d b/source/tanya/container/vector.d index 51c2e0b..3d138eb 100644 --- a/source/tanya/container/vector.d +++ b/source/tanya/container/vector.d @@ -10,9 +10,11 @@ */ module tanya.container.vector; -import core.stdc.string; +import core.checkedint; import core.exception; +import core.stdc.string; import std.algorithm.comparison; +import std.algorithm.mutation; import std.conv; import std.range.primitives; import std.meta; @@ -297,30 +299,6 @@ struct Vector(T) 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). * @@ -364,7 +342,8 @@ struct Vector(T) { return; } - initialize(len); + reserve(len); + initializeAll(vector[0 .. len]); capacity_ = length_ = len; } @@ -385,9 +364,9 @@ struct Vector(T) { return; } - initialize(len); + reserve(len); + uninitializedFill(vector[0 .. len], init); capacity_ = length_ = len; - opSliceAssign(init, 0, length_); } /// Ditto. @@ -503,7 +482,8 @@ struct Vector(T) } else if (len > length_) { - initialize(len); + reserve(len); + initializeAll(vector[length_ .. len]); } else { @@ -549,13 +529,41 @@ struct Vector(T) */ void reserve(in size_t size) @trusted { - if (capacity_ < size) + if (capacity_ >= size) { - void[] buf = vector[0 .. capacity_]; - allocator.reallocate(buf, size * T.sizeof); - vector = cast(T*) buf; - capacity_ = size; + return; } + 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)) { reserve(length_ + el.length); - if (capacity_ <= length_) - { - onOutOfMemoryError(); - } foreach (i; el) { emplace(vector + length_, i); @@ -737,8 +741,10 @@ struct Vector(T) && isImplicitlyConvertible!(ElementType!R, T)) { immutable rLen = walkLength(el); + immutable newLen = length_ + rLen; - initialize(length_ + rLen); + reserve(newLen); + initializeAll(vector[length_ .. newLen]); T* pos = vector + length_; foreach (e; el) { @@ -1270,11 +1276,7 @@ struct Vector(T) } body { - const T* end = vector + j; - for (T* v = vector + i; v != end; ++v) - { - *v = value; - } + fill(vector[i .. j], value); return opSlice(i, j); }