41 Commits

Author SHA1 Message Date
e77a499fa2 Annotate typecons unittests 2018-03-07 06:52:35 +01:00
54bcec216e Deprecate MmapPool for the standard build
Mallocator is the default allocator now and should be used instead.
2018-03-06 05:29:15 +01:00
fbbdb36853 Use defaultAllocator in the async
Instead of hard-coded MmapPool.
2018-03-05 17:42:44 +01:00
b795267e75 Rename ErrorCode.text() to toString() 2018-03-04 10:43:24 +01:00
81cbb96d45 Merge remote-tracking branch 'n8sh/isRandomAccessRange-definition' 2018-03-04 09:29:09 +01:00
467335460e Decouple isRandomAccessRange from isForwardRange and isBidirectionalRange 2018-03-04 03:02:18 -05:00
dc3b083097 Add dmd 2.079.0 2018-03-03 08:34:06 +01:00
16c5fa12df Implement Error.text()
Error.text() returns an error description.
2018-03-02 06:48:03 +01:00
9bf8754711 Fix setting new head/tail after removing in DList 2018-02-26 08:09:14 +01:00
760cea163d Add a workaround for dmd 2.076.1 on OSX 2018-02-25 21:33:29 +01:00
03c40ecace Fix removing all elements from DList 2018-02-25 18:25:19 +01:00
9c70e9a058 Annotate list unittests 2018-02-25 15:42:32 +01:00
5ae20512af Fix inserting before/after a range into the string 2018-02-25 12:53:42 +01:00
d30de300d6 Fix slicing a null pointer when deallocating 2018-02-25 11:09:57 +01:00
464a0fecbb Make math.nbtheory.ln to a template function 2018-02-25 05:38:21 +01:00
84d6e207c5 Ignore dub.selections.json 2018-02-24 06:42:06 +01:00
af942116e4 Merge remote-tracking branch 'n8sh/getrandom-syscall'
Fix #18.
2018-02-22 05:25:59 +01:00
7ee4af9e79 Use correct getrandom linux syscall on non-x86_64 2018-02-21 04:49:48 -05:00
9876d9245c Implement PlatformEntropySource for macOS, Microsoft Windows, NetBSD, OpenBSD, Solaris 2018-02-21 03:18:52 -05:00
bd2b88f16e Update latest supported dmd to 2.078.3 2018-02-16 16:35:53 +01:00
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
40 changed files with 1322 additions and 1013 deletions

2
.gitignore vendored
View File

@ -4,6 +4,8 @@
# D # D
.dub .dub
dub.selections.json
__test__*__ __test__*__
__test__*__.core __test__*__.core
/tanya-test-* /tanya-test-*

View File

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

View File

@ -12,8 +12,8 @@ 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.
* [API Documentation](https://docs.caraus.io/tanya) * [API Documentation](https://docs.caraus.io/tanya)
* [Contribution guidelines](CONTRIBUTING.md) * [Contribution guidelines](CONTRIBUTING.md)
@ -149,9 +149,10 @@ There are more containers in the `tanya.container` package.
| DMD | GCC | | DMD | GCC |
|:-------:|:--------------:| |:-------:|:--------------:|
| 2.077.0 | *gdc-5* branch | | 2.079.0 | *master* |
| 2.078.3 | |
| 2.077.1 | |
| 2.076.1 | | | 2.076.1 | |
| 2.075.1 | |
### Current status ### Current status
@ -161,17 +162,14 @@ 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
* Tanya is a native D library without any external dependencies. * Tanya is a native D library
* Tanya is cross-platform. The development happens on a 64-bit Linux, but it * Tanya is cross-platform. The development happens on a 64-bit Linux, but it
is being tested on Windows and FreeBSD as well. is being tested on Windows and FreeBSD as well.

View File

@ -4,10 +4,22 @@ os: Visual Studio 2015
environment: environment:
matrix: matrix:
- DC: dmd - DC: dmd
DVersion: 2.077.0 DVersion: 2.079.0
arch: x64 arch: x64
- DC: dmd - DC: dmd
DVersion: 2.077.0 DVersion: 2.079.0
arch: x86
- DC: dmd
DVersion: 2.078.3
arch: x64
- DC: dmd
DVersion: 2.078.3
arch: x86
- DC: dmd
DVersion: 2.077.1
arch: x64
- DC: dmd
DVersion: 2.077.1
arch: x86 arch: x86
- DC: dmd - DC: dmd
DVersion: 2.076.1 DVersion: 2.076.1
@ -15,12 +27,6 @@ environment:
- 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
skip_tags: true skip_tags: true

View File

@ -2,10 +2,10 @@
// logl. // logl.
.globl _D5tanya4math8nbtheory2lnFNaNbNiNfeZe .globl _D5tanya4math8nbtheory9__T2lnTeZ2lnFNaNbNiNfeZe
.type _D5tanya4math8nbtheory2lnFNaNbNiNfeZe, @function .type _D5tanya4math8nbtheory9__T2lnTeZ2lnFNaNbNiNfeZe, @function
_D5tanya4math8nbtheory2lnFNaNbNiNfeZe: _D5tanya4math8nbtheory9__T2lnTeZ2lnFNaNbNiNfeZe:
fldln2 // Put lb(e) onto the FPU stack fldln2 // Put lb(e) onto the FPU stack
fldt 8(%rsp) // Put the argument onto the FPU stack fldt 8(%rsp) // Put the argument onto the FPU stack
fyl2x // %st1 * lb(%st0) fyl2x // %st1 * lb(%st0)
@ -13,10 +13,10 @@ _D5tanya4math8nbtheory2lnFNaNbNiNfeZe:
// log. // log.
.globl _D5tanya4math8nbtheory2lnFNaNbNiNfdZd .globl _D5tanya4math8nbtheory9__T2lnTdZ2lnFNaNbNiNfdZd
.type _D5tanya4math8nbtheory2lnFNaNbNiNfdZd, @function .type _D5tanya4math8nbtheory9__T2lnTdZ2lnFNaNbNiNfdZd, @function
_D5tanya4math8nbtheory2lnFNaNbNiNfdZd: _D5tanya4math8nbtheory9__T2lnTdZ2lnFNaNbNiNfdZd:
movsd %xmm0, -8(%rsp) // Put the argument onto the stack movsd %xmm0, -8(%rsp) // Put the argument onto the stack
fldln2 // Put lb(e) onto the FPU stack fldln2 // Put lb(e) onto the FPU stack
@ -31,10 +31,10 @@ _D5tanya4math8nbtheory2lnFNaNbNiNfdZd:
// logf. // logf.
.globl _D5tanya4math8nbtheory2lnFNaNbNiNffZf .globl _D5tanya4math8nbtheory9__T2lnTfZ2lnFNaNbNiNffZf
.type _D5tanya4math8nbtheory2lnFNaNbNiNffZf, @function .type _D5tanya4math8nbtheory9__T2lnTfZ2lnFNaNbNiNffZf, @function
_D5tanya4math8nbtheory2lnFNaNbNiNffZf: _D5tanya4math8nbtheory9__T2lnTfZ2lnFNaNbNiNffZf:
movss %xmm0, -4(%rsp) // Put the argument onto the stack movss %xmm0, -4(%rsp) // Put the argument onto the stack
fldln2 // Put lb(e) onto the FPU stack fldln2 // Put lb(e) onto the FPU stack

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

@ -9,10 +9,19 @@
"targetType": "library", "targetType": "library",
"dependencies-linux": {
"mir-linux-kernel": "~>1.0.0",
},
"configurations": [ "configurations": [
{ {
"name": "library", "name": "library",
"targetType": "library", "targetType": "staticLibrary",
"versions": ["TanyaPhobos"]
},
{
"name": "dynamic",
"targetType": "dynamicLibrary",
"versions": ["TanyaPhobos"] "versions": ["TanyaPhobos"]
}, },
{ {
@ -23,5 +32,6 @@
"lflags": ["arch/tanya.a"], "lflags": ["arch/tanya.a"],
"versions": ["TanyaNative"] "versions": ["TanyaNative"]
} }
] ],
"libs-windows": ["advapi32"]
} }

View File

