Implement pure onOutOfMemory
This commit is contained in:
		| @@ -27,7 +27,10 @@ Tanya consists of the following packages and (top-level) modules: | |||||||
| * `async`: Event loop (epoll, kqueue and IOCP). | * `async`: Event loop (epoll, kqueue and IOCP). | ||||||
| * `container`: Queue, Array, Singly and doubly linked lists, Buffers, UTF-8 | * `container`: Queue, Array, Singly and doubly linked lists, Buffers, UTF-8 | ||||||
| string, Hash set. | string, Hash set. | ||||||
|  | * `conv`: This module provides functions for converting between different | ||||||
|  | types. | ||||||
| * `encoding`: This package provides tools to work with text encodings. | * `encoding`: This package provides tools to work with text encodings. | ||||||
|  | * `exception`: Common exceptions and errors. | ||||||
| * `format`: Formatting and conversion functions. | * `format`: Formatting and conversion functions. | ||||||
| * `math`: Arbitrary precision integer and a set of functions. | * `math`: Arbitrary precision integer and a set of functions. | ||||||
| * `memory`: Tools for manual memory management (allocators, smart pointers). | * `memory`: Tools for manual memory management (allocators, smart pointers). | ||||||
|   | |||||||
| @@ -15,11 +15,10 @@ | |||||||
| module tanya.container.array; | module tanya.container.array; | ||||||
|  |  | ||||||
| import core.checkedint; | import core.checkedint; | ||||||
| import core.exception; |  | ||||||
| import std.algorithm.comparison; | import std.algorithm.comparison; | ||||||
| import std.algorithm.mutation; | import std.algorithm.mutation; | ||||||
| import std.conv; |  | ||||||
| import std.meta; | import std.meta; | ||||||
|  | import tanya.exception; | ||||||
| import tanya.memory; | import tanya.memory; | ||||||
| import tanya.meta.trait; | import tanya.meta.trait; | ||||||
| import tanya.meta.transform; | import tanya.meta.transform; | ||||||
| @@ -501,7 +500,7 @@ struct Array(T) | |||||||
|             buf = allocator.allocate(byteSize); |             buf = allocator.allocate(byteSize); | ||||||
|             if (buf is null) |             if (buf is null) | ||||||
|             { |             { | ||||||
|                 onOutOfMemoryErrorNoGC(); |                 onOutOfMemoryError(); | ||||||
|             } |             } | ||||||
|             scope (failure) |             scope (failure) | ||||||
|             { |             { | ||||||
| @@ -708,9 +707,12 @@ struct Array(T) | |||||||
|     size_t insertBack(R)(ref R el) @trusted |     size_t insertBack(R)(ref R el) @trusted | ||||||
|         if (isImplicitlyConvertible!(R, T)) |         if (isImplicitlyConvertible!(R, T)) | ||||||
|     { |     { | ||||||
|         reserve(this.length_ + 1); |         this.length = this.length + 1; | ||||||
|         emplace(this.data + this.length_, el); |         scope (failure) | ||||||
|         ++this.length_; |         { | ||||||
|  |             this.length = this.length - 1; | ||||||
|  |         } | ||||||
|  |         opIndex(this.length - 1) = el; | ||||||
|         return 1; |         return 1; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -14,9 +14,9 @@ | |||||||
|  */ |  */ | ||||||
| module tanya.container.queue; | module tanya.container.queue; | ||||||
|  |  | ||||||
| import core.exception; |  | ||||||
| import std.algorithm.mutation; | import std.algorithm.mutation; | ||||||
| import tanya.container.entry; | import tanya.container.entry; | ||||||
|  | import tanya.exception; | ||||||
| import tanya.memory; | import tanya.memory; | ||||||
| import tanya.meta.trait; | import tanya.meta.trait; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -361,14 +361,14 @@ struct String | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// |     /// | ||||||
|     @safe @nogc unittest |     @nogc pure @safe unittest | ||||||
|     { |     { | ||||||
|         auto s = String("\u10437"w); |         auto s = String("\u10437"w); | ||||||
|         assert(s == "\u10437"); |         assert(s == "\u10437"); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// |     /// | ||||||
|     @safe @nogc unittest |     @nogc pure @safe unittest | ||||||
|     { |     { | ||||||
|         auto s = String("Отказаться от вина - в этом страшная вина."d); |         auto s = String("Отказаться от вина - в этом страшная вина."d); | ||||||
|         assert(s == "Отказаться от вина - в этом страшная вина."); |         assert(s == "Отказаться от вина - в этом страшная вина."); | ||||||
| @@ -392,8 +392,7 @@ struct String | |||||||
|      * |      * | ||||||
|      * Precondition: $(D_INLINECODE allocator is null). |      * Precondition: $(D_INLINECODE allocator is null). | ||||||
|      */ |      */ | ||||||
|     this(S)(S init, shared Allocator allocator = defaultAllocator) |     this(S)(S init, shared Allocator allocator = defaultAllocator) @trusted | ||||||
|     nothrow @trusted @nogc |  | ||||||
|     if (is(S == String)) |     if (is(S == String)) | ||||||
|     { |     { | ||||||
|         this(allocator); |         this(allocator); | ||||||
| @@ -417,8 +416,7 @@ struct String | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// ditto |     /// ditto | ||||||
|     this(S)(ref S init, shared Allocator allocator = defaultAllocator) |     this(S)(ref S init, shared Allocator allocator = defaultAllocator) @trusted | ||||||
|     nothrow @trusted @nogc |  | ||||||
|     if (is(Unqual!S == String)) |     if (is(Unqual!S == String)) | ||||||
|     { |     { | ||||||
|         this(allocator); |         this(allocator); | ||||||
| @@ -428,7 +426,7 @@ struct String | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// ditto |     /// ditto | ||||||
|     this(shared Allocator allocator) pure nothrow @safe @nogc |     this(shared Allocator allocator) @nogc nothrow pure @safe | ||||||
|     in |     in | ||||||
|     { |     { | ||||||
|         assert(allocator !is null); |         assert(allocator !is null); | ||||||
| @@ -478,7 +476,7 @@ struct String | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// |     /// | ||||||
|     @safe @nogc unittest |     @nogc pure @safe unittest | ||||||
|     { |     { | ||||||
|         { |         { | ||||||
|             auto s = String(1, 'О'); |             auto s = String(1, 'О'); | ||||||
| @@ -494,13 +492,13 @@ struct String | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @safe @nogc unittest |     @nogc pure @safe unittest | ||||||
|     { |     { | ||||||
|         auto s = String(0, 'K'); |         auto s = String(0, 'K'); | ||||||
|         assert(s.length == 0); |         assert(s.length == 0); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     this(this) @nogc nothrow @trusted |     this(this) @nogc nothrow pure @trusted | ||||||
|     { |     { | ||||||
|         auto buf = this.data[0 .. this.length_]; |         auto buf = this.data[0 .. this.length_]; | ||||||
|         this.length_ = capacity_ = 0; |         this.length_ = capacity_ = 0; | ||||||
| @@ -511,13 +509,13 @@ struct String | |||||||
|     /** |     /** | ||||||
|      * Destroys the string. |      * Destroys the string. | ||||||
|      */ |      */ | ||||||
|     ~this() nothrow @trusted @nogc |     ~this() @nogc nothrow pure @trusted | ||||||
|     { |     { | ||||||
|         allocator.resize(this.data[0 .. this.capacity_], 0); |         allocator.resize(this.data[0 .. this.capacity_], 0); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private void write4Bytes(ref const dchar src) |     private void write4Bytes(ref const dchar src) | ||||||
|     pure nothrow @trusted @nogc |     @nogc nothrow pure @trusted | ||||||
|     in |     in | ||||||
|     { |     { | ||||||
|         assert(capacity - length >= 4); |         assert(capacity - length >= 4); | ||||||
| @@ -578,7 +576,7 @@ struct String | |||||||
|      * |      * | ||||||
|      * Throws: $(D_PSYMBOL UTFException). |      * Throws: $(D_PSYMBOL UTFException). | ||||||
|      */ |      */ | ||||||
|     size_t insertBack(const char chr) @trusted @nogc |     size_t insertBack(const char chr) @nogc pure @trusted | ||||||
|     { |     { | ||||||
|         if ((chr & 0x80) != 0) |         if ((chr & 0x80) != 0) | ||||||
|         { |         { | ||||||
| @@ -593,7 +591,7 @@ struct String | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// ditto |     /// ditto | ||||||
|     size_t insertBack(const wchar chr) @trusted @nogc |     size_t insertBack(const wchar chr) @nogc pure @trusted | ||||||
|     { |     { | ||||||
|         reserve(length + 3); |         reserve(length + 3); | ||||||
|  |  | ||||||
| @@ -606,13 +604,13 @@ struct String | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     // Allocates enough space for 3-byte character. |     // Allocates enough space for 3-byte character. | ||||||
|     private @safe @nogc unittest |     @nogc pure @safe unittest | ||||||
|     { |     { | ||||||
|         String s; |         String s; | ||||||
|         s.insertBack('\u8100'); |         s.insertBack('\u8100'); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private @safe @nogc unittest |     @nogc pure @safe unittest | ||||||
|     { |     { | ||||||
|         UTFException exception; |         UTFException exception; | ||||||
|         try |         try | ||||||
| @@ -628,7 +626,7 @@ struct String | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// ditto |     /// ditto | ||||||
|     size_t insertBack(const dchar chr) @trusted @nogc |     size_t insertBack(const dchar chr) @nogc pure @trusted | ||||||
|     { |     { | ||||||
|         reserve(length + dchar.sizeof); |         reserve(length + dchar.sizeof); | ||||||
|  |  | ||||||
| @@ -648,7 +646,7 @@ struct String | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private @safe @nogc unittest |     @nogc pure @safe unittest | ||||||
|     { |     { | ||||||
|         UTFException exception; |         UTFException exception; | ||||||
|         try |         try | ||||||
| @@ -835,7 +833,7 @@ struct String | |||||||
|      * Params: |      * Params: | ||||||
|      *  size = Desired size in bytes. |      *  size = Desired size in bytes. | ||||||
|      */ |      */ | ||||||
|     void reserve(const size_t size) nothrow @trusted @nogc |     void reserve(const size_t size) @nogc nothrow pure @trusted | ||||||
|     { |     { | ||||||
|         if (this.capacity_ >= size) |         if (this.capacity_ >= size) | ||||||
|         { |         { | ||||||
| @@ -847,7 +845,7 @@ struct String | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// |     /// | ||||||
|     @nogc @safe unittest |     @nogc pure @safe unittest | ||||||
|     { |     { | ||||||
|         String s; |         String s; | ||||||
|         assert(s.capacity == 0); |         assert(s.capacity == 0); | ||||||
| @@ -871,7 +869,7 @@ struct String | |||||||
|      * Params: |      * Params: | ||||||
|      *  size = Desired size. |      *  size = Desired size. | ||||||
|      */ |      */ | ||||||
|     void shrink(const size_t size) nothrow @trusted @nogc |     void shrink(const size_t size) @nogc nothrow pure @trusted | ||||||
|     { |     { | ||||||
|         if (this.capacity_ <= size) |         if (this.capacity_ <= size) | ||||||
|         { |         { | ||||||
| @@ -888,7 +886,7 @@ struct String | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// |     /// | ||||||
|     @nogc @safe unittest |     @nogc pure @safe unittest | ||||||
|     { |     { | ||||||
|         auto s = String("Die Alten lasen laut."); |         auto s = String("Die Alten lasen laut."); | ||||||
|         assert(s.capacity == 21); |         assert(s.capacity == 21); | ||||||
| @@ -907,13 +905,13 @@ struct String | |||||||
|     /** |     /** | ||||||
|      * Returns: String capacity in bytes. |      * Returns: String capacity in bytes. | ||||||
|      */ |      */ | ||||||
|     @property size_t capacity() const pure nothrow @safe @nogc |     @property size_t capacity() const @nogc nothrow pure @safe | ||||||
|     { |     { | ||||||
|         return this.capacity_; |         return this.capacity_; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// |     /// | ||||||
|     @safe @nogc unittest |     @nogc pure @safe unittest | ||||||
|     { |     { | ||||||
|         auto s = String("In allem Schreiben ist Schamlosigkeit."); |         auto s = String("In allem Schreiben ist Schamlosigkeit."); | ||||||
|         assert(s.capacity == 38); |         assert(s.capacity == 38); | ||||||
| @@ -935,7 +933,7 @@ struct String | |||||||
|      */ |      */ | ||||||
|     ByCodeUnit!char opSliceAssign(R)(ByCodeUnit!R value, |     ByCodeUnit!char opSliceAssign(R)(ByCodeUnit!R value, | ||||||
|                                      const size_t i, |                                      const size_t i, | ||||||
|                                      const size_t j) @trusted |                                      const size_t j) | ||||||
|     if (is(Unqual!R == char)) |     if (is(Unqual!R == char)) | ||||||
|     in |     in | ||||||
|     { |     { | ||||||
| @@ -954,7 +952,7 @@ struct String | |||||||
|     ByCodeUnit!char opSliceAssign(const char[] value, |     ByCodeUnit!char opSliceAssign(const char[] value, | ||||||
|                                   const size_t i, |                                   const size_t i, | ||||||
|                                   const size_t j) |                                   const size_t j) | ||||||
|     pure nothrow @trusted @nogc |     @nogc nothrow pure @trusted | ||||||
|     in |     in | ||||||
|     { |     { | ||||||
|         assert(i <= j); |         assert(i <= j); | ||||||
| @@ -970,7 +968,7 @@ struct String | |||||||
|     ByCodeUnit!char opSliceAssign(const char value, |     ByCodeUnit!char opSliceAssign(const char value, | ||||||
|                                   const size_t i, |                                   const size_t i, | ||||||
|                                   const size_t j) |                                   const size_t j) | ||||||
|     pure nothrow @trusted @nogc |     @nogc nothrow pure @trusted | ||||||
|     in |     in | ||||||
|     { |     { | ||||||
|         assert(i <= j); |         assert(i <= j); | ||||||
| @@ -992,13 +990,13 @@ struct String | |||||||
|      * |      * | ||||||
|      * Returns: The array representing the string. |      * Returns: The array representing the string. | ||||||
|      */ |      */ | ||||||
|     inout(char)[] get() inout pure nothrow @trusted @nogc |     inout(char)[] get() inout @nogc nothrow pure @trusted | ||||||
|     { |     { | ||||||
|         return this.data[0 .. this.length_]; |         return this.data[0 .. this.length_]; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// |     /// | ||||||
|     nothrow @safe @nogc unittest |     @nogc nothrow pure @safe unittest | ||||||
|     { |     { | ||||||
|         auto s = String("Char array."); |         auto s = String("Char array."); | ||||||
|         assert(s.get().length == 11); |         assert(s.get().length == 11); | ||||||
| @@ -1010,7 +1008,7 @@ struct String | |||||||
|      * |      * | ||||||
|      * Returns: Null-terminated string. |      * Returns: Null-terminated string. | ||||||
|      */ |      */ | ||||||
|     const(char)* toStringz() nothrow @nogc |     const(char)* toStringz() @nogc nothrow pure | ||||||
|     { |     { | ||||||
|         reserve(length + 1); |         reserve(length + 1); | ||||||
|         this.data[length] = '\0'; |         this.data[length] = '\0'; | ||||||
| @@ -1018,7 +1016,7 @@ struct String | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// |     /// | ||||||
|     @nogc unittest |     @nogc pure unittest | ||||||
|     { |     { | ||||||
|         auto s = String("C string."); |         auto s = String("C string."); | ||||||
|         assert(s.toStringz()[0] == 'C'); |         assert(s.toStringz()[0] == 'C'); | ||||||
| @@ -1028,7 +1026,7 @@ struct String | |||||||
|     /** |     /** | ||||||
|      * Returns: The number of code units that are required to encode the string. |      * Returns: The number of code units that are required to encode the string. | ||||||
|      */ |      */ | ||||||
|     @property size_t length() const pure nothrow @safe @nogc |     @property size_t length() const @nogc nothrow pure @safe | ||||||
|     { |     { | ||||||
|         return this.length_; |         return this.length_; | ||||||
|     } |     } | ||||||
| @@ -1037,7 +1035,7 @@ struct String | |||||||
|     alias opDollar = length; |     alias opDollar = length; | ||||||
|  |  | ||||||
|     /// |     /// | ||||||
|     @safe @nogc unittest |     @nogc pure @safe unittest | ||||||
|     { |     { | ||||||
|         auto s = String("Piscis primuin a capite foetat."); |         auto s = String("Piscis primuin a capite foetat."); | ||||||
|         assert(s.length == 31); |         assert(s.length == 31); | ||||||
| @@ -1052,7 +1050,7 @@ struct String | |||||||
|      * |      * | ||||||
|      * Precondition: $(D_INLINECODE length > pos). |      * Precondition: $(D_INLINECODE length > pos). | ||||||
|      */ |      */ | ||||||
|     ref inout(char) opIndex(const size_t pos) inout pure nothrow @trusted @nogc |     ref inout(char) opIndex(const size_t pos) inout @nogc nothrow pure @trusted | ||||||
|     in |     in | ||||||
|     { |     { | ||||||
|         assert(length > pos); |         assert(length > pos); | ||||||
| @@ -1063,7 +1061,7 @@ struct String | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// |     /// | ||||||
|     @safe @nogc unittest |     @nogc pure @safe unittest | ||||||
|     { |     { | ||||||
|         auto s = String("Alea iacta est."); |         auto s = String("Alea iacta est."); | ||||||
|         assert(s[0] == 'A'); |         assert(s[0] == 'A'); | ||||||
| @@ -1074,7 +1072,7 @@ struct String | |||||||
|      * Returns: Random access range that iterates over the string by bytes, in |      * Returns: Random access range that iterates over the string by bytes, in | ||||||
|      *          forward order. |      *          forward order. | ||||||
|      */ |      */ | ||||||
|     ByCodeUnit!char opIndex() pure nothrow @trusted @nogc |     ByCodeUnit!char opIndex() @nogc nothrow pure @trusted | ||||||
|     { |     { | ||||||
|         return typeof(return)(this, this.data, this.data + length); |         return typeof(return)(this, this.data, this.data + length); | ||||||
|     } |     } | ||||||
| @@ -1086,7 +1084,7 @@ struct String | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// |     /// | ||||||
|     @safe @nogc unittest |     @nogc pure @safe unittest | ||||||
|     { |     { | ||||||
|         auto s = String("Plutarchus"); |         auto s = String("Plutarchus"); | ||||||
|         auto r = s[]; |         auto r = s[]; | ||||||
| @@ -1104,22 +1102,35 @@ struct String | |||||||
|         assert(r.length == 8); |         assert(r.length == 8); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// | ||||||
|  |     @nogc pure @safe unittest | ||||||
|  |     { | ||||||
|  |         auto s = const String("Was ich vermag, soll gern geschehen. Goethe"); | ||||||
|  |         auto r1 = s[]; | ||||||
|  |         assert(r1.front == 'W'); | ||||||
|  |  | ||||||
|  |         auto r2 = r1[]; | ||||||
|  |         r1.popFront(); | ||||||
|  |         assert(r1.front == 'a'); | ||||||
|  |         assert(r2.front == 'W'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Returns: Forward range that iterates over the string by code points. |      * Returns: Forward range that iterates over the string by code points. | ||||||
|      */ |      */ | ||||||
|     ByCodePoint!char byCodePoint() pure nothrow @trusted @nogc |     ByCodePoint!char byCodePoint() @nogc nothrow pure @trusted | ||||||
|     { |     { | ||||||
|         return typeof(return)(this, this.data, this.data + length); |         return typeof(return)(this, this.data, this.data + length); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// ditto |     /// ditto | ||||||
|     ByCodePoint!(const char) byCodePoint() const pure nothrow @trusted @nogc |     ByCodePoint!(const char) byCodePoint() const @nogc nothrow pure @trusted | ||||||
|     { |     { | ||||||
|         return typeof(return)(this, this.data, this.data + length); |         return typeof(return)(this, this.data, this.data + length); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// |     /// | ||||||
|     @nogc @safe unittest |     @nogc pure @safe unittest | ||||||
|     { |     { | ||||||
|         auto s = String("Мне есть, что спеть, представ перед Всевышним."); |         auto s = String("Мне есть, что спеть, представ перед Всевышним."); | ||||||
|         auto cp = s.byCodePoint(); |         auto cp = s.byCodePoint(); | ||||||
| @@ -1139,7 +1150,7 @@ struct String | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// |     /// | ||||||
|     @nogc @safe unittest |     @nogc pure @safe unittest | ||||||
|     { |     { | ||||||
|         auto s = const String("Высоцкий"); |         auto s = const String("Высоцкий"); | ||||||
|         auto cp1 = s.byCodePoint(); |         auto cp1 = s.byCodePoint(); | ||||||
| @@ -1157,15 +1168,18 @@ struct String | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Returns: $(D_KEYWORD true) if the string is empty. |      * Returns whether the string is empty. | ||||||
|  |      * | ||||||
|  |      * Returns: $(D_KEYWORD true) if the string is empty, $(D_KEYWORD false) | ||||||
|  |      *          otherwise. | ||||||
|      */ |      */ | ||||||
|     @property bool empty() const pure nothrow @safe @nogc |     @property bool empty() const @nogc nothrow pure @safe | ||||||
|     { |     { | ||||||
|         return length == 0; |         return length == 0; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// |     /// | ||||||
|     @safe @nogc unittest |     @nogc pure @safe unittest | ||||||
|     { |     { | ||||||
|         String s; |         String s; | ||||||
|         assert(s.empty); |         assert(s.empty); | ||||||
| @@ -1185,7 +1199,7 @@ struct String | |||||||
|      * Precondition: $(D_INLINECODE i <= j && j <= length). |      * Precondition: $(D_INLINECODE i <= j && j <= length). | ||||||
|      */ |      */ | ||||||
|     ByCodeUnit!char opSlice(const size_t i, const size_t j) |     ByCodeUnit!char opSlice(const size_t i, const size_t j) | ||||||
|     pure nothrow @trusted @nogc |     @nogc nothrow pure @trusted | ||||||
|     in |     in | ||||||
|     { |     { | ||||||
|         assert(i <= j); |         assert(i <= j); | ||||||
| @@ -1198,7 +1212,7 @@ struct String | |||||||
|  |  | ||||||
|     /// ditto |     /// ditto | ||||||
|     ByCodeUnit!(const char) opSlice(const size_t i, const size_t j) |     ByCodeUnit!(const char) opSlice(const size_t i, const size_t j) | ||||||
|     const pure nothrow @trusted @nogc |     const @nogc nothrow pure @trusted | ||||||
|     in |     in | ||||||
|     { |     { | ||||||
|         assert(i <= j); |         assert(i <= j); | ||||||
| @@ -1210,7 +1224,7 @@ struct String | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// |     /// | ||||||
|     @safe @nogc unittest |     @nogc pure @safe unittest | ||||||
|     { |     { | ||||||
|         auto s = String("Vladimir Soloviev"); |         auto s = String("Vladimir Soloviev"); | ||||||
|         auto r = s[9 .. $]; |         auto r = s[9 .. $]; | ||||||
| @@ -1274,7 +1288,7 @@ struct String | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// |     /// | ||||||
|     @safe @nogc unittest |     @nogc pure @safe unittest | ||||||
|     { |     { | ||||||
|         auto s = String("Черная, потом пропахшая выть!"); |         auto s = String("Черная, потом пропахшая выть!"); | ||||||
|         s = String("Как мне тебя не ласкать, не любить?"); |         s = String("Как мне тебя не ласкать, не любить?"); | ||||||
| @@ -1291,7 +1305,7 @@ struct String | |||||||
|      * |      * | ||||||
|      * Throws: $(D_PSYMBOL UTFException). |      * Throws: $(D_PSYMBOL UTFException). | ||||||
|      */ |      */ | ||||||
|     ref String opAssign(S)(S that) nothrow |     ref String opAssign(S)(S that) | ||||||
|     if (!isInfinite!S |     if (!isInfinite!S | ||||||
|      && isInputRange!S |      && isInputRange!S | ||||||
|      && isSomeChar!(ElementType!S)) |      && isSomeChar!(ElementType!S)) | ||||||
| @@ -1302,7 +1316,7 @@ struct String | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// |     /// | ||||||
|     @safe @nogc unittest |     @nogc pure @safe unittest | ||||||
|     { |     { | ||||||
|         auto s = String("Оловом светится лужная голь..."); |         auto s = String("Оловом светится лужная голь..."); | ||||||
|         s = "Грустная песня, ты - русская боль."; |         s = "Грустная песня, ты - русская боль."; | ||||||
| @@ -1347,7 +1361,7 @@ struct String | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// |     /// | ||||||
|     @safe @nogc unittest |     @nogc pure @safe unittest | ||||||
|     { |     { | ||||||
|         assert(String("Голубая кофта.") < String("Синие глаза.")); |         assert(String("Голубая кофта.") < String("Синие глаза.")); | ||||||
|         assert(String("Никакой я правды") < String("милой не сказал")[]); |         assert(String("Никакой я правды") < String("милой не сказал")[]); | ||||||
| @@ -1400,7 +1414,7 @@ struct String | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// |     /// | ||||||
|     @safe @nogc unittest |     @nogc pure @safe unittest | ||||||
|     { |     { | ||||||
|         assert(String("Милая спросила:") != String("Крутит ли метель?")); |         assert(String("Милая спросила:") != String("Крутит ли метель?")); | ||||||
|         assert(String("Затопить бы печку,") != String("постелить постель.")[]); |         assert(String("Затопить бы печку,") != String("постелить постель.")[]); | ||||||
| @@ -1427,13 +1441,13 @@ struct String | |||||||
|      * Precondition: $(D_INLINECODE length > pos). |      * Precondition: $(D_INLINECODE length > pos). | ||||||
|      */ |      */ | ||||||
|     ref char opIndexAssign(const char value, const size_t pos) |     ref char opIndexAssign(const char value, const size_t pos) | ||||||
|     pure nothrow @safe @nogc |     @nogc nothrow pure @safe | ||||||
|     { |     { | ||||||
|         return opIndex(pos) = value; |         return opIndex(pos) = value; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// |     /// | ||||||
|     @safe @nogc unittest |     @nogc pure @safe unittest | ||||||
|     { |     { | ||||||
|         auto s = String("alea iacta est."); |         auto s = String("alea iacta est."); | ||||||
|  |  | ||||||
| @@ -1458,7 +1472,7 @@ struct String | |||||||
|         return opSliceAssign(value, 0, length); |         return opSliceAssign(value, 0, length); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private unittest |     @nogc pure @safe unittest | ||||||
|     { |     { | ||||||
|         auto s1 = String("Buttercup"); |         auto s1 = String("Buttercup"); | ||||||
|         auto s2 = String("Cap"); |         auto s2 = String("Cap"); | ||||||
| @@ -1467,12 +1481,12 @@ struct String | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// ditto |     /// ditto | ||||||
|     ByCodeUnit!char opIndexAssign(const char value) pure nothrow @safe @nogc |     ByCodeUnit!char opIndexAssign(const char value) @nogc nothrow pure @safe | ||||||
|     { |     { | ||||||
|         return opSliceAssign(value, 0, length); |         return opSliceAssign(value, 0, length); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private unittest |     @nogc pure @safe unittest | ||||||
|     { |     { | ||||||
|         auto s1 = String("Wow"); |         auto s1 = String("Wow"); | ||||||
|         s1[] = 'a'; |         s1[] = 'a'; | ||||||
| @@ -1480,12 +1494,12 @@ struct String | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// ditto |     /// ditto | ||||||
|     ByCodeUnit!char opIndexAssign(const char[] value) pure nothrow @safe @nogc |     ByCodeUnit!char opIndexAssign(const char[] value) @nogc nothrow pure @safe | ||||||
|     { |     { | ||||||
|         return opSliceAssign(value, 0, length); |         return opSliceAssign(value, 0, length); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private unittest |     @nogc pure @safe unittest | ||||||
|     { |     { | ||||||
|         auto s1 = String("ö"); |         auto s1 = String("ö"); | ||||||
|         s1[] = "oe"; |         s1[] = "oe"; | ||||||
| @@ -1521,7 +1535,7 @@ struct String | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// |     /// | ||||||
|     @nogc @safe unittest |     @nogc pure @safe unittest | ||||||
|     { |     { | ||||||
|         auto s = String("Из пословицы слова не выкинешь."); |         auto s = String("Из пословицы слова не выкинешь."); | ||||||
|  |  | ||||||
| @@ -1575,7 +1589,7 @@ struct String | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// |     /// | ||||||
|     @safe @nogc unittest |     @nogc pure @safe unittest | ||||||
|     { |     { | ||||||
|         auto s = String("Казнить нельзя помиловать."); |         auto s = String("Казнить нельзя помиловать."); | ||||||
|         s.insertAfter(s[0 .. 27], ","); |         s.insertAfter(s[0 .. 27], ","); | ||||||
| @@ -1604,7 +1618,7 @@ struct String | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// |     /// | ||||||
|     @safe @nogc unittest |     @nogc pure @safe unittest | ||||||
|     { |     { | ||||||
|         auto s = String("Казнить нельзя помиловать."); |         auto s = String("Казнить нельзя помиловать."); | ||||||
|         s.insertBefore(s[27 .. $], ","); |         s.insertBefore(s[27 .. $], ","); | ||||||
| @@ -1619,7 +1633,7 @@ struct String | |||||||
| } | } | ||||||
|  |  | ||||||
| // Postblit works. | // Postblit works. | ||||||
| @nogc @safe unittest | @nogc pure @safe unittest | ||||||
| { | { | ||||||
|     void internFunc(String arg) |     void internFunc(String arg) | ||||||
|     { |     { | ||||||
|   | |||||||
							
								
								
									
										235
									
								
								source/tanya/conv.d
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										235
									
								
								source/tanya/conv.d
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,235 @@ | |||||||
|  | /* 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/. */ | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * This module provides functions for converting between different types. | ||||||
|  |  * | ||||||
|  |  * 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) | ||||||
|  |  * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/conv.d, | ||||||
|  |  *                 tanya/conv.d) | ||||||
|  |  */ | ||||||
|  | module tanya.conv; | ||||||
|  |  | ||||||
|  | import tanya.memory; | ||||||
|  | import tanya.memory.op; | ||||||
|  | import tanya.meta.trait; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Constructs a new object of type $(D_PARAM T) in $(D_PARAM memory) with the | ||||||
|  |  * given arguments. | ||||||
|  |  * | ||||||
|  |  * If $(D_PARAM T) is a $(D_KEYWORD class), emplace returns a class reference | ||||||
|  |  * of type $(D_PARAM T), otherwise a pointer to the constructed object is | ||||||
|  |  * returned. | ||||||
|  |  * | ||||||
|  |  * If $(D_PARAM T) is a nested class inside another class, $(D_PARAM outer) | ||||||
|  |  * should be an instance of the outer class. | ||||||
|  |  * | ||||||
|  |  * $(D_PARAM args) are arguments for the constructor of $(D_PARAM T). If | ||||||
|  |  * $(D_PARAM T) isn't an aggregate type and doesn't have a constructor, | ||||||
|  |  * $(D_PARAM memory) can be initialized to `args[0]` if `Args.length == 1`, | ||||||
|  |  * `Args[0]` should be implicitly convertible to $(D_PARAM T) then. | ||||||
|  |  * | ||||||
|  |  * Params: | ||||||
|  |  *  T     = Constructed type. | ||||||
|  |  *  U     = Type of the outer class if $(D_PARAM T) is a nested class. | ||||||
|  |  *  Args  = Types of the constructor arguments if $(D_PARAM T) has a constructor | ||||||
|  |  *          or the type of the initial value. | ||||||
|  |  *  outer = Outer class instance if $(D_PARAM T) is a nested class. | ||||||
|  |  *  args  = Constructor arguments if $(D_PARAM T) has a constructor or the | ||||||
|  |  *          initial value. | ||||||
|  |  * | ||||||
|  |  * Returns: New instance of type $(D_PARAM T) constructed in $(D_PARAM memory). | ||||||
|  |  * | ||||||
|  |  * Precondition: `memory.length == stateSize!T`. | ||||||
|  |  * Postcondition: $(D_PARAM memory) and the result point to the same memory. | ||||||
|  |  */ | ||||||
|  | T emplace(T, U, Args...)(void[] memory, U outer, auto ref Args args) | ||||||
|  | if (!isAbstractClass!T && isInnerClass!T && is(typeof(T.outer) == U)) | ||||||
|  | in | ||||||
|  | { | ||||||
|  |     assert(memory.length >= stateSize!T); | ||||||
|  | } | ||||||
|  | out (result) | ||||||
|  | { | ||||||
|  |     assert(memory.ptr is (() @trusted => cast(void*) result)()); | ||||||
|  | } | ||||||
|  | body | ||||||
|  | { | ||||||
|  |     copy(typeid(T).initializer, memory); | ||||||
|  |  | ||||||
|  |     auto result = (() @trusted => cast(T) memory.ptr)(); | ||||||
|  |     result.outer = outer; | ||||||
|  |  | ||||||
|  |     static if (is(typeof(result.__ctor(args)))) | ||||||
|  |     { | ||||||
|  |         result.__ctor(args); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// ditto | ||||||
|  | T emplace(T, Args...)(void[] memory, auto ref Args args) | ||||||
|  | if (is(T == class) && !isAbstractClass!T && !isInnerClass!T) | ||||||
|  | in | ||||||
|  | { | ||||||
|  |     assert(memory.length == stateSize!T); | ||||||
|  | } | ||||||
|  | out (result) | ||||||
|  | { | ||||||
|  |     assert(memory.ptr is (() @trusted => cast(void*) result)()); | ||||||
|  | }body | ||||||
|  | { | ||||||
|  |     copy(typeid(T).initializer, memory); | ||||||
|  |  | ||||||
|  |     auto result = (() @trusted => cast(T) memory.ptr)(); | ||||||
|  |     static if (is(typeof(result.__ctor(args)))) | ||||||
|  |     { | ||||||
|  |         result.__ctor(args); | ||||||
|  |     } | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// | ||||||
|  | @nogc nothrow pure @safe unittest | ||||||
|  | { | ||||||
|  |     import tanya.memory : stateSize; | ||||||
|  |  | ||||||
|  |     class C | ||||||
|  |     { | ||||||
|  |         int i = 5; | ||||||
|  |         class Inner | ||||||
|  |         { | ||||||
|  |             int i; | ||||||
|  |  | ||||||
|  |             this(int param) pure nothrow @safe @nogc | ||||||
|  |             { | ||||||
|  |                 this.i = param; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     ubyte[stateSize!C] memory1; | ||||||
|  |     ubyte[stateSize!(C.Inner)] memory2; | ||||||
|  |  | ||||||
|  |     auto c = emplace!C(memory1); | ||||||
|  |     assert(c.i == 5); | ||||||
|  |  | ||||||
|  |     auto inner = emplace!(C.Inner)(memory2, c, 8); | ||||||
|  |     assert(c.i == 5); | ||||||
|  |     assert(inner.i == 8); | ||||||
|  |     assert(inner.outer is c); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// ditto | ||||||
|  | T* emplace(T, Args...)(void[] memory, auto ref Args args) | ||||||
|  | if (!isAggregateType!T && (Args.length <= 1)) | ||||||
|  | in | ||||||
|  | { | ||||||
|  |     assert(memory.length >= T.sizeof); | ||||||
|  | } | ||||||
|  | out (result) | ||||||
|  | { | ||||||
|  |     assert(memory.ptr is result); | ||||||
|  | } | ||||||
|  | body | ||||||
|  | { | ||||||
|  |     auto result = (() @trusted => cast(T*) memory.ptr)(); | ||||||
|  |     static if (Args.length == 1) | ||||||
|  |     { | ||||||
|  |         *result = T(args[0]); | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |         *result = T.init; | ||||||
|  |     } | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// ditto | ||||||
|  | T* emplace(T, Args...)(void[] memory, auto ref Args args) | ||||||
|  | if (!isPolymorphicType!T && isAggregateType!T) | ||||||
|  | in | ||||||
|  | { | ||||||
|  |     assert(memory.length >= T.sizeof); | ||||||
|  | } | ||||||
|  | out (result) | ||||||
|  | { | ||||||
|  |     assert(memory.ptr is result); | ||||||
|  | } | ||||||
|  | body | ||||||
|  | { | ||||||
|  |     auto result = (() @trusted => cast(T*) memory.ptr)(); | ||||||
|  |     static if (!hasElaborateAssign!T && isAssignable!T) | ||||||
|  |     { | ||||||
|  |         *result = T.init; | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |         static const T init = T.init; | ||||||
|  |         copy((cast(void*) &init)[0 .. T.sizeof], memory); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     static if (Args.length == 0) | ||||||
|  |     { | ||||||
|  |         static assert(is(typeof({ static T t; })), | ||||||
|  |                       "Default constructor is disabled"); | ||||||
|  |     } | ||||||
|  |     else static if (is(typeof(T(args)))) | ||||||
|  |     { | ||||||
|  |         *result = T(args); | ||||||
|  |     } | ||||||
|  |     else static if (is(typeof(result.__ctor(args)))) | ||||||
|  |     { | ||||||
|  |         result.__ctor(args); | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |         static assert(false, | ||||||
|  |                       "Unable to construct value with the given arguments"); | ||||||
|  |     } | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// | ||||||
|  | @nogc nothrow pure @safe unittest | ||||||
|  | { | ||||||
|  |     ubyte[4] memory; | ||||||
|  |  | ||||||
|  |     auto i = emplace!int(memory); | ||||||
|  |     static assert(is(typeof(i) == int*)); | ||||||
|  |     assert(*i == 0); | ||||||
|  |  | ||||||
|  |     i = emplace!int(memory, 5); | ||||||
|  |     assert(*i == 5); | ||||||
|  |  | ||||||
|  |     static struct S | ||||||
|  |     { | ||||||
|  |         int i; | ||||||
|  |         @disable this(); | ||||||
|  |         @disable this(this); | ||||||
|  |         this(int i) @nogc nothrow pure @safe | ||||||
|  |         { | ||||||
|  |             this.i = i; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     auto s = emplace!S(memory, 8); | ||||||
|  |     static assert(is(typeof(s) == S*)); | ||||||
|  |     assert(s.i == 8); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Handles "Cannot access frame pointer" error. | ||||||
|  | @nogc nothrow pure @safe unittest | ||||||
|  | { | ||||||
|  |     struct F | ||||||
|  |     { | ||||||
|  |         ~this() @nogc nothrow pure @safe | ||||||
|  |         { | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     static assert(is(typeof(emplace!F((void[]).init)))); | ||||||
|  | } | ||||||
							
								
								
									
										66
									
								
								source/tanya/exception.d
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								source/tanya/exception.d
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,66 @@ | |||||||
|  | /* 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/. */ | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Common exceptions and errors. | ||||||
|  |  * | ||||||
|  |  * 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) | ||||||
|  |  * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/exception.d, | ||||||
|  |  *                 tanya/exception.d) | ||||||
|  |  */ | ||||||
|  | module tanya.exception; | ||||||
|  |  | ||||||
|  | import tanya.conv; | ||||||
|  | import tanya.memory; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Error thrown if memory allocation fails. | ||||||
|  |  */ | ||||||
|  | final class OutOfMemoryError : Error | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Constructs new error. | ||||||
|  |      * | ||||||
|  |      * Params: | ||||||
|  |      *  msg  = The message for the exception. | ||||||
|  |      *  file = The file where the exception occurred. | ||||||
|  |      *  line = The line number where the exception occurred. | ||||||
|  |      *  next = The previous exception in the chain of exceptions, if any. | ||||||
|  |      */ | ||||||
|  |     this(string msg = "Out of memory", | ||||||
|  |          string file = __FILE__, | ||||||
|  |          size_t line = __LINE__, | ||||||
|  |          Throwable next = null) @nogc nothrow pure @safe | ||||||
|  |     { | ||||||
|  |         super(msg, file, line, next); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// ditto | ||||||
|  |     this(string msg, | ||||||
|  |          Throwable next, | ||||||
|  |          string file = __FILE__, | ||||||
|  |          size_t line = __LINE__) @nogc nothrow pure @safe | ||||||
|  |     { | ||||||
|  |         super(msg, file, line, next); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Allocates $(D_PSYMBOL OutOfMemoryError) in a static storage and throws it. | ||||||
|  |  * | ||||||
|  |  * Params: | ||||||
|  |  *  msg = Custom error message. | ||||||
|  |  * | ||||||
|  |  * Throws: $(D_PSYMBOL OutOfMemoryError). | ||||||
|  |  */ | ||||||
|  | void onOutOfMemoryError(string msg = "Out of memory") | ||||||
|  | @nogc nothrow pure @trusted | ||||||
|  | { | ||||||
|  |     static ubyte[stateSize!OutOfMemoryError] memory; | ||||||
|  |     alias PureType = OutOfMemoryError function(string) @nogc nothrow pure; | ||||||
|  |     throw (cast(PureType) () => emplace!OutOfMemoryError(memory))(msg); | ||||||
|  | } | ||||||
| @@ -14,10 +14,10 @@ | |||||||
|  */ |  */ | ||||||
| module tanya.memory; | module tanya.memory; | ||||||
|  |  | ||||||
| import core.exception; |  | ||||||
| import std.algorithm.iteration; | import std.algorithm.iteration; | ||||||
| import std.algorithm.mutation; | import std.algorithm.mutation; | ||||||
| import std.conv; | import tanya.conv; | ||||||
|  | import tanya.exception; | ||||||
| public import tanya.memory.allocator; | public import tanya.memory.allocator; | ||||||
| import tanya.memory.mmappool; | import tanya.memory.mmappool; | ||||||
| import tanya.meta.trait; | import tanya.meta.trait; | ||||||
| @@ -229,14 +229,14 @@ package(tanya) T[] resize(T)(shared Allocator allocator, | |||||||
|         } |         } | ||||||
|         else |         else | ||||||
|         { |         { | ||||||
|             onOutOfMemoryErrorNoGC(); |             onOutOfMemoryError(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void[] buf = array; |     void[] buf = array; | ||||||
|     if (!allocator.reallocate(buf, length * T.sizeof)) |     if (!allocator.reallocate(buf, length * T.sizeof)) | ||||||
|     { |     { | ||||||
|         onOutOfMemoryErrorNoGC(); |         onOutOfMemoryError(); | ||||||
|     } |     } | ||||||
|     // Casting from void[] is unsafe, but we know we cast to the original type. |     // Casting from void[] is unsafe, but we know we cast to the original type. | ||||||
|     array = cast(T[]) buf; |     array = cast(T[]) buf; | ||||||
| @@ -453,9 +453,7 @@ body | |||||||
|     { |     { | ||||||
|         () @trusted { allocator.deallocate(mem); }(); |         () @trusted { allocator.deallocate(mem); }(); | ||||||
|     } |     } | ||||||
|  |     return emplace!T(mem[0 .. stateSize!T], args); | ||||||
|     auto ptr = (() @trusted => (cast(T*) mem[0 .. stateSize!T].ptr))(); |  | ||||||
|     return emplace!T(ptr, args); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| /// | /// | ||||||
|   | |||||||
| @@ -6,7 +6,13 @@ | |||||||
|  * Smart pointers. |  * Smart pointers. | ||||||
|  * |  * | ||||||
|  * A smart pointer is an object that wraps a raw pointer or a reference |  * A smart pointer is an object that wraps a raw pointer or a reference | ||||||
|  * (class, array) to manage its lifetime. |  * (class, dynamic array) to manage its lifetime. | ||||||
|  |  * | ||||||
|  |  * This module provides two kinds of lifetime management strategies: | ||||||
|  |  * $(UL | ||||||
|  |  *  $(LI Reference counting) | ||||||
|  |  *  $(LI Unique ownership) | ||||||
|  |  * ) | ||||||
|  * |  * | ||||||
|  * Copyright: Eugene Wissner 2016-2017. |  * Copyright: Eugene Wissner 2016-2017. | ||||||
|  * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, |  * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, | ||||||
| @@ -17,17 +23,17 @@ | |||||||
|  */ |  */ | ||||||
| module tanya.memory.smartref; | module tanya.memory.smartref; | ||||||
|  |  | ||||||
| import core.exception; |  | ||||||
| import std.algorithm.comparison; | import std.algorithm.comparison; | ||||||
| import std.algorithm.mutation; | import std.algorithm.mutation; | ||||||
| import std.conv; | import tanya.conv; | ||||||
|  | import tanya.exception; | ||||||
| import tanya.memory; | import tanya.memory; | ||||||
| import tanya.meta.trait; | import tanya.meta.trait; | ||||||
| import tanya.range.primitive; | import tanya.range.primitive; | ||||||
|  |  | ||||||
| private template Payload(T) | private template Payload(T) | ||||||
| { | { | ||||||
|     static if (is(T == class) || is(T == interface) || isArray!T) |     static if (isPolymorphicType!T || isArray!T) | ||||||
|     { |     { | ||||||
|         alias Payload = T; |         alias Payload = T; | ||||||
|     } |     } | ||||||
| @@ -202,13 +208,6 @@ struct RefCounted(T) | |||||||
|         return this; |         return this; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private @nogc unittest |  | ||||||
|     { |  | ||||||
|         auto rc = defaultAllocator.refCounted!int(5); |  | ||||||
|         rc = defaultAllocator.make!int(7); |  | ||||||
|         assert(*rc == 7); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// ditto |     /// ditto | ||||||
|     ref typeof(this) opAssign(typeof(null)) |     ref typeof(this) opAssign(typeof(null)) | ||||||
|     { |     { | ||||||
| @@ -229,14 +228,6 @@ struct RefCounted(T) | |||||||
|         return this; |         return this; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private @nogc unittest |  | ||||||
|     { |  | ||||||
|         RefCounted!int rc; |  | ||||||
|         assert(!rc.isInitialized); |  | ||||||
|         rc = null; |  | ||||||
|         assert(!rc.isInitialized); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// ditto |     /// ditto | ||||||
|     ref typeof(this) opAssign(typeof(this) rhs) |     ref typeof(this) opAssign(typeof(this) rhs) | ||||||
|     { |     { | ||||||
| @@ -308,7 +299,7 @@ struct RefCounted(T) | |||||||
| } | } | ||||||
|  |  | ||||||
| /// | /// | ||||||
| unittest | @nogc @system unittest | ||||||
| { | { | ||||||
|     auto rc = RefCounted!int(defaultAllocator.make!int(5), defaultAllocator); |     auto rc = RefCounted!int(defaultAllocator.make!int(5), defaultAllocator); | ||||||
|     auto val = rc.get(); |     auto val = rc.get(); | ||||||
| @@ -324,7 +315,22 @@ unittest | |||||||
|     assert(*rc.storage.payload == 9); |     assert(*rc.storage.payload == 9); | ||||||
| } | } | ||||||
|  |  | ||||||
| private @nogc unittest | @nogc @system unittest | ||||||
|  | { | ||||||
|  |     auto rc = defaultAllocator.refCounted!int(5); | ||||||
|  |     rc = defaultAllocator.make!int(7); | ||||||
|  |     assert(*rc == 7); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @nogc @system unittest | ||||||
|  | { | ||||||
|  |     RefCounted!int rc; | ||||||
|  |     assert(!rc.isInitialized); | ||||||
|  |     rc = null; | ||||||
|  |     assert(!rc.isInitialized); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @nogc @system unittest | ||||||
| { | { | ||||||
|     auto rc = defaultAllocator.refCounted!int(5); |     auto rc = defaultAllocator.refCounted!int(5); | ||||||
|  |  | ||||||
| @@ -340,7 +346,7 @@ private @nogc unittest | |||||||
|     assert(*rc == 5); |     assert(*rc == 5); | ||||||
| } | } | ||||||
|  |  | ||||||
| private @nogc unittest | @nogc @system unittest | ||||||
| { | { | ||||||
|     RefCounted!int rc; |     RefCounted!int rc; | ||||||
|  |  | ||||||
| @@ -355,7 +361,7 @@ private @nogc unittest | |||||||
|     assert(rc.count == 0); |     assert(rc.count == 0); | ||||||
| } | } | ||||||
|  |  | ||||||
| private unittest | @nogc @system unittest | ||||||
| { | { | ||||||
|     RefCounted!int rc1, rc2; |     RefCounted!int rc1, rc2; | ||||||
|     static assert(is(typeof(rc1 = rc2))); |     static assert(is(typeof(rc1 = rc2))); | ||||||
| @@ -389,7 +395,7 @@ version (unittest) | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| private @nogc unittest | @nogc @system unittest | ||||||
| { | { | ||||||
|     uint destroyed; |     uint destroyed; | ||||||
|     auto a = defaultAllocator.make!A(destroyed); |     auto a = defaultAllocator.make!A(destroyed); | ||||||
| @@ -399,7 +405,7 @@ private @nogc unittest | |||||||
|         auto rc = RefCounted!A(a, defaultAllocator); |         auto rc = RefCounted!A(a, defaultAllocator); | ||||||
|         assert(rc.count == 1); |         assert(rc.count == 1); | ||||||
|  |  | ||||||
|         void func(RefCounted!A rc) @nogc |         void func(RefCounted!A rc) @nogc @system | ||||||
|         { |         { | ||||||
|             assert(rc.count == 2); |             assert(rc.count == 2); | ||||||
|         } |         } | ||||||
| @@ -415,14 +421,14 @@ private @nogc unittest | |||||||
|     assert(rc.count == 1); |     assert(rc.count == 1); | ||||||
| } | } | ||||||
|  |  | ||||||
| private @nogc unittest | @nogc @system unittest | ||||||
| { | { | ||||||
|     auto rc = RefCounted!int(defaultAllocator); |     auto rc = RefCounted!int(defaultAllocator); | ||||||
|     assert(!rc.isInitialized); |     assert(!rc.isInitialized); | ||||||
|     assert(rc.allocator is defaultAllocator); |     assert(rc.allocator is defaultAllocator); | ||||||
| } | } | ||||||
|  |  | ||||||
| private @nogc unittest | @nogc @system unittest | ||||||
| { | { | ||||||
|     auto rc = defaultAllocator.refCounted!int(5); |     auto rc = defaultAllocator.refCounted!int(5); | ||||||
|     assert(rc.count == 1); |     assert(rc.count == 1); | ||||||
| @@ -444,7 +450,7 @@ private @nogc unittest | |||||||
|     assert(rc.count == 0); |     assert(rc.count == 0); | ||||||
| } | } | ||||||
|  |  | ||||||
| private unittest | @nogc @system unittest | ||||||
| { | { | ||||||
|     auto rc = defaultAllocator.refCounted!int(5); |     auto rc = defaultAllocator.refCounted!int(5); | ||||||
|     assert(*rc == 5); |     assert(*rc == 5); | ||||||
| @@ -460,7 +466,7 @@ private unittest | |||||||
|     assert(*rc == 5); |     assert(*rc == 5); | ||||||
| } | } | ||||||
|  |  | ||||||
| private unittest | @nogc nothrow pure @safe unittest | ||||||
| { | { | ||||||
|     static assert(is(typeof(RefCounted!int.storage.payload) == int*)); |     static assert(is(typeof(RefCounted!int.storage.payload) == int*)); | ||||||
|     static assert(is(typeof(RefCounted!A.storage.payload) == A)); |     static assert(is(typeof(RefCounted!A.storage.payload) == A)); | ||||||
| @@ -511,17 +517,9 @@ body | |||||||
|     { |     { | ||||||
|         () @trusted { allocator.deallocate(mem); }(); |         () @trusted { allocator.deallocate(mem); }(); | ||||||
|     } |     } | ||||||
|     rc.storage = emplace!((RefCounted!T.Storage))(mem[0 .. storageSize]); |     rc.storage = emplace!(RefCounted!T.Storage)(mem[0 .. storageSize]); | ||||||
|  |  | ||||||
|     static if (is(T == class)) |  | ||||||
|     { |  | ||||||
|     rc.storage.payload = emplace!T(mem[storageSize .. $], args); |     rc.storage.payload = emplace!T(mem[storageSize .. $], args); | ||||||
|     } |  | ||||||
|     else |  | ||||||
|     { |  | ||||||
|         auto ptr = (() @trusted => (cast(T*) mem[storageSize .. $].ptr))(); |  | ||||||
|         rc.storage.payload = emplace!T(ptr, args); |  | ||||||
|     } |  | ||||||
|     rc.deleter = &unifiedDeleter!(Payload!T); |     rc.deleter = &unifiedDeleter!(Payload!T); | ||||||
|     return rc; |     return rc; | ||||||
| } | } | ||||||
| @@ -554,7 +552,7 @@ body | |||||||
| } | } | ||||||
|  |  | ||||||
| /// | /// | ||||||
| unittest | @nogc @system unittest | ||||||
| { | { | ||||||
|     auto rc = defaultAllocator.refCounted!int(5); |     auto rc = defaultAllocator.refCounted!int(5); | ||||||
|     assert(rc.count == 1); |     assert(rc.count == 1); | ||||||
| @@ -575,7 +573,7 @@ unittest | |||||||
|     assert(rc.count == 1); |     assert(rc.count == 1); | ||||||
| } | } | ||||||
|  |  | ||||||
| private @nogc unittest | @nogc @system unittest | ||||||
| { | { | ||||||
|     struct E |     struct E | ||||||
|     { |     { | ||||||
| @@ -597,13 +595,13 @@ private @nogc unittest | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| private @nogc unittest | @nogc @system unittest | ||||||
| { | { | ||||||
|     auto rc = defaultAllocator.refCounted!(int[])(5); |     auto rc = defaultAllocator.refCounted!(int[])(5); | ||||||
|     assert(rc.length == 5); |     assert(rc.length == 5); | ||||||
| } | } | ||||||
|  |  | ||||||
| private @nogc unittest | @nogc @system unittest | ||||||
| { | { | ||||||
|     auto p1 = defaultAllocator.make!int(5); |     auto p1 = defaultAllocator.make!int(5); | ||||||
|     auto p2 = p1; |     auto p2 = p1; | ||||||
| @@ -611,13 +609,13 @@ private @nogc unittest | |||||||
|     assert(rc.get() is p2); |     assert(rc.get() is p2); | ||||||
| } | } | ||||||
|  |  | ||||||
| private @nogc unittest | @nogc @system unittest | ||||||
| { | { | ||||||
|     static bool destroyed = false; |     static bool destroyed = false; | ||||||
|  |  | ||||||
|     struct F |     static struct F | ||||||
|     { |     { | ||||||
|         ~this() @nogc |         ~this() @nogc nothrow @safe | ||||||
|         { |         { | ||||||
|             destroyed = true; |             destroyed = true; | ||||||
|         } |         } | ||||||
| @@ -723,7 +721,7 @@ struct Unique(T) | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// |     /// | ||||||
|     @nogc unittest |     @nogc nothrow pure @system unittest | ||||||
|     { |     { | ||||||
|         auto rc = defaultAllocator.unique!int(5); |         auto rc = defaultAllocator.unique!int(5); | ||||||
|         rc = defaultAllocator.make!int(7); |         rc = defaultAllocator.make!int(7); | ||||||
| @@ -770,7 +768,7 @@ struct Unique(T) | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// |     /// | ||||||
|     @nogc unittest |     @nogc nothrow pure @system unittest | ||||||
|     { |     { | ||||||
|         Unique!int u; |         Unique!int u; | ||||||
|         assert(!u.isInitialized); |         assert(!u.isInitialized); | ||||||
| @@ -789,7 +787,7 @@ struct Unique(T) | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// |     /// | ||||||
|     @nogc unittest |     @nogc nothrow pure @system unittest | ||||||
|     { |     { | ||||||
|         auto u = defaultAllocator.unique!int(5); |         auto u = defaultAllocator.unique!int(5); | ||||||
|         assert(u.isInitialized); |         assert(u.isInitialized); | ||||||
| @@ -804,7 +802,7 @@ struct Unique(T) | |||||||
| } | } | ||||||
|  |  | ||||||
| /// | /// | ||||||
| @nogc unittest | @nogc nothrow pure @system unittest | ||||||
| { | { | ||||||
|     auto p = defaultAllocator.make!int(5); |     auto p = defaultAllocator.make!int(5); | ||||||
|     auto s = Unique!int(p, defaultAllocator); |     auto s = Unique!int(p, defaultAllocator); | ||||||
| @@ -812,13 +810,13 @@ struct Unique(T) | |||||||
| } | } | ||||||
|  |  | ||||||
| /// | /// | ||||||
| @nogc unittest | @nogc nothrow @system unittest | ||||||
| { | { | ||||||
|     static bool destroyed = false; |     static bool destroyed = false; | ||||||
|  |  | ||||||
|     struct F |     static struct F | ||||||
|     { |     { | ||||||
|         ~this() @nogc |         ~this() @nogc nothrow @safe | ||||||
|         { |         { | ||||||
|             destroyed = true; |             destroyed = true; | ||||||
|         } |         } | ||||||
| @@ -885,13 +883,13 @@ body | |||||||
|     return Unique!T(payload, allocator); |     return Unique!T(payload, allocator); | ||||||
| } | } | ||||||
|  |  | ||||||
| private unittest | @nogc nothrow pure @safe unittest | ||||||
| { | { | ||||||
|     static assert(is(typeof(defaultAllocator.unique!B(5)))); |     static assert(is(typeof(defaultAllocator.unique!B(5)))); | ||||||
|     static assert(is(typeof(defaultAllocator.unique!(int[])(5)))); |     static assert(is(typeof(defaultAllocator.unique!(int[])(5)))); | ||||||
| } | } | ||||||
|  |  | ||||||
| private unittest | @nogc nothrow pure @system unittest | ||||||
| { | { | ||||||
|     auto s = defaultAllocator.unique!int(5); |     auto s = defaultAllocator.unique!int(5); | ||||||
|     assert(*s == 5); |     assert(*s == 5); | ||||||
| @@ -900,7 +898,7 @@ private unittest | |||||||
|     assert(s is null); |     assert(s is null); | ||||||
| } | } | ||||||
|  |  | ||||||
| private unittest | @nogc nothrow pure @system unittest | ||||||
| { | { | ||||||
|     auto s = defaultAllocator.unique!int(5); |     auto s = defaultAllocator.unique!int(5); | ||||||
|     assert(*s == 5); |     assert(*s == 5); | ||||||
| @@ -909,7 +907,7 @@ private unittest | |||||||
|     assert(*s == 4); |     assert(*s == 4); | ||||||
| } | } | ||||||
|  |  | ||||||
| private @nogc unittest | @nogc nothrow pure @system unittest | ||||||
| { | { | ||||||
|     auto p1 = defaultAllocator.make!int(5); |     auto p1 = defaultAllocator.make!int(5); | ||||||
|     auto p2 = p1; |     auto p2 = p1; | ||||||
| @@ -918,7 +916,7 @@ private @nogc unittest | |||||||
|     assert(rc.get() is p2); |     assert(rc.get() is p2); | ||||||
| } | } | ||||||
|  |  | ||||||
| private @nogc unittest | @nogc nothrow pure @system unittest | ||||||
| { | { | ||||||
|     auto rc = Unique!int(defaultAllocator); |     auto rc = Unique!int(defaultAllocator); | ||||||
|     assert(rc.allocator is defaultAllocator); |     assert(rc.allocator is defaultAllocator); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user