49 Commits

Author SHA1 Message Date
2946fd7f81 Update dmd to 2.078.2 2018-02-15 18:33:54 +01:00
2cda82eeea Fix handling of misaligned bytes in fill 2018-02-04 07:23:56 +01:00
e9f70853c6 Fix #12 2018-02-02 16:13:55 +01:00
4aaa71a7d0 Format ranges 2018-02-02 14:34:36 +01:00
cbc68c2c43 Implement formatting for enums 2018-02-01 16:29:13 +01:00
048ddf21ff Replace body with do 2018-01-31 12:05:06 +01:00
fd02c411e1 Update latest dmd version to 2.078.1 2018-01-23 05:21:19 +01:00
b69d737845 Add typeid formatting tests 2018-01-16 17:44:09 +01:00
904451ccaa Remove moved and deprecated conv module 2018-01-14 19:13:12 +01:00
c1864cf473 Add dynamic library target 2018-01-13 06:21:42 +01:00
8db1851c5c Update dmd to 2.078.0 2018-01-04 05:36:46 +01:00
12de700706 Fix formatting null class references 2017-12-16 09:42:57 +01:00
78a8afdf75 Format stringish ranges 2017-12-15 22:42:18 +01:00
3c996d7c57 Add struct formatting 2017-12-14 19:47:13 +01:00
2a68048fc1 Put real formatting code into a separate function 2017-12-09 10:02:54 +01:00
907f7a4e61 Remove IO branch 2017-12-09 09:53:23 +01:00
670328c047 Drop support for 2.075.1 2017-12-08 10:58:39 +01:00
7fe69ccc5c format: Aggregate types 2017-12-08 10:56:59 +01:00
26c3532e28 Wrap formatting into printToString
printToString gets the output string as argument and can be called
recursive with the same output string to format ranges.
2017-12-03 19:53:06 +01:00
75ce854192 Support dmd 2.077.1 2017-12-02 10:40:40 +01:00
9e16d84f9e Reintroduce isStruct, isClass and isInterface
since they can be useful for generic programming.
2017-11-29 19:53:28 +01:00
7e7bf40f70 Move remaining to methods to tanya.conv 2017-11-29 19:09:58 +01:00
642717883e Add boolean and null formatting 2017-11-29 18:44:51 +01:00
85be35c5e0 Make floating formatting safe 2017-11-29 07:49:20 +01:00
664298f038 Remove buffer argument from format 2017-11-28 22:11:19 +01:00
c199cdd47c Merge changes to reals formatting from master 2017-11-28 09:32:20 +01:00
3a24e9e462 Make pointer to string conversion safer 2017-11-27 15:10:17 +01:00
f334e6a1a0 Check format specifier at compile time 2017-11-25 22:29:45 +01:00
72d5760589 Change default pointer format 2017-11-25 19:01:20 +01:00
b28dde9d8e Remove triplet comma 2017-11-25 17:10:59 +01:00
b612e978bf format: Add format string tests 2017-11-25 15:24:45 +01:00
02d1d8218b Port vsprintf 2017-11-25 15:11:43 +01:00
fbf6ec5250 format: Check if the scientific form is to be used 2017-11-25 14:59:27 +01:00
ac317aa9d6 math.min: Drop useless second isFloatingPoint check 2017-11-19 22:37:15 +01:00
10022d158c Replace aho/ali usage with HP 2017-11-16 19:28:44 +01:00
a38242d0ac Make real2String more readable 2017-11-16 19:19:18 +01:00
a84c71f26d Revert usage of "do" instead of "body"
And fix GCC build.
2017-11-16 19:15:56 +01:00
7797f0a1fe format.conv.number2String -> format.integral2String (intern) 2017-11-12 11:57:47 +01:00
4bbc8b510a conv: Use assertThrown to check ConvException is thrown 2017-11-12 11:44:45 +01:00
87ea1f98dc Add range primitives that remove several elements
- isOutputRange
- popFrontN
- popFrontExactly
- popBackN
- popBackExactly
2017-11-05 07:00:10 +01:00
9422888b6c Support dmd 2.075.1 - 2.077.0 2017-11-04 00:35:47 +01:00
13407fcf8a math: Add min/max 2017-11-02 06:00:11 +01:00
e06cc5a071 Fix moveEmplace for static arrays 2017-11-01 14:27:39 +01:00
12fb9ff9f6 Add algorithm.mutation.swap 2017-11-01 13:03:48 +01:00
392cdcf192 Fix moveEmplace not being pure 2017-11-01 12:30:27 +01:00
09b6655b9a memory.op: Check for valid .ptr and .length
typeid(T).initializer can return an array, whose .ptr is null but the
length not. Assert that .ptr and .length are consistent.
2017-11-01 00:01:43 +01:00
7a2768340e Add algorithm package with move and moveEmplace 2017-10-29 07:51:00 +01:00
414d7a11a8 Add meta.trait.Fields 2017-10-27 20:28:34 +02:00
0d69c7fc79 Make math.mp.Integer pure 2017-10-24 11:50:32 +02:00
31 changed files with 3092 additions and 1125 deletions

View File

@ -7,9 +7,9 @@ os:
language: d language: d
d: d:
- dmd-2.078.2
- dmd-2.077.1
- dmd-2.076.1 - dmd-2.076.1
- dmd-2.075.1
- dmd-2.074.1
env: env:
matrix: matrix:
@ -22,7 +22,7 @@ addons:
- gcc-multilib - gcc-multilib
before_script: before_script:
- if [ "$PS1" = '(dmd-2.076.1)' ]; then - if [ "$PS1" = '(dmd-2.078.2)' ]; then
export UNITTEST="unittest-cov"; export UNITTEST="unittest-cov";
fi fi

View File