@ -77,7 +77,7 @@ in
{ {
assert(&source !is &target, "Source and target must be different"); assert(&source !is &target, "Source and target must be different");
} }
body do
{ {
static if (is(T == struct) || isStaticArray!T) static if (is(T == struct) || isStaticArray!T)
{ {

View File

@ -31,7 +31,6 @@ import tanya.async.transport;
import tanya.async.watcher; import tanya.async.watcher;
import tanya.container.array; import tanya.container.array;
import tanya.memory; import tanya.memory;
import tanya.memory.mmappool;
import tanya.network.socket; import tanya.network.socket;
extern (C) nothrow @nogc extern (C) nothrow @nogc
@ -56,7 +55,7 @@ final class EpollLoop : SelectorLoop
throw defaultAllocator.make!BadLoopException("epoll initialization failed"); throw defaultAllocator.make!BadLoopException("epoll initialization failed");
} }
super(); super();
events = Array!epoll_event(maxEvents, MmapPool.instance); events = Array!epoll_event(maxEvents);
} }
/** /**

View File

@ -27,7 +27,6 @@ import tanya.async.transport;
import tanya.async.watcher; import tanya.async.watcher;
import tanya.container.buffer; import tanya.container.buffer;
import tanya.memory; import tanya.memory;
import tanya.memory.mmappool;
import tanya.network.socket; import tanya.network.socket;
import tanya.sys.windows.winbase; import tanya.sys.windows.winbase;
@ -57,8 +56,8 @@ final class StreamTransport : SocketWatcher, DuplexTransport, SocketTransport
this(OverlappedConnectedSocket socket) @nogc this(OverlappedConnectedSocket socket) @nogc
{ {
super(socket); super(socket);
output = ReadBuffer!ubyte(8192, 1024, MmapPool.instance); output = ReadBuffer!ubyte(8192, 1024);
input = WriteBuffer!ubyte(8192, MmapPool.instance); input = WriteBuffer!ubyte(8192);
active = true; active = true;
} }
@ -72,7 +71,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_;
} }
@ -117,8 +116,7 @@ final class StreamTransport : SocketWatcher, DuplexTransport, SocketTransport
/** /**
* Switches the protocol. * Switches the protocol.
* *
* The protocol is deallocated by the event loop, it should currently be * The protocol is deallocated by the event loop.
* allocated with $(D_PSYMBOL MmapPool).
* *
* Params: * Params:
* protocol = Application protocol. * protocol = Application protocol.
@ -130,7 +128,7 @@ final class StreamTransport : SocketWatcher, DuplexTransport, SocketTransport
{ {
assert(protocol !is null); assert(protocol !is null);
} }
body do
{ {
protocol_ = protocol; protocol_ = protocol;
} }
@ -150,20 +148,20 @@ final class StreamTransport : SocketWatcher, DuplexTransport, SocketTransport
SocketState overlapped; SocketState overlapped;
try try
{ {
overlapped = MmapPool.instance.make!SocketState; overlapped = defaultAllocator.make!SocketState;
socket.beginSend(input[], overlapped); socket.beginSend(input[], overlapped);
} }
catch (SocketException e) catch (SocketException e)
{ {
MmapPool.instance.dispose(overlapped); defaultAllocator.dispose(overlapped);
MmapPool.instance.dispose(e); defaultAllocator.dispose(e);
} }
} }
} }
else else
{ {
protocol.disconnected(exception); protocol.disconnected(exception);
MmapPool.instance.dispose(protocol_); defaultAllocator.dispose(protocol_);
defaultAllocator.dispose(exception); defaultAllocator.dispose(exception);
active = false; active = false;
} }
@ -221,12 +219,12 @@ final class IOCPLoop : Loop
try try
{ {
overlapped = MmapPool.instance.make!SocketState; overlapped = defaultAllocator.make!SocketState;
socket.beginAccept(overlapped); socket.beginAccept(overlapped);
} }
catch (SocketException e) catch (SocketException e)
{ {
MmapPool.instance.dispose(overlapped); defaultAllocator.dispose(overlapped);
defaultAllocator.dispose(e); defaultAllocator.dispose(e);
return false; return false;
} }
@ -250,12 +248,12 @@ final class IOCPLoop : Loop
{ {
try try
{ {
overlapped = MmapPool.instance.make!SocketState; overlapped = defaultAllocator.make!SocketState;
transport.socket.beginReceive(transport.output[], overlapped); transport.socket.beginReceive(transport.output[], overlapped);
} }
catch (SocketException e) catch (SocketException e)
{ {
MmapPool.instance.dispose(overlapped); defaultAllocator.dispose(overlapped);
defaultAllocator.dispose(e); defaultAllocator.dispose(e);
return false; return false;
} }
@ -270,7 +268,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);
@ -302,7 +300,7 @@ final class IOCPLoop : Loop
assert(overlapped !is null); assert(overlapped !is null);
scope (failure) scope (failure)
{ {
MmapPool.instance.dispose(overlapped); defaultAllocator.dispose(overlapped);
} }
switch (overlapped.event) switch (overlapped.event)
@ -315,7 +313,7 @@ final class IOCPLoop : Loop
assert(listener !is null); assert(listener !is null);
auto socket = listener.endAccept(overlapped); auto socket = listener.endAccept(overlapped);
auto transport = MmapPool.instance.make!StreamTransport(socket); auto transport = defaultAllocator.make!StreamTransport(socket);
connection.incoming.enqueue(transport); connection.incoming.enqueue(transport);
@ -330,8 +328,8 @@ final class IOCPLoop : Loop
if (!transport.active) if (!transport.active)
{ {
MmapPool.instance.dispose(transport); defaultAllocator.dispose(transport);
MmapPool.instance.dispose(overlapped); defaultAllocator.dispose(overlapped);
return; return;
} }

View File

@ -59,7 +59,6 @@ import tanya.async.transport;
import tanya.async.watcher; import tanya.async.watcher;
import tanya.container.array; import tanya.container.array;
import tanya.memory; import tanya.memory;
import tanya.memory.mmappool;
import tanya.network.socket; import tanya.network.socket;
void EV_SET(kevent_t* kevp, typeof(kevent_t.tupleof) args) pure nothrow @nogc void EV_SET(kevent_t* kevp, typeof(kevent_t.tupleof) args) pure nothrow @nogc
@ -146,8 +145,8 @@ final class KqueueLoop : SelectorLoop
throw make!BadLoopException(defaultAllocator, throw make!BadLoopException(defaultAllocator,
"kqueue initialization failed"); "kqueue initialization failed");
} }
events = Array!kevent_t(64, MmapPool.instance); events = Array!kevent_t(64);
changes = Array!kevent_t(64, MmapPool.instance); changes = Array!kevent_t(64);
} }
/** /**

View File

@ -26,7 +26,6 @@ import tanya.async.watcher;
import tanya.container.array; import tanya.container.array;
import tanya.container.buffer; import tanya.container.buffer;
import tanya.memory; import tanya.memory;
import tanya.memory.mmappool;
import tanya.network.socket; import tanya.network.socket;
/** /**
@ -61,12 +60,12 @@ 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;
output = ReadBuffer!ubyte(8192, 1024, MmapPool.instance); output = ReadBuffer!ubyte(8192, 1024);
input = WriteBuffer!ubyte(8192, MmapPool.instance); input = WriteBuffer!ubyte(8192);
active = true; active = true;
} }
@ -80,7 +79,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 +90,7 @@ package class StreamTransport : SocketWatcher, DuplexTransport, SocketTransport
{ {
assert(socket !is null); assert(socket !is null);
} }
body do
{ {
socket_ = socket; socket_ = socket;
} }
@ -107,8 +106,7 @@ package class StreamTransport : SocketWatcher, DuplexTransport, SocketTransport
/** /**
* Switches the protocol. * Switches the protocol.
* *
* The protocol is deallocated by the event loop, it should currently be * The protocol is deallocated by the event loop.
* allocated with $(D_PSYMBOL MmapPool).
* *
* Params: * Params:
* protocol = Application protocol. * protocol = Application protocol.
@ -120,7 +118,7 @@ package class StreamTransport : SocketWatcher, DuplexTransport, SocketTransport
{ {
assert(protocol !is null); assert(protocol !is null);
} }
body do
{ {
protocol_ = protocol; protocol_ = protocol;
} }
@ -163,7 +161,7 @@ package class StreamTransport : SocketWatcher, DuplexTransport, SocketTransport
else else
{ {
protocol.disconnected(exception); protocol.disconnected(exception);
MmapPool.instance.dispose(protocol_); defaultAllocator.dispose(protocol_);
defaultAllocator.dispose(exception); defaultAllocator.dispose(exception);
active = false; active = false;
} }
@ -220,7 +218,7 @@ abstract class SelectorLoop : Loop
this() @nogc this() @nogc
{ {
super(); super();
connections = Array!SocketWatcher(maxEvents, MmapPool.instance); connections = Array!SocketWatcher(maxEvents);
} }
~this() @nogc ~this() @nogc
@ -231,7 +229,7 @@ abstract class SelectorLoop : Loop
// created by the user and should be freed by himself. // created by the user and should be freed by himself.
if (cast(StreamTransport) connection !is null) if (cast(StreamTransport) connection !is null)
{ {
MmapPool.instance.dispose(connection); defaultAllocator.dispose(connection);
} }
} }
} }
@ -263,7 +261,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 +287,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 +354,7 @@ abstract class SelectorLoop : Loop
{ {
assert(connection !is null); assert(connection !is null);
} }
body do
{ {
while (true) while (true)
{ {
@ -387,7 +385,7 @@ abstract class SelectorLoop : Loop
} }
if (transport is null) if (transport is null)
{ {
transport = MmapPool.instance.make!StreamTransport(this, client); transport = defaultAllocator.make!StreamTransport(this, client);
connections[client.handle] = transport; connections[client.handle] = transport;
} }
else else

View File

@ -78,7 +78,6 @@ import tanya.async.watcher;
import tanya.container.buffer; import tanya.container.buffer;
import tanya.container.queue; import tanya.container.queue;
import tanya.memory; import tanya.memory;
import tanya.memory.mmappool;
import tanya.network.socket; import tanya.network.socket;
version (DisableBackends) version (DisableBackends)
@ -189,7 +188,7 @@ abstract class Loop
*/ */
this() @nogc this() @nogc
{ {
pendings = Queue!Watcher(MmapPool.instance); pendings = Queue!Watcher();
} }
/** /**
@ -199,7 +198,7 @@ abstract class Loop
{ {
foreach (w; pendings) foreach (w; pendings)
{ {
MmapPool.instance.dispose(w); defaultAllocator.dispose(w);
} }
} }
@ -326,7 +325,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;
} }
@ -384,16 +383,16 @@ class BadLoopException : Exception
} }
version (Epoll) version (Epoll)
{ {
defaultLoop_ = MmapPool.instance.make!EpollLoop; defaultLoop_ = defaultAllocator.make!EpollLoop;
} }
else version (IOCP) else version (IOCP)
{ {
defaultLoop_ = MmapPool.instance.make!IOCPLoop; defaultLoop_ = defaultAllocator.make!IOCPLoop;
} }
else version (Kqueue) else version (Kqueue)
{ {
import tanya.async.event.kqueue; import tanya.async.event.kqueue;
defaultLoop_ = MmapPool.instance.make!KqueueLoop; defaultLoop_ = defaultAllocator.make!KqueueLoop;
} }
return defaultLoop_; return defaultLoop_;
} }
@ -414,7 +413,7 @@ in
{ {
assert(loop !is null); assert(loop !is null);
} }
body do
{ {
defaultLoop_ = loop; defaultLoop_ = loop;
} }

View File

@ -65,8 +65,7 @@ interface DuplexTransport : ReadTransport, WriteTransport
/** /**
* Switches the protocol. * Switches the protocol.
* *
* The protocol is deallocated by the event loop, it should currently be * The protocol is deallocated by the event loop.
* allocated with $(D_PSYMBOL MmapPool).
* *
* Params: * Params:
* protocol = Application protocol. * protocol = Application protocol.

View File

@ -22,7 +22,6 @@ import tanya.async.transport;
import tanya.container.buffer; import tanya.container.buffer;
import tanya.container.queue; import tanya.container.queue;
import tanya.memory; import tanya.memory;
import tanya.memory.mmappool;
import tanya.network.socket; import tanya.network.socket;
/** /**
@ -72,7 +71,7 @@ abstract class SocketWatcher : Watcher
{ {
assert(socket !is null); assert(socket !is null);
} }
body do
{ {
socket_ = socket; socket_ = socket;
} }
@ -103,7 +102,7 @@ class ConnectionWatcher : SocketWatcher
this(Socket socket) @nogc this(Socket socket) @nogc
{ {
super(socket); super(socket);
incoming = Queue!DuplexTransport(MmapPool.instance); incoming = Queue!DuplexTransport();
} }
/** /**
@ -112,7 +111,7 @@ class ConnectionWatcher : SocketWatcher
*/ */
void setProtocol(P : Protocol)() @nogc void setProtocol(P : Protocol)() @nogc
{ {
this.protocolFactory = () @nogc => cast(Protocol) MmapPool.instance.make!P; this.protocolFactory = () @nogc => cast(Protocol) defaultAllocator.make!P;
} }
/** /**
@ -123,7 +122,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

@ -56,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;
@ -87,7 +87,7 @@ struct Range(A)
{ {
assert(!empty); assert(!empty);
} }
body do
{ {
return *this.begin; return *this.begin;
} }
@ -97,7 +97,7 @@ struct Range(A)
{ {
assert(!empty); assert(!empty);
} }
body do
{ {
return *(this.end - 1); return *(this.end - 1);
} }
@ -107,7 +107,7 @@ struct Range(A)
{ {
assert(!empty); assert(!empty);
} }
body do
{ {
++this.begin; ++this.begin;
} }
@ -117,7 +117,7 @@ struct Range(A)
{ {
assert(!empty); assert(!empty);
} }
body do
{ {
--this.end; --this.end;
} }
@ -127,7 +127,7 @@ struct Range(A)
{ {
assert(i < length); assert(i < length);
} }
body do
{ {
return *(this.begin + i); return *(this.begin + i);
} }
@ -148,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);
} }
@ -159,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);
} }
@ -333,7 +333,7 @@ struct Array(T)
{ {
assert(allocator !is null); assert(allocator !is null);
} }
body do
{ {
allocator_ = allocator; allocator_ = allocator;
} }
@ -597,7 +597,7 @@ struct Array(T)
{ {
assert(!empty); assert(!empty);
} }
body do
{ {
length = length - 1; length = length - 1;
} }
@ -619,7 +619,7 @@ struct Array(T)
{ {
assert(removed <= howMany); assert(removed <= howMany);
} }
body do
{ {
const toRemove = min(howMany, length); const toRemove = min(howMany, length);
@ -662,7 +662,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
{ {
auto target = r.begin; auto target = r.begin;
for (auto source = r.end; source != end; ++source, ++target) for (auto source = r.end; source != end; ++source, ++target)
@ -821,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;
@ -838,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[]);
} }
@ -852,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;
@ -881,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);
} }
@ -894,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[]);
} }
@ -908,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;
@ -1080,7 +1080,7 @@ struct Array(T)
{ {
assert(length > pos); assert(length > pos);
} }
body do
{ {
return *(this.data + pos); return *(this.data + pos);
} }
@ -1185,7 +1185,7 @@ struct Array(T)
{ {
assert(!empty); assert(!empty);
} }
body do
{ {
return *this.data; return *this.data;
} }
@ -1212,7 +1212,7 @@ struct Array(T)
{ {
assert(!empty); assert(!empty);
} }
body do
{ {
return *(this.data + length - 1); return *(this.data + length - 1);
} }
@ -1245,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);
} }
@ -1257,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);
} }
@ -1328,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);
@ -1342,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);
@ -1356,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

@ -64,7 +64,7 @@ struct SRange(L)
{ {
assert(!empty); assert(!empty);
} }
body do
{ {
return (*this.head).content; return (*this.head).content;
} }
@ -74,7 +74,7 @@ struct SRange(L)
{ {
assert(!empty); assert(!empty);
} }
body do
{ {
this.head = &(*this.head).next; this.head = &(*this.head).next;
} }
@ -124,7 +124,7 @@ struct SList(T)
} }
/// ///
@safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
auto l = SList!int([5, 8, 15]); auto l = SList!int([5, 8, 15]);
assert(l.front == 5); assert(l.front == 5);
@ -172,19 +172,13 @@ struct SList(T)
} }
/// ///
@safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
auto l = SList!int(2, 3); auto l = SList!int(2, 3);
assert(l.length == 2); assert(l.length == 2);
assert(l.front == 3); assert(l.front == 3);
} }
private @safe @nogc unittest
{
auto l = SList!int(0, 0);
assert(l.empty);
}
/// ditto /// ditto
this(const size_t len, shared Allocator allocator = defaultAllocator) this(const size_t len, shared Allocator allocator = defaultAllocator)
{ {
@ -192,7 +186,7 @@ struct SList(T)
} }
/// ///
@safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
auto l = SList!int(2); auto l = SList!int(2);
assert(l.length == 2); assert(l.length == 2);
@ -205,7 +199,7 @@ struct SList(T)
{ {
assert(allocator !is null); assert(allocator !is null);
} }
body do
{ {
this.allocator_ = allocator; this.allocator_ = allocator;
} }
@ -263,7 +257,7 @@ struct SList(T)
} }
/// ///
@safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
auto l1 = SList!int([5, 1, 234]); auto l1 = SList!int([5, 1, 234]);
auto l2 = SList!int(l1); auto l2 = SList!int(l1);
@ -289,7 +283,7 @@ struct SList(T)
} }
/// ///
@safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
auto l1 = SList!int([5, 1, 234]); auto l1 = SList!int([5, 1, 234]);
auto l2 = l1; auto l2 = l1;
@ -308,7 +302,7 @@ struct SList(T)
} }
/// ///
@safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
SList!int l = SList!int([8, 5]); SList!int l = SList!int([8, 5]);
@ -325,7 +319,7 @@ struct SList(T)
{ {
assert(!empty); assert(!empty);
} }
body do
{ {
return this.head.content; return this.head.content;
} }
@ -366,7 +360,7 @@ struct SList(T)
} }
/// ///
unittest @nogc nothrow pure @safe unittest
{ {
SList!int l; SList!int l;
int value = 5; int value = 5;
@ -419,7 +413,7 @@ struct SList(T)
alias insert = insertFront; alias insert = insertFront;
/// ///
@safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
SList!int l1; SList!int l1;
@ -467,13 +461,13 @@ struct SList(T)
{ {
assert(checkRangeBelonging(r)); assert(checkRangeBelonging(r));
} }
body do
{ {
return moveEntry(*r.head, el); return moveEntry(*r.head, el);
} }
/// ///
@safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
auto l1 = SList!int([234, 5, 1]); auto l1 = SList!int([234, 5, 1]);
auto l2 = SList!int([5, 1]); auto l2 = SList!int([5, 1]);
@ -490,7 +484,7 @@ struct SList(T)
{ {
assert(checkRangeBelonging(r)); assert(checkRangeBelonging(r));
} }
body do
{ {
size_t inserted; size_t inserted;
foreach (e; el) foreach (e; el)
@ -502,7 +496,7 @@ struct SList(T)
} }
/// ///
@safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
auto l1 = SList!int([5, 234, 30, 1]); auto l1 = SList!int([5, 234, 30, 1]);
auto l2 = SList!int([5, 1]); auto l2 = SList!int([5, 1]);
@ -519,14 +513,14 @@ 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;
} }
/// ///
@safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
auto l1 = SList!int([234, 5, 1]); auto l1 = SList!int([234, 5, 1]);
auto l2 = SList!int([5, 1]); auto l2 = SList!int([5, 1]);
@ -553,7 +547,7 @@ struct SList(T)
} }
/// ///
@safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
auto l1 = SList!int([5, 234, 30, 1]); auto l1 = SList!int([5, 234, 30, 1]);
auto l2 = SList!int([5, 1]); auto l2 = SList!int([5, 1]);
@ -572,7 +566,7 @@ struct SList(T)
} }
/// ///
@safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
SList!int l; SList!int l;
@ -600,7 +594,7 @@ struct SList(T)
} }
/// ///
@safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
SList!int l1, l2; SList!int l1, l2;
@ -641,16 +635,16 @@ struct SList(T)
{ {
assert(!empty); assert(!empty);
} }
body do
{ {
auto n = this.head.next; auto n = this.head.next;
this.allocator.dispose(this.head); allocator.dispose(this.head);
this.head = n; this.head = n;
} }
/// ///
@safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
SList!int l; SList!int l;
@ -680,7 +674,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)
@ -691,7 +685,7 @@ struct SList(T)
} }
/// ///
@safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
SList!int l = SList!int([8, 5, 4]); SList!int l = SList!int([8, 5, 4]);
@ -716,7 +710,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;
@ -726,7 +720,7 @@ struct SList(T)
} }
/// ///
@safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
auto l1 = SList!int([5, 234, 30, 1]); auto l1 = SList!int([5, 234, 30, 1]);
auto l2 = SList!int([5]); auto l2 = SList!int([5]);
@ -784,7 +778,7 @@ struct SList(T)
} }
/// ///
@safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
{ {
auto l1 = SList!int([5, 4, 9]); auto l1 = SList!int([5, 4, 9]);
@ -834,7 +828,7 @@ struct SList(T)
} }
/// ///
@safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
auto l1 = SList!int([5, 4, 9]); auto l1 = SList!int([5, 4, 9]);
auto l2 = SList!int([9, 4]); auto l2 = SList!int([9, 4]);
@ -842,14 +836,6 @@ struct SList(T)
assert(l1 == l2); assert(l1 == l2);
} }
private @safe @nogc unittest
{
auto l1 = SList!int();
auto l2 = SList!int([9, 4]);
l1 = l2[];
assert(l1 == l2);
}
/** /**
* Assigns a static array. * Assigns a static array.
* *
@ -865,7 +851,7 @@ struct SList(T)
} }
/// ///
@safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
auto l1 = SList!int([5, 4, 9]); auto l1 = SList!int([5, 4, 9]);
auto l2 = SList!int([9, 4]); auto l2 = SList!int([9, 4]);
@ -877,7 +863,7 @@ struct SList(T)
} }
/// ///
@nogc unittest @nogc nothrow pure @safe unittest
{ {
SList!int l; SList!int l;
size_t i; size_t i;
@ -895,7 +881,7 @@ struct SList(T)
assert(i == 3); assert(i == 3);
} }
@safe @nogc private unittest @nogc nothrow pure @safe unittest
{ {
interface Stuff interface Stuff
{ {
@ -903,8 +889,14 @@ struct SList(T)
static assert(is(SList!Stuff)); static assert(is(SList!Stuff));
} }
@nogc nothrow pure @safe unittest
{
auto l = SList!int(0, 0);
assert(l.empty);
}
// foreach called using opIndex(). // foreach called using opIndex().
private @nogc @safe unittest @nogc nothrow pure @safe unittest
{ {
SList!int l; SList!int l;
size_t i; size_t i;
@ -921,6 +913,14 @@ private @nogc @safe unittest
} }
} }
@nogc nothrow pure @safe unittest
{
auto l1 = SList!int();
auto l2 = SList!int([9, 4]);
l1 = l2[];
assert(l1 == l2);
}
/** /**
* Forward range for the $(D_PSYMBOL DList). * Forward range for the $(D_PSYMBOL DList).
* *
@ -963,7 +963,7 @@ struct DRange(L)
{ {
assert(!empty); assert(!empty);
} }
body do
{ {
return (*this.head).content; return (*this.head).content;
} }
@ -973,7 +973,7 @@ struct DRange(L)
{ {
assert(!empty); assert(!empty);
} }
body do
{ {
return (*this.tail).content; return (*this.tail).content;
} }
@ -983,7 +983,7 @@ struct DRange(L)
{ {
assert(!empty); assert(!empty);
} }
body do
{ {
this.head = &(*this.head).next; this.head = &(*this.head).next;
} }
@ -993,7 +993,7 @@ struct DRange(L)
{ {
assert(!empty); assert(!empty);
} }
body do
{ {
this.tail = &(*this.tail).prev; this.tail = &(*this.tail).prev;
} }
@ -1051,7 +1051,7 @@ struct DList(T)
} }
/// ///
@safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
auto l = DList!int([5, 8, 15]); auto l = DList!int([5, 8, 15]);
assert(l.front == 5); assert(l.front == 5);
@ -1101,7 +1101,7 @@ struct DList(T)
} }
/// ///
@safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
auto l = DList!int(2, 3); auto l = DList!int(2, 3);
assert(l.length == 2); assert(l.length == 2);
@ -1109,12 +1109,6 @@ struct DList(T)
assert(l.back == 3); assert(l.back == 3);
} }
private @safe @nogc unittest
{
auto l = DList!int(0, 0);
assert(l.empty);
}
/// ditto /// ditto
this(const size_t len, shared Allocator allocator = defaultAllocator) this(const size_t len, shared Allocator allocator = defaultAllocator)
{ {
@ -1122,7 +1116,7 @@ struct DList(T)
} }
/// ///
@safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
auto l = DList!int(2); auto l = DList!int(2);
assert(l.length == 2); assert(l.length == 2);
@ -1135,7 +1129,7 @@ struct DList(T)
{ {
assert(allocator !is null); assert(allocator !is null);
} }
body do
{ {
this.allocator_ = allocator; this.allocator_ = allocator;
} }
@ -1196,7 +1190,7 @@ struct DList(T)
} }
/// ///
@safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
auto l1 = DList!int([5, 1, 234]); auto l1 = DList!int([5, 1, 234]);
auto l2 = DList!int(l1); auto l2 = DList!int(l1);
@ -1223,7 +1217,7 @@ struct DList(T)
} }
/// ///
@safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
auto l1 = DList!int([5, 1, 234]); auto l1 = DList!int([5, 1, 234]);
auto l2 = l1; auto l2 = l1;
@ -1242,7 +1236,7 @@ struct DList(T)
} }
/// ///
@safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
DList!int l = DList!int([8, 5]); DList!int l = DList!int([8, 5]);
@ -1259,7 +1253,7 @@ struct DList(T)
{ {
assert(!empty); assert(!empty);
} }
body do
{ {
return this.head.content; return this.head.content;
} }
@ -1272,13 +1266,13 @@ struct DList(T)
{ {
assert(!empty); assert(!empty);
} }
body do
{ {
return this.tail.content; return this.tail.content;
} }
/// ///
@safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
auto l = DList!int([25]); auto l = DList!int([25]);
assert(l.front == 25); assert(l.front == 25);
@ -1311,17 +1305,17 @@ struct DList(T)
return 1; return 1;
} }
// Creates a lsit of linked entries from a range. // Creates a lsit of linked entries from a range.
// Returns count of the elements in the list. // Returns count of the elements in the list.
private size_t makeList(R)(ref R el, out Entry* head, out Entry* tail) @trusted private size_t makeList(R)(ref R el, out Entry* head, out Entry* tail) @trusted
out (retLength) out (retLength)
{ {
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;
if (!el.empty) if (!el.empty)
{ {
@ -1336,8 +1330,8 @@ struct DList(T)
tail = tail.next; tail = tail.next;
++retLength; ++retLength;
} }
return retLength; return retLength;
} }
/** /**
* Inserts a new element at the beginning. * Inserts a new element at the beginning.
@ -1371,7 +1365,7 @@ struct DList(T)
} }
/// ///
unittest @nogc nothrow pure @safe unittest
{ {
DList!int l; DList!int l;
int value = 5; int value = 5;
@ -1408,12 +1402,6 @@ struct DList(T)
return inserted; return inserted;
} }
private @safe @nogc unittest
{
auto l1 = DList!int([5, 234]);
assert(l1.head is l1.head.next.prev);
}
/// ditto /// ditto
size_t insertFront(size_t R)(T[R] el) size_t insertFront(size_t R)(T[R] el)
{ {
@ -1421,7 +1409,7 @@ struct DList(T)
} }
/// ///
@safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
DList!int l1; DList!int l1;
@ -1497,7 +1485,7 @@ struct DList(T)
} }
/// ///
unittest @nogc nothrow pure @safe unittest
{ {
DList!int l; DList!int l;
int value = 5; int value = 5;
@ -1525,10 +1513,10 @@ struct DList(T)
{ {
this.head = begin; this.head = begin;
} }
else else
{ {
this.tail.next = begin; this.tail.next = begin;
} }
if (begin !is null) if (begin !is null)
{ {
this.tail = end; this.tail = end;
@ -1544,7 +1532,7 @@ struct DList(T)
} }
/// ///
@safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
DList!int l1; DList!int l1;
@ -1595,13 +1583,13 @@ struct DList(T)
{ {
assert(checkRangeBelonging(r)); assert(checkRangeBelonging(r));
} }
body do
{ {
return moveFront(*r.head, el); return moveFront(*r.head, el);
} }
/// ///
@safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
auto l1 = DList!int([234, 5, 1]); auto l1 = DList!int([234, 5, 1]);
auto l2 = DList!int([5, 1]); auto l2 = DList!int([5, 1]);
@ -1615,7 +1603,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);
@ -1634,7 +1622,7 @@ struct DList(T)
} }
/// ///
@safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
auto l1 = DList!int([234, 5, 1]); auto l1 = DList!int([234, 5, 1]);
auto l2 = DList!int([5, 1]); auto l2 = DList!int([5, 1]);
@ -1653,7 +1641,7 @@ struct DList(T)
{ {
assert(checkRangeBelonging(r)); assert(checkRangeBelonging(r));
} }
body do
{ {
size_t inserted; size_t inserted;
foreach (e; el) foreach (e; el)
@ -1665,7 +1653,7 @@ struct DList(T)
} }
/// ///
@safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
auto l1 = DList!int([5, 234, 30, 1]); auto l1 = DList!int([5, 234, 30, 1]);
auto l2 = DList!int([5, 1]); auto l2 = DList!int([5, 1]);
@ -1710,13 +1698,13 @@ struct DList(T)
{ {
assert(checkRangeBelonging(r)); assert(checkRangeBelonging(r));
} }
body do
{ {
return moveBack(*r.tail, el); return moveBack(*r.tail, el);
} }
/// ///
@safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
auto l1 = DList!int([5, 234, 1]); auto l1 = DList!int([5, 234, 1]);
auto l2 = DList!int([5, 1]); auto l2 = DList!int([5, 1]);
@ -1726,22 +1714,13 @@ struct DList(T)
assert(l1 == l2); assert(l1 == l2);
} }
private @safe @nogc unittest
{
DList!int l;
l.insertAfter(l[], 234);
assert(l.front == 234);
assert(l.back == 234);
assert(l.length == 1);
}
/// ditto /// ditto
size_t insertAfter(Range r, ref T el) @trusted size_t insertAfter(Range r, ref T el) @trusted
in in
{ {
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);
@ -1760,7 +1739,7 @@ struct DList(T)
} }
/// ///
@safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
auto l1 = DList!int([5, 1, 234]); auto l1 = DList!int([5, 1, 234]);
auto l2 = DList!int([5, 1]); auto l2 = DList!int([5, 1]);
@ -1779,7 +1758,7 @@ struct DList(T)
{ {
assert(checkRangeBelonging(r)); assert(checkRangeBelonging(r));
} }
body do
{ {
size_t inserted; size_t inserted;
foreach (e; el) foreach (e; el)
@ -1790,7 +1769,7 @@ struct DList(T)
} }
/// ///
@safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
auto l1 = DList!int([5, 234, 30, 1]); auto l1 = DList!int([5, 234, 30, 1]);
auto l2 = DList!int([5, 1]); auto l2 = DList!int([5, 1]);
@ -1827,7 +1806,7 @@ struct DList(T)
} }
/// ///
@safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
DList!int l; DList!int l;
@ -1855,7 +1834,7 @@ struct DList(T)
} }
/// ///
@safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
DList!int l1, l2; DList!int l1, l2;
@ -1896,11 +1875,11 @@ struct DList(T)
{ {
assert(!empty); assert(!empty);
} }
body do
{ {
auto n = this.head.next; auto n = this.head.next;
allocator.dispose(this.head); this.allocator_.dispose(this.head);
this.head = n; this.head = n;
if (this.head is null) if (this.head is null)
{ {
@ -1913,7 +1892,7 @@ struct DList(T)
} }
/// ///
@safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
DList!int l; DList!int l;
@ -1932,7 +1911,7 @@ struct DList(T)
{ {
assert(!empty); assert(!empty);
} }
body do
{ {
auto n = this.tail.prev; auto n = this.tail.prev;
@ -1949,7 +1928,7 @@ struct DList(T)
} }
/// ///
@safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
auto l = DList!int([9, 8]); auto l = DList!int([9, 8]);
@ -1978,7 +1957,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)
@ -1989,7 +1968,7 @@ struct DList(T)
} }
/// ///
@safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
DList!int l = DList!int([8, 5, 4]); DList!int l = DList!int([8, 5, 4]);
@ -2005,7 +1984,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)
@ -2016,7 +1995,7 @@ struct DList(T)
} }
/// ///
@safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
DList!int l = DList!int([8, 5, 4]); DList!int l = DList!int([8, 5, 4]);
@ -2041,13 +2020,14 @@ 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* headPrev;
if (*r.tail !is null && (*r.tail).next !is null) Entry** tailNext;
if (*r.tail !is null)
{ {
tailNext = (*r.tail).next; tailNext = &(*r.tail).next;
} }
if (*r.head !is null) if (*r.head !is null)
{ {
@ -2056,26 +2036,42 @@ struct DList(T)
// Remove the elements. // Remove the elements.
Entry* e = *r.head; Entry* e = *r.head;
while (e !is tailNext) while (e !is *tailNext)
{ {
auto next = e.next; auto next = e.next;
allocator.dispose(e); /* Workaround for dmd 2.076.1 bug on OSX. Invariants fail when
the allocator is called. Here it should be safe to use
allocator_ directory, since the list isn't empty.
See also removeFront. */
this.allocator_.dispose(e);
e = next; e = next;
} }
// Connect the elements before and after the removed range. // Connect the elements before and after the removed range.
if (tailNext !is null) if (*tailNext !is null)
{ {
tailNext.prev = headPrev; (*tailNext).prev = headPrev;
} }
*r.head = tailNext; else
*r.tail = tail; {
this.tail = headPrev;
}
if (headPrev !is null)
{
headPrev.next = *tailNext;
}
else
{
this.head = *tailNext;
}
r.head = tailNext;
r.tail = &this.tail;
return r; return r;
} }
/// ///
@safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
auto l1 = DList!int([5, 234, 30, 1]); auto l1 = DList!int([5, 234, 30, 1]);
auto l2 = DList!int([5]); auto l2 = DList!int([5]);
@ -2087,22 +2083,6 @@ struct DList(T)
assert(l1 == l2); assert(l1 == l2);
} }
// Issue 260: https://issues.caraus.io/issues/260.
private @safe @nogc unittest
{
auto l1 = DList!int([5, 234, 30, 1]);
auto l2 = DList!int([5, 1]);
auto r = l1[];
r.popFront();
r.popBack();
assert(r.front == 234);
assert(r.back == 30);
assert(!l1.remove(r).empty);
assert(l1 == l2);
}
/** /**
* Returns: Range that iterates over all elements of the container, in * Returns: Range that iterates over all elements of the container, in
* forward order. * forward order.
@ -2183,7 +2163,7 @@ struct DList(T)
} }
/// ///
@safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
auto l1 = DList!int([5, 4, 9]); auto l1 = DList!int([5, 4, 9]);
auto l2 = DList!int([9, 4]); auto l2 = DList!int([9, 4]);
@ -2191,14 +2171,6 @@ struct DList(T)
assert(l1 == l2); assert(l1 == l2);
} }
private @safe @nogc unittest
{
auto l1 = DList!int();
auto l2 = DList!int([9, 4]);
l1 = l2[];
assert(l1 == l2);
}
/** /**
* Assigns a static array. * Assigns a static array.
* *
@ -2214,7 +2186,7 @@ struct DList(T)
} }
/// ///
@safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
auto l1 = DList!int([5, 4, 9]); auto l1 = DList!int([5, 4, 9]);
auto l2 = DList!int([9, 4]); auto l2 = DList!int([9, 4]);
@ -2226,7 +2198,7 @@ struct DList(T)
} }
/// ///
@nogc unittest @nogc nothrow pure @safe unittest
{ {
DList!int l; DList!int l;
size_t i; size_t i;
@ -2244,8 +2216,7 @@ struct DList(T)
assert(i == 3); assert(i == 3);
} }
// Issue 232: https://issues.caraus.io/issues/232. @nogc nothrow pure @safe unittest
private @nogc unittest
{ {
class A class A
{ {
@ -2253,3 +2224,67 @@ private @nogc unittest
static assert(is(SList!(A*))); static assert(is(SList!(A*)));
static assert(is(DList!(A*))); static assert(is(DList!(A*)));
} }
// Removes all elements
@nogc nothrow pure @safe unittest
{
auto l = DList!int([5]);
assert(l.remove(l[]).empty);
}
@nogc nothrow pure @safe unittest
{
auto l1 = DList!int([5, 234, 30, 1]);
auto l2 = DList!int([5, 1]);
auto r = l1[];
r.popFront();
r.popBack();
assert(r.front == 234);
assert(r.back == 30);
assert(!l1.remove(r).empty);
assert(l1 == l2);
}
@nogc nothrow pure @safe unittest
{
auto l = DList!int(0, 0);
assert(l.empty);
}
@nogc nothrow pure @safe unittest
{
auto l1 = DList!int([5, 234]);
assert(l1.head is l1.head.next.prev);
}
@nogc nothrow pure @safe unittest
{
DList!int l;
l.insertAfter(l[], 234);
assert(l.front == 234);
assert(l.back == 234);
assert(l.length == 1);
}
@nogc nothrow pure @safe unittest
{
auto l1 = DList!int();
auto l2 = DList!int([9, 4]);
l1 = l2[];
assert(l1 == l2);
}
// Sets the new head
@nogc nothrow pure @safe unittest
{
auto l1 = DList!int([5, 234, 30, 1]);
auto l2 = DList!int([1]);
auto r = l1[];
r.popBack();
assert(!l1.remove(r).empty);
assert(l1 == l2);
}

View File

@ -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

@ -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

@ -91,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;
@ -122,7 +122,7 @@ if (is(Unqual!E == char))
{ {
assert(!empty); assert(!empty);
} }
body do
{ {
return *this.begin; return *this.begin;
} }
@ -132,7 +132,7 @@ if (is(Unqual!E == char))
{ {
assert(!empty); assert(!empty);
} }
body do
{ {
return *(this.end - 1); return *(this.end - 1);
} }
@ -142,7 +142,7 @@ if (is(Unqual!E == char))
{ {
assert(!empty); assert(!empty);
} }
body do
{ {
++this.begin; ++this.begin;
} }
@ -152,7 +152,7 @@ if (is(Unqual!E == char))
{ {
assert(!empty); assert(!empty);
} }
body do
{ {
--this.end; --this.end;
} }
@ -162,7 +162,7 @@ if (is(Unqual!E == char))
{ {
assert(i < length); assert(i < length);
} }
body do
{ {
return *(this.begin + i); return *(this.begin + i);
} }
@ -183,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);
} }
@ -194,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);
} }
@ -233,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;
@ -261,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)
@ -294,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)
@ -437,7 +438,7 @@ struct String
{ {
assert(allocator !is null); assert(allocator !is null);
} }
body do
{ {
this.allocator_ = allocator; this.allocator_ = allocator;
} }
@ -527,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;
@ -545,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)
@ -923,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);
@ -940,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);
@ -956,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)
{ {
@ -1037,7 +1038,7 @@ struct String
{ {
assert(length > pos); assert(length > pos);
} }
body do
{ {
return *(this.data + pos); return *(this.data + pos);
} }
@ -1187,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);
} }
@ -1200,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);
} }
@ -1508,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));
@ -1561,12 +1562,14 @@ 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; const oldLength = length;
const rangeEnd = r.end - this.data;
const inserted = insertBack(el); const inserted = insertBack(el);
bringToFront(ByCodeUnit!char(this, r.end, oldLen), auto containerEnd = this.data + oldLength;
ByCodeUnit!char(this, oldLen, this.data + length)); bringToFront(ByCodeUnit!char(this, this.data + rangeEnd, containerEnd),
ByCodeUnit!char(this, containerEnd, this.data + length));
return inserted; return inserted;
} }
@ -1594,7 +1597,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

@ -66,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);
@ -91,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);
@ -144,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)
@ -169,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)

View File

@ -16,7 +16,6 @@ module tanya.format;
import tanya.container.string; import tanya.container.string;
import tanya.encoding.ascii; import tanya.encoding.ascii;
public import tanya.format.conv;
import tanya.math; import tanya.math;
import tanya.memory.op; import tanya.memory.op;
import tanya.meta.metafunction; import tanya.meta.metafunction;
@ -323,9 +322,9 @@ private HP raise2Power10(const HP value, int power)
} }
/* /*
* Given a float value, returns the significant bits in bits, and the position * Given a float value, returns the significant bits, and the position of the
* of the decimal point in $(D_PARAM exponent). +/-Inf and NaN are specified * decimal point in $(D_PARAM exponent). +/-Inf and NaN are specified by
* by special values returned in the $(D_PARAM exponent). Sing bit is set in * special values returned in the $(D_PARAM exponent). Sing bit is set in
* $(D_PARAM sign). * $(D_PARAM sign).
*/ */
private const(char)[] real2String(double value, private const(char)[] real2String(double value,
@ -505,86 +504,120 @@ if (T.sizeof == U.sizeof)
copy((&src)[0 .. 1], (&dest)[0 .. 1]); copy((&src)[0 .. 1], (&dest)[0 .. 1]);
} }
package(tanya) String format(string fmt, Args...)(auto ref Args args) private void formatReal(T)(ref T arg, ref String result)
if (isFloatingPoint!T)
{ {
String result; char[512] buffer; // Big enough for e+308 or e-307.
char[8] tail = 0;
char[] bufferSlice = buffer[64 .. $];
uint precision = 6;
bool negative;
int decimalPoint;
static if (is(Unqual!(Args[0]) == typeof(null))) // Read the double into a string.
auto realString = real2String(arg, buffer, decimalPoint, negative);
auto length = cast(uint) realString.length;
// Clamp the precision and delete extra zeros after clamp.
uint n = precision;
if (length > precision)
{ {
result.insertBack("null"); length = precision;
} }
else static if(is(Unqual!(Args[0]) == bool)) while ((length > 1) && (precision != 0) && (realString[length - 1] == '0'))
{ {
result.insertBack(args[0] ? "true" : "false"); --precision;
--length;
} }
else static if (isSomeString!(Args[0])) // String
if (negative)
{ {
if (args[0] is null) result.insertBack('-');
}
if (decimalPoint == special)
{
result.insertBack(realString);
return;
}
// Should we use sceintific notation?
if ((decimalPoint <= -4) || (decimalPoint > cast(int) n))
{
if (precision > length)
{ {
result.insertBack("null"); precision = length - 1;
}
else if (precision > 0)
{
// When using scientific notation, there is one digit before the
// decimal.
--precision;
}
// Handle leading chars.
bufferSlice.front = realString[0];
bufferSlice.popFront();
if (precision != 0)
{
bufferSlice.front = period;
bufferSlice.popFront();
}
// Handle after decimal.
if ((length - 1) > precision)
{
length = precision + 1;
}
realString[1 .. length].copy(bufferSlice);
bufferSlice.popFrontExactly(length - 1);
// Dump the exponent.
tail[1] = 'e';
--decimalPoint;
if (decimalPoint < 0)
{
tail[2] = '-';
decimalPoint = -decimalPoint;
} }
else else
{ {
result.insertBack(args[0]); tail[2] = '+';
}
n = decimalPoint >= 100 ? 5 : 4;
tail[0] = cast(char) n;
while (true)
{
tail[n] = '0' + decimalPoint % 10;
if (n <= 3)
{
break;
}
--n;
decimalPoint /= 10;
} }
} }
else static if (isSomeChar!(Args[0])) // Char else
{ {
result.insertBack(args[0]); if (decimalPoint > 0)
}
else static if (isFloatingPoint!(Args[0])) // Float
{
char[512] buffer; // Big enough for e+308 or e-307.
char[8] tail = 0;
char[] bufferSlice = buffer[64 .. $];
uint precision = 6;
bool negative;
int decimalPoint;
// Read the double into a string.
auto realString = real2String(args[0], buffer, decimalPoint, negative);
auto length = cast(uint) realString.length;
// Clamp the precision and delete extra zeros after clamp.
uint n = precision;
if (length > precision)
{ {
length = precision; precision = decimalPoint < (cast(int) length)
? length - decimalPoint
: 0;
} }
while ((length > 1) else
&& (precision != 0)
&& (realString[length - 1] == '0'))
{ {
--precision; precision = -decimalPoint
--length; + (precision > length ? length : precision);
} }
if (negative) // Handle the three decimal varieties.
if (decimalPoint <= 0)
{ {
result.insertBack('-'); // Handle 0.000*000xxxx.
} bufferSlice.front = '0';
if (decimalPoint == special)
{
result.insertBack(realString);
goto ParamEnd;
}
// Should we use sceintific notation?
if ((decimalPoint <= -4) || (decimalPoint > cast(int) n))
{
if (precision > length)
{
precision = length - 1;
}
else if (precision > 0)
{
// When using scientific notation, there is one digit before the
// decimal.
--precision;
}
// Handle leading chars.
bufferSlice.front = realString[0];
bufferSlice.popFront(); bufferSlice.popFront();
if (precision != 0) if (precision != 0)
@ -592,143 +625,205 @@ package(tanya) String format(string fmt, Args...)(auto ref Args args)
bufferSlice.front = period; bufferSlice.front = period;
bufferSlice.popFront(); bufferSlice.popFront();
} }
n = -decimalPoint;
// Handle after decimal. if (n > precision)
if ((length - 1) > precision)
{ {
length = precision + 1; n = precision;
}
realString[1 .. length].copy(bufferSlice);
bufferSlice.popFrontExactly(length - 1);
// Dump the exponent.
tail[1] = 'e';
--decimalPoint;
if (decimalPoint < 0)
{
tail[2] = '-';
decimalPoint = -decimalPoint;
}
else
{
tail[2] = '+';
} }
n = decimalPoint >= 100 ? 5 : 4; fill!'0'(bufferSlice[0 .. n]);
bufferSlice.popFrontExactly(n);
tail[0] = cast(char) n; if ((length + n) > precision)
while (true)
{ {
tail[n] = '0' + decimalPoint % 10; length = precision - n;
if (n <= 3) }
{
break; realString[0 .. length].copy(bufferSlice);
} bufferSlice.popFrontExactly(length);
--n; }
decimalPoint /= 10; else if (cast(uint) decimalPoint >= length)
{
// Handle xxxx000*000.0.
n = 0;
do
{
bufferSlice.front = realString[n];
bufferSlice.popFront();
++n;
}
while (n < length);
if (n < cast(uint) decimalPoint)
{
n = decimalPoint - n;
fill!'0'(bufferSlice[0 .. n]);
bufferSlice.popFrontExactly(n);
}
if (precision != 0)
{
bufferSlice.front = period;
bufferSlice.popFront();
} }
} }
else else
{ {
if (decimalPoint > 0) // Handle xxxxx.xxxx000*000.
n = 0;
do
{ {
precision = decimalPoint < (cast(int) length) bufferSlice.front = realString[n];
? length - decimalPoint
: 0;
}
else
{
precision = -decimalPoint
+ (precision > length ? length : precision);
}
// Handle the three decimal varieties.
if (decimalPoint <= 0)
{
// Handle 0.000*000xxxx.
bufferSlice.front = '0';
bufferSlice.popFront(); bufferSlice.popFront();
++n;
if (precision != 0)
{
bufferSlice.front = period;
bufferSlice.popFront();
}
n = -decimalPoint;
if (n > precision)
{
n = precision;
}
fill!'0'(bufferSlice[0 .. n]);
bufferSlice.popFrontExactly(n);
if ((length + n) > precision)
{
length = precision - n;
}
realString[0 .. length].copy(bufferSlice);
bufferSlice.popFrontExactly(length);
} }
else if (cast(uint) decimalPoint >= length) while (n < cast(uint) decimalPoint);
{
// Handle xxxx000*000.0.
n = 0;
do
{
bufferSlice.front = realString[n];
bufferSlice.popFront();
++n;
}
while (n < length);
if (n < cast(uint) decimalPoint)
{
n = decimalPoint - n;
fill!'0'(bufferSlice[0 .. n]); if (precision > 0)
bufferSlice.popFrontExactly(n); {
} bufferSlice.front = period;
if (precision != 0) bufferSlice.popFront();
{
bufferSlice.front = period;
bufferSlice.popFront();
}
} }
else if ((length - decimalPoint) > precision)
{ {
// Handle xxxxx.xxxx000*000. length = precision + decimalPoint;
n = 0; }
do
{
bufferSlice.front = realString[n];
bufferSlice.popFront();
++n;
}
while (n < cast(uint) decimalPoint);
if (precision > 0) realString[n .. length].copy(bufferSlice);
{ bufferSlice.popFrontExactly(length - n);
bufferSlice.front = period; }
bufferSlice.popFront(); }
}
if ((length - decimalPoint) > precision)
{
length = precision + decimalPoint;
}
realString[n .. length].copy(bufferSlice); // Get the length that we've copied.
bufferSlice.popFrontExactly(length - n); length = cast(uint) (buffer.length - bufferSlice.length);
result.insertBack(buffer[64 .. length]); // Number.
result.insertBack(tail[1 .. tail[0] + 1]); // Tail.
}
private void formatStruct(T)(ref T arg, ref String result)
if (is(T == struct))
{
template pred(alias f)
{
static if (f == "this")
{
// Exclude context pointer from nested structs.
enum bool pred = false;
}
else
{
enum bool pred = !isSomeFunction!(__traits(getMember, arg, f));
}
}
alias fields = Filter!(pred, __traits(allMembers, T));
result.insertBack(T.stringof);
result.insertBack('(');
static if (fields.length > 0)
{
printToString!"{}"(result, __traits(getMember, arg, fields[0]));
foreach (field; fields[1 .. $])
{
result.insertBack(", ");
printToString!"{}"(result, __traits(getMember, arg, field));
}
}
result.insertBack(')');
}
private void formatRange(T)(ref T arg, ref String result)
if (isInputRange!T && !isInfinite!T)
{
result.insertBack('[');
if (!arg.empty)
{
printToString!"{}"(result, arg.front);
arg.popFront();
}
foreach (e; arg)
{
result.insertBack(", ");
printToString!"{}"(result, e);
}
result.insertBack(']');
}
private ref String printToString(string fmt, Args...)(return ref String result,
auto ref Args args)
{
alias Arg = Args[0];
static if (is(Unqual!Arg == typeof(null))) // null
{
result.insertBack("null");
}
else static if (is(Unqual!Arg == bool)) // Boolean
{
result.insertBack(args[0] ? "true" : "false");
}
else static if (is(Arg == enum)) // Enum
{
foreach (m; __traits(allMembers, Arg))
{
if (args[0] == __traits(getMember, Arg, m))
{
result.insertBack(m);
} }
} }
// Get the length that we've copied.
length = cast(uint) (buffer.length - bufferSlice.length);
result.insertBack(buffer[64 .. length]); // Number.
result.insertBack(tail[1 .. tail[0] + 1]); // Tail.
} }
else static if (isPointer!(Args[0])) // Pointer else static if (isSomeChar!Arg || isSomeString!Arg) // String or char
{
result.insertBack(args[0]);
}
else static if (isInputRange!Arg
&& !isInfinite!Arg
&& isSomeChar!(ElementType!Arg)) // Stringish range
{
result.insertBack(args[0]);
}
else static if (isInputRange!Arg && !isInfinite!Arg)
{
formatRange(args[0], result);
}
else static if (is(Unqual!(typeof(args[0].stringify())) == String))
{
static if (is(Arg == class) || is(Arg == interface))
{
if (args[0] is null)
{
result.insertBack("null");
}
else
{
result.insertBack(args[0].stringify()[]);
}
}
else
{
result.insertBack(args[0].stringify()[]);
}
}
else static if (is(Arg == class))
{
result.insertBack(args[0] is null ? "null" : args[0].toString());
}
else static if (is(Arg == interface))
{
result.insertBack(Arg.classinfo.name);
}
else static if (is(Arg == struct))
{
formatStruct(args[0], result);
}
else static if (is(Arg == union))
{
result.insertBack(Arg.stringof);
}
else static if (isFloatingPoint!Arg) // Float
{
formatReal(args[0], result);
}
else static if (isPointer!Arg) // Pointer
{ {
char[size_t.sizeof * 2] buffer; char[size_t.sizeof * 2] buffer;
size_t position = buffer.length; size_t position = buffer.length;
@ -744,20 +839,40 @@ package(tanya) String format(string fmt, Args...)(auto ref Args args)
result.insertBack("0x"); result.insertBack("0x");
result.insertBack(buffer[position .. $]); result.insertBack(buffer[position .. $]);
} }
else static if (isIntegral!(Args[0])) // Integer else static if (isIntegral!Arg) // Integer
{ {
char[21] buffer; char[21] buffer;
result.insertBack(integral2String(args[0], buffer)); result.insertBack(integral2String(args[0], buffer));
} }
else else
{ {
static assert(false); static assert(false,
"Formatting type " ~ Arg.stringof ~ " is not supported");
} }
ParamEnd:
return result; return result;
} }
package(tanya) String format(string fmt, Args...)(auto ref Args args)
{
String formatted;
return printToString!fmt(formatted, args);
}
// Enum.
@nogc nothrow pure @safe unittest
{
enum E1 : int
{
one,
two,
}
assert(format!"{}"(E1.one) == "one");
const E1 e1;
assert(format!"{}"(e1) == "one");
}
// One argument tests. // One argument tests.
@nogc pure @safe unittest @nogc pure @safe unittest
{ {
@ -772,7 +887,7 @@ ParamEnd:
// String printing. // String printing.
assert(format!"{}"("Some weired string") == "Some weired string"); assert(format!"{}"("Some weired string") == "Some weired string");
assert(format!"{}"(cast(string) null) == "null"); assert(format!"{}"(cast(string) null) == "");
assert(format!"{}"('c') == "c"); assert(format!"{}"('c') == "c");
// Integer. // Integer.
@ -826,6 +941,145 @@ ParamEnd:
assert(format!"{}"(cast(void*) null) == "0x0"); assert(format!"{}"(cast(void*) null) == "0x0");
} }
// Structs.
@nogc pure @safe unittest
{
static struct WithoutStringify1
{
int a;
void func()
{
}
}
assert(format!"{}"(WithoutStringify1(6)) == "WithoutStringify1(6)");
static struct WithoutStringify2
{
}
assert(format!"{}"(WithoutStringify2()) == "WithoutStringify2()");
static struct WithoutStringify3
{
int a = -2;
int b = 8;
}
assert(format!"{}"(WithoutStringify3()) == "WithoutStringify3(-2, 8)");
struct Nested
{
int i;
void func()
{
}
}
assert(format!"{}"(Nested()) == "Nested(0)");
static struct WithStringify
{
String stringify() const @nogc nothrow pure @safe
{
return String("stringify method");
}
}
assert(format!"{}"(WithStringify()) == "stringify method");
}
// Aggregate types.
@system unittest // Object.toString has no attributes.
{
import tanya.memory;
import tanya.memory.smartref;
interface I
{
}
class A : I
{
}
auto instance = defaultAllocator.unique!A();
assert(format!"{}"(instance.get()) == instance.get().toString());
assert(format!"{}"(cast(I) instance.get()) == I.classinfo.name);
assert(format!"{}"(cast(A) null) == "null");
class B
{
String stringify() @nogc nothrow pure @safe
{
return String("Class B");
}
}
assert(format!"{}"(cast(B) null) == "null");
}
// Unions.
unittest
{
union U
{
int i;
char c;
}
assert(format!"{}"(U(2)) == "U");
}
// Ranges.
@nogc pure @safe unittest
{
static struct Stringish
{
private string content = "Some content";
immutable(char) front() const @nogc nothrow pure @safe
{
return this.content[0];
}
void popFront() @nogc nothrow pure @safe
{
this.content = this.content[1 .. $];
}
bool empty() const @nogc nothrow pure @safe
{
return this.content.length == 0;
}
}
assert(format!"{}"(Stringish()) == "Some content");
static struct Intish
{
private int front_ = 3;
int front() const @nogc nothrow pure @safe
{
return this.front_;
}
void popFront() @nogc nothrow pure @safe
{
--this.front_;
}
bool empty() const @nogc nothrow pure @safe
{
return this.front == 0;
}
}
assert(format!"{}"(Intish()) == "[3, 2, 1]");
}
// Typeid.
nothrow pure @safe unittest
{
assert(format!"{}"(typeid(int[])) == "int[]");
class C
{
}
assert(format!"{}"(typeid(C)) == typeid(C).toString());
}
private struct FormatSpec private struct FormatSpec
{ {
} }

View File

@ -1,293 +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;
version (unittest)
{
import tanya.test.assertion;
}
/**
* 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).
*/
deprecated("Use tanya.conv.to instead")
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;
}
}
/**
* 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).
*/
deprecated("Use tanya.conv.to instead")
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;
}
}
/**
* 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.
*/
deprecated("Use tanya.conv.to instead")
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");
}
/// ditto
deprecated("Use tanya.conv.to instead")
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");
}
/**
* 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).
*/
deprecated("Use tanya.conv.to instead")
To to(To, From)(const From from)
if (is(Unqual!From == bool) && isNumeric!To && !is(Unqual!To == Unqual!From))
{
return from;
}
/// ditto
deprecated("Use tanya.conv.to instead")
To to(To, From)(const From from)
if (is(Unqual!From == bool) && is(Unqual!To == String))
{
return String(from ? "true" : "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).
*/
deprecated("Use tanya.conv.to instead")
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;
}
/**
* 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).
*/
deprecated("Use tanya.conv.to instead")
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 ~ "'");
}

View File

@ -112,7 +112,7 @@ struct Integer
{ {
assert(allocator !is null); assert(allocator !is null);
} }
body do
{ {
this.allocator_ = allocator; this.allocator_ = allocator;
} }
@ -393,7 +393,9 @@ 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;
} }
/// ///
@ -871,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;
@ -883,7 +885,7 @@ 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;
@ -1072,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
@ -1166,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;");
} }
@ -1285,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)
{ {
@ -1470,7 +1472,7 @@ struct Integer
{ {
assert(array.length == length); assert(array.length == length);
} }
body do
{ {
Array!ubyte array; Array!ubyte array;

View File

@ -30,15 +30,15 @@ else
* Calculates the absolute value of a number. * Calculates the absolute value of a number.
* *
* Params: * Params:
* I = Value type. * T = Argument type.
* x = Value. * x = Argument.
* *
* Returns: Absolute value of $(D_PARAM x). * Returns: Absolute value of $(D_PARAM x).
*/ */
I abs(I)(I x) T abs(T)(T x)
if (isIntegral!I) if (isIntegral!T)
{ {
static if (isSigned!I) static if (isSigned!T)
{ {
return x >= 0 ? x : -x; return x >= 0 ? x : -x;
} }
@ -49,7 +49,7 @@ if (isIntegral!I)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
int i = -1; int i = -1;
assert(i.abs == 1); assert(i.abs == 1);
@ -63,25 +63,25 @@ pure nothrow @safe @nogc unittest
version (D_Ddoc) version (D_Ddoc)
{ {
/// ditto /// ditto
I abs(I)(I x) T abs(T)(T x)
if (isFloatingPoint!I); if (isFloatingPoint!T);
} }
else version (TanyaNative) else version (TanyaNative)
{ {
extern I abs(I)(I number) pure nothrow @safe @nogc extern T abs(T)(T number) @nogc nothrow pure @safe
if (isFloatingPoint!I); if (isFloatingPoint!T);
} }
else else
{ {
I abs(I)(I x) T abs(T)(T x)
if (isFloatingPoint!I) if (isFloatingPoint!T)
{ {
return fabs(cast(real) x); return fabs(cast(real) x);
} }
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
float f = -1.64; float f = -1.64;
assert(f.abs == 1.64F); assert(f.abs == 1.64F);
@ -97,7 +97,7 @@ pure nothrow @safe @nogc unittest
} }
/// ditto /// ditto
I abs(I : Integer)(const auto ref I x) T abs(T : Integer)(const auto ref T x)
{ {
auto result = Integer(x, x.allocator); auto result = Integer(x, x.allocator);
result.sign = Sign.positive; result.sign = Sign.positive;
@ -105,7 +105,7 @@ I abs(I : Integer)(const auto ref I x)
} }
/// ditto /// ditto
I abs(I : Integer)(I x) T abs(T : Integer)(T x)
{ {
x.sign = Sign.positive; x.sign = Sign.positive;
return x; return x;
@ -117,37 +117,30 @@ version (D_Ddoc)
* Calculates natural logarithm of $(D_PARAM x). * Calculates natural logarithm of $(D_PARAM x).
* *
* Params: * Params:
* T = Argument type.
* x = Argument. * x = Argument.
* *
* Returns: Natural logarithm of $(D_PARAM x). * Returns: Natural logarithm of $(D_PARAM x).
*/ */
float ln(float x) pure nothrow @safe @nogc; T ln(T)(T x)
/// ditto if (isFloatingPoint!T);
double ln(double x) pure nothrow @safe @nogc;
/// ditto
real ln(real x) pure nothrow @safe @nogc;
} }
else version (TanyaNative) else version (TanyaNative)
{ {
extern float ln(float x) pure nothrow @safe @nogc; extern T ln(T)(T x) @nogc nothrow pure @safe
extern double ln(double x) pure nothrow @safe @nogc; if (isFloatingPoint!T);
extern real ln(real x) pure nothrow @safe @nogc;
} }
else else
{ {
float ln(float x) pure nothrow @safe @nogc T ln(T)(T x)
if (isFloatingPoint!T)
{ {
return log(x); return log(x);
} }
double ln(double x) pure nothrow @safe @nogc
{
return log(x);
}
alias ln = log;
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
import tanya.math; import tanya.math;

View File

@ -586,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;
@ -627,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);

View File

@ -94,9 +94,31 @@ abstract class EntropySource
Nullable!ubyte poll(out ubyte[maxGather] output) @nogc; Nullable!ubyte poll(out ubyte[maxGather] output) @nogc;
} }
version (CRuntime_Bionic)
{
version = SecureARC4Random;
}
else version (OSX)
{
version = SecureARC4Random;
}
else version (OpenBSD)
{
version = SecureARC4Random;
}
else version (NetBSD)
{
version = SecureARC4Random;
}
else version (Solaris)
{
version = SecureARC4Random;
}
version (linux) version (linux)
{ {
extern (C) long syscall(long number, ...) nothrow @system @nogc; import core.stdc.config : c_long;
extern (C) c_long syscall(c_long number, ...) nothrow @system @nogc;
/** /**
* Uses getrandom system call. * Uses getrandom system call.
@ -134,10 +156,11 @@ 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); import mir.linux._asm.unistd : NR_getrandom;
auto length = syscall(NR_getrandom, output.ptr, output.length, 0);
Nullable!ubyte ret; Nullable!ubyte ret;
if (length >= 0) if (length >= 0)
@ -148,16 +171,180 @@ version (linux)
} }
} }
version (X86_64) @nogc @system unittest
{ {
private unittest auto entropy = defaultAllocator.make!Entropy();
{ ubyte[blockSize] output;
auto entropy = defaultAllocator.make!Entropy(); output = entropy.random;
ubyte[blockSize] output;
output = entropy.random;
defaultAllocator.dispose(entropy); defaultAllocator.dispose(entropy);
}
}
else version (SecureARC4Random)
{
private extern (C) void arc4random_buf(scope void* buf, size_t nbytes) nothrow @nogc @system;
/**
* Uses arc4random_buf.
*/
class PlatformEntropySource : EntropySource
{
/**
* Returns: Minimum bytes required from the entropy source.
*/
override @property ubyte threshold() const pure nothrow @safe @nogc
{
return 32;
} }
/**
* Returns: Whether this entropy source is strong.
*/
override @property bool strong() const pure nothrow @safe @nogc
{
return true;
}
/**
* Poll the entropy source.
*
* Params:
* output = Buffer to save the generate random sequence (the method will
* to fill the buffer).
*
* Returns: Number of bytes that were copied to the $(D_PARAM output)
* or $(D_PSYMBOL Nullable!ubyte.init) on error.
*/
override Nullable!ubyte poll(out ubyte[maxGather] output) nothrow @nogc @safe
{
(() @trusted => arc4random_buf(output.ptr, output.length))();
return Nullable!ubyte(cast(ubyte) (output.length));
}
}
@nogc @system unittest
{
auto entropy = defaultAllocator.make!Entropy();
ubyte[blockSize] output;
output = entropy.random;
defaultAllocator.dispose(entropy);
}
}
else version (Windows)
{
import core.sys.windows.basetsd : ULONG_PTR;
import core.sys.windows.windef : BOOL, DWORD, PBYTE;
import core.sys.windows.winnt : LPCSTR, LPCWSTR;
import core.sys.windows.wincrypt;
private extern(Windows) @nogc nothrow
{
BOOL CryptGenRandom(HCRYPTPROV, DWORD, PBYTE);
BOOL CryptAcquireContextA(HCRYPTPROV*, LPCSTR, LPCSTR, DWORD, DWORD);
BOOL CryptAcquireContextW(HCRYPTPROV*, LPCWSTR, LPCWSTR, DWORD, DWORD);
BOOL CryptReleaseContext(HCRYPTPROV, ULONG_PTR);
}
private bool initCryptGenRandom(scope ref HCRYPTPROV hProvider) @nogc nothrow @trusted
{
import core.sys.windows.winbase : GetLastError;
import core.sys.windows.winerror : NTE_BAD_KEYSET;
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa379886(v=vs.85).aspx
// For performance reasons, we recommend that you set the pszContainer
// parameter to NULL and the dwFlags parameter to CRYPT_VERIFYCONTEXT
// in all situations where you do not require a persisted key.
// CRYPT_SILENT is intended for use with applications for which the UI cannot be displayed by the CSP.
if (!CryptAcquireContextW(&hProvider, null, null, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
{
if (GetLastError() == NTE_BAD_KEYSET)
{
// Attempt to create default container
if (!CryptAcquireContextA(&hProvider, null, null, PROV_RSA_FULL, CRYPT_NEWKEYSET | CRYPT_SILENT))
return false;
}
else
{
return false;
}
}
return true;
}
class PlatformEntropySource : EntropySource
{
private HCRYPTPROV hProvider;
/**
* Uses CryptGenRandom.
*/
this() @nogc
{
if (!initCryptGenRandom(hProvider))
{
throw defaultAllocator.make!EntropyException("CryptAcquireContextW failed.");
}
assert(hProvider > 0, "hProvider not properly initialized.");
}
~this() @nogc nothrow @safe
{
if (hProvider > 0)
{
(() @trusted => CryptReleaseContext(hProvider, 0))();
}
}
/**
* Returns: Minimum bytes required from the entropy source.
*/
override @property ubyte threshold() const pure nothrow @safe @nogc
{
return 32;
}
/**
* Returns: Whether this entropy source is strong.
*/
override @property bool strong() const pure nothrow @safe @nogc
{
return true;
}
/**
* Poll the entropy source.
*
* Params:
* output = Buffer to save the generate random sequence (the method will
* to fill the buffer).
*
* Returns: Number of bytes that were copied to the $(D_PARAM output)
* or $(D_PSYMBOL Nullable!ubyte.init) on error.
*/
override Nullable!ubyte poll(out ubyte[maxGather] output) @nogc nothrow @safe
in
{
assert(hProvider > 0, "hProvider not properly initialized.");
}
do
{
Nullable!ubyte ret;
if ((() @trusted => CryptGenRandom(hProvider, output.length, cast(PBYTE) output.ptr))())
{
ret = cast(ubyte) (output.length);
}
return ret;
}
}
@nogc @system unittest
{
auto entropy = defaultAllocator.make!Entropy();
ubyte[blockSize] output;
output = entropy.random;
defaultAllocator.dispose(entropy);
} }
} }
@ -180,8 +367,6 @@ class Entropy
private ubyte sourceCount_; private ubyte sourceCount_;
private shared Allocator allocator;
/// Entropy accumulator. /// Entropy accumulator.
protected SHA!(maxGather * 8, 512) accumulator; protected SHA!(maxGather * 8, 512) accumulator;
@ -198,11 +383,11 @@ 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);
version (linux) static if (is(PlatformEntropySource))
{ {
this ~= allocator.make!PlatformEntropySource; this ~= allocator.make!PlatformEntropySource;
} }
@ -234,7 +419,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 +436,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;
@ -289,7 +474,7 @@ class Entropy
if (!haveStrong) if (!haveStrong)
{ {
throw allocator.make!EntropyException("No strong entropy source defined."); throw defaultAllocator.make!EntropyException("No strong entropy source defined.");
} }
output = accumulator.finish(); output = accumulator.finish();

View File

@ -14,7 +14,10 @@
*/ */
module tanya.memory.mallocator; module tanya.memory.mallocator;
version (TanyaPhobos): version (TanyaNative)
{
}
else:
import core.stdc.stdlib; import core.stdc.stdlib;
import tanya.memory.allocator; import tanya.memory.allocator;

View File

@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/** /*
* Native allocator for Posix and Windows. * Native allocator for Posix and Windows.
* *
* Copyright: Eugene Wissner 2016-2017. * Copyright: Eugene Wissner 2016-2017.
@ -82,7 +82,7 @@ else version (Windows)
} }
} }
/** /*
* This allocator allocates memory in regions (multiple of 64 KB for example). * This allocator allocates memory in regions (multiple of 64 KB for example).
* Each region is then splitted in blocks. So it doesn't request the memory * Each region is then splitted in blocks. So it doesn't request the memory
* from the operating system on each call, but only if there are no large * from the operating system on each call, but only if there are no large
@ -106,6 +106,7 @@ else version (Windows)
* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* </pre> * </pre>
*/ */
deprecated("Use tanya.memory.mallocator instead")
final class MmapPool : Allocator final class MmapPool : Allocator
{ {
version (none) version (none)
@ -126,7 +127,7 @@ final class MmapPool : Allocator
} }
} }
/** /*
* Allocates $(D_PARAM size) bytes of memory. * Allocates $(D_PARAM size) bytes of memory.
* *
* Params: * Params:
@ -155,8 +156,7 @@ final class MmapPool : Allocator
return data is null ? null : data[0 .. size]; return data is null ? null : data[0 .. size];
} }
/// version (TanyaNative) @nogc nothrow pure unittest
nothrow unittest
{ {
auto p = MmapPool.instance.allocate(20); auto p = MmapPool.instance.allocate(20);
assert(p); assert(p);
@ -167,7 +167,7 @@ final class MmapPool : Allocator
} }
// Issue 245: https://issues.caraus.io/issues/245. // Issue 245: https://issues.caraus.io/issues/245.
private @nogc unittest version (TanyaNative) @nogc nothrow pure unittest
{ {
// allocate() check. // allocate() check.
size_t tooMuchMemory = size_t.max size_t tooMuchMemory = size_t.max
@ -245,7 +245,7 @@ final class MmapPool : Allocator
block.next = block.next.next; block.next = block.next.next;
} }
/** /*
* Deallocates a memory block. * Deallocates a memory block.
* *
* Params: * Params:
@ -299,15 +299,14 @@ final class MmapPool : Allocator
return true; return true;
} }
/// version (TanyaNative) @nogc nothrow pure unittest
nothrow unittest
{ {
auto p = MmapPool.instance.allocate(20); auto p = MmapPool.instance.allocate(20);
assert(MmapPool.instance.deallocate(p)); assert(MmapPool.instance.deallocate(p));
} }
/** /*
* Reallocates a memory block in place if possible or returns * Reallocates a memory block in place if possible or returns
* $(D_KEYWORD false). This function cannot be used to allocate or * $(D_KEYWORD false). This function cannot be used to allocate or
* deallocate memory, so if $(D_PARAM p) is $(D_KEYWORD null) or * deallocate memory, so if $(D_PARAM p) is $(D_KEYWORD null) or
@ -383,8 +382,7 @@ final class MmapPool : Allocator
return true; return true;
} }
/// version (TanyaNative) @nogc nothrow pure unittest
nothrow unittest
{ {
void[] p; void[] p;
assert(!MmapPool.instance.reallocateInPlace(p, 5)); assert(!MmapPool.instance.reallocateInPlace(p, 5));
@ -408,7 +406,7 @@ final class MmapPool : Allocator
MmapPool.instance.deallocate(p); MmapPool.instance.deallocate(p);
} }
/** /*
* Increases or decreases the size of a memory block. * Increases or decreases the size of a memory block.
* *
* Params: * Params:
@ -449,8 +447,7 @@ final class MmapPool : Allocator
return true; return true;
} }
/// version (TanyaNative) @nogc nothrow pure unittest
nothrow unittest
{ {
void[] p; void[] p;
MmapPool.instance.reallocate(p, 10 * int.sizeof); MmapPool.instance.reallocate(p, 10 * int.sizeof);
@ -514,7 +511,7 @@ final class MmapPool : Allocator
return instance_; return instance_;
} }
/** /*
* Static allocator instance and initializer. * Static allocator instance and initializer.
* *
* Returns: Global $(D_PSYMBOL MmapPool) instance. * Returns: Global $(D_PSYMBOL MmapPool) instance.
@ -524,8 +521,7 @@ final class MmapPool : Allocator
return (cast(GetPureInstance!MmapPool) &instantiate)(); return (cast(GetPureInstance!MmapPool) &instantiate)();
} }
/// version (TanyaNative) @nogc nothrow pure unittest
nothrow unittest
{ {
assert(instance is instance); assert(instance is instance);
} }
@ -622,7 +618,7 @@ final class MmapPool : Allocator
/ pageSize * pageSize + pageSize; / pageSize * pageSize + pageSize;
} }
/** /*
* Returns: Alignment offered. * Returns: Alignment offered.
*/ */
@property uint alignment() shared const pure nothrow @safe @nogc @property uint alignment() shared const pure nothrow @safe @nogc
@ -630,7 +626,7 @@ final class MmapPool : Allocator
return alignment_; return alignment_;
} }
private nothrow @nogc unittest version (TanyaNative) @nogc nothrow pure unittest
{ {
assert(MmapPool.instance.alignment == MmapPool.alignment_); assert(MmapPool.instance.alignment == MmapPool.alignment_);
} }
@ -661,9 +657,11 @@ final class MmapPool : Allocator
private alias Block = shared BlockEntry*; private alias Block = shared BlockEntry*;
} }
version (TanyaNative):
// A lot of allocations/deallocations, but it is the minimum caused a // A lot of allocations/deallocations, but it is the minimum caused a
// segmentation fault because MmapPool reallocateInPlace moves a block wrong. // segmentation fault because MmapPool reallocateInPlace moves a block wrong.
private @nogc unittest @nogc nothrow pure unittest
{ {
auto a = MmapPool.instance.allocate(16); auto a = MmapPool.instance.allocate(16);
auto d = MmapPool.instance.allocate(16); auto d = MmapPool.instance.allocate(16);

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;
/** /**
@ -58,7 +68,7 @@ in
assert(source.length == 0 || source.ptr !is null); assert(source.length == 0 || source.ptr !is null);
assert(target.length == 0 || target.ptr !is null); assert(target.length == 0 || target.ptr !is null);
} }
body do
{ {
version (TanyaNative) version (TanyaNative)
{ {
@ -126,7 +136,7 @@ in
{ {
assert(memory.length == 0 || memory.ptr !is null); assert(memory.length == 0 || memory.ptr !is null);
} }
body do
{ {
version (TanyaNative) version (TanyaNative)
{ {
@ -149,31 +159,6 @@ body
} }
} }
// Stress test. Checks that `fill` can handle unaligned pointers and different
// lengths.
@nogc nothrow pure @safe 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).
@ -203,7 +188,7 @@ in
assert(source.length == 0 || source.ptr !is null); assert(source.length == 0 || source.ptr !is null);
assert(target.length == 0 || target.ptr !is null); assert(target.length == 0 || target.ptr !is null);
} }
body do
{ {
version (TanyaNative) version (TanyaNative)
{ {
@ -257,7 +242,7 @@ in
assert(r1.length == 0 || r1.ptr !is null); assert(r1.length == 0 || r1.ptr !is null);
assert(r2.length == 0 || r2.ptr !is null); assert(r2.length == 0 || r2.ptr !is null);
} }
body do
{ {
version (TanyaNative) version (TanyaNative)
{ {
@ -321,7 +306,7 @@ in
{ {
assert(haystack.length == 0 || haystack.ptr !is null); assert(haystack.length == 0 || haystack.ptr !is null);
} }
body 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;

View File

@ -14,12 +14,10 @@
*/ */
module tanya.memory; module tanya.memory;
import std.algorithm.iteration;
import std.algorithm.mutation; import std.algorithm.mutation;
import tanya.conv; import tanya.conv;
import tanya.exception; import tanya.exception;
public import tanya.memory.allocator; public import tanya.memory.allocator;
import tanya.memory.mmappool;
import tanya.meta.trait; import tanya.meta.trait;
import tanya.range.primitive; import tanya.range.primitive;
@ -45,7 +43,7 @@ mixin template DefaultAllocator()
{ {
assert(allocator !is null); assert(allocator !is null);
} }
body do
{ {
this.allocator_ = allocator; this.allocator_ = allocator;
} }
@ -63,7 +61,7 @@ mixin template DefaultAllocator()
{ {
assert(allocator !is null); assert(allocator !is null);
} }
body do
{ {
if (allocator_ is null) if (allocator_ is null)
{ {
@ -78,7 +76,7 @@ mixin template DefaultAllocator()
{ {
assert(allocator !is null); assert(allocator !is null);
} }
body do
{ {
if (allocator_ is null) if (allocator_ is null)
{ {
@ -94,13 +92,21 @@ private void _d_monitordelete(Object h, bool det) pure nothrow @nogc;
shared Allocator allocator; shared Allocator allocator;
shared static this() nothrow @nogc
{
allocator = MmapPool.instance;
}
private shared(Allocator) getAllocatorInstance() nothrow @nogc private shared(Allocator) getAllocatorInstance() nothrow @nogc
{ {
if (allocator is null)
{
version (TanyaNative)
{
import tanya.memory.mmappool;
defaultAllocator = MmapPool.instance;
}
else
{
import tanya.memory.mallocator;
defaultAllocator = Mallocator.instance;
}
}
return allocator; return allocator;
} }
@ -114,7 +120,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 +138,7 @@ in
{ {
assert(allocator !is null); assert(allocator !is null);
} }
body do
{ {
.allocator = allocator; .allocator = allocator;
} }
@ -244,7 +250,7 @@ package(tanya) T[] resize(T)(shared Allocator allocator,
return array; return array;
} }
private unittest @nogc nothrow pure @safe unittest
{ {
int[] p; int[] p;
@ -267,6 +273,10 @@ private unittest
*/ */
package(tanya) void[] finalize(T)(ref T* p) package(tanya) void[] finalize(T)(ref T* p)
{ {
if (p is null)
{
return null;
}
static if (hasElaborateDestructor!T) static if (hasElaborateDestructor!T)
{ {
destroy(*p); destroy(*p);
@ -333,7 +343,10 @@ package(tanya) void[] finalize(T)(ref T[] p)
{ {
static if (hasElaborateDestructor!(typeof(p[0]))) static if (hasElaborateDestructor!(typeof(p[0])))
{ {
p.each!((ref e) => destroy(e)); foreach (ref e; p)
{
destroy(e);
}
} }
return p; return p;
} }
@ -354,11 +367,11 @@ void dispose(T)(shared Allocator allocator, auto ref T p)
p = null; p = null;
} }
private unittest @nogc nothrow pure @system unittest
{ {
struct S static struct S
{ {
~this() ~this() @nogc nothrow pure @safe
{ {
} }
} }
@ -368,7 +381,7 @@ private unittest
} }
// Works with interfaces. // Works with interfaces.
private pure unittest @nogc nothrow pure @safe unittest
{ {
interface I interface I
{ {
@ -403,7 +416,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 +455,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)
@ -457,7 +470,7 @@ body
} }
/// ///
unittest @nogc nothrow pure @safe unittest
{ {
int* i = defaultAllocator.make!int(5); int* i = defaultAllocator.make!int(5);
assert(*i == 5); assert(*i == 5);
@ -484,7 +497,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);
@ -492,7 +505,7 @@ body
} }
/// ///
unittest @nogc nothrow pure @safe unittest
{ {
int[] i = defaultAllocator.make!(int[])(2); int[] i = defaultAllocator.make!(int[])(2);
assert(i.length == 2); assert(i.length == 2);

View File

@ -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);
} }
@ -664,7 +664,7 @@ struct Unique(T)
{ {
assert(allocator !is null); assert(allocator !is null);
} }
body do
{ {
this.allocator_ = allocator; this.allocator_ = allocator;
} }
@ -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).

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

@ -5,7 +5,7 @@
/** /**
* This module provides a portable way of using operating system error codes. * This module provides a portable way of using operating system error codes.
* *
* Copyright: Eugene Wissner 2017. * Copyright: Eugene Wissner 2017-2018.
* 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)
@ -14,6 +14,8 @@
*/ */
module tanya.os.error; module tanya.os.error;
import tanya.meta.trait;
// Socket API error. // Socket API error.
private template SAError(int posix, int wsa = posix) private template SAError(int posix, int wsa = posix)
{ {
@ -120,7 +122,7 @@ struct ErrorCode
/// Protocol not available. /// Protocol not available.
noProtocolOption = SAError!(92, 42), noProtocolOption = SAError!(92, 42),
/// The protocol is not implemented orR has not been configured. /// The protocol is not implemented or has not been configured.
protocolNotSupported = SAError!(93, 43), protocolNotSupported = SAError!(93, 43),
/// The support for the specified socket type does not exist in this /// The support for the specified socket type does not exist in this
@ -186,19 +188,66 @@ struct ErrorCode
cancelled = SAError!(125, 103), cancelled = SAError!(125, 103),
} }
/**
* Error descriptions.
*/
private enum ErrorStr : string
{
success = "The operation completed successfully",
noPermission = "Operation not permitted",
interrupted = "Interrupted system call",
badDescriptor = "Bad file descriptor",
wouldBlock = "An operation on a non-blocking socket would block",
noMemory = "Out of memory",
accessDenied = "Access denied",
fault = "An invalid pointer address detected",
noSuchDevice = "No such device",
invalidArgument = "An invalid argument was supplied",
tooManyDescriptors = "The limit on the number of open file descriptors",
noDescriptors = "The limit on the number of open file descriptors",
brokenPipe = "Broken pipe",
nameTooLong = "The name was too long",
notSocket = "A socket operation was attempted on a non-socket",
protocolError = "Protocol error",
messageTooLong = "Message too long",
wrongProtocolType = "Wrong protocol type for socket",
noProtocolOption = "Protocol not available",
protocolNotSupported = "The protocol is not implemented or has not been configured",
socketNotSupported = "Socket type not supported",
operationNotSupported = "The address family is no supported by the protocol family",
addressFamilyNotSupported = "Address family specified is not supported",
addressInUse = "Address already in use",
networkDown = "The network is not available",
networkUnreachable = "No route to host",
networkReset = "Network dropped connection because of reset",
connectionAborted = "The connection has been aborted",
connectionReset = "Connection reset by peer",
noBufferSpace = "No free buffer space is available for a socket operation",
alreadyConnected = "Transport endpoint is already connected",
notConnected = "Transport endpoint is not connected",
shutdown = "Cannot send after transport endpoint shutdown",
timedOut = "Operation timed out",
connectionRefused = "Connection refused",
hostDown = "Host is down",
hostUnreachable = "No route to host",
alreadyStarted = "Operation already in progress",
inProgress = "Operation now in progress",
cancelled = "Operation cancelled",
}
/** /**
* Constructor. * Constructor.
* *
* Params: * Params:
* value = Numeric error code. * value = Numeric error code.
*/ */
this(const ErrorNo value) pure nothrow @safe @nogc this(const ErrorNo value) @nogc nothrow pure @safe
{ {
this.value_ = value; this.value_ = value;
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
ErrorCode ec; ErrorCode ec;
assert(ec == ErrorCode.success); assert(ec == ErrorCode.success);
@ -211,13 +260,13 @@ struct ErrorCode
* Resets this $(D_PSYMBOL ErrorCode) to default * Resets this $(D_PSYMBOL ErrorCode) to default
* ($(D_PSYMBOL ErrorCode.success)). * ($(D_PSYMBOL ErrorCode.success)).
*/ */
void reset() pure nothrow @safe @nogc void reset() @nogc nothrow pure @safe
{ {
this.value_ = ErrorNo.success; this.value_ = ErrorNo.success;
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
auto ec = ErrorCode(ErrorCode.fault); auto ec = ErrorCode(ErrorCode.fault);
assert(ec == ErrorCode.fault); assert(ec == ErrorCode.fault);
@ -241,7 +290,7 @@ struct ErrorCode
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
ErrorCode ec = ErrorCode.fault; ErrorCode ec = ErrorCode.fault;
auto errorNo = cast(ErrorCode.ErrorNo) ec; auto errorNo = cast(ErrorCode.ErrorNo) ec;
@ -258,38 +307,38 @@ struct ErrorCode
* *
* Returns: $(D_KEYWORD this). * Returns: $(D_KEYWORD this).
*/ */
ref ErrorCode opAssign(const ErrorNo that) pure nothrow @safe @nogc ref ErrorCode opAssign(const ErrorNo that) @nogc nothrow pure @safe
{ {
this.value_ = that; this.value_ = that;
return this; return this;
} }
/// ditto /// ditto
ref ErrorCode opAssign()(auto ref const ErrorCode that) ref ErrorCode opAssign(const ErrorCode that) @nogc nothrow pure @safe
pure nothrow @safe @nogc
{ {
this.value_ = that.value_; this.value_ = that.value_;
return this; return this;
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
{ ErrorCode ec;
ErrorCode ec; assert(ec == ErrorCode.success);
assert(ec == ErrorCode.success);
ec = ErrorCode.fault; ec = ErrorCode.fault;
assert(ec == ErrorCode.fault); assert(ec == ErrorCode.fault);
} }
{
auto ec1 = ErrorCode(ErrorCode.fault);
ErrorCode ec2;
assert(ec2 == ErrorCode.success);
ec2 = ec1; ///
assert(ec1 == ec2); @nogc nothrow pure @safe unittest
} {
auto ec1 = ErrorCode(ErrorCode.fault);
ErrorCode ec2;
assert(ec2 == ErrorCode.success);
ec2 = ec1;
assert(ec1 == ec2);
} }
/** /**
@ -300,37 +349,68 @@ struct ErrorCode
* *
* Returns: Whether $(D_KEYWORD this) and $(D_PARAM that) are equal. * Returns: Whether $(D_KEYWORD this) and $(D_PARAM that) are equal.
*/ */
bool opEquals(const ErrorNo that) const pure nothrow @safe @nogc bool opEquals(const ErrorNo that) const @nogc nothrow pure @safe
{ {
return this.value_ == that; return this.value_ == that;
} }
/// ditto /// ditto
bool opEquals()(auto ref const ErrorCode that) bool opEquals(const ErrorCode that) const @nogc nothrow pure @safe
const pure nothrow @safe @nogc
{ {
return this.value_ == that.value_; return this.value_ == that.value_;
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
{ ErrorCode ec1 = ErrorCode.fault;
ErrorCode ec1 = ErrorCode.fault; ErrorCode ec2 = ErrorCode.accessDenied;
ErrorCode ec2 = ErrorCode.accessDenied;
assert(ec1 != ec2); assert(ec1 != ec2);
assert(ec1 != ErrorCode.accessDenied); assert(ec1 != ErrorCode.accessDenied);
assert(ErrorCode.fault != ec2); assert(ErrorCode.fault != ec2);
} }
{
ErrorCode ec1 = ErrorCode.fault;
ErrorCode ec2 = ErrorCode.fault;
assert(ec1 == ec2); ///
assert(ec1 == ErrorCode.fault); @nogc nothrow pure @safe unittest
assert(ErrorCode.fault == ec2); {
ErrorCode ec1 = ErrorCode.fault;
ErrorCode ec2 = ErrorCode.fault;
assert(ec1 == ec2);
assert(ec1 == ErrorCode.fault);
assert(ErrorCode.fault == ec2);
}
/**
* Returns string describing the error number. If a description for a
* specific error number is not available, returns $(D_KEYWORD null).
*
* Returns: String describing the error number.
*/
string toString() const @nogc nothrow pure @safe
{
foreach (e; __traits(allMembers, ErrorNo))
{
if (__traits(getMember, ErrorNo, e) == this.value_)
{
return __traits(getMember, ErrorStr, e);
}
} }
return null;
}
///
@nogc nothrow pure @safe unittest
{
ErrorCode ec = ErrorCode.fault;
assert(ec.toString() == "An invalid pointer address detected");
}
@nogc nothrow pure @safe unittest
{
ErrorCode ec = cast(ErrorCode.ErrorNo) -1;
assert(ec.toString() is null);
} }
private ErrorNo value_ = ErrorNo.success; private ErrorNo value_ = ErrorNo.success;

View File

@ -59,7 +59,7 @@ in
{ {
assert(array.length > 0); assert(array.length > 0);
} }
body do
{ {
return array[0]; return array[0];
} }
@ -99,7 +99,7 @@ in
{ {
assert(array.length > 0); assert(array.length > 0);
} }
body do
{ {
return array[$ - 1]; return array[$ - 1];
} }
@ -138,7 +138,7 @@ in
{ {
assert(array.length > 0); assert(array.length > 0);
} }
body do
{ {
array = array[1 .. $]; array = array[1 .. $];
} }
@ -149,7 +149,7 @@ in
{ {
assert(array.length > 0); assert(array.length > 0);
} }
body do
{ {
array = array[0 .. $ - 1]; array = array[0 .. $ - 1];
} }

View File

@ -633,8 +633,8 @@ template isBidirectionalRange(R)
* *
* A random-access range is a range that allows random access to its * A random-access range is a range that allows random access to its
* elements by index using $(D_INLINECODE [])-operator (defined with * elements by index using $(D_INLINECODE [])-operator (defined with
* $(D_INLINECODE opIndex())). Further a random access range should be a * $(D_INLINECODE opIndex())). Further a random access range should
* bidirectional range that also has a length or an infinite forward range. * have a length or be infinite.
* *
* Params: * Params:
* R = The type to be tested. * R = The type to be tested.
@ -642,19 +642,21 @@ template isBidirectionalRange(R)
* Returns: $(D_KEYWORD true) if $(D_PARAM R) is a random-access range, * Returns: $(D_KEYWORD true) if $(D_PARAM R) is a random-access range,
* $(D_KEYWORD false) otherwise. * $(D_KEYWORD false) otherwise.
* *
* See_Also: $(D_PSYMBOL isBidirectionalRange), * See_Also: $(D_PSYMBOL isInfinite),
* $(D_PSYMBOL isForwardRange),
* $(D_PSYMBOL isInfinite),
* $(D_PSYMBOL hasLength). * $(D_PSYMBOL hasLength).
*
* Note: This definition differs from `std.range.primitives.isRandomAccessRange`
* in the D standard library in that it does not also require $(D_PARAM R) to
* be a forward range and a bidirectional range. Those properties may be tested
* separately with $(D_PSYMBOL isForwardRange) and
* $(D_PSYMBOL isBidirectionalRange).
*/ */
template isRandomAccessRange(R) template isRandomAccessRange(R)
{ {
static if (is(ReturnType!((R r) => r.opIndex(size_t.init)) U)) static if (is(ReturnType!((R r) => r.opIndex(size_t.init)) U))
{ {
private enum bool isBidirectional = isBidirectionalRange!R enum bool isRandomAccessRange = isInputRange!R
&& hasLength!R; && (hasLength!R || isInfinite!R)
private enum bool isForward = isInfinite!R && isForwardRange!R;
enum bool isRandomAccessRange = (isBidirectional || isForward)
&& is(U == ReturnType!((R r) => r.front())); && is(U == ReturnType!((R r) => r.front()));
} }
else else
@ -1053,7 +1055,7 @@ in
assert(count <= range.length); assert(count <= range.length);
} }
} }
body do
{ {
static if (hasSlicing!R) static if (hasSlicing!R)
{ {
@ -1112,7 +1114,7 @@ in
assert(count <= range.length); assert(count <= range.length);
} }
} }
body do
{ {
static if (hasSlicing!R) static if (hasSlicing!R)
{ {

View File

@ -92,7 +92,7 @@ template Pair(Specs...)
} }
/// ///
unittest @nogc nothrow pure @safe unittest
{ {
static assert(is(Pair!(int, int))); static assert(is(Pair!(int, int)));
static assert(!is(Pair!(int, 5))); static assert(!is(Pair!(int, 5)));