@ -12,10 +12,9 @@ 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 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
Garbage Collector heap. Everything in the library is usable in @nogc code. Garbage Collector heap. Everything in the library is usable in @nogc code.
Tanya extends Phobos functionality and provides alternative implementations for Tanya provides data structures and utilities to facilitate painless systems
data structures and utilities that depend on the Garbage Collector in Phobos. programming in D.
* [Bug tracker](https://issues.caraus.io/projects/tanya/issues)
* [API Documentation](https://docs.caraus.io/tanya) * [API Documentation](https://docs.caraus.io/tanya)
* [Contribution guidelines](CONTRIBUTING.md) * [Contribution guidelines](CONTRIBUTING.md)
@ -24,6 +23,7 @@ data structures and utilities that depend on the Garbage Collector in Phobos.
Tanya consists of the following packages and (top-level) modules: Tanya consists of the following packages and (top-level) modules:
* `algorithm`: Collection of generic algorithms.
* `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.
@ -149,9 +149,9 @@ There are more containers in the `tanya.container` package.
| DMD | GCC | | DMD | GCC |
|:-------:|:--------------:| |:-------:|:--------------:|
| 2.076.1 | *gdc-5* branch | | 2.078.2 | *gdc-5* branch |
| 2.075.1 | | | 2.077.1 | |
| 2.074.1 | | | 2.076.1 | |
### Current status ### Current status
@ -161,13 +161,10 @@ Following modules are under development:
|----------|:---------:|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| |----------|:---------:|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| BitArray | bitvector | [![bitvector](https://travis-ci.org/caraus-ecms/tanya.svg?branch=bitvector)](https://travis-ci.org/caraus-ecms/tanya) [![bitvector](https://ci.appveyor.com/api/projects/status/djkmverdfsylc7ti/branch/bitvector?svg=true)](https://ci.appveyor.com/project/belka-ew/tanya/branch/bitvector) | | BitArray | bitvector | [![bitvector](https://travis-ci.org/caraus-ecms/tanya.svg?branch=bitvector)](https://travis-ci.org/caraus-ecms/tanya) [![bitvector](https://ci.appveyor.com/api/projects/status/djkmverdfsylc7ti/branch/bitvector?svg=true)](https://ci.appveyor.com/project/belka-ew/tanya/branch/bitvector) |
| TLS | crypto | [![crypto](https://travis-ci.org/caraus-ecms/tanya.svg?branch=crypto)](https://travis-ci.org/caraus-ecms/tanya) [![crypto](https://ci.appveyor.com/api/projects/status/djkmverdfsylc7ti/branch/crypto?svg=true)](https://ci.appveyor.com/project/belka-ew/tanya/branch/crypto) | | TLS | crypto | [![crypto](https://travis-ci.org/caraus-ecms/tanya.svg?branch=crypto)](https://travis-ci.org/caraus-ecms/tanya) [![crypto](https://ci.appveyor.com/api/projects/status/djkmverdfsylc7ti/branch/crypto?svg=true)](https://ci.appveyor.com/project/belka-ew/tanya/branch/crypto) |
| File IO | io | [![io](https://travis-ci.org/caraus-ecms/tanya.svg?branch=io)](https://travis-ci.org/caraus-ecms/tanya) [![io](https://ci.appveyor.com/api/projects/status/djkmverdfsylc7ti/branch/io?svg=true)](https://ci.appveyor.com/project/belka-ew/tanya/branch/io) |
### Release management ### Release management
3-week release cycle. Deprecated features are removed after one release that includes these deprecations.
Deprecated features are removed after one release (in approximately 6 weeks after deprecating).
## Further characteristics ## Further characteristics

View File

@ -3,24 +3,24 @@ os: Visual Studio 2015
environment: environment:
matrix: matrix:
- DC: dmd
DVersion: 2.078.2
arch: x64
- DC: dmd
DVersion: 2.078.2
arch: x86
- DC: dmd
DVersion: 2.077.1
arch: x64
- DC: dmd
DVersion: 2.077.1
arch: x86
- DC: dmd - DC: dmd
DVersion: 2.076.1 DVersion: 2.076.1
arch: x64 arch: x64
- DC: dmd - DC: dmd
DVersion: 2.076.1 DVersion: 2.076.1
arch: x86 arch: x86
- DC: dmd
DVersion: 2.075.1
arch: x64
- DC: dmd
DVersion: 2.075.1
arch: x86
- DC: dmd
DVersion: 2.074.1
arch: x64
- DC: dmd
DVersion: 2.074.1
arch: x86
skip_tags: true skip_tags: true

View File

@ -37,6 +37,11 @@ _D5tanya6memory2op10fillMemoryFNaNbNiAvmZv:
mov %rsi, %r8 mov %rsi, %r8
// If the length is less than the number of misaligned bytes,
// write one byte at a time and exit
cmp %rax, %rcx
jg aligned_1
naligned: naligned:
mov %dl, (%r8) // Write a byte mov %dl, (%r8) // Write a byte

View File

@ -12,7 +12,12 @@
"configurations": [ "configurations": [
{ {
"name": "library", "name": "library",
"targetType": "library", "targetType": "staticLibrary",
"versions": ["TanyaPhobos"]
},
{
"name": "dynamic",
"targetType": "dynamicLibrary",
"versions": ["TanyaPhobos"] "versions": ["TanyaPhobos"]
}, },
{ {

View File

@ -0,0 +1,275 @@
/* 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/. */
/**
* Algorithms that modify its arguments.
*
* 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/algorithm/mutation.d,
* tanya/algorithm/mutation.d)
*/
module tanya.algorithm.mutation;
import tanya.memory.op;
import tanya.meta.trait;
private void deinitialize(bool zero, T)(ref T value)
{
static if (is(T == U[S], U, size_t S))
{
foreach (ref e; value)
{
deinitialize!zero(e);
}
}
else
{
static if (isNested!T)
{
// Don't override the context pointer.
enum size_t size = T.sizeof - (void*).sizeof;
}
else
{
enum size_t size = T.sizeof;
}
static if (zero)
{
fill!0((cast(void*) &value)[0 .. size]);
}
else
{
copy(typeid(T).initializer()[0 .. size], (&value)[0 .. 1]);
}
}
}
/**
* Moves $(D_PARAM source) into $(D_PARAM target) assuming that
* $(D_PARAM target) isn't initialized.
*
* Moving the $(D_PARAM source) copies it into the $(D_PARAM target) and places
* the $(D_PARAM source) into a valid but unspecified state, which means that
* after moving $(D_PARAM source) can be destroyed or assigned a new value, but
* accessing it yields an unspecified value. No postblits or destructors are
* called. If the $(D_PARAM target) should be destroyed before, use
* $(D_PSYMBOL move).
*
* $(D_PARAM source) and $(D_PARAM target) must be different objects.
*
* Params:
* T = Object type.
* source = Source object.
* target = Target object.
*
* See_Also: $(D_PSYMBOL move),
* $(D_PSYMBOL hasElaborateCopyConstructor),
* $(D_PSYMBOL hasElaborateDestructor).
*
* Precondition: `&source !is &target`.
*/
void moveEmplace(T)(ref T source, ref T target) @system
in
{
assert(&source !is &target, "Source and target must be different");
}
do
{
static if (is(T == struct) || isStaticArray!T)
{
copy((&source)[0 .. 1], (&target)[0 .. 1]);
static if (hasElaborateCopyConstructor!T || hasElaborateDestructor!T)
{
if (typeid(T).initializer().ptr is null)
{
deinitialize!true(source);
}
else
{
deinitialize!false(source);
}
}
}
else
{
target = source;
}
}
///
@nogc nothrow pure @system unittest
{
static struct S
{
int member = 5;
this(this) @nogc nothrow pure @safe
{
assert(false);
}
}
S source, target = void;
moveEmplace(source, target);
assert(target.member == 5);
int x1 = 5, x2;
moveEmplace(x1, x2);
assert(x2 == 5);
}
// Is pure.
@nogc nothrow pure @system unittest
{
struct S
{
this(this)
{
}
}
S source, target = void;
static assert(is(typeof({ moveEmplace(source, target); })));
}
// Moves nested.
@nogc nothrow pure @system unittest
{
struct Nested
{
void method() @nogc nothrow pure @safe
{
}
}
Nested source, target = void;
moveEmplace(source, target);
assert(source == target);
}
// Emplaces static arrays.
@nogc nothrow pure @system unittest
{
static struct S
{
size_t member;
this(size_t i) @nogc nothrow pure @safe
{
this.member = i;
}
~this() @nogc nothrow pure @safe
{
}
}
S[2] source = [ S(5), S(5) ], target = void;
moveEmplace(source, target);
assert(source[0].member == 0);
assert(target[0].member == 5);
assert(source[1].member == 0);
assert(target[1].member == 5);
}
/**
* Moves $(D_PARAM source) into $(D_PARAM target) assuming that
* $(D_PARAM target) isn't initialized.
*
* Moving the $(D_PARAM source) copies it into the $(D_PARAM target) and places
* the $(D_PARAM source) into a valid but unspecified state, which means that
* after moving $(D_PARAM source) can be destroyed or assigned a new value, but
* accessing it yields an unspecified value. $(D_PARAM target) is destroyed before
* the new value is assigned. If $(D_PARAM target) isn't initialized and
* therefore shouldn't be destroyed, $(D_PSYMBOL moveEmplace) can be used.
*
* If $(D_PARAM target) isn't specified, $(D_PSYMBOL move) returns the source
* as rvalue without calling its copy constructor or destructor.
*
* $(D_PARAM source) and $(D_PARAM target) are the same object,
* $(D_PSYMBOL move) does nothing.
*
* Params:
* T = Object type.
* source = Source object.
* target = Target object.
*
* See_Also: $(D_PSYMBOL moveEmplace).
*/
void move(T)(ref T source, ref T target)
{
if ((() @trusted => &source is &target)())
{
return;
}
static if (hasElaborateDestructor!T)
{
target.__xdtor();
}
(() @trusted => moveEmplace(source, target))();
}
/// ditto
T move(T)(ref T source) @trusted
{
T target = void;
moveEmplace(source, target);
return target;
}
///
@nogc nothrow pure @safe unittest
{
static struct S
{
int member = 5;
this(this) @nogc nothrow pure @safe
{
assert(false);
}
}
S source, target = void;
move(source, target);
assert(target.member == 5);
assert(move(target).member == 5);
int x1 = 5, x2;
move(x1, x2);
assert(x2 == 5);
assert(move(x2) == 5);
}
// Moves if source is target.
@nogc nothrow pure @safe unittest
{
int x = 5;
move(x, x);
assert(x == 5);
}
/**
* Exchanges the values of $(D_PARAM a) and $(D_PARAM b).
*
* $(D_PSYMBOL swap) moves the contents of $(D_PARAM a) and $(D_PARAM b)
* without calling its postblits or destructors.
*
* Params:
* a = The first object.
* a = The second object.
*/
void swap(T)(ref T a, ref T b) @trusted
{
T tmp = void;
moveEmplace(a, tmp);
moveEmplace(b, a);
moveEmplace(tmp, b);
}
///
@nogc nothrow pure @safe unittest
{
int a = 3, b = 5;
swap(a, b);
assert(a == 5);
assert(b == 3);
}

View File

@ -3,15 +3,15 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/** /**
* This package contains formatting and conversion functions. * Collection of generic algorithms.
* *
* Copyright: Eugene Wissner 2017. * Copyright: Eugene Wissner 2017.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
* Mozilla Public License, v. 2.0). * Mozilla Public License, v. 2.0).
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/format/package.d, * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/algorithm/package.d,
* tanya/format/package.d) * tanya/algorithm/package.d)
*/ */
module tanya.format; module tanya.algorithm;
public import tanya.format.conv; public import tanya.algorithm.mutation;

View File

@ -72,7 +72,7 @@ final class StreamTransport : SocketWatcher, DuplexTransport, SocketTransport
{ {
assert(socket !is null); assert(socket !is null);
} }
body do
{ {
return cast(OverlappedConnectedSocket) socket_; return cast(OverlappedConnectedSocket) socket_;
} }
@ -130,7 +130,7 @@ final class StreamTransport : SocketWatcher, DuplexTransport, SocketTransport
{ {
assert(protocol !is null); assert(protocol !is null);
} }
body do
{ {
protocol_ = protocol; protocol_ = protocol;
} }
@ -270,7 +270,7 @@ final class IOCPLoop : Loop
{ {
assert(transport !is null); assert(transport !is null);
} }
body do
{ {
transport.socket.shutdown(); transport.socket.shutdown();
defaultAllocator.dispose(transport.socket); defaultAllocator.dispose(transport.socket);

View File

@ -61,7 +61,7 @@ package class StreamTransport : SocketWatcher, DuplexTransport, SocketTransport
{ {
assert(loop !is null); assert(loop !is null);
} }
body do
{ {
super(socket); super(socket);
this.loop = loop; this.loop = loop;
@ -80,7 +80,7 @@ package class StreamTransport : SocketWatcher, DuplexTransport, SocketTransport
{ {
assert(socket !is null); assert(socket !is null);
} }
body do
{ {
return cast(ConnectedSocket) socket_; return cast(ConnectedSocket) socket_;
} }
@ -91,7 +91,7 @@ package class StreamTransport : SocketWatcher, DuplexTransport, SocketTransport
{ {
assert(socket !is null); assert(socket !is null);
} }
body do
{ {
socket_ = socket; socket_ = socket;
} }
@ -120,7 +120,7 @@ package class StreamTransport : SocketWatcher, DuplexTransport, SocketTransport
{ {
assert(protocol !is null); assert(protocol !is null);
} }
body do
{ {
protocol_ = protocol; protocol_ = protocol;
} }
@ -263,7 +263,7 @@ abstract class SelectorLoop : Loop
{ {
assert(transport !is null); assert(transport !is null);
} }
body do
{ {
transport.socket.shutdown(); transport.socket.shutdown();
defaultAllocator.dispose(transport.socket); defaultAllocator.dispose(transport.socket);
@ -289,7 +289,7 @@ abstract class SelectorLoop : Loop
{ {
assert(transport !is null); assert(transport !is null);
} }
body do
{ {
while (transport.input.length && transport.writeReady) while (transport.input.length && transport.writeReady)
{ {
@ -356,7 +356,7 @@ abstract class SelectorLoop : Loop
{ {
assert(connection !is null); assert(connection !is null);
} }
body do
{ {
while (true) while (true)
{ {

View File

@ -326,7 +326,7 @@ abstract class Loop
assert(blockTime <= 1.dur!"hours", "Too long to wait."); assert(blockTime <= 1.dur!"hours", "Too long to wait.");
assert(!blockTime.isNegative); assert(!blockTime.isNegative);
} }
body do
{ {
blockTime_ = blockTime; blockTime_ = blockTime;
} }
@ -414,7 +414,7 @@ in
{ {
assert(loop !is null); assert(loop !is null);
} }
body do
{ {
defaultLoop_ = loop; defaultLoop_ = loop;
} }

View File

@ -72,7 +72,7 @@ abstract class SocketWatcher : Watcher
{ {
assert(socket !is null); assert(socket !is null);
} }
body do
{ {
socket_ = socket; socket_ = socket;
} }
@ -123,7 +123,7 @@ class ConnectionWatcher : SocketWatcher
{ {
assert(protocolFactory !is null, "Protocol isn't set."); assert(protocolFactory !is null, "Protocol isn't set.");
} }
body do
{ {
foreach (transport; incoming) foreach (transport; incoming)
{ {

View File

@ -16,8 +16,13 @@ module tanya.container.array;
import core.checkedint; import core.checkedint;
import std.algorithm.comparison; import std.algorithm.comparison;
import std.algorithm.mutation; import std.algorithm.mutation : bringToFront,
copy,
fill,
initializeAll,
uninitializedFill;
import std.meta; import std.meta;
import tanya.algorithm.mutation;
import tanya.exception; import tanya.exception;
import tanya.memory; import tanya.memory;
import tanya.meta.trait; import tanya.meta.trait;
@ -51,7 +56,7 @@ struct Range(A)
assert(begin >= container.data); assert(begin >= container.data);
assert(end <= container.data + container.length); assert(end <= container.data + container.length);
} }
body do
{ {
this.container = &container; this.container = &container;
this.begin = begin; this.begin = begin;
@ -82,7 +87,7 @@ struct Range(A)
{ {
assert(!empty); assert(!empty);
} }
body do
{ {
return *this.begin; return *this.begin;
} }
@ -92,7 +97,7 @@ struct Range(A)
{ {
assert(!empty); assert(!empty);
} }
body do
{ {
return *(this.end - 1); return *(this.end - 1);
} }
@ -102,7 +107,7 @@ struct Range(A)
{ {
assert(!empty); assert(!empty);
} }
body do
{ {
++this.begin; ++this.begin;
} }
@ -112,7 +117,7 @@ struct Range(A)
{ {
assert(!empty); assert(!empty);
} }
body do
{ {
--this.end; --this.end;
} }
@ -122,7 +127,7 @@ struct Range(A)
{ {
assert(i < length); assert(i < length);
} }
body do
{ {
return *(this.begin + i); return *(this.begin + i);
} }
@ -143,7 +148,7 @@ struct Range(A)
assert(i <= j); assert(i <= j);
assert(j <= length); assert(j <= length);
} }
body do
{ {
return typeof(return)(*this.container, this.begin + i, this.begin + j); return typeof(return)(*this.container, this.begin + i, this.begin + j);
} }
@ -154,7 +159,7 @@ struct Range(A)
assert(i <= j); assert(i <= j);
assert(j <= length); assert(j <= length);
} }
body do
{ {
return typeof(return)(*this.container, this.begin + i, this.begin + j); return typeof(return)(*this.container, this.begin + i, this.begin + j);
} }
@ -264,7 +269,10 @@ struct Array(T)
{ {
// Move each element. // Move each element.
reserve(init.length_); reserve(init.length_);
moveEmplaceAll(init.data[0 .. init.length_], this.data[0 .. init.length_]); foreach (ref target; this.data[0 .. init.length_])
{
moveEmplace(*init.data++, target);
}
this.length_ = init.length_; this.length_ = init.length_;
// Destructor of init should destroy it here. // Destructor of init should destroy it here.
} }
@ -325,7 +333,7 @@ struct Array(T)
{ {
assert(allocator !is null); assert(allocator !is null);
} }
body do
{ {
allocator_ = allocator; allocator_ = allocator;
} }
@ -506,7 +514,6 @@ struct Array(T)
{ {
allocator.deallocate(buf); allocator.deallocate(buf);
} }
const T* end = this.data + this.length_;
for (T* src = this.data, dest = cast(T*) buf; src != end; ++src, ++dest) for (T* src = this.data, dest = cast(T*) buf; src != end; ++src, ++dest)
{ {
moveEmplace(*src, *dest); moveEmplace(*src, *dest);
@ -590,7 +597,7 @@ struct Array(T)
{ {
assert(!empty); assert(!empty);
} }
body do
{ {
length = length - 1; length = length - 1;
} }
@ -612,7 +619,7 @@ struct Array(T)
{ {
assert(removed <= howMany); assert(removed <= howMany);
} }
body do
{ {
const toRemove = min(howMany, length); const toRemove = min(howMany, length);
@ -632,6 +639,11 @@ struct Array(T)
assert(v.removeBack(3) == 0); assert(v.removeBack(3) == 0);
} }
private @property inout(T)* end() inout
{
return this.data + this.length_;
}
/** /**
* Remove all elements beloning to $(D_PARAM r). * Remove all elements beloning to $(D_PARAM r).
* *
@ -650,10 +662,13 @@ struct Array(T)
assert(r.begin >= this.data); assert(r.begin >= this.data);
assert(r.end <= this.data + length); assert(r.end <= this.data + length);
} }
body do
{ {
auto end = this.data + this.length; auto target = r.begin;
moveAll(Range(this, r.end, end), Range(this, r.begin, end)); for (auto source = r.end; source != end; ++source, ++target)
{
move(*source, *target);
}
length = length - r.length; length = length - r.length;
return Range(this, r.begin, this.data + length); return Range(this, r.begin, this.data + length);
} }
@ -683,7 +698,7 @@ struct Array(T)
if (isImplicitlyConvertible!(R, T)) if (isImplicitlyConvertible!(R, T))
{ {
reserve(this.length + 1); reserve(this.length + 1);
moveEmplace(el, *(this.data + this.length_)); moveEmplace(el, *end);
++this.length_; ++this.length_;
} }
@ -806,7 +821,7 @@ struct Array(T)
assert(r.begin >= this.data); assert(r.begin >= this.data);
assert(r.end <= this.data + length); assert(r.end <= this.data + length);
} }
body do
{ {
const oldLen = length; const oldLen = length;
const offset = r.end - this.data; const offset = r.end - this.data;
@ -823,7 +838,7 @@ struct Array(T)
assert(r.begin >= this.data); assert(r.begin >= this.data);
assert(r.end <= this.data + length); assert(r.end <= this.data + length);
} }
body do
{ {
return insertAfter!(T[])(r, el[]); return insertAfter!(T[])(r, el[]);
} }
@ -837,7 +852,7 @@ struct Array(T)
assert(r.begin >= this.data); assert(r.begin >= this.data);
assert(r.end <= this.data + length); assert(r.end <= this.data + length);
} }
body do
{ {
const oldLen = length; const oldLen = length;
const offset = r.end - this.data; const offset = r.end - this.data;
@ -866,7 +881,7 @@ struct Array(T)
assert(r.begin >= this.data); assert(r.begin >= this.data);
assert(r.end <= this.data + length); assert(r.end <= this.data + length);
} }
body do
{ {
return insertAfter(Range(this, this.data, r.begin), el); return insertAfter(Range(this, this.data, r.begin), el);
} }
@ -879,7 +894,7 @@ struct Array(T)
assert(r.begin >= this.data); assert(r.begin >= this.data);
assert(r.end <= this.data + length); assert(r.end <= this.data + length);
} }
body do
{ {
return insertBefore!(T[])(r, el[]); return insertBefore!(T[])(r, el[]);
} }
@ -893,7 +908,7 @@ struct Array(T)
assert(r.begin >= this.data); assert(r.begin >= this.data);
assert(r.end <= this.data + length); assert(r.end <= this.data + length);
} }
body do
{ {
const oldLen = length; const oldLen = length;
const offset = r.begin - this.data; const offset = r.begin - this.data;
@ -1065,7 +1080,7 @@ struct Array(T)
{ {
assert(length > pos); assert(length > pos);
} }
body do
{ {
return *(this.data + pos); return *(this.data + pos);
} }
@ -1170,7 +1185,7 @@ struct Array(T)
{ {
assert(!empty); assert(!empty);
} }
body do
{ {
return *this.data; return *this.data;
} }
@ -1197,7 +1212,7 @@ struct Array(T)
{ {
assert(!empty); assert(!empty);
} }
body do
{ {
return *(this.data + length - 1); return *(this.data + length - 1);
} }
@ -1230,7 +1245,7 @@ struct Array(T)
assert(i <= j); assert(i <= j);
assert(j <= length); assert(j <= length);
} }
body do
{ {
return typeof(return)(this, this.data + i, this.data + j); return typeof(return)(this, this.data + i, this.data + j);
} }
@ -1242,7 +1257,7 @@ struct Array(T)
assert(i <= j); assert(i <= j);
assert(j <= length); assert(j <= length);
} }
body do
{ {
return typeof(return)(this, this.data + i, this.data + j); return typeof(return)(this, this.data + i, this.data + j);
} }
@ -1313,7 +1328,7 @@ struct Array(T)
assert(i <= j); assert(i <= j);
assert(j <= length); assert(j <= length);
} }
body do
{ {
copy(value[], this.data[i .. j]); copy(value[], this.data[i .. j]);
return opSlice(i, j); return opSlice(i, j);
@ -1327,7 +1342,7 @@ struct Array(T)
assert(i <= j); assert(i <= j);
assert(j <= length); assert(j <= length);
} }
body do
{ {
fill(this.data[i .. j], value); fill(this.data[i .. j], value);
return opSlice(i, j); return opSlice(i, j);
@ -1341,7 +1356,7 @@ struct Array(T)
assert(j <= length); assert(j <= length);
assert(j - i == value.length); assert(j - i == value.length);
} }
body do
{ {
copy(value, this.data[i .. j]); copy(value, this.data[i .. j]);
return opSlice(i, j); return opSlice(i, j);

View File

@ -27,7 +27,7 @@ version (unittest)
{ {
assert(start < end); assert(start < end);
} }
body do
{ {
auto numberRead = end - start; auto numberRead = end - start;
for (ubyte i; i < numberRead; ++i) for (ubyte i; i < numberRead; ++i)
@ -106,7 +106,7 @@ struct ReadBuffer(T = ubyte)
{ {
assert(allocator_ is null); assert(allocator_ is null);
} }
body do
{ {
allocator_ = allocator; allocator_ = allocator;
} }
@ -349,7 +349,7 @@ struct WriteBuffer(T = ubyte)
assert(size > 0); assert(size > 0);
assert(allocator !is null); assert(allocator !is null);
} }
body do
{ {
blockSize = size; blockSize = size;
ring = size - 1; ring = size - 1;
@ -549,7 +549,7 @@ struct WriteBuffer(T = ubyte)
{ {
assert(length <= this.length); assert(length <= this.length);
} }
body do
{ {
auto afterRing = ring + 1; auto afterRing = ring + 1;
auto oldStart = start; auto oldStart = start;

View File

@ -15,11 +15,12 @@
module tanya.container.list; module tanya.container.list;
import std.algorithm.comparison; import std.algorithm.comparison;
import std.algorithm.mutation;
import std.algorithm.searching; import std.algorithm.searching;
import tanya.algorithm.mutation;
import tanya.container.entry; import tanya.container.entry;
import tanya.memory; import tanya.memory;
import tanya.meta.trait; import tanya.meta.trait;
import tanya.meta.transform;
import tanya.range.array; import tanya.range.array;
import tanya.range.primitive; import tanya.range.primitive;
@ -63,7 +64,7 @@ struct SRange(L)
{ {
assert(!empty); assert(!empty);
} }
body do
{ {
return (*this.head).content; return (*this.head).content;
} }
@ -73,7 +74,7 @@ struct SRange(L)
{ {
assert(!empty); assert(!empty);
} }
body do
{ {
this.head = &(*this.head).next; this.head = &(*this.head).next;
} }
@ -204,7 +205,7 @@ struct SList(T)
{ {
assert(allocator !is null); assert(allocator !is null);
} }
body do
{ {
this.allocator_ = allocator; this.allocator_ = allocator;
} }
@ -324,7 +325,7 @@ struct SList(T)
{ {
assert(!empty); assert(!empty);
} }
body do
{ {
return this.head.content; return this.head.content;
} }
@ -466,7 +467,7 @@ struct SList(T)
{ {
assert(checkRangeBelonging(r)); assert(checkRangeBelonging(r));
} }
body do
{ {
return moveEntry(*r.head, el); return moveEntry(*r.head, el);
} }
@ -489,7 +490,7 @@ struct SList(T)
{ {
assert(checkRangeBelonging(r)); assert(checkRangeBelonging(r));
} }
body do
{ {
size_t inserted; size_t inserted;
foreach (e; el) foreach (e; el)
@ -518,7 +519,7 @@ struct SList(T)
{ {
assert(checkRangeBelonging(r)); assert(checkRangeBelonging(r));
} }
body do
{ {
*r.head = allocator.make!Entry(el, *r.head); *r.head = allocator.make!Entry(el, *r.head);
return 1; return 1;
@ -640,7 +641,7 @@ struct SList(T)
{ {
assert(!empty); assert(!empty);
} }
body do
{ {
auto n = this.head.next; auto n = this.head.next;
@ -679,7 +680,7 @@ struct SList(T)
{ {
assert(removed <= howMany); assert(removed <= howMany);
} }
body do
{ {
size_t i; size_t i;
for (; i < howMany && !empty; ++i) for (; i < howMany && !empty; ++i)
@ -715,7 +716,7 @@ struct SList(T)
{ {
assert(checkRangeBelonging(r)); assert(checkRangeBelonging(r));
} }
body do
{ {
auto outOfScopeList = typeof(this)(allocator); auto outOfScopeList = typeof(this)(allocator);
outOfScopeList.head = *r.head; outOfScopeList.head = *r.head;
@ -962,7 +963,7 @@ struct DRange(L)
{ {
assert(!empty); assert(!empty);
} }
body do
{ {
return (*this.head).content; return (*this.head).content;
} }
@ -972,7 +973,7 @@ struct DRange(L)
{ {
assert(!empty); assert(!empty);
} }
body do
{ {
return (*this.tail).content; return (*this.tail).content;
} }
@ -982,7 +983,7 @@ struct DRange(L)
{ {
assert(!empty); assert(!empty);
} }
body do
{ {
this.head = &(*this.head).next; this.head = &(*this.head).next;
} }
@ -992,7 +993,7 @@ struct DRange(L)
{ {
assert(!empty); assert(!empty);
} }
body do
{ {
this.tail = &(*this.tail).prev; this.tail = &(*this.tail).prev;
} }
@ -1134,7 +1135,7 @@ struct DList(T)
{ {
assert(allocator !is null); assert(allocator !is null);
} }
body do
{ {
this.allocator_ = allocator; this.allocator_ = allocator;
} }
@ -1258,7 +1259,7 @@ struct DList(T)
{ {
assert(!empty); assert(!empty);
} }
body do
{ {
return this.head.content; return this.head.content;
} }
@ -1271,7 +1272,7 @@ struct DList(T)
{ {
assert(!empty); assert(!empty);
} }
body do
{ {
return this.tail.content; return this.tail.content;
} }
@ -1318,7 +1319,7 @@ struct DList(T)
assert((retLength == 0 && head is null && tail is null) assert((retLength == 0 && head is null && tail is null)
|| (retLength > 0 && head !is null && tail !is null)); || (retLength > 0 && head !is null && tail !is null));
} }
body do
{ {
size_t retLength; size_t retLength;
@ -1594,7 +1595,7 @@ struct DList(T)
{ {
assert(checkRangeBelonging(r)); assert(checkRangeBelonging(r));
} }
body do
{ {
return moveFront(*r.head, el); return moveFront(*r.head, el);
} }
@ -1614,7 +1615,7 @@ struct DList(T)
{ {
assert(checkRangeBelonging(r)); assert(checkRangeBelonging(r));
} }
body do
{ {
auto temp = allocator.make!Entry(el, *r.head); auto temp = allocator.make!Entry(el, *r.head);
@ -1652,7 +1653,7 @@ struct DList(T)
{ {
assert(checkRangeBelonging(r)); assert(checkRangeBelonging(r));
} }
body do
{ {
size_t inserted; size_t inserted;
foreach (e; el) foreach (e; el)
@ -1709,7 +1710,7 @@ struct DList(T)
{ {
assert(checkRangeBelonging(r)); assert(checkRangeBelonging(r));
} }
body do
{ {
return moveBack(*r.tail, el); return moveBack(*r.tail, el);
} }
@ -1740,7 +1741,7 @@ struct DList(T)
{ {
assert(checkRangeBelonging(r)); assert(checkRangeBelonging(r));
} }
body do
{ {
auto temp = allocator.make!Entry(el, null, *r.tail); auto temp = allocator.make!Entry(el, null, *r.tail);
@ -1778,7 +1779,7 @@ struct DList(T)
{ {
assert(checkRangeBelonging(r)); assert(checkRangeBelonging(r));
} }
body do
{ {
size_t inserted; size_t inserted;
foreach (e; el) foreach (e; el)
@ -1895,7 +1896,7 @@ struct DList(T)
{ {
assert(!empty); assert(!empty);
} }
body do
{ {
auto n = this.head.next; auto n = this.head.next;
@ -1931,7 +1932,7 @@ struct DList(T)
{ {
assert(!empty); assert(!empty);
} }
body do
{ {
auto n = this.tail.prev; auto n = this.tail.prev;
@ -1977,7 +1978,7 @@ struct DList(T)
{ {
assert(removed <= howMany); assert(removed <= howMany);
} }
body do
{ {
size_t i; size_t i;
for (; i < howMany && !empty; ++i) for (; i < howMany && !empty; ++i)
@ -2004,7 +2005,7 @@ struct DList(T)
{ {
assert(removed <= howMany); assert(removed <= howMany);
} }
body do
{ {
size_t i; size_t i;
for (; i < howMany && !empty; ++i) for (; i < howMany && !empty; ++i)
@ -2040,7 +2041,7 @@ struct DList(T)
{ {
assert(checkRangeBelonging(r)); assert(checkRangeBelonging(r));
} }
body do
{ {
// Save references to the elements before and after the range. // Save references to the elements before and after the range.
Entry* tailNext, headPrev; Entry* tailNext, headPrev;

View File

@ -14,7 +14,7 @@
*/ */
module tanya.container.queue; module tanya.container.queue;
import std.algorithm.mutation; import tanya.algorithm.mutation;
import tanya.container.entry; import tanya.container.entry;
import tanya.exception; import tanya.exception;
import tanya.memory; import tanya.memory;
@ -167,7 +167,7 @@ struct Queue(T)
{ {
assert(!empty); assert(!empty);
} }
body do
{ {
auto n = first.next; auto n = first.next;
T ret = move(first.content); T ret = move(first.content);

View File

@ -15,7 +15,7 @@
*/ */
module tanya.container.set; module tanya.container.set;
import std.algorithm.mutation; import tanya.algorithm.mutation;
import tanya.container; import tanya.container;
import tanya.container.entry; import tanya.container.entry;
import tanya.memory; import tanya.memory;
@ -76,7 +76,7 @@ struct Range(E)
assert(this.dataRange.empty assert(this.dataRange.empty
|| this.dataRange.back.status == BucketStatus.used); || this.dataRange.back.status == BucketStatus.used);
} }
body do
{ {
do do
{ {
@ -96,7 +96,7 @@ struct Range(E)
assert(this.dataRange.empty assert(this.dataRange.empty
|| this.dataRange.back.status == BucketStatus.used); || this.dataRange.back.status == BucketStatus.used);
} }
body do
{ {
do do
{ {
@ -111,7 +111,7 @@ struct Range(E)
assert(!this.dataRange.empty); assert(!this.dataRange.empty);
assert(this.dataRange.front.status == BucketStatus.used); assert(this.dataRange.front.status == BucketStatus.used);
} }
body do
{ {
return dataRange.front.content; return dataRange.front.content;
} }
@ -122,7 +122,7 @@ struct Range(E)
assert(!this.dataRange.empty); assert(!this.dataRange.empty);
assert(this.dataRange.back.status == BucketStatus.used); assert(this.dataRange.back.status == BucketStatus.used);
} }
body do
{ {
return dataRange.back.content; return dataRange.back.content;
} }
@ -180,7 +180,7 @@ struct Set(T)
{ {
assert(allocator !is null); assert(allocator !is null);
} }
body do
{ {
this(allocator); this(allocator);
rehash(n); rehash(n);
@ -192,7 +192,7 @@ struct Set(T)
{ {
assert(allocator !is null); assert(allocator !is null);
} }
body do
{ {
this.data = typeof(this.data)(allocator); this.data = typeof(this.data)(allocator);
} }
@ -227,7 +227,7 @@ struct Set(T)
{ {
assert(allocator !is null); assert(allocator !is null);
} }
body do
{ {
this.data = typeof(this.data)(init.data, allocator); this.data = typeof(this.data)(init.data, allocator);
} }
@ -239,7 +239,7 @@ struct Set(T)
{ {
assert(allocator !is null); assert(allocator !is null);
} }
body do
{ {
this.data = typeof(this.data)(move(init.data), allocator); this.data = typeof(this.data)(move(init.data), allocator);
this.lengthIndex = init.lengthIndex; this.lengthIndex = init.lengthIndex;
@ -285,7 +285,7 @@ struct Set(T)
{ {
assert(allocator !is null); assert(allocator !is null);
} }
body do
{ {
return cast(shared Allocator) this.data.allocator; return cast(shared Allocator) this.data.allocator;
} }
@ -371,7 +371,7 @@ struct Set(T)
{ {
assert(buckets.length > 0); assert(buckets.length > 0);
} }
body do
{ {
return hash % buckets.length; return hash % buckets.length;
} }

View File

@ -27,9 +27,10 @@
module tanya.container.string; module tanya.container.string;
import std.algorithm.comparison; import std.algorithm.comparison;
import std.algorithm.mutation; import std.algorithm.mutation : bringToFront, copy;
import std.algorithm.searching; import std.algorithm.searching;
static import std.range; static import std.range;
import tanya.algorithm.mutation;
import tanya.memory; import tanya.memory;
import tanya.meta.trait; import tanya.meta.trait;
import tanya.meta.transform; import tanya.meta.transform;
@ -90,7 +91,7 @@ if (is(Unqual!E == char))
assert(begin >= container.data); assert(begin >= container.data);
assert(end <= container.data + container.length); assert(end <= container.data + container.length);
} }
body do
{ {
this.container = &container; this.container = &container;
this.begin = begin; this.begin = begin;
@ -121,7 +122,7 @@ if (is(Unqual!E == char))
{ {
assert(!empty); assert(!empty);
} }
body do
{ {
return *this.begin; return *this.begin;
} }
@ -131,7 +132,7 @@ if (is(Unqual!E == char))
{ {
assert(!empty); assert(!empty);
} }
body do
{ {
return *(this.end - 1); return *(this.end - 1);
} }
@ -141,7 +142,7 @@ if (is(Unqual!E == char))
{ {
assert(!empty); assert(!empty);
} }
body do
{ {
++this.begin; ++this.begin;
} }
@ -151,7 +152,7 @@ if (is(Unqual!E == char))
{ {
assert(!empty); assert(!empty);
} }
body do
{ {
--this.end; --this.end;
} }
@ -161,7 +162,7 @@ if (is(Unqual!E == char))
{ {
assert(i < length); assert(i < length);
} }
body do
{ {
return *(this.begin + i); return *(this.begin + i);
} }
@ -182,7 +183,7 @@ if (is(Unqual!E == char))
assert(i <= j); assert(i <= j);
assert(j <= length); assert(j <= length);
} }
body do
{ {
return typeof(return)(*this.container, this.begin + i, this.begin + j); return typeof(return)(*this.container, this.begin + i, this.begin + j);
} }
@ -193,7 +194,7 @@ if (is(Unqual!E == char))
assert(i <= j); assert(i <= j);
assert(j <= length); assert(j <= length);
} }
body do
{ {
return typeof(return)(*this.container, this.begin + i, this.begin + j); return typeof(return)(*this.container, this.begin + i, this.begin + j);
} }
@ -232,7 +233,7 @@ if (is(Unqual!E == char))
assert(begin >= container.data); assert(begin >= container.data);
assert(end <= container.data + container.length); assert(end <= container.data + container.length);
} }
body do
{ {
this.container = &container; this.container = &container;
this.begin = begin; this.begin = begin;
@ -260,10 +261,11 @@ if (is(Unqual!E == char))
{ {
assert(chr < 0xd800 || chr > 0xdfff); assert(chr < 0xd800 || chr > 0xdfff);
} }
body do
{ {
dchar chr; dchar chr;
ubyte units, mask; ubyte units;
int mask;
const(char)* it = this.begin; const(char)* it = this.begin;
if (*it & 0x80) if (*it & 0x80)
@ -293,7 +295,7 @@ if (is(Unqual!E == char))
{ {
assert(!empty); assert(!empty);
} }
body do
{ {
ubyte units; ubyte units;
if ((*begin & 0xf0) == 0xf0) if ((*begin & 0xf0) == 0xf0)
@ -436,7 +438,7 @@ struct String
{ {
assert(allocator !is null); assert(allocator !is null);
} }
body do
{ {
this.allocator_ = allocator; this.allocator_ = allocator;
} }
@ -526,7 +528,7 @@ struct String
assert(capacity - length >= 4); assert(capacity - length >= 4);
assert(src - 0x10000 < 0x100000); assert(src - 0x10000 < 0x100000);
} }
body do
{ {
auto dst = this.data + length; auto dst = this.data + length;
@ -544,7 +546,7 @@ struct String
{ {
assert(capacity - length >= 3); assert(capacity - length >= 3);
} }
body do
{ {
auto dst = this.data + length; auto dst = this.data + length;
if (chr < 0x80) if (chr < 0x80)
@ -922,7 +924,7 @@ struct String
assert(j <= length); assert(j <= length);
assert(j - i == value.length); assert(j - i == value.length);
} }
body do
{ {
auto target = opSlice(i, j); auto target = opSlice(i, j);
copy(value, target); copy(value, target);
@ -939,7 +941,7 @@ struct String
assert(i <= j); assert(i <= j);
assert(j <= length); assert(j <= length);
} }
body do
{ {
copy(value[], this.data[i .. j]); copy(value[], this.data[i .. j]);
return opSlice(i, j); return opSlice(i, j);
@ -955,7 +957,7 @@ struct String
assert(i <= j); assert(i <= j);
assert(j <= length); assert(j <= length);
} }
body do
{ {
for (auto p = this.data + i; p < this.data + j; ++p) for (auto p = this.data + i; p < this.data + j; ++p)
{ {
@ -1036,7 +1038,7 @@ struct String
{ {
assert(length > pos); assert(length > pos);
} }
body do
{ {
return *(this.data + pos); return *(this.data + pos);
} }
@ -1186,7 +1188,7 @@ struct String
assert(i <= j); assert(i <= j);
assert(j <= length); assert(j <= length);
} }
body do
{ {
return typeof(return)(this, this.data + i, this.data + j); return typeof(return)(this, this.data + i, this.data + j);
} }
@ -1199,7 +1201,7 @@ struct String
assert(i <= j); assert(i <= j);
assert(j <= length); assert(j <= length);
} }
body do
{ {
return typeof(return)(this, this.data + i, this.data + j); return typeof(return)(this, this.data + i, this.data + j);
} }
@ -1507,7 +1509,7 @@ struct String
assert(r.begin >= this.data); assert(r.begin >= this.data);
assert(r.end <= this.data + length); assert(r.end <= this.data + length);
} }
body do
{ {
auto end = this.data + this.length; auto end = this.data + this.length;
copy(ByCodeUnit!char(this, r.end, end), ByCodeUnit!char(this, r.begin, end)); copy(ByCodeUnit!char(this, r.end, end), ByCodeUnit!char(this, r.begin, end));
@ -1560,7 +1562,7 @@ struct String
assert(r.begin >= this.data); assert(r.begin >= this.data);
assert(r.end <= this.data + length); assert(r.end <= this.data + length);
} }
body do
{ {
auto oldLen = this.data + length; auto oldLen = this.data + length;
const inserted = insertBack(el); const inserted = insertBack(el);
@ -1593,7 +1595,7 @@ struct String
assert(r.begin >= this.data); assert(r.begin >= this.data);
assert(r.end <= this.data + length); assert(r.end <= this.data + length);
} }
body do
{ {
return insertAfter(R(this, this.data, r.begin), el); return insertAfter(R(this, this.data, r.begin), el);
} }

View File

@ -14,9 +14,17 @@
*/ */
module tanya.conv; module tanya.conv;
import tanya.container.string;
import tanya.format;
import tanya.memory; import tanya.memory;
import tanya.memory.op; import tanya.memory.op;
import tanya.meta.trait; import tanya.meta.trait;
import tanya.meta.transform;
version (unittest)
{
import tanya.test.assertion;
}
/** /**
* Constructs a new object of type $(D_PARAM T) in $(D_PARAM memory) with the * Constructs a new object of type $(D_PARAM T) in $(D_PARAM memory) with the
@ -58,7 +66,7 @@ out (result)
{ {
assert(memory.ptr is (() @trusted => cast(void*) result)()); assert(memory.ptr is (() @trusted => cast(void*) result)());
} }
body do
{ {
copy(typeid(T).initializer, memory); copy(typeid(T).initializer, memory);
@ -83,7 +91,8 @@ in
out (result) out (result)
{ {
assert(memory.ptr is (() @trusted => cast(void*) result)()); assert(memory.ptr is (() @trusted => cast(void*) result)());
}body }
do
{ {
copy(typeid(T).initializer, memory); copy(typeid(T).initializer, memory);
@ -136,7 +145,7 @@ out (result)
{ {
assert(memory.ptr is result); assert(memory.ptr is result);
} }
body do
{ {
auto result = (() @trusted => cast(T*) memory.ptr)(); auto result = (() @trusted => cast(T*) memory.ptr)();
static if (Args.length == 1) static if (Args.length == 1)
@ -161,7 +170,7 @@ out (result)
{ {
assert(memory.ptr is result); assert(memory.ptr is result);
} }
body do
{ {
auto result = (() @trusted => cast(T*) memory.ptr)(); auto result = (() @trusted => cast(T*) memory.ptr)();
static if (!hasElaborateAssign!T && isAssignable!T) static if (!hasElaborateAssign!T && isAssignable!T)
@ -233,3 +242,469 @@ body
} }
static assert(is(typeof(emplace!F((void[]).init)))); static assert(is(typeof(emplace!F((void[]).init))));
} }
/**
* Thrown if a type conversion fails.
*/
final class ConvException : Exception
{
/**
* 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,
string file = __FILE__,
size_t line = __LINE__,
Throwable next = null) @nogc @safe pure nothrow
{
super(msg, file, line, next);
}
}
/**
* If the source type $(D_PARAM From) and the target type $(D_PARAM To) are
* equal, does nothing. If $(D_PARAM From) can be implicitly converted to
* $(D_PARAM To), just returns $(D_PARAM from).
*
* Params:
* To = Target type.
*
* Returns: $(D_PARAM from).
*/
template to(To)
{
/**
* Params:
* From = Source type.
* from = Source value.
*/
ref To to(From)(ref From from)
if (is(To == From))
{
return from;
}
/// ditto
To to(From)(From from)
if (is(Unqual!To == Unqual!From) || (isNumeric!From && isFloatingPoint!To))
{
return from;
}
}
///
@nogc nothrow pure @safe unittest
{
auto val = 5.to!int();
assert(val == 5);
static assert(is(typeof(val) == int));
}
@nogc nothrow pure @safe unittest
{
int val = 5;
assert(val.to!int() == 5);
}
/**
* Performs checked conversion from an integral type $(D_PARAM From) to an
* integral type $(D_PARAM To).
*
* Params:
* From = Source type.
* To = Target type.
* from = Source value.
*
* Returns: $(D_PARAM from) converted to $(D_PARAM To).
*
* Throws: $(D_PSYMBOL ConvException) if $(D_PARAM from) is too small or too
* large to be represented by $(D_PARAM To).
*/
To to(To, From)(From from)
if (isIntegral!From
&& isIntegral!To
&& !is(Unqual!To == Unqual!From)
&& !is(To == enum))
{
static if ((isUnsigned!From && isSigned!To && From.sizeof == To.sizeof)
|| From.sizeof > To.sizeof)
{
if (from > To.max)
{
throw make!ConvException(defaultAllocator,
"Positive integer overflow");
}
}
static if (isSigned!From)
{
static if (isUnsigned!To)
{
if (from < 0)
{
throw make!ConvException(defaultAllocator,
"Negative integer overflow");
}
}
else static if (From.sizeof > To.sizeof)
{
if (from < To.min)
{
throw make!ConvException(defaultAllocator,
"Negative integer overflow");
}
}
}
static if (From.sizeof <= To.sizeof)
{
return from;
}
else static if (isSigned!To)
{
return cast(To) from;
}
else
{
return from & To.max;
}
}
@nogc nothrow pure @safe unittest
{
// ubyte -> ushort
assert((cast(ubyte) 0).to!ushort == 0);
assert((cast(ubyte) 1).to!ushort == 1);
assert((cast(ubyte) (ubyte.max - 1)).to!ushort == ubyte.max - 1);
assert((cast(ubyte) ubyte.max).to!ushort == ubyte.max);
// ubyte -> short
assert((cast(ubyte) 0).to!short == 0);
assert((cast(ubyte) 1).to!short == 1);
assert((cast(ubyte) (ubyte.max - 1)).to!short == ubyte.max - 1);
assert((cast(ubyte) ubyte.max).to!short == ubyte.max);
}
@nogc pure @safe unittest
{
// ubyte <- ushort
assert((cast(ushort) 0).to!ubyte == 0);
assert((cast(ushort) 1).to!ubyte == 1);
assert((cast(ushort) (ubyte.max - 1)).to!ubyte == ubyte.max - 1);
assert((cast(ushort) ubyte.max).to!ubyte == ubyte.max);
// ubyte <- short
assert((cast(short) 0).to!ubyte == 0);
assert((cast(short) 1).to!ubyte == 1);
assert((cast(short) (ubyte.max - 1)).to!ubyte == ubyte.max - 1);
assert((cast(short) ubyte.max).to!ubyte == ubyte.max);
// short <-> int
assert(short.min.to!int == short.min);
assert((short.min + 1).to!int == short.min + 1);
assert((cast(short) -1).to!int == -1);
assert((cast(short) 0).to!int == 0);
assert((cast(short) 1).to!int == 1);
assert((short.max - 1).to!int == short.max - 1);
assert(short.max.to!int == short.max);
assert((cast(int) short.min).to!short == short.min);
assert((cast(int) short.min + 1).to!short == short.min + 1);
assert((cast(int) -1).to!short == -1);
assert((cast(int) 0).to!short == 0);
assert((cast(int) 1).to!short == 1);
assert((cast(int) short.max - 1).to!short == short.max - 1);
assert((cast(int) short.max).to!short == short.max);
// uint <-> int
assert((cast(uint) 0).to!int == 0);
assert((cast(uint) 1).to!int == 1);
assert((cast(uint) (int.max - 1)).to!int == int.max - 1);
assert((cast(uint) int.max).to!int == int.max);
assert((cast(int) 0).to!uint == 0);
assert((cast(int) 1).to!uint == 1);
assert((cast(int) (int.max - 1)).to!uint == int.max - 1);
assert((cast(int) int.max).to!uint == int.max);
}
@nogc pure @safe unittest
{
assertThrown!ConvException(&to!(short, int), int.min);
assertThrown!ConvException(&to!(short, int), int.max);
assertThrown!ConvException(&to!(ushort, uint), uint.max);
assertThrown!ConvException(&to!(uint, int), -1);
}
@nogc nothrow pure @safe unittest
{
enum Test : int
{
one,
two,
}
assert(Test.one.to!int == 0);
assert(Test.two.to!int == 1);
}
/**
* Converts a floating point number to an integral type.
*
* Params:
* From = Source type.
* To = Target type.
* from = Source value.
*
* Returns: Truncated $(D_PARAM from) (everything after the decimal point is
* dropped).
*
* Throws: $(D_PSYMBOL ConvException) if
* $(D_INLINECODE from < To.min || from > To.max).
*/
To to(To, From)(From from)
if (isFloatingPoint!From
&& isIntegral!To
&& !is(Unqual!To == Unqual!From)
&& !is(To == enum))
{
if (from > To.max)
{
throw make!ConvException(defaultAllocator,
"Positive number overflow");
}
else if (from < To.min)
{
throw make!ConvException(defaultAllocator,
"Negative number overflow");
}
return cast(To) from;
}
///
@nogc pure @safe unittest
{
assert(1.5.to!int == 1);
assert(2147483646.5.to!int == 2147483646);
assert((-2147483647.5).to!int == -2147483647);
assert(2147483646.5.to!uint == 2147483646);
}
@nogc pure @safe unittest
{
assertThrown!ConvException(&to!(int, double), 2147483647.5);
assertThrown!ConvException(&to!(int, double), -2147483648.5);
assertThrown!ConvException(&to!(uint, double), -21474.5);
}
/**
* Performs checked conversion from an integral type $(D_PARAM From) to an
* $(D_KEYWORD enum).
*
* Params:
* From = Source type.
* To = Target type.
* from = Source value.
*
* Returns: $(D_KEYWORD enum) value.
*
* Throws: $(D_PSYMBOL ConvException) if $(D_PARAM from) is not a member of
* $(D_PSYMBOL To).
*/
To to(To, From)(From from)
if (isIntegral!From && is(To == enum))
{
foreach (m; EnumMembers!To)
{
if (from == m)
{
return m;
}
}
throw make!ConvException(defaultAllocator,
"Value not found in enum '" ~ To.stringof ~ "'");
}
///
@nogc pure @safe unittest
{
enum Test : int
{
one,
two,
}
static assert(is(typeof(1.to!Test) == Test));
assert(0.to!Test == Test.one);
assert(1.to!Test == Test.two);
}
@nogc pure @safe unittest
{
enum Test : uint
{
one,
two,
}
assertThrown!ConvException(&to!(Test, int), 5);
}
/**
* Converts $(D_PARAM from) to a boolean.
*
* If $(D_PARAM From) is a numeric type, then `1` becomes $(D_KEYWORD true),
* `0` $(D_KEYWORD false). Otherwise $(D_PSYMBOL ConvException) is thrown.
*
* If $(D_PARAM To) is a string (built-in string or $(D_PSYMBOL String)),
* then `"true"` or `"false"` are converted to the appropriate boolean value.
* Otherwise $(D_PSYMBOL ConvException) is thrown.
*
* Params:
* From = Source type.
* To = Target type.
* from = Source value.
*
* Returns: $(D_KEYWORD from) converted to a boolean.
*
* Throws: $(D_PSYMBOL ConvException) if $(D_PARAM from) isn't convertible.
*/
To to(To, From)(From from)
if (isNumeric!From && is(Unqual!To == bool) && !is(Unqual!To == Unqual!From))
{
if (from == 0)
{
return false;
}
else if (from < 0)
{
throw make!ConvException(defaultAllocator,
"Negative number overflow");
}
else if (from <= 1)
{
return true;
}
throw make!ConvException(defaultAllocator,
"Positive number overflow");
}
///
@nogc pure @safe unittest
{
assert(!0.0.to!bool);
assert(0.2.to!bool);
assert(0.5.to!bool);
assert(1.0.to!bool);
assert(!0.to!bool);
assert(1.to!bool);
}
@nogc pure @safe unittest
{
assertThrown!ConvException(&to!(bool, int), -1);
assertThrown!ConvException(&to!(bool, int), 2);
}
/// ditto
To to(To, From)(auto ref const From from)
if ((is(From == String) || isSomeString!From) && is(Unqual!To == bool))
{
if (from == "true")
{
return true;
}
else if (from == "false")
{
return false;
}
throw make!ConvException(defaultAllocator,
"String doesn't contain a boolean value");
}
///
@nogc pure @safe unittest
{
assert("true".to!bool);
assert(!"false".to!bool);
assert(String("true").to!bool);
assert(!String("false").to!bool);
}
@nogc pure @safe unittest
{
assertThrown!ConvException(() => "1".to!bool);
}
/**
* Converts a boolean to $(D_PARAM To).
*
* If $(D_PARAM To) is a numeric type, then $(D_KEYWORD true) becomes `1`,
* $(D_KEYWORD false) `0`.
*
* If $(D_PARAM To) is a $(D_PSYMBOL String), then `"true"` or `"false"`
* is returned.
*
* Params:
* From = Source type.
* To = Target type.
* from = Source value.
*
* Returns: $(D_PARAM from) converted to $(D_PARAM To).
*/
To to(To, From)(From from)
if (is(Unqual!From == bool) && isNumeric!To && !is(Unqual!To == Unqual!From))
{
return from;
}
///
@nogc nothrow pure @safe unittest
{
assert(true.to!float == 1.0);
assert(true.to!double == 1.0);
assert(true.to!ubyte == 1);
assert(true.to!byte == 1);
assert(true.to!ushort == 1);
assert(true.to!short == 1);
assert(true.to!uint == 1);
assert(true.to!int == 1);
assert(false.to!float == 0);
assert(false.to!double == 0);
assert(false.to!ubyte == 0);
assert(false.to!byte == 0);
assert(false.to!ushort == 0);
assert(false.to!short == 0);
assert(false.to!uint == 0);
assert(false.to!int == 0);
}
/**
* Converts $(D_PARAM From) to a $(D_PSYMBOL String).
*
* Params:
* From = Source type.
* To = Target type.
* from = Source value.
*
* Returns: $(D_PARAM from) converted to $(D_PSYMBOL String).
*/
To to(To, From)(auto ref From from)
if (is(Unqual!To == String))
{
return format!"{}"(from);
}
///
@nogc nothrow pure @safe unittest
{
assert(true.to!String == "true");
assert(false.to!String == "false");
}
@nogc nothrow pure @safe unittest
{
static assert(is(typeof((const String("true")).to!bool)));
static assert(is(typeof(false.to!(const String) == "false")));
}

1145
source/tanya/format.d Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,691 +0,0 @@
/* 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: Jeff Roberts, $(LINK2 mailto:info@caraus.de, Eugene Wissner)
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/format/conv.d,
* tanya/format/conv.d)
*/
module tanya.format.conv;
import tanya.container.string;
import tanya.memory;
import tanya.memory.op;
import tanya.meta.trait;
import tanya.meta.transform;
/**
* Thrown if a type conversion fails.
*/
final class ConvException : Exception
{
/**
* 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,
string file = __FILE__,
size_t line = __LINE__,
Throwable next = null) @nogc @safe pure nothrow
{
super(msg, file, line, next);
}
}
/**
* If the source type $(D_PARAM From) and the target type $(D_PARAM To) are
* equal, does nothing. If $(D_PARAM From) can be implicitly converted to
* $(D_PARAM To), just returns $(D_PARAM from).
*
* Params:
* To = Target type.
*
* Returns: $(D_PARAM from).
*/
template to(To)
{
/**
* Params:
* From = Source type.
* from = Source value.
*/
ref To to(From)(ref From from)
if (is(To == From))
{
return from;
}
/// ditto
To to(From)(From from)
if (is(Unqual!To == Unqual!From) || (isNumeric!From && isFloatingPoint!To))
{
return from;
}
}
///
pure nothrow @safe @nogc unittest
{
auto val = 5.to!int();
assert(val == 5);
static assert(is(typeof(val) == int));
}
private pure nothrow @safe @nogc unittest
{
int val = 5;
assert(val.to!int() == 5);
}
/**
* Performs checked conversion from an integral type $(D_PARAM From) to an
* integral type $(D_PARAM To).
*
* Params:
* From = Source type.
* To = Target type.
* from = Source value.
*
* Returns: $(D_PARAM from) converted to $(D_PARAM To).
*
* Throws: $(D_PSYMBOL ConvException) if $(D_PARAM from) is too small or too
* large to be represented by $(D_PARAM To).
*/
To to(To, From)(From from)
if (isIntegral!From
&& isIntegral!To
&& !is(Unqual!To == Unqual!From)
&& !is(To == enum))
{
static if ((isUnsigned!From && isSigned!To && From.sizeof == To.sizeof)
|| From.sizeof > To.sizeof)
{
if (from > To.max)
{
throw make!ConvException(defaultAllocator,
"Positive integer overflow");
}
}
static if (isSigned!From)
{
static if (isUnsigned!To)
{
if (from < 0)
{
throw make!ConvException(defaultAllocator,
"Negative integer overflow");
}
}
else static if (From.sizeof > To.sizeof)
{
if (from < To.min)
{
throw make!ConvException(defaultAllocator,
"Negative integer overflow");
}
}
}
static if (From.sizeof <= To.sizeof)
{
return from;
}
else static if (isSigned!To)
{
return cast(To) from;
}
else
{
return from & To.max;
}
}
private pure nothrow @safe @nogc unittest
{
// ubyte -> ushort
assert((cast(ubyte) 0).to!ushort == 0);
assert((cast(ubyte) 1).to!ushort == 1);
assert((cast(ubyte) (ubyte.max - 1)).to!ushort == ubyte.max - 1);
assert((cast(ubyte) ubyte.max).to!ushort == ubyte.max);
// ubyte -> short
assert((cast(ubyte) 0).to!short == 0);
assert((cast(ubyte) 1).to!short == 1);
assert((cast(ubyte) (ubyte.max - 1)).to!short == ubyte.max - 1);
assert((cast(ubyte) ubyte.max).to!short == ubyte.max);
}
private unittest
{
// ubyte <- ushort
assert((cast(ushort) 0).to!ubyte == 0);
assert((cast(ushort) 1).to!ubyte == 1);
assert((cast(ushort) (ubyte.max - 1)).to!ubyte == ubyte.max - 1);
assert((cast(ushort) ubyte.max).to!ubyte == ubyte.max);
// ubyte <- short
assert((cast(short) 0).to!ubyte == 0);
assert((cast(short) 1).to!ubyte == 1);
assert((cast(short) (ubyte.max - 1)).to!ubyte == ubyte.max - 1);
assert((cast(short) ubyte.max).to!ubyte == ubyte.max);
// short <-> int
assert(short.min.to!int == short.min);
assert((short.min + 1).to!int == short.min + 1);
assert((cast(short) -1).to!int == -1);
assert((cast(short) 0).to!int == 0);
assert((cast(short) 1).to!int == 1);
assert((short.max - 1).to!int == short.max - 1);
assert(short.max.to!int == short.max);
assert((cast(int) short.min).to!short == short.min);
assert((cast(int) short.min + 1).to!short == short.min + 1);
assert((cast(int) -1).to!short == -1);
assert((cast(int) 0).to!short == 0);
assert((cast(int) 1).to!short == 1);
assert((cast(int) short.max - 1).to!short == short.max - 1);
assert((cast(int) short.max).to!short == short.max);
// uint <-> int
assert((cast(uint) 0).to!int == 0);
assert((cast(uint) 1).to!int == 1);
assert((cast(uint) (int.max - 1)).to!int == int.max - 1);
assert((cast(uint) int.max).to!int == int.max);
assert((cast(int) 0).to!uint == 0);
assert((cast(int) 1).to!uint == 1);
assert((cast(int) (int.max - 1)).to!uint == int.max - 1);
assert((cast(int) int.max).to!uint == int.max);
}
private unittest
{
ConvException exception;
try
{
assert(int.min.to!short == int.min);
}
catch (ConvException e)
{
exception = e;
}
assert(exception !is null);
defaultAllocator.dispose(exception);
}
private unittest
{
ConvException exception;
try
{
assert(int.max.to!short == int.max);
}
catch (ConvException e)
{
exception = e;
}
assert(exception !is null);
defaultAllocator.dispose(exception);
}
private unittest
{
ConvException exception;
try
{
assert(uint.max.to!ushort == ushort.max);
}
catch (ConvException e)
{
exception = e;
}
assert(exception !is null);
defaultAllocator.dispose(exception);
}
private unittest
{
ConvException exception;
try
{
assert((-1).to!uint == -1);
}
catch (ConvException e)
{
exception = e;
}
assert(exception !is null);
defaultAllocator.dispose(exception);
}
private @nogc unittest
{
enum Test : int
{
one,
two,
}
assert(Test.one.to!int == 0);
assert(Test.two.to!int == 1);
}
/**
* Converts $(D_PARAM from) to a boolean.
*
* If $(D_PARAM From) is a numeric type, then `1` becomes $(D_KEYWORD true),
* `0` $(D_KEYWORD false). Otherwise $(D_PSYMBOL ConvException) is thrown.
*
* If $(D_PARAM To) is a string (built-in string or $(D_PSYMBOL String)),
* then `"true"` or `"false"` are converted to the appropriate boolean value.
* Otherwise $(D_PSYMBOL ConvException) is thrown.
*
* Params:
* From = Source type.
* To = Target type.
* from = Source value.
*
* Returns: $(D_KEYWORD from) converted to a boolean.
*
* Throws: $(D_PSYMBOL ConvException) if $(D_PARAM from) isn't convertible.
*/
To to(To, From)(From from)
if (isNumeric!From && is(Unqual!To == bool) && !is(Unqual!To == Unqual!From))
{
if (from == 0)
{
return false;
}
else if (from < 0)
{
throw make!ConvException(defaultAllocator,
"Negative number overflow");
}
else if (from <= 1)
{
return true;
}
throw make!ConvException(defaultAllocator,
"Positive number overflow");
}
///
@nogc unittest
{
assert(!0.0.to!bool);
assert(0.2.to!bool);
assert(0.5.to!bool);
assert(1.0.to!bool);
assert(!0.to!bool);
assert(1.to!bool);
}
private @nogc unittest
{
ConvException exception;
try
{
assert((-1).to!bool);
}
catch (ConvException e)
{
exception = e;
}
assert(exception !is null);
defaultAllocator.dispose(exception);
}
private @nogc unittest
{
ConvException exception;
try
{
assert(2.to!bool);
}
catch (ConvException e)
{
exception = e;
}
assert(exception !is null);
defaultAllocator.dispose(exception);
}
/// ditto
To to(To, From)(auto ref const From from)
if ((is(From == String) || isSomeString!From) && is(Unqual!To == bool))
{
if (from == "true")
{
return true;
}
else if (from == "false")
{
return false;
}
throw make!ConvException(defaultAllocator,
"String doesn't contain a boolean value");
}
///
@nogc unittest
{
assert("true".to!bool);
assert(!"false".to!bool);
assert(String("true").to!bool);
assert(!String("false").to!bool);
}
private @nogc unittest
{
ConvException exception;
try
{
assert("1".to!bool);
}
catch (ConvException e)
{
exception = e;
}
assert(exception !is null);
defaultAllocator.dispose(exception);
}
/**
* Converts a boolean to $(D_PARAM To).
*
* If $(D_PARAM To) is a numeric type, then $(D_KEYWORD true) becomes `1`,
* $(D_KEYWORD false) `0`.
*
* If $(D_PARAM To) is a $(D_PSYMBOL String), then `"true"` or `"false"`
* is returned.
*
* Params:
* From = Source type.
* To = Target type.
* from = Source value.
*
* Returns: $(D_PARAM from) converted to $(D_PARAM To).
*/
To to(To, From)(const From from)
if (is(Unqual!From == bool) && isNumeric!To && !is(Unqual!To == Unqual!From))
{
return from;
}
///
pure nothrow @safe @nogc unittest
{
assert(true.to!float == 1.0);
assert(true.to!double == 1.0);
assert(true.to!ubyte == 1);
assert(true.to!byte == 1);
assert(true.to!ushort == 1);
assert(true.to!short == 1);
assert(true.to!uint == 1);
assert(true.to!int == 1);
assert(false.to!float == 0);
assert(false.to!double == 0);
assert(false.to!ubyte == 0);
assert(false.to!byte == 0);
assert(false.to!ushort == 0);
assert(false.to!short == 0);
assert(false.to!uint == 0);
assert(false.to!int == 0);
}
/// ditto
To to(To, From)(const From from)
if (is(Unqual!From == bool) && is(Unqual!To == String))
{
return String(from ? "true" : "false");
}
///
@nogc unittest
{
assert(true.to!String == "true");
assert(false.to!String == "false");
}
private @nogc unittest
{
static assert(is(typeof((const String("true")).to!bool)));
static assert(is(typeof(false.to!(const String) == "false")));
}
/**
* Converts a floating point number to an integral type.
*
* Params:
* From = Source type.
* To = Target type.
* from = Source value.
*
* Returns: Truncated $(D_PARAM from) (everything after the decimal point is
* dropped).
*
* Throws: $(D_PSYMBOL ConvException) if
* $(D_INLINECODE from < To.min || from > To.max).
*/
To to(To, From)(From from)
if (isFloatingPoint!From
&& isIntegral!To
&& !is(Unqual!To == Unqual!From)
&& !is(To == enum))
{
if (from > To.max)
{
throw make!ConvException(defaultAllocator,
"Positive number overflow");
}
else if (from < To.min)
{
throw make!ConvException(defaultAllocator,
"Negative number overflow");
}
return cast(To) from;
}
///
@nogc unittest
{
assert(1.5.to!int == 1);
assert(2147483646.5.to!int == 2147483646);
assert((-2147483647.5).to!int == -2147483647);
assert(2147483646.5.to!uint == 2147483646);
}
private @nogc unittest
{
ConvException exception;
try
{
assert(2147483647.5.to!int == 2147483647);
}
catch (ConvException e)
{
exception = e;
}
assert(exception !is null);
defaultAllocator.dispose(exception);
}
private @nogc unittest
{
ConvException exception;
try
{
assert((-2147483648.5).to!int == -2147483648);
}
catch (ConvException e)
{
exception = e;
}
assert(exception !is null);
defaultAllocator.dispose(exception);
}
private @nogc unittest
{
ConvException exception;
try
{
assert((-21474.5).to!uint == -21474);
}
catch (ConvException e)
{
exception = e;
}
assert(exception !is null);
defaultAllocator.dispose(exception);
}
/**
* Performs checked conversion from an integral type $(D_PARAM From) to an
* $(D_KEYWORD enum).
*
* Params:
* From = Source type.
* To = Target type.
* from = Source value.
*
* Returns: $(D_KEYWORD enum) value.
*
* Throws: $(D_PSYMBOL ConvException) if $(D_PARAM from) is not a member of
* $(D_PSYMBOL To).
*/
To to(To, From)(From from)
if (isIntegral!From && is(To == enum))
{
foreach (m; EnumMembers!To)
{
if (from == m)
{
return m;
}
}
throw make!ConvException(defaultAllocator,
"Value not found in enum '" ~ To.stringof ~ "'");
}
///
@nogc unittest
{
enum Test : int
{
one,
two,
}
static assert(is(typeof(1.to!Test) == Test));
assert(0.to!Test == Test.one);
assert(1.to!Test == Test.two);
}
private @nogc unittest
{
enum Test : uint
{
one,
two,
}
ConvException exception;
try
{
assert(5.to!Test == Test.one);
}
catch (ConvException e)
{
exception = e;
}
assert(exception !is null);
defaultAllocator.dispose(exception);
}
// Returns the last part of buffer with converted number.
package(tanya) char[] number2String(T)(const T number,
return ref char[21] buffer)
if (isIntegral!T)
{
// abs the integer.
ulong n64 = number < 0 ? -cast(long) number : number;
char* start = buffer[].ptr + buffer.sizeof - 1;
while (true)
{
// Do in 32-bit chunks (avoid lots of 64-bit divides even with constant
// denominators).
char* o = start - 8;
uint n;
if (n64 >= 100000000)
{
n = n64 % 100000000;
n64 /= 100000000;
}
else
{
n = cast(uint) n64;
n64 = 0;
}
while (n)
{
*--start = cast(char) (n % 10) + '0';
n /= 10;
}
// Ignore the leading zero if it was the last part of the integer.
if (n64 == 0)
{
if ((start[0] == '0')
&& (start != (buffer[].ptr + buffer.sizeof -1)))
{
++start;
}
break;
}
// Copy leading zeros if it wasn't the most significant part of the
// integer.
while (start != o)
{
*--start = '0';
}
}
// Get the length that we have copied.
uint l = cast(uint) ((buffer[].ptr + buffer.sizeof - 1) - start);
if (l == 0)
{
*--start = '0';
l = 1;
}
else if (number < 0) // Set the sign.
{
*--start = '-';
++l;
}
return buffer[$ - l - 1 .. $ - 1];
}
// Converting an integer to string.
private pure nothrow @system @nogc unittest
{
char[21] buf;
assert(number2String(80, buf) == "80");
assert(number2String(-80, buf) == "-80");
assert(number2String(0, buf) == "0");
assert(number2String(uint.max, buf) == "4294967295");
assert(number2String(int.min, buf) == "-2147483648");
}

View File

@ -14,11 +14,14 @@
*/ */
module tanya.math.mp; module tanya.math.mp;
import std.algorithm; import std.algorithm.comparison;
import std.algorithm.mutation : copy, fill, reverse;
import std.range; import std.range;
import tanya.algorithm.mutation;
import tanya.container.array; import tanya.container.array;
import tanya.encoding.ascii; import tanya.encoding.ascii;
import tanya.memory; import tanya.memory;
static import tanya.memory.op;
import tanya.meta.trait; import tanya.meta.trait;
import tanya.meta.transform; import tanya.meta.transform;
@ -104,12 +107,12 @@ struct Integer
} }
/// 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);
} }
body do
{ {
this.allocator_ = allocator; this.allocator_ = allocator;
} }
@ -156,7 +159,7 @@ struct Integer
} }
/// ///
nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
ubyte[8] range = [ 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xdd, 0xee ]; ubyte[8] range = [ 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xdd, 0xee ];
auto integer = Integer(Sign.positive, range[]); auto integer = Integer(Sign.positive, range[]);
@ -187,7 +190,7 @@ struct Integer
} }
/// ///
nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
{ {
ubyte[8] range = [ 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xdd, 0xee ]; ubyte[8] range = [ 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xdd, 0xee ];
@ -204,17 +207,17 @@ struct Integer
/** /**
* Copies the integer. * Copies the integer.
*/ */
this(this) nothrow @trusted @nogc this(this) @nogc nothrow pure @safe
{ {
auto tmp = allocator.resize!digit(null, this.size); auto tmp = allocator.resize!digit(null, this.size);
this.rep[0 .. this.size].copy(tmp); tanya.memory.op.copy(this.rep[0 .. this.size], tmp);
this.rep = tmp; this.rep = tmp;
} }
/** /**
* Destroys the integer. * Destroys the integer.
*/ */
~this() nothrow @trusted @nogc ~this() @nogc nothrow pure @safe
{ {
allocator.resize(this.rep, 0); allocator.resize(this.rep, 0);
} }
@ -224,7 +227,7 @@ struct Integer
]; ];
// Counts the number of LSBs before the first non-zero bit. // Counts the number of LSBs before the first non-zero bit.
private ptrdiff_t countLSBs() const pure nothrow @safe @nogc private ptrdiff_t countLSBs() const @nogc nothrow pure @safe
{ {
if (this.size == 0) if (this.size == 0)
{ {
@ -256,7 +259,7 @@ struct Integer
/** /**
* Returns: Number of bytes in the two's complement representation. * Returns: Number of bytes in the two's complement representation.
*/ */
@property size_t length() const pure nothrow @safe @nogc @property size_t length() const @nogc nothrow pure @safe
{ {
if (this.sign) if (this.sign)
{ {
@ -280,7 +283,7 @@ struct Integer
} }
/// ///
private nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
{ {
Integer i; Integer i;
@ -336,11 +339,12 @@ struct Integer
} }
/// ditto /// ditto
ref Integer opAssign(T)(ref T value) @trusted ref Integer opAssign(T)(ref T value)
if (is(Unqual!T == Integer)) if (is(Unqual!T == Integer))
{ {
this.rep = allocator.resize(this.rep, value.size); this.rep = allocator.resize(this.rep, value.size);
value.rep[0 .. value.size].copy(this.rep[0 .. value.size]); tanya.memory.op.copy(value.rep[0 .. value.size],
this.rep[0 .. value.size]);
this.size = value.size; this.size = value.size;
this.sign = value.sign; this.sign = value.sign;
@ -348,7 +352,7 @@ struct Integer
} }
/// ditto /// ditto
ref Integer opAssign(T)(T value) nothrow @safe @nogc ref Integer opAssign(T)(T value)
if (is(T == Integer)) if (is(T == Integer))
{ {
swap(this.rep, value.rep); swap(this.rep, value.rep);
@ -389,11 +393,13 @@ struct Integer
T opCast(T)() const T opCast(T)() const
if (isIntegral!T && isSigned!T) if (isIntegral!T && isSigned!T)
{ {
return this.sign ? -(cast(Unsigned!T) this) : cast(Unsigned!T) this; return this.sign
? cast(T) -(cast(Promoted!(Unsigned!T)) (cast(Unsigned!T) this))
: cast(Unsigned!T) this;
} }
/// ///
@safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
auto integer = Integer(79); auto integer = Integer(79);
assert(cast(ushort) integer == 79); assert(cast(ushort) integer == 79);
@ -424,7 +430,7 @@ struct Integer
* Typically very fast. Also fixes the sign if there * Typically very fast. Also fixes the sign if there
* are no more leading digits * are no more leading digits
*/ */
void contract() nothrow @safe @nogc void contract() @nogc nothrow pure @safe
{ {
/* decrease size while the most significant digit is /* decrease size while the most significant digit is
* zero. * zero.
@ -441,7 +447,7 @@ struct Integer
} }
} }
private void grow(const size_t size) nothrow @trusted @nogc private void grow(const size_t size) @nogc nothrow pure @safe
{ {
if (this.rep.length >= size) if (this.rep.length >= size)
{ {
@ -452,7 +458,7 @@ struct Integer
this.rep[oldLength .. $].fill(digit.init); this.rep[oldLength .. $].fill(digit.init);
} }
private size_t countBits() const pure nothrow @safe @nogc private size_t countBits() const @nogc nothrow pure @safe
{ {
if (this.size == 0) if (this.size == 0)
{ {
@ -470,7 +476,7 @@ struct Integer
} }
private void add(ref const Integer summand, ref Integer sum) private void add(ref const Integer summand, ref Integer sum)
const nothrow @safe @nogc const @nogc nothrow pure @safe
{ {
const(digit)[] max, min; const(digit)[] max, min;
@ -521,7 +527,7 @@ struct Integer
} }
private void add(const digit summand, ref Integer sum) private void add(const digit summand, ref Integer sum)
const nothrow @safe @nogc const @nogc nothrow pure @safe
{ {
sum.grow(this.size + 2); sum.grow(this.size + 2);
@ -547,7 +553,7 @@ struct Integer
} }
private void subtract(ref const Integer subtrahend, ref Integer difference) private void subtract(ref const Integer subtrahend, ref Integer difference)
const nothrow @safe @nogc const @nogc nothrow pure @safe
{ {
difference.grow(this.size); difference.grow(this.size);
@ -583,7 +589,7 @@ struct Integer
} }
private void subtract(const digit subtrahend, ref Integer difference) private void subtract(const digit subtrahend, ref Integer difference)
const nothrow @safe @nogc const @nogc nothrow pure @safe
{ {
difference.grow(this.size); difference.grow(this.size);
@ -612,7 +618,7 @@ struct Integer
} }
// Compare the magnitude. // Compare the magnitude.
private int compare(ref const Integer that) const pure nothrow @safe @nogc private int compare(ref const Integer that) const @nogc nothrow pure @safe
{ {
if (this.size > that.size) if (this.size > that.size)
{ {
@ -661,7 +667,7 @@ struct Integer
} }
/// ///
@safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
auto integer1 = Integer(1019); auto integer1 = Integer(1019);
auto integer2 = Integer(1019); auto integer2 = Integer(1019);
@ -707,7 +713,7 @@ struct Integer
} }
/// ///
@safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
auto integer = Integer(1019); auto integer = Integer(1019);
@ -731,7 +737,7 @@ struct Integer
} }
/// ///
@safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
auto integer = Integer(1019); auto integer = Integer(1019);
@ -767,7 +773,7 @@ struct Integer
} }
/// ///
unittest @nogc nothrow pure @safe unittest
{ {
{ {
auto h1 = Integer(1019); auto h1 = Integer(1019);
@ -809,7 +815,7 @@ struct Integer
} }
/// ///
unittest @nogc nothrow pure @safe unittest
{ {
{ {
auto h1 = Integer(3); auto h1 = Integer(3);
@ -853,7 +859,7 @@ struct Integer
} }
/// ///
nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
auto h1 = Integer(123); auto h1 = Integer(123);
auto h2 = Integer(456); auto h2 = Integer(456);
@ -867,7 +873,7 @@ struct Integer
{ {
assert(operand.length > 0, "Division by zero."); assert(operand.length > 0, "Division by zero.");
} }
body do
{ {
divide(operand, this); divide(operand, this);
return this; return this;
@ -879,13 +885,13 @@ struct Integer
{ {
assert(operand.length > 0, "Division by zero."); assert(operand.length > 0, "Division by zero.");
} }
body do
{ {
divide(operand, null, this); divide(operand, null, this);
return this; return this;
} }
nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
auto h1 = Integer(18); auto h1 = Integer(18);
auto h2 = Integer(4); auto h2 = Integer(4);
@ -937,7 +943,7 @@ struct Integer
} }
/// ///
nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
auto integer = Integer(4294967294); auto integer = Integer(4294967294);
integer >>= 10; integer >>= 10;
@ -1005,7 +1011,7 @@ struct Integer
} }
/// ///
nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
auto integer = Integer(4294967295); auto integer = Integer(4294967295);
integer <<= 1; integer <<= 1;
@ -1023,7 +1029,10 @@ struct Integer
Integer opUnary(string op : "~")() const Integer opUnary(string op : "~")() const
{ {
auto ret = Integer(this, allocator); auto ret = Integer(this, allocator);
ret.rep[0 .. ret.size].each!((ref a) => a = ~a & mask); foreach (ref a; ret.rep[0 .. ret.size])
{
a = ~a & mask;
}
return ret; return ret;
} }
@ -1049,7 +1058,7 @@ struct Integer
} }
// //
nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
auto h1 = Integer(79); auto h1 = Integer(79);
Integer h2; Integer h2;
@ -1065,7 +1074,7 @@ struct Integer
assert(h1 == 79); assert(h1 == 79);
h2 = ~h1; h2 = ~h1;
assert(h2 == ~cast(ubyte) 79); assert(h2 == cast(ubyte) ~79);
} }
/// ditto /// ditto
@ -1102,7 +1111,7 @@ struct Integer
} }
/// ///
nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
Integer integer; Integer integer;
@ -1159,7 +1168,7 @@ struct Integer
{ {
assert(operand.length > 0, "Division by zero."); assert(operand.length > 0, "Division by zero.");
} }
body do
{ {
mixin("return Integer(this, allocator) " ~ op ~ "= operand;"); mixin("return Integer(this, allocator) " ~ op ~ "= operand;");
} }
@ -1172,7 +1181,7 @@ struct Integer
} }
// Shift right a certain amount of digits. // Shift right a certain amount of digits.
private void shiftRight(const size_t operand) nothrow @safe @nogc private void shiftRight(const size_t operand) @nogc nothrow pure @safe
{ {
if (operand == 0) if (operand == 0)
{ {
@ -1191,7 +1200,7 @@ struct Integer
} }
// Shift left a certain amount of digits. // Shift left a certain amount of digits.
private void shiftLeft(const size_t operand) nothrow @safe @nogc private void shiftLeft(const size_t operand) @nogc nothrow pure @safe
{ {
if (operand == 0) if (operand == 0)
{ {
@ -1213,7 +1222,7 @@ struct Integer
} }
private void multiply(const digit factor, ref Integer product) private void multiply(const digit factor, ref Integer product)
const nothrow @safe @nogc const @nogc nothrow pure @safe
{ {
product.grow(this.size + 1); product.grow(this.size + 1);
product.sign = this.sign; product.sign = this.sign;
@ -1239,7 +1248,7 @@ struct Integer
private void multiply(ref const Integer factor, private void multiply(ref const Integer factor,
ref Integer product, ref Integer product,
const size_t digits) const nothrow @safe @nogc const size_t digits) const @nogc nothrow pure @safe
{ {
Integer intermediate; Integer intermediate;
intermediate.grow(digits); intermediate.grow(digits);
@ -1270,8 +1279,7 @@ struct Integer
private void divide(Q, ARGS...)(ref const Integer divisor, private void divide(Q, ARGS...)(ref const Integer divisor,
auto ref Q quotient, auto ref Q quotient,
ref ARGS args) ref ARGS args) const
const nothrow @safe @nogc
if ((is(Q : typeof(null)) if ((is(Q : typeof(null))
|| (is(Q : Integer) && __traits(isRef, quotient))) || (is(Q : Integer) && __traits(isRef, quotient)))
&& (ARGS.length == 0 || (ARGS.length == 1 && is(ARGS[0] : Integer)))) && (ARGS.length == 0 || (ARGS.length == 1 && is(ARGS[0] : Integer))))
@ -1279,7 +1287,7 @@ struct Integer
{ {
assert(divisor != 0, "Division by zero."); assert(divisor != 0, "Division by zero.");
} }
body do
{ {
if (compare(divisor) < 0) if (compare(divisor) < 0)
{ {
@ -1404,7 +1412,7 @@ struct Integer
} }
} }
private Integer square() nothrow @safe @nogc private Integer square() @nogc nothrow pure @safe
{ {
Integer result; Integer result;
const resultSize = 2 * this.size + 1; const resultSize = 2 * this.size + 1;
@ -1444,7 +1452,7 @@ struct Integer
} }
// Returns 2^^n. // Returns 2^^n.
private Integer exp2(size_t n) const nothrow @safe @nogc private Integer exp2(size_t n) const @nogc nothrow pure @safe
{ {
auto ret = Integer(allocator); auto ret = Integer(allocator);
const bytes = n / digitBitCount; const bytes = n / digitBitCount;
@ -1459,12 +1467,12 @@ struct Integer
/** /**
* Returns: Two's complement representation of the integer. * Returns: Two's complement representation of the integer.
*/ */
Array!ubyte toArray() const nothrow @safe @nogc Array!ubyte toArray() const @nogc nothrow pure @safe
out (array) out (array)
{ {
assert(array.length == length); assert(array.length == length);
} }
body do
{ {
Array!ubyte array; Array!ubyte array;
@ -1512,7 +1520,7 @@ struct Integer
} }
/// ///
nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
{ {
auto integer = Integer(0x66778899aabbddee); auto integer = Integer(0x66778899aabbddee);
@ -1521,6 +1529,14 @@ struct Integer
auto array = integer.toArray(); auto array = integer.toArray();
assert(equal(array[], expected[])); assert(equal(array[], expected[]));
} }
}
@nogc nothrow pure @safe unittest
{
{
Integer integer;
assert(integer.toArray().length == 0);
}
{ {
auto integer = Integer(0x03); auto integer = Integer(0x03);
ubyte[1] expected = [ 0x03 ]; ubyte[1] expected = [ 0x03 ];

View File

@ -21,9 +21,11 @@
*/ */
module tanya.math; module tanya.math;
import tanya.algorithm.mutation;
import tanya.math.mp; import tanya.math.mp;
import tanya.math.nbtheory; import tanya.math.nbtheory;
import tanya.meta.trait; import tanya.meta.trait;
import tanya.meta.transform;
/// Floating-point number precisions according to IEEE-754. /// Floating-point number precisions according to IEEE-754.
enum IEEEPrecision : ubyte enum IEEEPrecision : ubyte
@ -79,7 +81,7 @@ if (isFloatingPoint!F)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(ieeePrecision!float == IEEEPrecision.single); static assert(ieeePrecision!float == IEEEPrecision.single);
static assert(ieeePrecision!double == IEEEPrecision.double_); static assert(ieeePrecision!double == IEEEPrecision.double_);
@ -231,7 +233,7 @@ if (isFloatingPoint!F)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
assert(classify(0.0) == FloatingPointClass.zero); assert(classify(0.0) == FloatingPointClass.zero);
assert(classify(double.nan) == FloatingPointClass.nan); assert(classify(double.nan) == FloatingPointClass.nan);
@ -253,7 +255,7 @@ pure nothrow @safe @nogc unittest
assert(classify(-real.infinity) == FloatingPointClass.infinite); assert(classify(-real.infinity) == FloatingPointClass.infinite);
} }
private pure nothrow @nogc @safe unittest @nogc nothrow pure @safe unittest
{ {
static if (ieeePrecision!float == IEEEPrecision.doubleExtended) static if (ieeePrecision!float == IEEEPrecision.doubleExtended)
{ {
@ -300,7 +302,7 @@ if (isFloatingPoint!F)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
assert(!isFinite(float.infinity)); assert(!isFinite(float.infinity));
assert(!isFinite(-double.infinity)); assert(!isFinite(-double.infinity));
@ -345,7 +347,7 @@ if (isFloatingPoint!F)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
assert(isNaN(float.init)); assert(isNaN(float.init));
assert(isNaN(double.init)); assert(isNaN(double.init));
@ -382,7 +384,7 @@ if (isFloatingPoint!F)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
assert(isInfinity(float.infinity)); assert(isInfinity(float.infinity));
assert(isInfinity(-float.infinity)); assert(isInfinity(-float.infinity));
@ -436,7 +438,7 @@ if (isFloatingPoint!F)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
assert(!isSubnormal(0.0f)); assert(!isSubnormal(0.0f));
assert(!isSubnormal(float.nan)); assert(!isSubnormal(float.nan));
@ -496,7 +498,7 @@ if (isFloatingPoint!F)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
assert(!isNormal(0.0f)); assert(!isNormal(0.0f));
assert(!isNormal(float.nan)); assert(!isNormal(float.nan));
@ -547,7 +549,7 @@ if (isFloatingPoint!F)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
assert(signBit(-1.0f)); assert(signBit(-1.0f));
assert(!signBit(1.0f)); assert(!signBit(1.0f));
@ -584,7 +586,7 @@ in
{ {
assert(z > 0, "Division by zero."); assert(z > 0, "Division by zero.");
} }
body do
{ {
G mask = G.max / 2 + 1; G mask = G.max / 2 + 1;
H result; H result;
@ -625,7 +627,7 @@ in
{ {
assert(z.length > 0, "Division by zero."); assert(z.length > 0, "Division by zero.");
} }
body do
{ {
size_t i; size_t i;
auto tmp1 = Integer(x, x.allocator); auto tmp1 = Integer(x, x.allocator);
@ -659,7 +661,7 @@ body
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
assert(pow(3, 5, 7) == 5); assert(pow(3, 5, 7) == 5);
assert(pow(2, 2, 1) == 0); assert(pow(2, 2, 1) == 0);
@ -673,7 +675,7 @@ pure nothrow @safe @nogc unittest
} }
/// ///
nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
assert(pow(Integer(3), Integer(5), Integer(7)) == 5); assert(pow(Integer(3), Integer(5), Integer(7)) == 5);
assert(pow(Integer(2), Integer(2), Integer(1)) == 0); assert(pow(Integer(2), Integer(2), Integer(1)) == 0);
@ -695,13 +697,13 @@ nothrow @safe @nogc unittest
* Returns: $(D_KEYWORD true) if $(D_PARAM x) is a prime number, * Returns: $(D_KEYWORD true) if $(D_PARAM x) is a prime number,
* $(D_KEYWORD false) otherwise. * $(D_KEYWORD false) otherwise.
*/ */
bool isPseudoprime(ulong x) nothrow pure @safe @nogc bool isPseudoprime(ulong x) @nogc nothrow pure @safe
{ {
return pow(2, x - 1, x) == 1; return pow(2, x - 1, x) == 1;
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
assert(74623.isPseudoprime); assert(74623.isPseudoprime);
assert(104729.isPseudoprime); assert(104729.isPseudoprime);
@ -709,7 +711,7 @@ pure nothrow @safe @nogc unittest
assert(!15485868.isPseudoprime); assert(!15485868.isPseudoprime);
} }
private pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
assert(74653.isPseudoprime); assert(74653.isPseudoprime);
assert(74687.isPseudoprime); assert(74687.isPseudoprime);
@ -738,3 +740,158 @@ private pure nothrow @safe @nogc unittest
assert(899809363.isPseudoprime); assert(899809363.isPseudoprime);
assert(982451653.isPseudoprime); assert(982451653.isPseudoprime);
} }
/**
* Determines minimum of two numbers.
*
* Params:
* x = First number.
* y = Second number.
*
* Returns: $(D_PARAM x) if $(D_PARAM x) is smaller than $(D_PSYMBOL y),
* $(D_PARAM y) otherwise.
*
* See_Also: $(D_PSYMBOL max).
*/
T min(T)(T x, T y)
if (isIntegral!T)
{
return x < y ? x : y;
}
///
@nogc nothrow pure @safe unittest
{
assert(min(5, 3) == 3);
assert(min(4, 4) == 4);
}
/// ditto
T min(T)(T x, T y)
if (isFloatingPoint!T)
{
if (isNaN(x))
{
return y;
}
if (isNaN(y))
{
return x;
}
return x < y ? x : y;
}
///
@nogc nothrow pure @safe unittest
{
assert(min(5.2, 3.0) == 3.0);
assert(min(5.2, double.nan) == 5.2);
assert(min(double.nan, 3.0) == 3.0);
assert(isNaN(min(double.nan, double.nan)));
}
/// ditto
ref T min(T)(ref T x, ref T y)
if (is(Unqual!T == Integer))
{
return x < y ? x : y;
}
/// ditto
T min(T)(T x, T y)
if (is(T == Integer))
{
return x < y ? move(x) : move(y);
}
///
@nogc nothrow pure @safe unittest
{
assert(min(Integer(5), Integer(3)) == 3);
}
/**
* Determines maximum of two numbers.
*
* Params:
* x = First number.
* y = Second number.
*
* Returns: $(D_PARAM x) if $(D_PARAM x) is larger than $(D_PSYMBOL y),
* $(D_PARAM y) otherwise.
*
* See_Also: $(D_PSYMBOL min).
*/
T max(T)(T x, T y)
if (isIntegral!T)
{
return x > y ? x : y;
}
///
@nogc nothrow pure @safe unittest
{
assert(max(5, 3) == 5);
assert(max(4, 4) == 4);
}
/// ditto
T max(T)(T x, T y)
if (isFloatingPoint!T)
{
if (isNaN(x))
{
return y;
}
if (isNaN(y))
{
return x;
}
return x > y ? x : y;
}
///
@nogc nothrow pure @safe unittest
{
assert(max(5.2, 3.0) == 5.2);
assert(max(5.2, double.nan) == 5.2);
assert(max(double.nan, 3.0) == 3.0);
assert(isNaN(max(double.nan, double.nan)));
}
/// ditto
ref T max(T)(ref T x, ref T y)
if (is(Unqual!T == Integer))
{
return x > y ? x : y;
}
/// ditto
T max(T)(T x, T y)
if (is(T == Integer))
{
return x > y ? move(x) : move(y);
}
///
@nogc nothrow pure @safe unittest
{
assert(max(Integer(5), Integer(3)) == 5);
}
// min/max accept const and mutable references.
@nogc nothrow pure @safe unittest
{
{
Integer i1 = 5, i2 = 3;
assert(min(i1, i2) == 3);
assert(max(i1, i2) == 5);
}
{
const Integer i1 = 5, i2 = 3;
assert(min(i1, i2) == 3);
assert(max(i1, i2) == 5);
}
}

View File

@ -134,7 +134,7 @@ version (linux)
{ {
assert(length <= maxGather); assert(length <= maxGather);
} }
body do
{ {
// int getrandom(void *buf, size_t buflen, unsigned int flags); // int getrandom(void *buf, size_t buflen, unsigned int flags);
auto length = syscall(318, output.ptr, output.length, 0); auto length = syscall(318, output.ptr, output.length, 0);
@ -198,7 +198,7 @@ class Entropy
assert(maxSources > 0 && maxSources <= ubyte.max); assert(maxSources > 0 && maxSources <= ubyte.max);
assert(allocator !is null); assert(allocator !is null);
} }
body do
{ {
allocator.resize(sources, maxSources); allocator.resize(sources, maxSources);
@ -234,7 +234,7 @@ class Entropy
{ {
assert(sourceCount_ <= sources.length); assert(sourceCount_ <= sources.length);
} }
body do
{ {
sources[sourceCount_++] = source; sources[sourceCount_++] = source;
return this; return this;
@ -251,7 +251,7 @@ class Entropy
{ {
assert(sourceCount_ > 0, "No entropy sources defined."); assert(sourceCount_ > 0, "No entropy sources defined.");
} }
body do
{ {
bool haveStrong; bool haveStrong;
ushort done; ushort done;

View File

@ -32,6 +32,16 @@ else
import core.stdc.string; import core.stdc.string;
} }
version (TanyaNative)
{
@nogc nothrow pure @system unittest
{
ubyte[2] buffer = 1;
fillMemory(buffer[1 .. $], 0);
assert(buffer[0] == 1 && buffer[1] == 0);
}
}
private enum alignMask = size_t.sizeof - 1; private enum alignMask = size_t.sizeof - 1;
/** /**
@ -51,12 +61,14 @@ private enum alignMask = size_t.sizeof - 1;
* *
* Precondition: $(D_INLINECODE source.length <= target.length). * Precondition: $(D_INLINECODE source.length <= target.length).
*/ */
void copy(const void[] source, void[] target) pure nothrow @trusted @nogc void copy(const void[] source, void[] target) @nogc nothrow pure @trusted
in in
{ {
assert(source.length <= target.length); assert(source.length <= target.length);
assert(source.length == 0 || source.ptr !is null);
assert(target.length == 0 || target.ptr !is null);
} }
body do
{ {
version (TanyaNative) version (TanyaNative)
{ {
@ -69,7 +81,7 @@ body
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
ubyte[9] source = [1, 2, 3, 4, 5, 6, 7, 8, 9]; ubyte[9] source = [1, 2, 3, 4, 5, 6, 7, 8, 9];
ubyte[9] target; ubyte[9] target;
@ -77,7 +89,7 @@ pure nothrow @safe @nogc unittest
assert(cmp(source, target) == 0); assert(cmp(source, target) == 0);
} }
private pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
{ {
ubyte[0] source, target; ubyte[0] source, target;
@ -120,6 +132,11 @@ private template filledBytes(ubyte Byte, ubyte I = 0)
* memory = Memory block. * memory = Memory block.
*/ */
void fill(ubyte c = 0)(void[] memory) @trusted void fill(ubyte c = 0)(void[] memory) @trusted
in
{
assert(memory.length == 0 || memory.ptr !is null);
}
do
{ {
version (TanyaNative) version (TanyaNative)
{ {
@ -132,7 +149,7 @@ void fill(ubyte c = 0)(void[] memory) @trusted
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
ubyte[9] memory = [1, 2, 3, 4, 5, 6, 7, 8, 9]; ubyte[9] memory = [1, 2, 3, 4, 5, 6, 7, 8, 9];
memory.fill!0(); memory.fill!0();
@ -142,31 +159,6 @@ pure nothrow @safe @nogc unittest
} }
} }
// Stress test. Checks that `fill` can handle unaligned pointers and different
// lengths.
pure nothrow @safe @nogc private unittest
{
ubyte[192] memory;
foreach (j; 0 .. 192)
{
foreach (ubyte i, ref ubyte v; memory[j .. $])
{
v = i;
}
fill(memory[j .. $]);
foreach (ubyte v; memory[j .. $])
{
assert(v == 0);
}
fill!1(memory[j .. $]);
foreach (ubyte v; memory[j .. $])
{
assert(v == 1);
}
}
}
/** /**
* Copies starting from the end of $(D_PARAM source) into the end of * Copies starting from the end of $(D_PARAM source) into the end of
* $(D_PARAM target). * $(D_PARAM target).
@ -189,12 +181,14 @@ pure nothrow @safe @nogc private unittest
* *
* Precondition: $(D_INLINECODE source.length <= target.length). * Precondition: $(D_INLINECODE source.length <= target.length).
*/ */
void copyBackward(const void[] source, void[] target) pure nothrow @trusted @nogc void copyBackward(const void[] source, void[] target) @nogc nothrow pure @trusted
in in
{ {
assert(source.length <= target.length); assert(source.length <= target.length);
assert(source.length == 0 || source.ptr !is null);
assert(target.length == 0 || target.ptr !is null);
} }
body do
{ {
version (TanyaNative) version (TanyaNative)
{ {
@ -207,7 +201,7 @@ body
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
ubyte[6] mem = [ 'a', 'a', 'b', 'b', 'c', 'c' ]; ubyte[6] mem = [ 'a', 'a', 'b', 'b', 'c', 'c' ];
ubyte[6] expected = [ 'a', 'a', 'a', 'a', 'b', 'b' ]; ubyte[6] expected = [ 'a', 'a', 'a', 'a', 'b', 'b' ];
@ -216,7 +210,7 @@ pure nothrow @safe @nogc unittest
assert(cmp(expected, mem) == 0); assert(cmp(expected, mem) == 0);
} }
private nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
ubyte[9] r1 = [ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i' ]; ubyte[9] r1 = [ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i' ];
ubyte[9] r2; ubyte[9] r2;
@ -242,7 +236,13 @@ private nothrow @safe @nogc unittest
* negative integer if $(D_INLINECODE r2 > r1), * negative integer if $(D_INLINECODE r2 > r1),
* `0` if $(D_INLINECODE r1 == r2). * `0` if $(D_INLINECODE r1 == r2).
*/ */
int cmp(const void[] r1, const void[] r2) pure nothrow @trusted @nogc int cmp(const void[] r1, const void[] r2) @nogc nothrow pure @trusted
in
{
assert(r1.length == 0 || r1.ptr !is null);
assert(r2.length == 0 || r2.ptr !is null);
}
do
{ {
version (TanyaNative) version (TanyaNative)
{ {
@ -259,7 +259,7 @@ int cmp(const void[] r1, const void[] r2) pure nothrow @trusted @nogc
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
ubyte[4] r1 = [ 'a', 'b', 'c', 'd' ]; ubyte[4] r1 = [ 'a', 'b', 'c', 'd' ];
ubyte[3] r2 = [ 'c', 'a', 'b' ]; ubyte[3] r2 = [ 'c', 'a', 'b' ];
@ -271,7 +271,7 @@ pure nothrow @safe @nogc unittest
assert(cmp(r2, r1) < 0); assert(cmp(r2, r1) < 0);
} }
private pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
ubyte[16] r1 = [ ubyte[16] r1 = [
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
@ -301,7 +301,12 @@ private pure nothrow @safe @nogc unittest
* couldn't be found, an empty `inout void[]` is returned. * couldn't be found, an empty `inout void[]` is returned.
*/ */
inout(void[]) find(return inout void[] haystack, const ubyte needle) inout(void[]) find(return inout void[] haystack, const ubyte needle)
pure nothrow @trusted @nogc @nogc nothrow pure @trusted
in
{
assert(haystack.length == 0 || haystack.ptr !is null);
}
do
{ {
auto length = haystack.length; auto length = haystack.length;
const size_t needleWord = size_t.max * needle; const size_t needleWord = size_t.max * needle;
@ -348,7 +353,7 @@ pure nothrow @trusted @nogc
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
const ubyte[9] haystack = ['a', 'b', 'c', 'd', 'e', 'f', 'b', 'g', 'h']; const ubyte[9] haystack = ['a', 'b', 'c', 'd', 'e', 'f', 'b', 'g', 'h'];

View File

@ -45,7 +45,7 @@ mixin template DefaultAllocator()
{ {
assert(allocator !is null); assert(allocator !is null);
} }
body do
{ {
this.allocator_ = allocator; this.allocator_ = allocator;
} }
@ -63,7 +63,7 @@ mixin template DefaultAllocator()
{ {
assert(allocator !is null); assert(allocator !is null);
} }
body do
{ {
if (allocator_ is null) if (allocator_ is null)
{ {
@ -78,7 +78,7 @@ mixin template DefaultAllocator()
{ {
assert(allocator !is null); assert(allocator !is null);
} }
body do
{ {
if (allocator_ is null) if (allocator_ is null)
{ {
@ -114,7 +114,7 @@ out (allocator)
{ {
assert(allocator !is null); assert(allocator !is null);
} }
body do
{ {
return (cast(GetPureInstance!Allocator) &getAllocatorInstance)(); return (cast(GetPureInstance!Allocator) &getAllocatorInstance)();
} }
@ -132,7 +132,7 @@ in
{ {
assert(allocator !is null); assert(allocator !is null);
} }
body do
{ {
.allocator = allocator; .allocator = allocator;
} }
@ -403,7 +403,7 @@ in
{ {
assert(allocator !is null); assert(allocator !is null);
} }
body do
{ {
auto mem = (() @trusted => allocator.allocate(stateSize!T))(); auto mem = (() @trusted => allocator.allocate(stateSize!T))();
if (mem is null) if (mem is null)
@ -442,7 +442,7 @@ in
{ {
assert(allocator !is null); assert(allocator !is null);
} }
body do
{ {
auto mem = (() @trusted => allocator.allocate(stateSize!T))(); auto mem = (() @trusted => allocator.allocate(stateSize!T))();
if (mem is null) if (mem is null)
@ -484,7 +484,7 @@ in
assert(allocator !is null); assert(allocator !is null);
assert(n <= size_t.max / ElementType!T.sizeof); assert(n <= size_t.max / ElementType!T.sizeof);
} }
body do
{ {
auto ret = allocator.resize!(ElementType!T)(null, n); auto ret = allocator.resize!(ElementType!T)(null, n);
ret.uninitializedFill(ElementType!T.init); ret.uninitializedFill(ElementType!T.init);

View File

@ -24,7 +24,7 @@
module tanya.memory.smartref; module tanya.memory.smartref;
import std.algorithm.comparison; import std.algorithm.comparison;
import std.algorithm.mutation; import tanya.algorithm.mutation;
import tanya.conv; import tanya.conv;
import tanya.exception; import tanya.exception;
import tanya.memory; import tanya.memory;
@ -54,7 +54,7 @@ private final class RefCountedStore(T)
{ {
assert(this.counter > 0); assert(this.counter > 0);
} }
body do
{ {
mixin("return " ~ op ~ "counter;"); mixin("return " ~ op ~ "counter;");
} }
@ -139,7 +139,7 @@ struct RefCounted(T)
{ {
assert(allocator !is null); assert(allocator !is null);
} }
body do
{ {
this.allocator_ = allocator; this.allocator_ = allocator;
} }
@ -247,7 +247,7 @@ struct RefCounted(T)
{ {
assert(count > 0, "Attempted to access an uninitialized reference"); assert(count > 0, "Attempted to access an uninitialized reference");
} }
body do
{ {
return this.storage.payload; return this.storage.payload;
} }
@ -501,7 +501,7 @@ in
{ {
assert(allocator !is null); assert(allocator !is null);
} }
body do
{ {
auto rc = typeof(return)(allocator); auto rc = typeof(return)(allocator);
@ -546,7 +546,7 @@ in
assert(allocator !is null); assert(allocator !is null);
assert(size <= size_t.max / ElementType!T.sizeof); assert(size <= size_t.max / ElementType!T.sizeof);
} }
body do
{ {
return RefCounted!T(allocator.make!T(size), allocator); return RefCounted!T(allocator.make!T(size), allocator);
} }
@ -611,7 +611,7 @@ body
@nogc @system unittest @nogc @system unittest
{ {
static bool destroyed = false; static bool destroyed;
static struct F static struct F
{ {
@ -664,7 +664,7 @@ struct Unique(T)
{ {
assert(allocator !is null); assert(allocator !is null);
} }
body do
{ {
this.allocator_ = allocator; this.allocator_ = allocator;
} }
@ -812,7 +812,7 @@ struct Unique(T)
/// ///
@nogc nothrow @system unittest @nogc nothrow @system unittest
{ {
static bool destroyed = false; static bool destroyed;
static struct F static struct F
{ {
@ -849,7 +849,7 @@ in
{ {
assert(allocator !is null); assert(allocator !is null);
} }
body do
{ {
auto payload = allocator.make!(T, A)(args); auto payload = allocator.make!(T, A)(args);
return Unique!T(payload, allocator); return Unique!T(payload, allocator);
@ -877,7 +877,7 @@ in
assert(allocator !is null); assert(allocator !is null);
assert(size <= size_t.max / ElementType!T.sizeof); assert(size <= size_t.max / ElementType!T.sizeof);
} }
body do
{ {
auto payload = allocator.resize!(ElementType!T)(null, size); auto payload = allocator.resize!(ElementType!T)(null, size);
return Unique!T(payload, allocator); return Unique!T(payload, allocator);

View File

@ -275,15 +275,50 @@ enum bool isTemplate(alias T) = __traits(isTemplate, T);
static assert(!isTemplate!(S!int)); static assert(!isTemplate!(S!int));
} }
deprecated("Use is(T == interface) instead") /**
* Tests whether $(D_PARAM T) is an interface.
*
* Params:
* T = A type.
*
* Returns: $(D_KEYWORD true) if $(D_PARAM T) is an interface,
* $(D_KEYWORD false) otherwise.
*/
enum bool isInterface(T) = is(T == interface); enum bool isInterface(T) = is(T == interface);
deprecated("Use is(T == class) instead") /**
* Tests whether $(D_PARAM T) is a class.
*
* Params:
* T = A type.
*
* Returns: $(D_KEYWORD true) if $(D_PARAM T) is a class,
* $(D_KEYWORD false) otherwise.
*/
enum bool isClass(T) = is(T == class); enum bool isClass(T) = is(T == class);
deprecated("Use is(T == struct) instead") /**
* Tests whether $(D_PARAM T) is a struct.
*
* Params:
* T = A type.
*
* Returns: $(D_KEYWORD true) if $(D_PARAM T) is a struct,
* $(D_KEYWORD false) otherwise.
*/
enum bool isStruct(T) = is(T == struct); enum bool isStruct(T) = is(T == struct);
/**
* Tests whether $(D_PARAM T) is a enum.
*
* Params:
* T = A type.
*
* Returns: $(D_KEYWORD true) if $(D_PARAM T) is an enum,
* $(D_KEYWORD false) otherwise.
*/
enum bool isEnum(T) = is(T == enum);
/** /**
* Determines whether $(D_PARAM T) is a polymorphic type, i.e. a * Determines whether $(D_PARAM T) is a polymorphic type, i.e. a
* $(D_KEYWORD class) or an $(D_KEYWORD interface). * $(D_KEYWORD class) or an $(D_KEYWORD interface).
@ -1758,6 +1793,10 @@ template isMutable(T)
} }
/** /**
* Determines whether $(D_PARAM T) is a nested type, i.e. $(D_KEYWORD class),
* $(D_KEYWORD struct) or $(D_KEYWORD union), which internally stores a context
* pointer.
*
* Params: * Params:
* T = $(D_KEYWORD class), $(D_KEYWORD struct) or $(D_KEYWORD union) type. * T = $(D_KEYWORD class), $(D_KEYWORD struct) or $(D_KEYWORD union) type.
* *
@ -1788,6 +1827,8 @@ pure nothrow @safe unittest
} }
/** /**
* Determines whether $(D_PARAM T) is a nested function.
*
* Params: * Params:
* F = A function. * F = A function.
* *
@ -1809,6 +1850,8 @@ enum bool isNestedFunction(alias F) = __traits(isNested, F);
} }
/** /**
* Determines the type of the callable $(D_PARAM F).
*
* Params: * Params:
* F = A function. * F = A function.
* *
@ -1898,6 +1941,8 @@ if (isCallable!F)
} }
/** /**
* Determines the return type of the callable $(D_PARAM F).
*
* Params: * Params:
* F = A callable object. * F = A callable object.
* *
@ -3055,3 +3100,60 @@ template isInnerClass(T)
} }
static assert(!isInnerClass!(RefCountedStore!int)); static assert(!isInnerClass!(RefCountedStore!int));
} }
/**
* Returns the types of all members of $(D_PARAM T).
*
* If $(D_PARAM T) is a $(D_KEYWORD struct) or $(D_KEYWORD union) or
* $(D_KEYWORD class), returns the types of all its fields. It is actually the
* same as `T.tupleof`, but the content pointer for the nested type isn't
* included.
*
* If $(D_PARAM T) is neither a $(D_KEYWORD struct) nor $(D_KEYWORD union) nor
* $(D_KEYWORD class), $(D_PSYMBOL Fields) returns an $(D_PSYMBOL AliasSeq)
* with the single element $(D_PARAM T).
*
* Params:
* T = A type.
*
* Returns: $(D_PARAM T)'s fields.
*/
template Fields(T)
{
static if ((is(T == struct) || is(T == union)) && isNested!T)
{
// The last element of .tupleof of a nested struct or union is "this",
// the context pointer, type "void*".
alias Fields = typeof(T.tupleof[0 .. $ - 1]);
}
else static if (is(T == class) || is(T == struct) || is(T == union))
{
alias Fields = typeof(T.tupleof);
}
else
{
alias Fields = AliasSeq!T;
}
}
///
@nogc nothrow pure @safe unittest
{
struct Nested
{
int i;
void func()
{
}
}
static assert(is(Fields!Nested == AliasSeq!int));
class C
{
uint u;
}
static assert(is(Fields!C == AliasSeq!uint));
static assert(is(Fields!short == AliasSeq!short));
}

View File

@ -77,7 +77,7 @@ struct NetworkOrder(uint L)
{ {
assert(value <= pow(2, L * 8) - 1); assert(value <= pow(2, L * 8) - 1);
} }
body do
{ {
this.value = value & StorageType.max; this.value = value & StorageType.max;
} }
@ -92,7 +92,7 @@ struct NetworkOrder(uint L)
{ {
assert(this.length > 0); assert(this.length > 0);
} }
body do
{ {
return this.value & 0xff; return this.value & 0xff;
} }
@ -107,7 +107,7 @@ struct NetworkOrder(uint L)
{ {
assert(this.length > 0); assert(this.length > 0);
} }
body do
{ {
return (this.value >> ((this.length - 1) * 8)) & 0xff; return (this.value >> ((this.length - 1) * 8)) & 0xff;
} }
@ -122,7 +122,7 @@ struct NetworkOrder(uint L)
{ {
assert(this.length > 0); assert(this.length > 0);
} }
body do
{ {
this.value >>= 8; this.value >>= 8;
--this.size; --this.size;
@ -138,7 +138,7 @@ struct NetworkOrder(uint L)
{ {
assert(this.length > 0); assert(this.length > 0);
} }
body do
{ {
this.value &= StorageType.max >> ((StorageType.sizeof - this.length) * 8); this.value &= StorageType.max >> ((StorageType.sizeof - this.length) * 8);
--this.size; --this.size;

View File

@ -185,7 +185,7 @@ else version (Windows)
{ {
assert(count >= 0); assert(count >= 0);
} }
body do
{ {
DWORD lpNumber; DWORD lpNumber;
BOOL result = GetOverlappedResult(overlapped.handle, BOOL result = GetOverlappedResult(overlapped.handle,
@ -259,7 +259,7 @@ else version (Windows)
{ {
assert(count >= 0); assert(count >= 0);
} }
body do
{ {
DWORD lpNumber; DWORD lpNumber;
BOOL result = GetOverlappedResult(overlapped.handle, BOOL result = GetOverlappedResult(overlapped.handle,
@ -720,7 +720,7 @@ abstract class Socket
assert(handle != SocketType.init); assert(handle != SocketType.init);
assert(handle_ == SocketType.init, "Socket handle cannot be changed"); assert(handle_ == SocketType.init, "Socket handle cannot be changed");
} }
body do
{ {
handle_ = handle; handle_ = handle;
@ -749,7 +749,7 @@ abstract class Socket
{ {
assert(handle != SocketType.init); assert(handle != SocketType.init);
} }
body do
{ {
scope (failure) scope (failure)
{ {

View File

@ -59,13 +59,13 @@ in
{ {
assert(array.length > 0); assert(array.length > 0);
} }
body do
{ {
return array[0]; return array[0];
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
string s = "Wenn die Wunde nicht mehr wehtut, schmerzt die Narbe"; string s = "Wenn die Wunde nicht mehr wehtut, schmerzt die Narbe";
static assert(is(typeof(s.front) == immutable char)); static assert(is(typeof(s.front) == immutable char));
@ -99,13 +99,13 @@ in
{ {
assert(array.length > 0); assert(array.length > 0);
} }
body do
{ {
return array[$ - 1]; return array[$ - 1];
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
string s = "Brecht"; string s = "Brecht";
static assert(is(typeof(s.back) == immutable char)); static assert(is(typeof(s.back) == immutable char));
@ -138,7 +138,7 @@ in
{ {
assert(array.length > 0); assert(array.length > 0);
} }
body do
{ {
array = array[1 .. $]; array = array[1 .. $];
} }
@ -149,13 +149,13 @@ in
{ {
assert(array.length > 0); assert(array.length > 0);
} }
body do
{ {
array = array[0 .. $ - 1]; array = array[0 .. $ - 1];
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
wstring array = "Der finstere Ozean der Metaphysik. Nietzsche"; wstring array = "Der finstere Ozean der Metaphysik. Nietzsche";
@ -184,7 +184,7 @@ pure nothrow @safe @nogc unittest
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
int[1] array; int[1] array;
assert(!array.empty); assert(!array.empty);
@ -209,7 +209,7 @@ pure nothrow @safe @nogc unittest
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
ubyte[8] array; ubyte[8] array;
auto slice = array.save; auto slice = array.save;

File diff suppressed because it is too large Load Diff